Bug Summary

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