Bug Summary

File:lib/lwan-request.c
Warning:line 1715, column 13
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name lwan-request.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -fno-plt -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/buildbot/lwan-worker/clang-analyze/build/src/lib -resource-dir /usr/lib/clang/14.0.6 -include /home/buildbot/lwan-worker/clang-analyze/build/lwan-build-config.h -D _FILE_OFFSET_BITS=64 -D _TIME_BITS=64 -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib/missing -I /usr/include/python3.10 -I /usr/include/luajit-2.1 -I /usr/include/valgrind -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib -I /home/buildbot/lwan-worker/clang-analyze/build -internal-isystem /usr/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../x86_64-pc-linux-gnu/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -Wno-free-nonheap-object -std=gnu99 -fdebug-compilation-dir=/home/buildbot/lwan-worker/clang-analyze/build/src/lib -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/buildbot/lwan-worker/clang-analyze/CLANG/2022-08-27-050644-418776-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c
1/*
2 * lwan - simple web server
3 * Copyright (c) 2012-2014 L. A. F. Pereira <l@tia.mat.br>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#define _GNU_SOURCE
21#include <arpa/inet.h>
22#include <assert.h>
23#include <errno(*__errno_location ()).h>
24#include <fcntl.h>
25#include <inttypes.h>
26#include <limits.h>
27#include <stddef.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <strings.h>
32#include <sys/mman.h>
33#include <sys/socket.h>
34#include <sys/stat.h>
35#include <sys/types.h>
36#include <sys/vfs.h>
37#include <unistd.h>
38
39#include "lwan-private.h"
40
41#include "base64.h"
42#include "list.h"
43#include "lwan-config.h"
44#include "lwan-http-authorize.h"
45#include "lwan-io-wrappers.h"
46#include "sha1.h"
47
48#define HEADER_VALUE_SEPARATOR_LEN(sizeof(": ") - 1) (sizeof(": ") - 1)
49#define HEADER_TERMINATOR_LEN(sizeof("\r\n") - 1) (sizeof("\r\n") - 1)
50#define MIN_REQUEST_SIZE(sizeof("GET / HTTP/1.1\r\n\r\n") - 1) (sizeof("GET / HTTP/1.1\r\n\r\n") - 1)
51
52enum lwan_read_finalizer {
53 FINALIZER_DONE,
54 FINALIZER_TRY_AGAIN,
55 FINALIZER_TIMEOUT,
56};
57
58struct proxy_header_v2 {
59 uint8_t sig[12];
60 uint8_t cmd_ver;
61 uint8_t fam;
62 uint16_t len;
63 union {
64 struct {
65 in_addr_t src_addr;
66 in_addr_t dst_addr;
67 uint16_t src_port;
68 uint16_t dst_port;
69 } ip4;
70 struct {
71 struct in6_addr src_addr;
72 struct in6_addr dst_addr;
73 uint16_t src_port;
74 uint16_t dst_port;
75 } ip6;
76 } addr;
77};
78
79static char decode_hex_digit(char ch) __attribute__((pure));
80static char *ignore_leading_whitespace(char *buffer) __attribute__((pure));
81
82
83static bool_Bool
84parse_ascii_port(char *port, unsigned short *out)
85{
86 unsigned long parsed;
87 char *end_ptr;
88
89 errno(*__errno_location ()) = 0;
90 parsed = strtoul(port, &end_ptr, 10);
91
92 if (UNLIKELY(errno != 0)__builtin_expect((((*__errno_location ()) != 0)), (0)))
93 return false0;
94
95 if (UNLIKELY(*end_ptr != '\0')__builtin_expect(((*end_ptr != '\0')), (0)))
96 return false0;
97
98 if (UNLIKELY((unsigned long)(unsigned short)parsed != parsed)__builtin_expect((((unsigned long)(unsigned short)parsed != parsed
)), (0))
)
99 return false0;
100
101 *out = htons((unsigned short)parsed);
102 return true1;
103}
104
105static char *
106strsep_char(char *strp, const char *end, char delim)
107{
108 char *ptr;
109
110 if (UNLIKELY(!strp)__builtin_expect(((!strp)), (0)))
111 return NULL((void*)0);
112
113 if (UNLIKELY(strp > end)__builtin_expect(((strp > end)), (0)))
114 return NULL((void*)0);
115
116 ptr = strchr(strp, delim);
117 if (UNLIKELY(!ptr)__builtin_expect(((!ptr)), (0)))
118 return NULL((void*)0);
119
120 *ptr = '\0';
121 return ptr + 1;
122}
123
124static char *
125parse_proxy_protocol_v1(struct lwan_request *request, char *buffer)
126{
127 static const size_t line_size = 108;
128 char *end, *protocol, *src_addr, *dst_addr, *src_port, *dst_port;
129 unsigned int size;
130 struct lwan_proxy *const proxy = request->proxy;
131
132 end = memchr(buffer, '\r', line_size);
133 if (UNLIKELY(!end || end[1] != '\n')__builtin_expect(((!end || end[1] != '\n')), (0)))
134 return NULL((void*)0);
135 *end = '\0';
136 size = (unsigned int) (end + 2 - buffer);
137
138 protocol = buffer + sizeof("PROXY ") - 1;
139 src_addr = strsep_char(protocol, end, ' ');
140 dst_addr = strsep_char(src_addr, end, ' ');
141 src_port = strsep_char(dst_addr, end, ' ');
142 dst_port = strsep_char(src_port, end, ' ');
143
144 if (UNLIKELY(!dst_port)__builtin_expect(((!dst_port)), (0)))
145 return NULL((void*)0);
146
147 STRING_SWITCH(protocol)switch (string_as_uint32(protocol)) {
148 case STR4_INT('T', 'C', 'P', '4')((uint32_t)(('T') | ('C') << 8 | ('P') << 16 | ('4'
) << 24))
: {
149 struct sockaddr_in *from = &proxy->from.ipv4;
150 struct sockaddr_in *to = &proxy->to.ipv4;
151
152 from->sin_family = to->sin_family = AF_INET2;
153
154 if (UNLIKELY(inet_pton(AF_INET, src_addr, &from->sin_addr) <= 0)__builtin_expect(((inet_pton(2, src_addr, &from->sin_addr
) <= 0)), (0))
)
155 return NULL((void*)0);
156 if (UNLIKELY(inet_pton(AF_INET, dst_addr, &to->sin_addr) <= 0)__builtin_expect(((inet_pton(2, dst_addr, &to->sin_addr
) <= 0)), (0))
)
157 return NULL((void*)0);
158 if (UNLIKELY(!parse_ascii_port(src_port, &from->sin_port))__builtin_expect(((!parse_ascii_port(src_port, &from->
sin_port))), (0))
)
159 return NULL((void*)0);
160 if (UNLIKELY(!parse_ascii_port(dst_port, &to->sin_port))__builtin_expect(((!parse_ascii_port(dst_port, &to->sin_port
))), (0))
)
161 return NULL((void*)0);
162
163 break;
164 }
165 case STR4_INT('T', 'C', 'P', '6')((uint32_t)(('T') | ('C') << 8 | ('P') << 16 | ('6'
) << 24))
: {
166 struct sockaddr_in6 *from = &proxy->from.ipv6;
167 struct sockaddr_in6 *to = &proxy->to.ipv6;
168
169 from->sin6_family = to->sin6_family = AF_INET610;
170
171 if (UNLIKELY(inet_pton(AF_INET6, src_addr, &from->sin6_addr) <= 0)__builtin_expect(((inet_pton(10, src_addr, &from->sin6_addr
) <= 0)), (0))
)
172 return NULL((void*)0);
173 if (UNLIKELY(inet_pton(AF_INET6, dst_addr, &to->sin6_addr) <= 0)__builtin_expect(((inet_pton(10, dst_addr, &to->sin6_addr
) <= 0)), (0))
)
174 return NULL((void*)0);
175 if (UNLIKELY(!parse_ascii_port(src_port, &from->sin6_port))__builtin_expect(((!parse_ascii_port(src_port, &from->
sin6_port))), (0))
)
176 return NULL((void*)0);
177 if (UNLIKELY(!parse_ascii_port(dst_port, &to->sin6_port))__builtin_expect(((!parse_ascii_port(dst_port, &to->sin6_port
))), (0))
)
178 return NULL((void*)0);
179
180 break;
181 }
182 default:
183 return NULL((void*)0);
184 }
185
186 request->flags |= REQUEST_PROXIED;
187 return buffer + size;
188}
189
190static char *parse_proxy_protocol_v2(struct lwan_request *request, char *buffer)
191{
192 struct proxy_header_v2 *hdr = (struct proxy_header_v2 *)buffer;
193 struct lwan_request_parser_helper *helper = request->helper;
194 const unsigned int proto_signature_length = 16;
195 unsigned int size;
196 struct lwan_proxy *const proxy = request->proxy;
197
198 enum { LOCAL = 0x20, PROXY = 0x21, TCP4 = 0x11, TCP6 = 0x21 };
199
200 size = proto_signature_length + (unsigned int)ntohs(hdr->len);
201 if (UNLIKELY(size > (unsigned int)sizeof(*hdr))__builtin_expect(((size > (unsigned int)sizeof(*hdr))), (0
))
)
202 return NULL((void*)0);
203 if (UNLIKELY(size >= helper->buffer->len)__builtin_expect(((size >= helper->buffer->len)), (0
))
)
204 return NULL((void*)0);
205
206 if (LIKELY(hdr->cmd_ver == PROXY)__builtin_expect((!!(hdr->cmd_ver == PROXY)), (1))) {
207 if (hdr->fam == TCP4) {
208 struct sockaddr_in *from = &proxy->from.ipv4;
209 struct sockaddr_in *to = &proxy->to.ipv4;
210
211 to->sin_family = from->sin_family = AF_INET2;
212
213 from->sin_addr.s_addr = hdr->addr.ip4.src_addr;
214 from->sin_port = hdr->addr.ip4.src_port;
215
216 to->sin_addr.s_addr = hdr->addr.ip4.dst_addr;
217 to->sin_port = hdr->addr.ip4.dst_port;
218 } else if (hdr->fam == TCP6) {
219 struct sockaddr_in6 *from = &proxy->from.ipv6;
220 struct sockaddr_in6 *to = &proxy->to.ipv6;
221
222 from->sin6_family = to->sin6_family = AF_INET610;
223
224 from->sin6_addr = hdr->addr.ip6.src_addr;
225 from->sin6_port = hdr->addr.ip6.src_port;
226
227 to->sin6_addr = hdr->addr.ip6.dst_addr;
228 to->sin6_port = hdr->addr.ip6.dst_port;
229 } else {
230 return NULL((void*)0);
231 }
232 } else if (hdr->cmd_ver == LOCAL) {
233 struct sockaddr_in *from = &proxy->from.ipv4;
234 struct sockaddr_in *to = &proxy->to.ipv4;
235
236 from->sin_family = to->sin_family = AF_UNSPEC0;
237 } else {
238 return NULL((void*)0);
239 }
240
241 request->flags |= REQUEST_PROXIED;
242 return buffer + size;
243}
244
245#if !defined(LWAN_HAVE_BUILTIN_EXPECT_PROBABILITY)
246#define __builtin_expect_with_probability(value1, value2, probability) \
247 __builtin_expect(value1, value2)
248#endif
249
250static ALWAYS_INLINEinline __attribute__((always_inline)) char *identify_http_method(struct lwan_request *request,
251 char *buffer)
252{
253 const uint32_t first_four = string_as_uint32(buffer);
254
255#define GENERATE_IF(upper, lower, mask, constant, probability) \
256 if (__builtin_expect_with_probability(first_four == (constant), 1, \
257 probability)) { \
258 request->flags |= (mask); \
259 return buffer + sizeof(#upper); \
260 }
261
262 FOR_EACH_REQUEST_METHOD(GENERATE_IF)GENERATE_IF(GET, get, (1 << 0), (((uint32_t)(('G') | ('E'
) << 8 | ('T') << 16 | (' ') << 24))), 0.6)
GENERATE_IF(POST, post, (1 << 3 | 1 << 1 | 1 <<
0), (((uint32_t)(('P') | ('O') << 8 | ('S') << 16
| ('T') << 24))), 0.2) GENERATE_IF(HEAD, head, (1 <<
1), (((uint32_t)(('H') | ('E') << 8 | ('A') << 16
| ('D') << 24))), 0.2) GENERATE_IF(OPTIONS, options, (
1 << 2), (((uint32_t)(('O') | ('P') << 8 | ('T') <<
16 | ('I') << 24))), 0.1) GENERATE_IF(DELETE, delete, (
1 << 1 | 1 << 2), (((uint32_t)(('D') | ('E') <<
8 | ('L') << 16 | ('E') << 24))), 0.1) GENERATE_IF
(PUT, put, (1 << 3 | 1 << 2 | 1 << 0), (((uint32_t
)(('P') | ('U') << 8 | ('T') << 16 | (' ') <<
24))), 0.1)
263
264#undef GENERATE_IF
265
266 return NULL((void*)0);
267}
268
269static ALWAYS_INLINEinline __attribute__((always_inline)) char decode_hex_digit(char ch)
270{
271 static const char hex_digit_tbl[256] = {
272 ['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4, ['5'] = 5,
273 ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9, ['a'] = 10, ['b'] = 11,
274 ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15, ['A'] = 10, ['B'] = 11,
275 ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15,
276 };
277 return hex_digit_tbl[(unsigned char)ch];
278}
279
280static ssize_t url_decode(char *str)
281{
282 if (UNLIKELY(!str)__builtin_expect(((!str)), (0)))
283 return -EINVAL22;
284
285 char *ch, *decoded;
286 for (decoded = ch = str; *ch; ch++) {
287 if (*ch == '%') {
288 char tmp =
289 (char)(decode_hex_digit(ch[1]) << 4 | decode_hex_digit(ch[2]));
290
291 if (UNLIKELY(!tmp)__builtin_expect(((!tmp)), (0)))
292 return -EINVAL22;
293
294 *decoded++ = tmp;
295 ch += 2;
296 } else if (*ch == '+') {
297 *decoded++ = ' ';
298 } else {
299 *decoded++ = *ch;
300 }
301 }
302
303 *decoded = '\0';
304 return (ssize_t)(decoded - str);
305}
306
307static int key_value_compare(const void *a, const void *b)
308{
309 return strcmp(((const struct lwan_key_value *)a)->key,
310 ((const struct lwan_key_value *)b)->key);
311}
312
313static void
314reset_key_value_array(void *data)
315{
316 struct lwan_key_value_array *array = data;
317
318 lwan_key_value_array_reset(array);
319}
320
321static void parse_key_values(struct lwan_request *request,
322 struct lwan_value *helper_value,
323 struct lwan_key_value_array *array,
324 ssize_t (*decode_value)(char *value),
325 const char separator)
326{
327 struct lwan_key_value *kv;
328 char *ptr = helper_value->value;
329 const char *end = helper_value->value + helper_value->len;
330 struct coro_defer *reset_defer;
331
332 if (!helper_value->len)
333 return;
334
335 lwan_key_value_array_init(array);
336 reset_defer = coro_defer(request->conn->coro, reset_key_value_array, array);
337
338 do {
339 char *key, *value;
340
341 while (*ptr == ' ' || *ptr == separator)
342 ptr++;
343 if (UNLIKELY(*ptr == '\0')__builtin_expect(((*ptr == '\0')), (0)))
344 break;
345
346 key = ptr;
347 ptr = strsep_char(key, end, separator);
348
349 value = strsep_char(key, end, '=');
350 if (UNLIKELY(!value)__builtin_expect(((!value)), (0))) {
351 value = "";
352 } else if (UNLIKELY(decode_value(value) < 0)__builtin_expect(((decode_value(value) < 0)), (0))) {
353 /* Disallow values that failed decoding, but allow empty values */
354 goto error;
355 }
356
357 if (UNLIKELY(decode_value(key) <= 0)__builtin_expect(((decode_value(key) <= 0)), (0))) {
358 /* Disallow keys that failed decoding, or empty keys */
359 goto error;
360 }
361
362 kv = lwan_key_value_array_append(array);
363 if (UNLIKELY(!kv)__builtin_expect(((!kv)), (0)))
364 goto error;
365
366 kv->key = key;
367 kv->value = value;
368 } while (ptr);
369
370 lwan_key_value_array_sort(array, key_value_compare);
371
372 return;
373
374error:
375 coro_defer_fire_and_disarm(request->conn->coro, reset_defer);
376}
377
378static ssize_t
379identity_decode(char *input __attribute__((unused)))
380{
381 return 1;
382}
383
384static void parse_cookies(struct lwan_request *request)
385{
386 const char *cookies = lwan_request_get_header(request, "Cookie");
387
388 if (!cookies)
389 return;
390
391 struct lwan_value header = {.value = (char *)cookies,
392 .len = strlen(cookies)};
393 parse_key_values(request, &header, &request->helper->cookies,
394 identity_decode, ';');
395}
396
397static void parse_query_string(struct lwan_request *request)
398{
399 struct lwan_request_parser_helper *helper = request->helper;
400
401 parse_key_values(request, &helper->query_string, &helper->query_params,
402 url_decode, '&');
403}
404
405static void parse_form_data(struct lwan_request *request)
406{
407 struct lwan_request_parser_helper *helper = request->helper;
408 static const char content_type[] = "application/x-www-form-urlencoded";
409
410 if (helper->content_type.len < sizeof(content_type) - 1)
411 return;
412 if (UNLIKELY(strncmp(helper->content_type.value, content_type,__builtin_expect(((strncmp(helper->content_type.value, content_type
, sizeof(content_type) - 1))), (0))
413 sizeof(content_type) - 1))__builtin_expect(((strncmp(helper->content_type.value, content_type
, sizeof(content_type) - 1))), (0))
)
414 return;
415
416 parse_key_values(request, &helper->body_data, &helper->post_params,
417 url_decode, '&');
418}
419
420static void find_query_string(struct lwan_request *request, const char *space)
421{
422 struct lwan_request_parser_helper *helper = request->helper;
423
424 char *query_string = memchr(request->url.value, '?', request->url.len);
425 if (query_string) {
426 *query_string = '\0';
427 helper->query_string.value = query_string + 1;
428 helper->query_string.len = (size_t)(space - query_string - 1);
429 request->url.len -= helper->query_string.len + 1;
430 request->flags |= REQUEST_HAS_QUERY_STRING;
431 }
432}
433
434static char *
435identify_http_path(struct lwan_request *request, char *buffer)
436{
437 struct lwan_request_parser_helper *helper = request->helper;
438 static const size_t minimal_request_line_len = sizeof("/ HTTP/1.0") - 1;
439 char *space, *end_of_line;
440 ptrdiff_t end_len;
441
442 if (UNLIKELY(*buffer != '/')__builtin_expect(((*buffer != '/')), (0)))
443 return NULL((void*)0);
444
445 end_len = buffer - helper->buffer->value;
446 if (UNLIKELY((size_t)end_len >= helper->buffer->len)__builtin_expect((((size_t)end_len >= helper->buffer->
len)), (0))
)
447 return NULL((void*)0);
448
449 end_of_line = memchr(buffer, '\r', helper->buffer->len - (size_t)end_len);
450 if (UNLIKELY(!end_of_line)__builtin_expect(((!end_of_line)), (0)))
451 return NULL((void*)0);
452 if (UNLIKELY((size_t)(end_of_line - buffer) < minimal_request_line_len)__builtin_expect((((size_t)(end_of_line - buffer) < minimal_request_line_len
)), (0))
)
453 return NULL((void*)0);
454 *end_of_line = '\0';
455
456 space = end_of_line - sizeof("HTTP/X.X");
457
458 request->url.value = buffer;
459 request->url.len = (size_t)(space - buffer);
460 find_query_string(request, space);
461 request->original_url = request->url;
462
463 *space++ = '\0';
464
465 STRING_SWITCH_LARGE(space)switch (string_as_uint64(space)) {
466 case STR8_INT('H','T','T','P','/','1','.','0')((uint64_t)((uint32_t)(('H') | ('T') << 8 | ('T') <<
16 | ('P') << 24)) | (uint64_t)((uint32_t)(('/') | ('1'
) << 8 | ('.') << 16 | ('0') << 24)) <<
32)
:
467 request->flags |= REQUEST_IS_HTTP_1_0;
468 break;
469 case STR8_INT('H','T','T','P','/','1','.','1')((uint64_t)((uint32_t)(('H') | ('T') << 8 | ('T') <<
16 | ('P') << 24)) | (uint64_t)((uint32_t)(('/') | ('1'
) << 8 | ('.') << 16 | ('1') << 24)) <<
32)
:
470 break;
471 default:
472 return NULL((void*)0);
473 }
474
475 return end_of_line + 1;
476}
477
478__attribute__((noinline)) static void set_header_value(
479 struct lwan_value *header, char *end, char *p, size_t header_len)
480{
481 p += header_len;
482
483 if (LIKELY(string_as_uint16(p) == STR2_INT(':', ' '))__builtin_expect((!!(string_as_uint16(p) == ((uint16_t)((':')
| (' ') << 8)))), (1))
) {
484 *end = '\0';
485 char *value = p + sizeof(": ") - 1;
486
487 header->value = value;
488 header->len = (size_t)(end - value);
489 }
490}
491
492#define HEADER_LENGTH(hdr) \
493 ({ \
494 if (UNLIKELY(end - sizeof(hdr) + 1 < p)__builtin_expect(((end - sizeof(hdr) + 1 < p)), (0))) \
495 continue; \
496 sizeof(hdr) - 1; \
497 })
498
499#define SET_HEADER_VALUE(dest, hdr) \
500 do { \
501 const size_t header_len = HEADER_LENGTH(hdr); \
502 set_header_value(&(helper->dest), end, p, header_len); \
503 } while (0)
504
505static ALWAYS_INLINEinline __attribute__((always_inline)) ssize_t find_headers(char **header_start,
506 struct lwan_value *request_buffer,
507 char **next_request)
508{
509 char *buffer = request_buffer->value;
510 char *buffer_end = buffer + request_buffer->len;
511 ssize_t n_headers = 0;
512 char *next_header;
513
514 for (char *next_chr = buffer + 1;;) {
515 next_header = memchr(next_chr, '\r', (size_t)(buffer_end - next_chr));
516
517 if (UNLIKELY(!next_header)__builtin_expect(((!next_header)), (0)))
518 return -1;
519
520 if (next_chr == next_header) {
521 if (buffer_end - next_chr >= (ptrdiff_t)HEADER_TERMINATOR_LEN(sizeof("\r\n") - 1)) {
522 STRING_SWITCH_SMALL (next_header)switch (string_as_uint16(next_header)) {
523 case STR2_INT('\r', '\n')((uint16_t)(('\r') | ('\n') << 8)):
524 *next_request = next_header + HEADER_TERMINATOR_LEN(sizeof("\r\n") - 1);
525 }
526 }
527 goto out;
528 }
529
530 /* Is there at least a space for a minimal (H)eader and a (V)alue? */
531 if (LIKELY(next_header - next_chr >= (ptrdiff_t)(sizeof("H: V") - 1))__builtin_expect((!!(next_header - next_chr >= (ptrdiff_t)
(sizeof("H: V") - 1))), (1))
) {
532 header_start[n_headers++] = next_chr;
533
534 if (UNLIKELY(n_headers >= N_HEADER_START - 1)__builtin_expect(((n_headers >= 64 - 1)), (0)))
535 return -1;
536 } else {
537 /* Better to abort early if there's no space. */
538 return -1;
539 }
540
541 next_chr = next_header + HEADER_TERMINATOR_LEN(sizeof("\r\n") - 1);
542 if (UNLIKELY(next_chr >= buffer_end)__builtin_expect(((next_chr >= buffer_end)), (0)))
543 return -1;
544 }
545
546out:
547 header_start[n_headers] = next_header;
548 return n_headers;
549}
550
551static bool_Bool parse_headers(struct lwan_request_parser_helper *helper,
552 char *buffer)
553{
554 char **header_start = helper->header_start;
555 ssize_t n_headers = 0;
556
557 n_headers = find_headers(header_start, helper->buffer,
558 &helper->next_request);
559 if (UNLIKELY(n_headers < 0)__builtin_expect(((n_headers < 0)), (0)))
560 return false0;
561
562 for (ssize_t i = 0; i < n_headers; i++) {
563 char *p = header_start[i];
564 char *end = header_start[i + 1] - HEADER_TERMINATOR_LEN(sizeof("\r\n") - 1);
565
566 STRING_SWITCH_L (p)switch (((string_as_uint32(p)) | (uint32_t)0x20202020)) {
567 case STR4_INT_L('A', 'c', 'c', 'e')((((uint32_t)(('A') | ('c') << 8 | ('c') << 16 | (
'e') << 24))) | (uint32_t)0x20202020)
:
568 p += HEADER_LENGTH("Accept");
569
570 STRING_SWITCH_L (p)switch (((string_as_uint32(p)) | (uint32_t)0x20202020)) {
571 case STR4_INT_L('-', 'E', 'n', 'c')((((uint32_t)(('-') | ('E') << 8 | ('n') << 16 | (
'c') << 24))) | (uint32_t)0x20202020)
:
572 SET_HEADER_VALUE(accept_encoding, "-Encoding");
573 break;
574 }
575 break;
576 case STR4_INT_L('C', 'o', 'n', 'n')((((uint32_t)(('C') | ('o') << 8 | ('n') << 16 | (
'n') << 24))) | (uint32_t)0x20202020)
:
577 SET_HEADER_VALUE(connection, "Connection");
578 break;
579 case STR4_INT_L('C', 'o', 'n', 't')((((uint32_t)(('C') | ('o') << 8 | ('n') << 16 | (
't') << 24))) | (uint32_t)0x20202020)
:
580 p += HEADER_LENGTH("Content");
581
582 STRING_SWITCH_L (p)switch (((string_as_uint32(p)) | (uint32_t)0x20202020)) {
583 case STR4_INT_L('-', 'T', 'y', 'p')((((uint32_t)(('-') | ('T') << 8 | ('y') << 16 | (
'p') << 24))) | (uint32_t)0x20202020)
:
584 SET_HEADER_VALUE(content_type, "-Type");
585 break;
586 case STR4_INT_L('-', 'L', 'e', 'n')((((uint32_t)(('-') | ('L') << 8 | ('e') << 16 | (
'n') << 24))) | (uint32_t)0x20202020)
:
587 SET_HEADER_VALUE(content_length, "-Length");
588 break;
589 }
590 break;
591 case STR4_INT_L('I', 'f', '-', 'M')((((uint32_t)(('I') | ('f') << 8 | ('-') << 16 | (
'M') << 24))) | (uint32_t)0x20202020)
:
592 SET_HEADER_VALUE(if_modified_since.raw, "If-Modified-Since");
593 break;
594 case STR4_INT_L('H', 'o', 's', 't')((((uint32_t)(('H') | ('o') << 8 | ('s') << 16 | (
't') << 24))) | (uint32_t)0x20202020)
:
595 SET_HEADER_VALUE(host, "Host");
596 break;
597 case STR4_INT_L('R', 'a', 'n', 'g')((((uint32_t)(('R') | ('a') << 8 | ('n') << 16 | (
'g') << 24))) | (uint32_t)0x20202020)
:
598 SET_HEADER_VALUE(range.raw, "Range");
599 break;
600 }
601 }
602
603 helper->n_header_start = (size_t)n_headers;
604 return true1;
605}
606#undef HEADER_LENGTH
607#undef SET_HEADER_VALUE
608
609ssize_t lwan_find_headers(char **header_start, struct lwan_value *buffer,
610 char **next_request)
611{
612 return find_headers(header_start, buffer, next_request);
613}
614
615static void parse_if_modified_since(struct lwan_request_parser_helper *helper)
616{
617 static const size_t header_len =
618 sizeof("Wed, 17 Apr 2019 13:59:27 GMT") - 1;
619 time_t parsed;
620
621 if (UNLIKELY(helper->if_modified_since.raw.len != header_len)__builtin_expect(((helper->if_modified_since.raw.len != header_len
)), (0))
)
622 return;
623
624 if (UNLIKELY(lwan_parse_rfc_time(helper->if_modified_since.raw.value,__builtin_expect(((lwan_parse_rfc_time(helper->if_modified_since
.raw.value, &parsed) < 0)), (0))
625 &parsed) < 0)__builtin_expect(((lwan_parse_rfc_time(helper->if_modified_since
.raw.value, &parsed) < 0)), (0))
)
626 return;
627
628 helper->if_modified_since.parsed = parsed;
629}
630
631static bool_Bool
632parse_off_without_sign(const char *ptr, char **end, off_t *off)
633{
634 unsigned long long val;
635
636 static_assert_Static_assert(sizeof(val) >= sizeof(off_t),
637 "off_t fits in a long long");
638
639 errno(*__errno_location ()) = 0;
640
641 val = strtoull(ptr, end, 10);
642 if (UNLIKELY(val == 0 && *end == ptr)__builtin_expect(((val == 0 && *end == ptr)), (0)))
643 return false0;
644 if (UNLIKELY(errno != 0)__builtin_expect((((*__errno_location ()) != 0)), (0)))
645 return false0;
646 if (UNLIKELY(val > OFF_MAX)__builtin_expect(((val > 9223372036854775807LL)), (0)))
647 return false0;
648
649 *off = (off_t)val;
650 return true1;
651}
652
653static void
654parse_range(struct lwan_request_parser_helper *helper)
655{
656 if (UNLIKELY(helper->range.raw.len <= (sizeof("bytes=") - 1))__builtin_expect(((helper->range.raw.len <= (sizeof("bytes="
) - 1))), (0))
)
657 return;
658
659 char *range = helper->range.raw.value;
660 if (UNLIKELY(strncmp(range, "bytes=", sizeof("bytes=") - 1))__builtin_expect(((strncmp(range, "bytes=", sizeof("bytes=") -
1))), (0))
)
661 return;
662
663 range += sizeof("bytes=") - 1;
664
665 off_t from, to;
666 char *end;
667
668 if (*range == '-') {
669 from = 0;
670
671 if (!parse_off_without_sign(range + 1, &end, &to))
672 goto invalid_range;
673 if (*end != '\0')
674 goto invalid_range;
675 } else if (lwan_char_isdigit(*range)) {
676 if (!parse_off_without_sign(range, &end, &from))
677 goto invalid_range;
678 if (*end != '-')
679 goto invalid_range;
680
681 range = end + 1;
682 if (*range == '\0') {
683 to = -1;
684 } else {
685 if (!parse_off_without_sign(range, &end, &to))
686 goto invalid_range;
687 if (*end != '\0')
688 goto invalid_range;
689 }
690 } else {
691invalid_range:
692 to = from = -1;
693 }
694
695 helper->range.from = from;
696 helper->range.to = to;
697}
698
699static void
700parse_accept_encoding(struct lwan_request *request)
701{
702 struct lwan_request_parser_helper *helper = request->helper;
703
704 if (!helper->accept_encoding.len)
705 return;
706
707 for (const char *p = helper->accept_encoding.value; *p; p++) {
708 STRING_SWITCH(p)switch (string_as_uint32(p)) {
709 case STR4_INT('d','e','f','l')((uint32_t)(('d') | ('e') << 8 | ('f') << 16 | ('l'
) << 24))
:
710 case STR4_INT(' ','d','e','f')((uint32_t)((' ') | ('d') << 8 | ('e') << 16 | ('f'
) << 24))
:
711 request->flags |= REQUEST_ACCEPT_DEFLATE;
712 break;
713 case STR4_INT('g','z','i','p')((uint32_t)(('g') | ('z') << 8 | ('i') << 16 | ('p'
) << 24))
:
714 case STR4_INT(' ','g','z','i')((uint32_t)((' ') | ('g') << 8 | ('z') << 16 | ('i'
) << 24))
:
715 request->flags |= REQUEST_ACCEPT_GZIP;
716 break;
717#if defined(LWAN_HAVE_ZSTD)
718 case STR4_INT('z','s','t','d')((uint32_t)(('z') | ('s') << 8 | ('t') << 16 | ('d'
) << 24))
:
719 case STR4_INT(' ','z','s','t')((uint32_t)((' ') | ('z') << 8 | ('s') << 16 | ('t'
) << 24))
:
720 request->flags |= REQUEST_ACCEPT_ZSTD;
721 break;
722#endif
723#if defined(LWAN_HAVE_BROTLI)
724 default:
725 while (lwan_char_isspace(*p))
726 p++;
727
728 STRING_SWITCH_SMALL(p)switch (string_as_uint16(p)) {
729 case STR2_INT('b', 'r')((uint16_t)(('b') | ('r') << 8)):
730 request->flags |= REQUEST_ACCEPT_BROTLI;
731 break;
732 }
733#endif
734 }
735
736 if (!(p = strchr(p, ',')))
737 break;
738 }
739}
740
741static ALWAYS_INLINEinline __attribute__((always_inline)) char *
742ignore_leading_whitespace(char *buffer)
743{
744 while (lwan_char_isspace(*buffer))
745 buffer++;
746 return buffer;
747}
748
749static ALWAYS_INLINEinline __attribute__((always_inline)) void parse_connection_header(struct lwan_request *request)
750{
751 struct lwan_request_parser_helper *helper = request->helper;
752 bool_Bool has_keep_alive = false0;
753 bool_Bool has_close = false0;
754
755 if (!helper->connection.len)
756 goto out;
757
758 for (const char *p = helper->connection.value; *p; p++) {
759 STRING_SWITCH_L(p)switch (((string_as_uint32(p)) | (uint32_t)0x20202020)) {
760 case STR4_INT_L('k','e','e','p')((((uint32_t)(('k') | ('e') << 8 | ('e') << 16 | (
'p') << 24))) | (uint32_t)0x20202020)
:
761 case STR4_INT_L(' ', 'k','e','e')((((uint32_t)((' ') | ('k') << 8 | ('e') << 16 | (
'e') << 24))) | (uint32_t)0x20202020)
:
762 has_keep_alive = true1;
763 break;
764 case STR4_INT_L('c','l','o','s')((((uint32_t)(('c') | ('l') << 8 | ('o') << 16 | (
's') << 24))) | (uint32_t)0x20202020)
:
765 case STR4_INT_L(' ', 'c','l','o')((((uint32_t)((' ') | ('c') << 8 | ('l') << 16 | (
'o') << 24))) | (uint32_t)0x20202020)
:
766 has_close = true1;
767 break;
768 case STR4_INT_L('u','p','g','r')((((uint32_t)(('u') | ('p') << 8 | ('g') << 16 | (
'r') << 24))) | (uint32_t)0x20202020)
:
769 case STR4_INT_L(' ', 'u','p','g')((((uint32_t)((' ') | ('u') << 8 | ('p') << 16 | (
'g') << 24))) | (uint32_t)0x20202020)
:
770 request->conn->flags |= CONN_IS_UPGRADE;
771 break;
772 }
773
774 if (!(p = strchr(p, ',')))
775 break;
776 }
777
778out:
779 if (LIKELY(!(request->flags & REQUEST_IS_HTTP_1_0))__builtin_expect((!!(!(request->flags & REQUEST_IS_HTTP_1_0
))), (1))
)
780 has_keep_alive = !has_close;
781
782 if (has_keep_alive) {
783 request->conn->flags |= CONN_IS_KEEP_ALIVE;
784 } else {
785 request->conn->flags &=
786 ~(CONN_IS_KEEP_ALIVE | CONN_SENT_CONNECTION_HEADER);
787 }
788}
789
790#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
791static void save_to_corpus_for_fuzzing(struct lwan_value buffer)
792{
793 struct lwan_value buffer_copy;
794 char corpus_name[PATH_MAX4096];
795 const char *crlfcrlf;
796 int fd;
797
798 if (!(crlfcrlf = memmem(buffer.value, buffer.len, "\r\n\r\n", 4)))
799 return;
800 buffer.len = (size_t)(crlfcrlf - buffer.value + 4);
801
802try_another_file_name:
803 buffer_copy = buffer;
804
805 snprintf(corpus_name, sizeof(corpus_name), "corpus-request-%d", rand());
806
807 fd = open(corpus_name, O_WRONLY01 | O_CLOEXEC02000000 | O_CREAT0100 | O_EXCL0200, 0644);
808 if (fd < 0)
809 goto try_another_file_name;
810
811 while (buffer_copy.len) {
812 ssize_t r = write(fd, buffer_copy.value, buffer_copy.len);
813
814 if (r < 0) {
815 if (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EINTR4)
816 continue;
817
818 close(fd);
819 unlink(corpus_name);
820 goto try_another_file_name;
821 }
822
823 buffer_copy.value += r;
824 buffer_copy.len -= r;
825 }
826
827 close(fd);
828 lwan_status_debug("Request saved to %s", corpus_name)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 828, __FUNCTION__, "Request saved to %s", corpus_name)
;
829}
830#endif
831
832static enum lwan_http_status
833client_read(struct lwan_request *request,
834 struct lwan_value *buffer,
835 const size_t want_to_read,
836 enum lwan_read_finalizer (*finalizer)(const struct lwan_value *buffer,
837 size_t want_to_read,
838 const struct lwan_request *request,
839 int n_packets))
840{
841 struct lwan_request_parser_helper *helper = request->helper;
842 int n_packets = 0;
843
844 if (helper->next_request) {
845 const size_t next_request_len = (size_t)(helper->next_request - buffer->value);
846 size_t new_len;
847
848 if (__builtin_sub_overflow(buffer->len, next_request_len, &new_len)) {
849 helper->next_request = NULL((void*)0);
850 } else if (new_len) {
851 /* FIXME: This memmove() could be eventually removed if a better
852 * stucture (maybe a ringbuffer, reading with readv(), and each
853 * pointer is coro_strdup() if they wrap around?) were used for
854 * the request buffer. */
855 buffer->len = new_len;
856 memmove(buffer->value, helper->next_request, new_len);
857 goto try_to_finalize;
858 }
859 }
860
861 for (buffer->len = 0;; n_packets++) {
862 size_t to_read = (size_t)(want_to_read - buffer->len);
863
864 if (UNLIKELY(to_read == 0)__builtin_expect(((to_read == 0)), (0)))
865 return HTTP_TOO_LARGE;
866
867 ssize_t n = recv(request->fd, buffer->value + buffer->len, to_read, 0);
868 if (UNLIKELY(n <= 0)__builtin_expect(((n <= 0)), (0))) {
869 if (n < 0) {
870 switch (errno(*__errno_location ())) {
871 case EINTR4:
872 case EAGAIN11:
873yield_and_read_again:
874 coro_yield(request->conn->coro, CONN_CORO_WANT_READ);
875 continue;
876 }
877
878 /* Unexpected error before reading anything */
879 if (UNLIKELY(!buffer->len)__builtin_expect(((!buffer->len)), (0)))
880 return HTTP_BAD_REQUEST;
881 }
882
883 /* Client shut down orderly (n = 0), or unrecoverable error (n < 0);
884 * shut down coro. */
885 break;
886 }
887
888 buffer->len += (size_t)n;
889
890try_to_finalize:
891 switch (finalizer(buffer, want_to_read, request, n_packets)) {
892 case FINALIZER_DONE:
893 buffer->value[buffer->len] = '\0';
894#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
895 save_to_corpus_for_fuzzing(*buffer);
896#endif
897 return HTTP_OK;
898
899 case FINALIZER_TRY_AGAIN:
900 goto yield_and_read_again;
901
902 case FINALIZER_TIMEOUT:
903 return HTTP_TIMEOUT;
904 }
905 }
906
907 coro_yield(request->conn->coro, CONN_CORO_ABORT);
908 __builtin_unreachable();
909 return HTTP_INTERNAL_ERROR;
910}
911
912static enum lwan_read_finalizer
913read_request_finalizer_from_helper(const struct lwan_value *buffer,
914 struct lwan_request_parser_helper *helper,
915 int n_packets,
916 bool_Bool allow_proxy_reqs)
917{
918 static const size_t min_proxied_request_size =
919 MIN_REQUEST_SIZE(sizeof("GET / HTTP/1.1\r\n\r\n") - 1) + sizeof(struct proxy_header_v2);
920
921 if (LIKELY(buffer->len >= MIN_REQUEST_SIZE)__builtin_expect((!!(buffer->len >= (sizeof("GET / HTTP/1.1\r\n\r\n"
) - 1))), (1))
) {
922 STRING_SWITCH (buffer->value + buffer->len - 4)switch (string_as_uint32(buffer->value + buffer->len - 4
))
{
923 case STR4_INT('\r', '\n', '\r', '\n')((uint32_t)(('\r') | ('\n') << 8 | ('\r') << 16 |
('\n') << 24))
:
924 return FINALIZER_DONE;
925 }
926 }
927
928 char *crlfcrlf = memmem(buffer->value, buffer->len, "\r\n\r\n", 4);
929 if (LIKELY(crlfcrlf)__builtin_expect((!!(crlfcrlf)), (1))) {
930 if (LIKELY(helper->next_request)__builtin_expect((!!(helper->next_request)), (1))) {
931 helper->next_request = NULL((void*)0);
932 return FINALIZER_DONE;
933 }
934
935 const size_t crlfcrlf_to_base = (size_t)(crlfcrlf - buffer->value);
936 if (crlfcrlf_to_base >= MIN_REQUEST_SIZE(sizeof("GET / HTTP/1.1\r\n\r\n") - 1) - 4)
937 return FINALIZER_DONE;
938
939 if (buffer->len > min_proxied_request_size && allow_proxy_reqs) {
940 /* FIXME: Checking for PROXYv2 protocol header here is a layering
941 * violation. */
942 STRING_SWITCH_LARGE (crlfcrlf + 4)switch (string_as_uint64(crlfcrlf + 4)) {
943 case STR8_INT(0x00, 0x0d, 0x0a, 0x51, 0x55, 0x49, 0x54, 0x0a)((uint64_t)((uint32_t)((0x00) | (0x0d) << 8 | (0x0a) <<
16 | (0x51) << 24)) | (uint64_t)((uint32_t)((0x55) | (
0x49) << 8 | (0x54) << 16 | (0x0a) << 24)) <<
32)
:
944 return FINALIZER_DONE;
945 }
946 }
947 }
948
949 /* Yield a timeout error to avoid clients being intentionally slow and
950 * hogging the server. (Clients can't only connect and do nothing, they
951 * need to send data, otherwise the timeout queue timer will kick in and
952 * close the connection. Limit the number of packets to avoid them sending
953 * just a byte at a time.) See lwan_calculate_n_packets() to see how this is
954 * calculated. */
955 if (UNLIKELY(n_packets > helper->error_when_n_packets)__builtin_expect(((n_packets > helper->error_when_n_packets
)), (0))
)
956 return FINALIZER_TIMEOUT;
957
958 return FINALIZER_TRY_AGAIN;
959}
960
961static inline enum lwan_read_finalizer
962read_request_finalizer(const struct lwan_value *buffer,
963 size_t want_to_read __attribute__((unused)),
964 const struct lwan_request *request,
965 int n_packets)
966{
967 return read_request_finalizer_from_helper(
968 buffer, request->helper, n_packets,
969 request->flags & REQUEST_ALLOW_PROXY_REQS);
970}
971
972static ALWAYS_INLINEinline __attribute__((always_inline)) enum lwan_http_status
973read_request(struct lwan_request *request)
974{
975 return client_read(request, request->helper->buffer,
976 DEFAULT_BUFFER_SIZE4096 - 1 /* -1 for NUL byte */,
977 read_request_finalizer);
978}
979
980static enum lwan_read_finalizer
981body_data_finalizer(const struct lwan_value *buffer,
982 size_t want_to_read,
983 const struct lwan_request *request,
984 int n_packets)
985{
986 const struct lwan_request_parser_helper *helper = request->helper;
987
988 if (want_to_read == buffer->len)
989 return FINALIZER_DONE;
990
991 /* For POST requests, the body can be larger, and due to small MTUs on
992 * most ethernet connections, responding with a timeout solely based on
993 * number of packets doesn't work. Use keepalive timeout instead. */
994 if (UNLIKELY(time(NULL) > helper->error_when_time)__builtin_expect(((time(((void*)0)) > helper->error_when_time
)), (0))
)
995 return FINALIZER_TIMEOUT;
996
997 /* In addition to time, also estimate the number of packets based on an
998 * usual MTU value and the request body size. */
999 if (UNLIKELY(n_packets > helper->error_when_n_packets)__builtin_expect(((n_packets > helper->error_when_n_packets
)), (0))
)
1000 return FINALIZER_TIMEOUT;
1001
1002 return FINALIZER_TRY_AGAIN;
1003}
1004
1005static const char *is_dir(const char *v)
1006{
1007 struct stat st;
1008
1009 if (!v)
1010 return NULL((void*)0);
1011
1012 if (*v != '/')
1013 return NULL((void*)0);
1014
1015 if (stat(v, &st) < 0)
1016 return NULL((void*)0);
1017
1018 if (!S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
1019 return NULL((void*)0);
1020
1021 if (!(st.st_mode & S_ISVTX01000)) {
1022 lwan_status_warning(lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1025, __FUNCTION__, "Using %s as temporary directory, but it doesn't have "
"the sticky bit set.", v)
1023 "Using %s as temporary directory, but it doesn't have "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1025, __FUNCTION__, "Using %s as temporary directory, but it doesn't have "
"the sticky bit set.", v)
1024 "the sticky bit set.",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1025, __FUNCTION__, "Using %s as temporary directory, but it doesn't have "
"the sticky bit set.", v)
1025 v)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1025, __FUNCTION__, "Using %s as temporary directory, but it doesn't have "
"the sticky bit set.", v)
;
1026 }
1027
1028 return v;
1029}
1030
1031static const char *is_dir_good_for_tmp(const char *v)
1032{
1033 struct statfs sb;
1034
1035 v = is_dir(v);
1036 if (!v)
1037 return NULL((void*)0);
1038
1039 if (!statfs(v, &sb) && sb.f_type == TMPFS_MAGIC0x01021994) {
1040 lwan_status_warning("%s is a tmpfs filesystem, "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1041, __FUNCTION__, "%s is a tmpfs filesystem, " "not considering it"
, v)
1041 "not considering it", v)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1041, __FUNCTION__, "%s is a tmpfs filesystem, " "not considering it"
, v)
;
1042 return NULL((void*)0);
1043 }
1044
1045 return v;
1046}
1047
1048static const char *temp_dir;
1049static const size_t body_buffer_temp_file_thresh = 1<<20;
1050
1051static const char *
1052get_temp_dir(void)
1053{
1054 const char *tmpdir;
1055
1056 tmpdir = is_dir_good_for_tmp(secure_getenv("TMPDIR"));
1057 if (tmpdir)
1058 return tmpdir;
1059
1060 tmpdir = is_dir_good_for_tmp(secure_getenv("TMP"));
1061 if (tmpdir)
1062 return tmpdir;
1063
1064 tmpdir = is_dir_good_for_tmp(secure_getenv("TEMP"));
1065 if (tmpdir)
1066 return tmpdir;
1067
1068 tmpdir = is_dir_good_for_tmp("/var/tmp");
1069 if (tmpdir)
1070 return tmpdir;
1071
1072 tmpdir = is_dir_good_for_tmp(P_tmpdir"/tmp");
1073 if (tmpdir)
1074 return tmpdir;
1075
1076 lwan_status_warning("Temporary directory could not be determined. POST "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1078, __FUNCTION__, "Temporary directory could not be determined. POST "
"or PUT requests over %zu bytes bytes will fail.", body_buffer_temp_file_thresh
)
1077 "or PUT requests over %zu bytes bytes will fail.",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1078, __FUNCTION__, "Temporary directory could not be determined. POST "
"or PUT requests over %zu bytes bytes will fail.", body_buffer_temp_file_thresh
)
1078 body_buffer_temp_file_thresh)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1078, __FUNCTION__, "Temporary directory could not be determined. POST "
"or PUT requests over %zu bytes bytes will fail.", body_buffer_temp_file_thresh
)
;
1079 return NULL((void*)0);
1080}
1081
1082__attribute__((constructor)) static void initialize_temp_dir(void)
1083{
1084 temp_dir = get_temp_dir();
1085}
1086
1087static int create_temp_file(void)
1088{
1089 char template[PATH_MAX4096];
1090 mode_t prev_mask;
1091 int ret;
1092
1093 if (UNLIKELY(!temp_dir)__builtin_expect(((!temp_dir)), (0)))
1094 return -ENOENT2;
1095
1096#if defined(O_TMPFILE(020000000 | 0200000))
1097 int fd = open(temp_dir,
1098 O_TMPFILE(020000000 | 0200000) | O_CREAT0100 | O_RDWR02 | O_EXCL0200 | O_CLOEXEC02000000 |
1099 O_NOFOLLOW0400000 | O_NOATIME01000000,
1100 S_IRUSR0400 | S_IWUSR0200);
1101 if (LIKELY(fd >= 0)__builtin_expect((!!(fd >= 0)), (1)))
1102 return fd;
1103#endif
1104
1105 ret = snprintf(template, sizeof(template), "%s/lwanXXXXXX", temp_dir);
1106 if (UNLIKELY(ret < 0 || ret >= (int)sizeof(template))__builtin_expect(((ret < 0 || ret >= (int)sizeof(template
))), (0))
)
1107 return -EOVERFLOW75;
1108
1109 prev_mask = umask_for_tmpfile(S_IRUSR | S_IWUSR)({ (void)(0400 | 0200); 0U; });
1110 ret = mkostemp(template, O_CLOEXEC02000000);
1111 umask_for_tmpfile(prev_mask)({ (void)(prev_mask); 0U; });
1112
1113 if (LIKELY(ret >= 0)__builtin_expect((!!(ret >= 0)), (1)))
1114 unlink(template);
1115
1116 return ret;
1117}
1118
1119struct file_backed_buffer {
1120 void *ptr;
1121 size_t size;
1122};
1123
1124static void
1125free_body_buffer(void *data)
1126{
1127 struct file_backed_buffer *buf = data;
1128
1129 munmap(buf->ptr, buf->size);
1130 free(buf);
1131}
1132
1133static void*
1134alloc_body_buffer(struct coro *coro, size_t size, bool_Bool allow_file)
1135{
1136 struct file_backed_buffer *buf;
1137 void *ptr = (void *)MAP_FAILED((void *) -1);
1138 int fd;
1139
1140 if (LIKELY(size < body_buffer_temp_file_thresh)__builtin_expect((!!(size < body_buffer_temp_file_thresh))
, (1))
) {
1141 ptr = coro_malloc(coro, size);
1142
1143 if (LIKELY(ptr)__builtin_expect((!!(ptr)), (1)))
1144 return ptr;
1145 }
1146
1147 if (UNLIKELY(!allow_file)__builtin_expect(((!allow_file)), (0)))
1148 return NULL((void*)0);
1149
1150 fd = create_temp_file();
1151 if (UNLIKELY(fd < 0)__builtin_expect(((fd < 0)), (0)))
1152 return NULL((void*)0);
1153
1154 if (UNLIKELY(ftruncate(fd, (off_t)size) < 0)__builtin_expect(((ftruncate(fd, (off_t)size) < 0)), (0))) {
1155 close(fd);
1156 return NULL((void*)0);
1157 }
1158
1159 if (MAP_HUGETLB0x40000) {
1160 ptr = mmap(NULL((void*)0), size, PROT_READ0x1 | PROT_WRITE0x2,
1161 MAP_SHARED0x01 | MAP_HUGETLB0x40000, fd, 0);
1162 }
1163 if (UNLIKELY(ptr == MAP_FAILED)__builtin_expect(((ptr == ((void *) -1))), (0)))
1164 ptr = mmap(NULL((void*)0), size, PROT_READ0x1 | PROT_WRITE0x2, MAP_SHARED0x01, fd, 0);
1165 close(fd);
1166 if (UNLIKELY(ptr == MAP_FAILED)__builtin_expect(((ptr == ((void *) -1))), (0)))
1167 return NULL((void*)0);
1168
1169 buf = coro_malloc_full(coro, sizeof(*buf), free_body_buffer);
1170 if (UNLIKELY(!buf)__builtin_expect(((!buf)), (0))) {
1171 munmap(ptr, size);
1172 return NULL((void*)0);
1173 }
1174
1175 buf->ptr = ptr;
1176 buf->size = size;
1177 return ptr;
1178}
1179
1180static enum lwan_http_status
1181get_remaining_body_data_length(struct lwan_request *request,
1182 const size_t max_size,
1183 size_t *total,
1184 size_t *have)
1185{
1186 struct lwan_request_parser_helper *helper = request->helper;
1187 long long parsed_size;
1188
1189 if (UNLIKELY(!helper->content_length.value)__builtin_expect(((!helper->content_length.value)), (0)))
1190 return HTTP_BAD_REQUEST;
1191
1192 parsed_size = parse_long_long(helper->content_length.value, -1);
1193 if (UNLIKELY(parsed_size < 0)__builtin_expect(((parsed_size < 0)), (0)))
1194 return HTTP_BAD_REQUEST;
1195 if (UNLIKELY((size_t)parsed_size >= max_size)__builtin_expect((((size_t)parsed_size >= max_size)), (0)))
1196 return HTTP_TOO_LARGE;
1197 if (UNLIKELY(!parsed_size)__builtin_expect(((!parsed_size)), (0)))
1198 return HTTP_OK;
1199
1200 *total = (size_t)parsed_size;
1201
1202 if (!helper->next_request) {
1203 *have = 0;
1204 return HTTP_PARTIAL_CONTENT;
1205 }
1206
1207 char *buffer_end = helper->buffer->value + helper->buffer->len;
1208
1209 *have = (size_t)(buffer_end - helper->next_request);
1210
1211 if (*have < *total)
1212 return HTTP_PARTIAL_CONTENT;
1213
1214 helper->body_data.value = helper->next_request;
1215 helper->body_data.len = *total;
1216 helper->next_request += *total;
1217 return HTTP_OK;
1218}
1219
1220static int read_body_data(struct lwan_request *request)
1221{
1222 /* Holy indirection, Batman! */
1223 const struct lwan_config *config = &request->conn->thread->lwan->config;
1224 struct lwan_request_parser_helper *helper = request->helper;
1225 enum lwan_http_status status;
1226 size_t total, have, max_data_size;
1227 bool_Bool allow_temp_file;
1228 char *new_buffer;
1229
1230 switch (lwan_request_get_method(request)) {
1231 case REQUEST_METHOD_POST:
1232 allow_temp_file = config->allow_post_temp_file;
1233 max_data_size = config->max_post_data_size;
1234 break;
1235 case REQUEST_METHOD_PUT:
1236 allow_temp_file = config->allow_put_temp_file;
1237 max_data_size = config->max_put_data_size;
1238 break;
1239 default:
1240 return -HTTP_NOT_ALLOWED;
1241 }
1242
1243 status =
1244 get_remaining_body_data_length(request, max_data_size, &total, &have);
1245 if (status != HTTP_PARTIAL_CONTENT)
1246 return -(int)status;
1247
1248 new_buffer =
1249 alloc_body_buffer(request->conn->coro, total + 1, allow_temp_file);
1250 if (UNLIKELY(!new_buffer)__builtin_expect(((!new_buffer)), (0)))
1251 return -HTTP_INTERNAL_ERROR;
1252
1253 if (!(request->flags & REQUEST_IS_HTTP_1_0)) {
1254 /* §8.2.3 https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html */
1255 const char *expect = lwan_request_get_header(request, "Expect");
1256
1257 if (expect && strncmp(expect, "100-", 4) == 0) {
1258 static const char continue_header[] = "HTTP/1.1 100 Continue\r\n\r\n";
1259
1260 lwan_send(request, continue_header, sizeof(continue_header) - 1, 0);
1261 }
1262 }
1263
1264 helper->body_data.value = new_buffer;
1265 helper->body_data.len = total;
1266 if (have) {
1267 new_buffer = mempcpy(new_buffer, helper->next_request, have);
1268 total -= have;
1269 }
1270 helper->next_request = NULL((void*)0);
1271
1272 helper->error_when_time = time(NULL((void*)0)) + config->keep_alive_timeout;
1273 helper->error_when_n_packets = lwan_calculate_n_packets(total);
1274
1275 struct lwan_value buffer = {.value = new_buffer, .len = total};
1276 return (int)client_read(request, &buffer, total, body_data_finalizer);
1277}
1278
1279static char *
1280parse_proxy_protocol(struct lwan_request *request, char *buffer)
1281{
1282 STRING_SWITCH(buffer)switch (string_as_uint32(buffer)) {
1283 case STR4_INT('P','R','O','X')((uint32_t)(('P') | ('R') << 8 | ('O') << 16 | ('X'
) << 24))
:
1284 return parse_proxy_protocol_v1(request, buffer);
1285 case STR4_INT('\x0D','\x0A','\x0D','\x0A')((uint32_t)(('\x0D') | ('\x0A') << 8 | ('\x0D') <<
16 | ('\x0A') << 24))
:
1286 return parse_proxy_protocol_v2(request, buffer);
1287 }
1288
1289 return buffer;
1290}
1291
1292static enum lwan_http_status parse_http_request(struct lwan_request *request)
1293{
1294 struct lwan_request_parser_helper *helper = request->helper;
1295 char *buffer = helper->buffer->value;
1296
1297 if (request->flags & REQUEST_ALLOW_PROXY_REQS) {
1298 /* REQUEST_ALLOW_PROXY_REQS will be cleared in lwan_process_request() */
1299
1300 buffer = parse_proxy_protocol(request, buffer);
1301 if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0)))
1302 return HTTP_BAD_REQUEST;
1303 }
1304
1305 buffer = ignore_leading_whitespace(buffer);
1306
1307 if (UNLIKELY(buffer > helper->buffer->value + helper->buffer->len -__builtin_expect(((buffer > helper->buffer->value + helper
->buffer->len - (sizeof("GET / HTTP/1.1\r\n\r\n") - 1))
), (0))
1308 MIN_REQUEST_SIZE)__builtin_expect(((buffer > helper->buffer->value + helper
->buffer->len - (sizeof("GET / HTTP/1.1\r\n\r\n") - 1))
), (0))
)
1309 return HTTP_BAD_REQUEST;
1310
1311 char *path = identify_http_method(request, buffer);
1312 if (UNLIKELY(!path)__builtin_expect(((!path)), (0)))
1313 return HTTP_NOT_ALLOWED;
1314
1315 buffer = identify_http_path(request, path);
1316 if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0)))
1317 return HTTP_BAD_REQUEST;
1318
1319 if (UNLIKELY(!parse_headers(helper, buffer))__builtin_expect(((!parse_headers(helper, buffer))), (0)))
1320 return HTTP_BAD_REQUEST;
1321
1322 ssize_t decoded_len = url_decode(request->url.value);
1323 if (UNLIKELY(decoded_len < 0)__builtin_expect(((decoded_len < 0)), (0)))
1324 return HTTP_BAD_REQUEST;
1325 request->original_url.len = request->url.len = (size_t)decoded_len;
1326
1327 parse_connection_header(request);
1328
1329 return HTTP_OK;
1330}
1331
1332static enum lwan_http_status
1333prepare_websocket_handshake(struct lwan_request *request, char **encoded)
1334{
1335 static const unsigned char websocket_uuid[] =
1336 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
1337 unsigned char digest[20];
1338 sha1_context ctx;
1339
1340 if (UNLIKELY(request->flags & RESPONSE_SENT_HEADERS)__builtin_expect(((request->flags & RESPONSE_SENT_HEADERS
)), (0))
)
1341 return HTTP_INTERNAL_ERROR;
1342
1343 if (UNLIKELY(!(request->conn->flags & CONN_IS_UPGRADE))__builtin_expect(((!(request->conn->flags & CONN_IS_UPGRADE
))), (0))
)
1344 return HTTP_BAD_REQUEST;
1345
1346 const char *upgrade = lwan_request_get_header(request, "Upgrade");
1347 if (UNLIKELY(!upgrade || !streq(upgrade, "websocket"))__builtin_expect(((!upgrade || !streq(upgrade, "websocket")))
, (0))
)
1348 return HTTP_BAD_REQUEST;
1349
1350 const char *sec_websocket_key =
1351 lwan_request_get_header(request, "Sec-WebSocket-Key");
1352 if (UNLIKELY(!sec_websocket_key)__builtin_expect(((!sec_websocket_key)), (0)))
1353 return HTTP_BAD_REQUEST;
1354
1355 const size_t sec_websocket_key_len = strlen(sec_websocket_key);
1356 if (base64_encoded_len(16) != sec_websocket_key_len)
1357 return HTTP_BAD_REQUEST;
1358 if (UNLIKELY(!base64_validate((void *)sec_websocket_key, sec_websocket_key_len))__builtin_expect(((!base64_validate((void *)sec_websocket_key
, sec_websocket_key_len))), (0))
)
1359 return HTTP_BAD_REQUEST;
1360
1361 sha1_init(&ctx);
1362 sha1_update(&ctx, (void *)sec_websocket_key, sec_websocket_key_len);
1363 sha1_update(&ctx, websocket_uuid, sizeof(websocket_uuid) - 1);
1364 sha1_finalize(&ctx, digest);
1365
1366 *encoded = (char *)base64_encode(digest, sizeof(digest), NULL((void*)0));
1367 return LIKELY(*encoded)__builtin_expect((!!(*encoded)), (1)) ? HTTP_SWITCHING_PROTOCOLS : HTTP_INTERNAL_ERROR;
1368}
1369
1370enum lwan_http_status
1371lwan_request_websocket_upgrade(struct lwan_request *request)
1372{
1373 char header_buf[DEFAULT_HEADERS_SIZE2048];
1374 size_t header_buf_len;
1375 char *encoded;
1376
1377 enum lwan_http_status r = prepare_websocket_handshake(request, &encoded);
1378 if (r != HTTP_SWITCHING_PROTOCOLS)
1379 return r;
1380
1381 request->flags |= RESPONSE_NO_CONTENT_LENGTH;
1382 header_buf_len = lwan_prepare_response_header_full(
1383 request, HTTP_SWITCHING_PROTOCOLS, header_buf, sizeof(header_buf),
1384 (struct lwan_key_value[]){
1385 /* Connection: Upgrade is implicit if conn->flags & CONN_IS_UPGRADE */
1386 {.key = "Sec-WebSocket-Accept", .value = encoded},
1387 {.key = "Upgrade", .value = "websocket"},
1388 {},
1389 });
1390 free(encoded);
1391 if (UNLIKELY(!header_buf_len)__builtin_expect(((!header_buf_len)), (0)))
1392 return HTTP_INTERNAL_ERROR;
1393
1394 request->conn->flags |= CONN_IS_WEBSOCKET;
1395 lwan_send(request, header_buf, header_buf_len, 0);
1396
1397 return HTTP_SWITCHING_PROTOCOLS;
1398}
1399
1400static inline bool_Bool request_has_body(const struct lwan_request *request)
1401{
1402 /* 3rd bit set in method: request method has body. See lwan.h,
1403 * definition of FOR_EACH_REQUEST_METHOD() for more info. */
1404 return lwan_request_get_method(request) & 1 << 3;
1405}
1406
1407static enum lwan_http_status
1408maybe_read_body_data(const struct lwan_url_map *url_map,
1409 struct lwan_request *request)
1410{
1411 int status = 0;
1412
1413 if (url_map->flags & HANDLER_EXPECTS_BODY_DATA) {
1414 status = read_body_data(request);
1415 if (status > 0)
1416 return (enum lwan_http_status)status;
1417 }
1418
1419 /* Instead of trying to read the body here, which will require
1420 * us to allocate and read potentially a lot of bytes, force
1421 * this connection to be closed as soon as we send a "not allowed"
1422 * response. */
1423 request->conn->flags &= ~CONN_IS_KEEP_ALIVE;
1424
1425 if (status < 0) {
1426 status = -status;
1427 return (enum lwan_http_status)status;
1428 }
1429
1430 return HTTP_NOT_ALLOWED;
1431}
1432
1433static enum lwan_http_status prepare_for_response(const struct lwan_url_map *url_map,
1434 struct lwan_request *request)
1435{
1436 request->url.value += url_map->prefix_len;
1437 request->url.len -= url_map->prefix_len;
1438 while (*request->url.value == '/' && request->url.len > 0) {
1439 request->url.value++;
1440 request->url.len--;
1441 }
1442
1443 if (UNLIKELY(url_map->flags & HANDLER_MUST_AUTHORIZE)__builtin_expect(((url_map->flags & HANDLER_MUST_AUTHORIZE
)), (0))
) {
1444 if (!lwan_http_authorize_urlmap(request, url_map))
1445 return HTTP_NOT_AUTHORIZED;
1446 }
1447
1448 if (UNLIKELY(request_has_body(request))__builtin_expect(((request_has_body(request))), (0)))
1449 return maybe_read_body_data(url_map, request);
1450
1451 return HTTP_OK;
1452}
1453
1454static bool_Bool handle_rewrite(struct lwan_request *request)
1455{
1456 struct lwan_request_parser_helper *helper = request->helper;
1457
1458 request->flags &= ~RESPONSE_URL_REWRITTEN;
1459
1460 find_query_string(request, request->url.value + request->url.len);
1461
1462 helper->urls_rewritten++;
1463 if (UNLIKELY(helper->urls_rewritten > 4)__builtin_expect(((helper->urls_rewritten > 4)), (0))) {
1464 lwan_default_response(request, HTTP_INTERNAL_ERROR);
1465 return false0;
1466 }
1467
1468 return true1;
1469}
1470
1471const char *lwan_request_get_method_str(const struct lwan_request *request)
1472{
1473#define GENERATE_CASE_STMT(upper, lower, mask, constant, probability) \
1474 case REQUEST_METHOD_##upper: \
1475 return #upper;
1476
1477 switch (lwan_request_get_method(request)) {
1478 FOR_EACH_REQUEST_METHOD(GENERATE_CASE_STMT)GENERATE_CASE_STMT(GET, get, (1 << 0), (((uint32_t)(('G'
) | ('E') << 8 | ('T') << 16 | (' ') << 24)
)), 0.6) GENERATE_CASE_STMT(POST, post, (1 << 3 | 1 <<
1 | 1 << 0), (((uint32_t)(('P') | ('O') << 8 | (
'S') << 16 | ('T') << 24))), 0.2) GENERATE_CASE_STMT
(HEAD, head, (1 << 1), (((uint32_t)(('H') | ('E') <<
8 | ('A') << 16 | ('D') << 24))), 0.2) GENERATE_CASE_STMT
(OPTIONS, options, (1 << 2), (((uint32_t)(('O') | ('P')
<< 8 | ('T') << 16 | ('I') << 24))), 0.1) GENERATE_CASE_STMT
(DELETE, delete, (1 << 1 | 1 << 2), (((uint32_t)(
('D') | ('E') << 8 | ('L') << 16 | ('E') <<
24))), 0.1) GENERATE_CASE_STMT(PUT, put, (1 << 3 | 1 <<
2 | 1 << 0), (((uint32_t)(('P') | ('U') << 8 | (
'T') << 16 | (' ') << 24))), 0.1)
1479 default:
1480 return "UNKNOWN";
1481 }
1482#undef GENERATE_CASE_STMT
1483}
1484
1485#ifndef NDEBUG
1486static void log_request(struct lwan_request *request,
1487 enum lwan_http_status status,
1488 double time_to_read_request,
1489 double time_to_process_request)
1490{
1491 char ip_buffer[INET6_ADDRSTRLEN46];
1492
1493 lwan_status_debug(lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
5
Calling 'lwan_request_get_remote_address'
1494 "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
1495 lwan_request_get_remote_address(request, ip_buffer),lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
1496 request->conn->thread->date.date, lwan_request_get_id(request),lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
1497 lwan_request_get_method_str(request), request->original_url.value,lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
1498 request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" : "1.1", status,lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
1499 request->response.mime_type, time_to_read_request,lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
1500 time_to_process_request)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1500, __FUNCTION__, "%s [%s] %016lx \"%s %s HTTP/%s\" %d %s (r:%.3fms p:%.3fms)"
, lwan_request_get_remote_address(request, ip_buffer), request
->conn->thread->date.date, lwan_request_get_id(request
), lwan_request_get_method_str(request), request->original_url
.value, request->flags & REQUEST_IS_HTTP_1_0 ? "1.0" :
"1.1", status, request->response.mime_type, time_to_read_request
, time_to_process_request)
;
1501}
1502#else
1503#define log_request(...)
1504#endif
1505
1506#ifndef NDEBUG
1507static struct timespec current_precise_monotonic_timespec(void)
1508{
1509 struct timespec now;
1510
1511 if (UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &now) < 0)__builtin_expect(((clock_gettime(1, &now) < 0)), (0))) {
1512 lwan_status_perror("clock_gettime")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1512, __FUNCTION__, "clock_gettime")
;
1513 return (struct timespec){};
1514 }
1515
1516 return now;
1517}
1518
1519static double elapsed_time_ms(const struct timespec then)
1520{
1521 const struct timespec now = current_precise_monotonic_timespec();
1522 struct timespec diff = {
1523 .tv_sec = now.tv_sec - then.tv_sec,
1524 .tv_nsec = now.tv_nsec - then.tv_nsec,
1525 };
1526
1527 if (diff.tv_nsec < 0) {
1528 diff.tv_sec--;
1529 diff.tv_nsec += 1000000000l;
1530 }
1531
1532 return (double)diff.tv_sec / 1000.0 + (double)diff.tv_nsec / 1000000.0;
1533}
1534#endif
1535
1536void lwan_process_request(struct lwan *l, struct lwan_request *request)
1537{
1538 enum lwan_http_status status;
1539 struct lwan_url_map *url_map;
1540
1541#ifndef NDEBUG
1542 struct timespec request_read_begin_time = current_precise_monotonic_timespec();
1543#endif
1544 status = read_request(request);
1545
1546#ifndef NDEBUG
1547 double time_to_read_request = elapsed_time_ms(request_read_begin_time);
1548
1549 struct timespec request_begin_time = current_precise_monotonic_timespec();
1550#endif
1551 if (UNLIKELY(status != HTTP_OK)__builtin_expect(((status != HTTP_OK)), (0))) {
1
Taking false branch
1552 /* If read_request() returns any error at this point, it's probably
1553 * better to just send an error response and abort the coroutine and
1554 * let the client handle the error instead: we don't have
1555 * information to even log the request because it has not been
1556 * parsed yet at this stage. Even if there are other requests waiting
1557 * in the pipeline, this seems like the safer thing to do. */
1558 request->conn->flags &= ~CONN_IS_KEEP_ALIVE;
1559 lwan_default_response(request, status);
1560 coro_yield(request->conn->coro, CONN_CORO_ABORT);
1561 __builtin_unreachable();
1562 }
1563
1564 status = parse_http_request(request);
1565 if (UNLIKELY(status != HTTP_OK)__builtin_expect(((status != HTTP_OK)), (0)))
2
Taking true branch
1566 goto log_and_return;
3
Control jumps to line 1589
1567
1568lookup_again:
1569 url_map = lwan_trie_lookup_prefix(&l->url_map_trie, request->url.value);
1570 if (UNLIKELY(!url_map)__builtin_expect(((!url_map)), (0))) {
1571 status = HTTP_NOT_FOUND;
1572 goto log_and_return;
1573 }
1574
1575 status = prepare_for_response(url_map, request);
1576 if (UNLIKELY(status != HTTP_OK)__builtin_expect(((status != HTTP_OK)), (0)))
1577 goto log_and_return;
1578
1579 status = url_map->handler(request, &request->response, url_map->data);
1580 if (UNLIKELY(url_map->flags & HANDLER_CAN_REWRITE_URL)__builtin_expect(((url_map->flags & HANDLER_CAN_REWRITE_URL
)), (0))
) {
1581 if (request->flags & RESPONSE_URL_REWRITTEN) {
1582 if (LIKELY(handle_rewrite(request))__builtin_expect((!!(handle_rewrite(request))), (1)))
1583 goto lookup_again;
1584 return;
1585 }
1586 }
1587
1588log_and_return:
1589 lwan_response(request, status);
1590
1591 log_request(request, status, time_to_read_request, elapsed_time_ms(request_begin_time));
4
Calling 'log_request'
1592}
1593
1594static inline void *
1595value_lookup(const struct lwan_key_value_array *array, const char *key)
1596{
1597 const struct lwan_array *la = (const struct lwan_array *)array;
1598
1599 if (LIKELY(la->elements)__builtin_expect((!!(la->elements)), (1))) {
1600 struct lwan_key_value k = { .key = (char *)key };
1601 struct lwan_key_value *entry;
1602
1603 entry = bsearch(&k, la->base, la->elements, sizeof(k), key_value_compare);
1604 if (LIKELY(entry)__builtin_expect((!!(entry)), (1)))
1605 return entry->value;
1606 }
1607
1608 return NULL((void*)0);
1609}
1610
1611const char *lwan_request_get_query_param(struct lwan_request *request,
1612 const char *key)
1613{
1614 return value_lookup(lwan_request_get_query_params(request), key);
1615}
1616
1617const char *lwan_request_get_post_param(struct lwan_request *request,
1618 const char *key)
1619{
1620 return value_lookup(lwan_request_get_post_params(request), key);
1621}
1622
1623const char *lwan_request_get_cookie(struct lwan_request *request,
1624 const char *key)
1625{
1626 return value_lookup(lwan_request_get_cookies(request), key);
1627}
1628
1629const char *
1630lwan_request_get_header_from_helper(struct lwan_request_parser_helper *helper,
1631 const char *header)
1632{
1633 const size_t header_len = strlen(header);
1634 const size_t header_len_with_separator =
1635 header_len + HEADER_VALUE_SEPARATOR_LEN(sizeof(": ") - 1);
1636
1637 assert(strchr(header, ':') == NULL)((void) sizeof ((strchr(header, ':') == ((void*)0)) ? 1 : 0),
__extension__ ({ if (strchr(header, ':') == ((void*)0)) ; else
__assert_fail ("strchr(header, ':') == NULL", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1637, __extension__ __PRETTY_FUNCTION__); }))
;
1638
1639 for (size_t i = 0; i < helper->n_header_start; i++) {
1640 const char *start = helper->header_start[i];
1641 char *end = helper->header_start[i + 1] - HEADER_TERMINATOR_LEN(sizeof("\r\n") - 1);
1642
1643 if (UNLIKELY((size_t)(end - start) < header_len_with_separator)__builtin_expect((((size_t)(end - start) < header_len_with_separator
)), (0))
)
1644 continue;
1645
1646 STRING_SWITCH_SMALL (start + header_len)switch (string_as_uint16(start + header_len)) {
1647 case STR2_INT(':', ' ')((uint16_t)((':') | (' ') << 8)):
1648 if (!strncasecmp(start, header, header_len)) {
1649 *end = '\0';
1650 return start + header_len_with_separator;
1651 }
1652 }
1653 }
1654
1655 return NULL((void*)0);
1656}
1657
1658inline const char *lwan_request_get_header(struct lwan_request *request,
1659 const char *header)
1660{
1661 return lwan_request_get_header_from_helper(request->helper, header);
1662}
1663
1664const char *lwan_request_get_host(struct lwan_request *request)
1665{
1666 const struct lwan_request_parser_helper *helper = request->helper;
1667
1668 return helper->host.len ? helper->host.value : NULL((void*)0);
1669}
1670
1671ALWAYS_INLINEinline __attribute__((always_inline)) int
1672lwan_connection_get_fd(const struct lwan *lwan, const struct lwan_connection *conn)
1673{
1674 return (int)(intptr_t)(conn - lwan->conns);
1675}
1676
1677const char *
1678lwan_request_get_remote_address_and_port(struct lwan_request *request,
1679 char buffer[static INET6_ADDRSTRLEN46],
1680 uint16_t *port)
1681{
1682 struct sockaddr_storage non_proxied_addr = {.ss_family = AF_UNSPEC0};
1683 struct sockaddr_storage *sock_addr;
1684
1685 *port = 0;
1686
1687 if (request->flags & REQUEST_PROXIED) {
7
Assuming the condition is false
8
Taking false branch
1688 sock_addr = (struct sockaddr_storage *)&request->proxy->from;
1689
1690 if (UNLIKELY(sock_addr->ss_family == AF_UNSPEC)__builtin_expect(((sock_addr->ss_family == 0)), (0))) {
1691 static const char unspecified[] = "*unspecified*";
1692
1693 static_assert_Static_assert(sizeof(unspecified) <= INET6_ADDRSTRLEN46,
1694 "Enough space for unspecified address family");
1695 return memcpy(buffer, unspecified, sizeof(unspecified));
1696 }
1697 } else {
1698 socklen_t sock_len = sizeof(non_proxied_addr);
1699
1700 sock_addr = &non_proxied_addr;
1701
1702 if (UNLIKELY(getpeername(request->fd, (struct sockaddr *)sock_addr,__builtin_expect(((getpeername(request->fd, (struct sockaddr
*)sock_addr, &sock_len) < 0)), (0))
9
Assuming the condition is false
10
Taking false branch
1703 &sock_len) < 0)__builtin_expect(((getpeername(request->fd, (struct sockaddr
*)sock_addr, &sock_len) < 0)), (0))
) {
1704 return NULL((void*)0);
1705 }
1706 }
1707
1708 if (sock_addr->ss_family
10.1
Field 'ss_family' is not equal to AF_INET
== AF_INET2) {
11
Taking false branch
1709 struct sockaddr_in *sin = (struct sockaddr_in *)sock_addr;
1710 *port = ntohs(sin->sin_port);
1711 return inet_ntop(AF_INET2, &sin->sin_addr, buffer, INET6_ADDRSTRLEN46);
1712 }
1713
1714 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sock_addr;
1715 *port = ntohs(sin6->sin6_port);
12
1st function call argument is an uninitialized value
1716 return inet_ntop(AF_INET610, &sin6->sin6_addr, buffer, INET6_ADDRSTRLEN46);
1717}
1718
1719const char *
1720lwan_request_get_remote_address(struct lwan_request *request,
1721 char buffer[static INET6_ADDRSTRLEN46])
1722{
1723 uint16_t port;
1724 return lwan_request_get_remote_address_and_port(request, buffer, &port);
6
Calling 'lwan_request_get_remote_address_and_port'
1725}
1726
1727static void remove_sleep(void *data1, void *data2)
1728{
1729 static const enum lwan_connection_flags suspended_sleep =
1730 CONN_SUSPENDED | CONN_HAS_REMOVE_SLEEP_DEFER;
1731 struct timeouts *wheel = data1;
1732 struct timeout *timeout = data2;
1733 struct lwan_request *request =
1734 container_of(timeout, struct lwan_request, timeout)((struct lwan_request *) ((char *)(timeout) - __builtin_offsetof
(struct lwan_request, timeout)) + ((typeof(*(timeout)) *)0 !=
(typeof(((struct lwan_request *)0)->timeout) *)0))
;
1735
1736 if ((request->conn->flags & suspended_sleep) == suspended_sleep)
1737 timeouts_del(wheel, timeout);
1738
1739 request->conn->flags &= ~CONN_HAS_REMOVE_SLEEP_DEFER;
1740}
1741
1742void lwan_request_sleep(struct lwan_request *request, uint64_t ms)
1743{
1744 struct lwan_connection *conn = request->conn;
1745 struct timeouts *wheel = conn->thread->wheel;
1746 struct timespec now;
1747 struct coro_defer *defer = NULL((void*)0);
1748
1749 /* We need to update the timer wheel right now because
1750 * a request might have requested to sleep a long time
1751 * before it was being serviced -- causing the timeout
1752 * to essentially be a no-op. */
1753 if (UNLIKELY(clock_gettime(monotonic_clock_id, &now) < 0)__builtin_expect(((clock_gettime(monotonic_clock_id, &now
) < 0)), (0))
)
1754 lwan_status_critical("Could not get monotonic time")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1754, __FUNCTION__, "Could not get monotonic time")
;
1755 timeouts_update(wheel, (timeout_t)(now.tv_sec * 1000 + now.tv_nsec / 1000000));
1756
1757 request->timeout = (struct timeout) {};
1758 timeouts_add(wheel, &request->timeout, ms);
1759
1760 if (!(conn->flags & CONN_HAS_REMOVE_SLEEP_DEFER)) {
1761 defer = coro_defer2(conn->coro, remove_sleep, wheel, &request->timeout);
1762 conn->flags |= CONN_HAS_REMOVE_SLEEP_DEFER;
1763 }
1764
1765 coro_yield(conn->coro, CONN_CORO_SUSPEND);
1766
1767 if (defer)
1768 coro_defer_fire_and_disarm(conn->coro, defer);
1769}
1770
1771ALWAYS_INLINEinline __attribute__((always_inline)) int
1772lwan_request_get_range(struct lwan_request *request, off_t *from, off_t *to)
1773{
1774 struct lwan_request_parser_helper *helper = request->helper;
1775
1776 if (!(request->flags & REQUEST_PARSED_RANGE)) {
1777 parse_range(helper);
1778 request->flags |= REQUEST_PARSED_RANGE;
1779 }
1780
1781 if (LIKELY(helper->range.raw.len)__builtin_expect((!!(helper->range.raw.len)), (1))) {
1782 *from = helper->range.from;
1783 *to = helper->range.to;
1784 return 0;
1785 }
1786
1787 return -ENOENT2;
1788}
1789
1790ALWAYS_INLINEinline __attribute__((always_inline)) int
1791lwan_request_get_if_modified_since(struct lwan_request *request, time_t *value)
1792{
1793 struct lwan_request_parser_helper *helper = request->helper;
1794
1795 if (!(request->flags & REQUEST_PARSED_IF_MODIFIED_SINCE)) {
1796 parse_if_modified_since(helper);
1797 request->flags |= REQUEST_PARSED_IF_MODIFIED_SINCE;
1798 }
1799
1800 if (LIKELY(helper->if_modified_since.raw.len)__builtin_expect((!!(helper->if_modified_since.raw.len)), (
1))
) {
1801 *value = helper->if_modified_since.parsed;
1802 return 0;
1803 }
1804
1805 return -ENOENT2;
1806}
1807
1808ALWAYS_INLINEinline __attribute__((always_inline)) const struct lwan_value *
1809lwan_request_get_request_body(struct lwan_request *request)
1810{
1811 return &request->helper->body_data;
1812}
1813
1814ALWAYS_INLINEinline __attribute__((always_inline)) const struct lwan_value *
1815lwan_request_get_content_type(struct lwan_request *request)
1816{
1817 return &request->helper->content_type;
1818}
1819
1820ALWAYS_INLINEinline __attribute__((always_inline)) const struct lwan_key_value_array *
1821lwan_request_get_cookies(struct lwan_request *request)
1822{
1823 if (!(request->flags & REQUEST_PARSED_COOKIES)) {
1824 parse_cookies(request);
1825 request->flags |= REQUEST_PARSED_COOKIES;
1826 }
1827
1828 return &request->helper->cookies;
1829}
1830
1831ALWAYS_INLINEinline __attribute__((always_inline)) const struct lwan_key_value_array *
1832lwan_request_get_query_params(struct lwan_request *request)
1833{
1834 if (!(request->flags & REQUEST_PARSED_QUERY_STRING)) {
1835 parse_query_string(request);
1836 request->flags |= REQUEST_PARSED_QUERY_STRING;
1837 }
1838
1839 return &request->helper->query_params;
1840}
1841
1842ALWAYS_INLINEinline __attribute__((always_inline)) const struct lwan_key_value_array *
1843lwan_request_get_post_params(struct lwan_request *request)
1844{
1845 if (!(request->flags & REQUEST_PARSED_FORM_DATA)) {
1846 parse_form_data(request);
1847 request->flags |= REQUEST_PARSED_FORM_DATA;
1848 }
1849
1850 return &request->helper->post_params;
1851}
1852
1853ALWAYS_INLINEinline __attribute__((always_inline)) enum lwan_request_flags
1854lwan_request_get_accept_encoding(struct lwan_request *request)
1855{
1856 if (!(request->flags & REQUEST_PARSED_ACCEPT_ENCODING)) {
1857 parse_accept_encoding(request);
1858 request->flags |= REQUEST_PARSED_ACCEPT_ENCODING;
1859 }
1860
1861 return request->flags & REQUEST_ACCEPT_MASK;
1862}
1863
1864#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1865static int useless_coro_for_fuzzing(struct coro *c __attribute__((unused)),
1866 void *data __attribute__((unused)))
1867{
1868 return 0;
1869}
1870
1871static bool_Bool request_seems_complete(struct lwan_request_parser_helper *helper)
1872{
1873 return read_request_finalizer_from_helper(helper->buffer, helper, 1,
1874 false0) == FINALIZER_DONE;
1875}
1876
1877__attribute__((used)) int fuzz_parse_http_request(const uint8_t *data,
1878 size_t length)
1879{
1880 static struct coro_switcher switcher;
1881 static struct coro *coro;
1882 static char *header_start[N_HEADER_START64];
1883 static char data_copy[32767] = {0};
1884
1885 if (length > sizeof(data_copy))
1886 length = sizeof(data_copy);
1887 memcpy(data_copy, data, length);
1888
1889 if (!coro) {
1890 coro = coro_new(&switcher, useless_coro_for_fuzzing, NULL((void*)0));
1891
1892 lwan_job_thread_init();
1893 lwan_http_authorize_init();
1894 }
1895
1896 struct lwan_request_parser_helper helper = {
1897 .buffer = &(struct lwan_value){.value = data_copy, .len = length},
1898 .header_start = header_start,
1899 .error_when_n_packets = 2,
1900 };
1901 struct lwan_connection conn = {.coro = coro};
1902 struct lwan_proxy proxy = {};
1903 struct lwan_request request = {
1904 .helper = &helper,
1905 .conn = &conn,
1906 .flags = REQUEST_ALLOW_PROXY_REQS,
1907 .proxy = &proxy,
1908 };
1909
1910 /* If the finalizer isn't happy with a request, there's no point in
1911 * going any further with parsing it. */
1912 if (!request_seems_complete(&helper))
1913 return 0;
1914
1915 /* client_read() NUL-terminates the string */
1916 data_copy[length - 1] = '\0';
1917
1918 if (parse_http_request(&request) != HTTP_OK)
1919 return 0;
1920
1921 off_t trash1;
1922 time_t trash2;
1923 char *trash3;
1924 size_t gen = coro_deferred_get_generation(coro);
1925
1926 /* Only pointers were set in helper struct; actually parse them here. */
1927 parse_accept_encoding(&request);
1928
1929 /* Requesting these items will force them to be parsed, and also
1930 * exercise the lookup function. */
1931 LWAN_NO_DISCARD(lwan_request_get_header(&request, "Non-Existing-Header"))do { __typeof__(lwan_request_get_header(&request, "Non-Existing-Header"
)) no_discard_ = lwan_request_get_header(&request, "Non-Existing-Header"
); __asm__ __volatile__("" ::"g"(no_discard_) : "memory"); } while
(0)
;
1932
1933 /* Usually existing short header */
1934 LWAN_NO_DISCARD(lwan_request_get_header(&request, "Host"))do { __typeof__(lwan_request_get_header(&request, "Host")
) no_discard_ = lwan_request_get_header(&request, "Host")
; __asm__ __volatile__("" ::"g"(no_discard_) : "memory"); } while
(0)
;
1935
1936 LWAN_NO_DISCARD(lwan_request_get_cookie(&request, "Non-Existing-Cookie"))do { __typeof__(lwan_request_get_cookie(&request, "Non-Existing-Cookie"
)) no_discard_ = lwan_request_get_cookie(&request, "Non-Existing-Cookie"
); __asm__ __volatile__("" ::"g"(no_discard_) : "memory"); } while
(0)
;
1937 /* Set by some tests */
1938 LWAN_NO_DISCARD(lwan_request_get_cookie(&request, "FOO"))do { __typeof__(lwan_request_get_cookie(&request, "FOO"))
no_discard_ = lwan_request_get_cookie(&request, "FOO"); __asm__
__volatile__("" ::"g"(no_discard_) : "memory"); } while (0)
;
1939
1940 LWAN_NO_DISCARD(do { __typeof__(lwan_request_get_query_param(&request, "Non-Existing-Query-Param"
)) no_discard_ = lwan_request_get_query_param(&request, "Non-Existing-Query-Param"
); __asm__ __volatile__("" ::"g"(no_discard_) : "memory"); } while
(0)
1941 lwan_request_get_query_param(&request, "Non-Existing-Query-Param"))do { __typeof__(lwan_request_get_query_param(&request, "Non-Existing-Query-Param"
)) no_discard_ = lwan_request_get_query_param(&request, "Non-Existing-Query-Param"
); __asm__ __volatile__("" ::"g"(no_discard_) : "memory"); } while
(0)
;
1942
1943 LWAN_NO_DISCARD(do { __typeof__(lwan_request_get_post_param(&request, "Non-Existing-Post-Param"
)) no_discard_ = lwan_request_get_post_param(&request, "Non-Existing-Post-Param"
); __asm__ __volatile__("" ::"g"(no_discard_) : "memory"); } while
(0)
1944 lwan_request_get_post_param(&request, "Non-Existing-Post-Param"))do { __typeof__(lwan_request_get_post_param(&request, "Non-Existing-Post-Param"
)) no_discard_ = lwan_request_get_post_param(&request, "Non-Existing-Post-Param"
); __asm__ __volatile__("" ::"g"(no_discard_) : "memory"); } while
(0)
;
1945
1946 lwan_request_get_range(&request, &trash1, &trash1);
1947 LWAN_NO_DISCARD(trash1)do { __typeof__(trash1) no_discard_ = trash1; __asm__ __volatile__
("" ::"g"(no_discard_) : "memory"); } while (0)
;
1948
1949 lwan_request_get_if_modified_since(&request, &trash2);
1950 LWAN_NO_DISCARD(trash2)do { __typeof__(trash2) no_discard_ = trash2; __asm__ __volatile__
("" ::"g"(no_discard_) : "memory"); } while (0)
;
1951
1952 enum lwan_http_status handshake =
1953 prepare_websocket_handshake(&request, &trash3);
1954 LWAN_NO_DISCARD(trash3)do { __typeof__(trash3) no_discard_ = trash3; __asm__ __volatile__
("" ::"g"(no_discard_) : "memory"); } while (0)
;
1955 if (handshake == HTTP_SWITCHING_PROTOCOLS)
1956 free(trash3);
1957
1958 LWAN_NO_DISCARD(lwan_http_authorize(&request, "Fuzzy Realm", "/dev/null"))do { __typeof__(lwan_http_authorize(&request, "Fuzzy Realm"
, "/dev/null")) no_discard_ = lwan_http_authorize(&request
, "Fuzzy Realm", "/dev/null"); __asm__ __volatile__("" ::"g"(
no_discard_) : "memory"); } while (0)
;
1959
1960 coro_deferred_run(coro, gen);
1961
1962 return 0;
1963}
1964#endif
1965
1966static inline int64_t
1967make_async_yield_value(int fd, enum lwan_connection_coro_yield event)
1968{
1969 return (int64_t)(((uint64_t)fd << 32 | event));
1970}
1971
1972static inline void async_await_fd(struct coro *coro,
1973 int fd,
1974 enum lwan_connection_coro_yield events)
1975{
1976 assert(events >= CONN_CORO_ASYNC_AWAIT_READ &&((void) sizeof ((events >= CONN_CORO_ASYNC_AWAIT_READ &&
events <= CONN_CORO_ASYNC_AWAIT_READ_WRITE) ? 1 : 0), __extension__
({ if (events >= CONN_CORO_ASYNC_AWAIT_READ && events
<= CONN_CORO_ASYNC_AWAIT_READ_WRITE) ; else __assert_fail
("events >= CONN_CORO_ASYNC_AWAIT_READ && events <= CONN_CORO_ASYNC_AWAIT_READ_WRITE"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1977, __extension__ __PRETTY_FUNCTION__); }))
1977 events <= CONN_CORO_ASYNC_AWAIT_READ_WRITE)((void) sizeof ((events >= CONN_CORO_ASYNC_AWAIT_READ &&
events <= CONN_CORO_ASYNC_AWAIT_READ_WRITE) ? 1 : 0), __extension__
({ if (events >= CONN_CORO_ASYNC_AWAIT_READ && events
<= CONN_CORO_ASYNC_AWAIT_READ_WRITE) ; else __assert_fail
("events >= CONN_CORO_ASYNC_AWAIT_READ && events <= CONN_CORO_ASYNC_AWAIT_READ_WRITE"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-request.c"
, 1977, __extension__ __PRETTY_FUNCTION__); }))
;
1978
1979 return (void)coro_yield(coro, make_async_yield_value(fd, events));
1980}
1981
1982void lwan_request_await_read(struct lwan_request *r, int fd)
1983{
1984 return async_await_fd(r->conn->coro, fd, CONN_CORO_ASYNC_AWAIT_READ);
1985}
1986
1987void lwan_request_await_write(struct lwan_request *r, int fd)
1988{
1989 return async_await_fd(r->conn->coro, fd, CONN_CORO_ASYNC_AWAIT_WRITE);
1990}
1991
1992void lwan_request_await_read_write(struct lwan_request *r, int fd)
1993{
1994 return async_await_fd(r->conn->coro, fd, CONN_CORO_ASYNC_AWAIT_READ_WRITE);
1995}
1996
1997ssize_t lwan_request_async_read_flags(
1998 struct lwan_request *request, int fd, void *buf, size_t len, int flags)
1999{
2000 while (true1) {
2001 ssize_t r = recv(fd, buf, len, MSG_DONTWAITMSG_DONTWAIT | MSG_NOSIGNALMSG_NOSIGNAL | flags);
2002
2003 if (r < 0) {
2004 switch (errno(*__errno_location ())) {
2005 case EWOULDBLOCK11:
2006 lwan_request_await_read(request, fd);
2007 /* Fallthrough */
2008 case EINTR4:
2009 continue;
2010 case EPIPE32:
2011 return -errno(*__errno_location ());
2012 }
2013 }
2014
2015 return r;
2016 }
2017}
2018
2019ssize_t lwan_request_async_read(struct lwan_request *request,
2020 int fd,
2021 void *buf,
2022 size_t len)
2023{
2024 return lwan_request_async_read_flags(request, fd, buf, len, 0);
2025}
2026
2027ssize_t lwan_request_async_write(struct lwan_request *request,
2028 int fd,
2029 const void *buf,
2030 size_t len)
2031{
2032 while (true1) {
2033 ssize_t r = send(fd, buf, len, MSG_DONTWAITMSG_DONTWAIT|MSG_NOSIGNALMSG_NOSIGNAL);
2034
2035 if (r < 0) {
2036 switch (errno(*__errno_location ())) {
2037 case EWOULDBLOCK11:
2038 lwan_request_await_write(request, fd);
2039 /* Fallthrough */
2040 case EINTR4:
2041 continue;
2042 case EPIPE32:
2043 return -errno(*__errno_location ());
2044 }
2045 }
2046
2047 return r;
2048 }
2049}
2050
2051ssize_t lwan_request_async_writev(struct lwan_request *request,
2052 int fd,
2053 struct iovec *iov,
2054 int iov_count)
2055{
2056 ssize_t total_written = 0;
2057 int curr_iov = 0;
2058
2059 for (int tries = 10; tries;) {
2060 const int remaining_len = (int)(iov_count - curr_iov);
2061 ssize_t written;
2062
2063 if (remaining_len == 1) {
2064 const struct iovec *vec = &iov[curr_iov];
2065 return lwan_request_async_write(request, fd, vec->iov_base,
2066 vec->iov_len);
2067 }
2068
2069 written = writev(fd, iov + curr_iov, (size_t)remaining_len);
2070 if (UNLIKELY(written < 0)__builtin_expect(((written < 0)), (0))) {
2071 /* FIXME: Consider short writes as another try as well? */
2072 tries--;
2073
2074 switch (errno(*__errno_location ())) {
2075 case EAGAIN11:
2076 case EINTR4:
2077 goto try_again;
2078 default:
2079 goto out;
2080 }
2081 }
2082
2083 total_written += written;
2084
2085 while (curr_iov < iov_count &&
2086 written >= (ssize_t)iov[curr_iov].iov_len) {
2087 written -= (ssize_t)iov[curr_iov].iov_len;
2088 curr_iov++;
2089 }
2090
2091 if (curr_iov == iov_count)
2092 return total_written;
2093
2094 iov[curr_iov].iov_base = (char *)iov[curr_iov].iov_base + written;
2095 iov[curr_iov].iov_len -= (size_t)written;
2096
2097 try_again:
2098 lwan_request_await_write(request, fd);
2099 }
2100
2101out:
2102 coro_yield(request->conn->coro, CONN_CORO_ABORT);
2103 __builtin_unreachable();
2104}