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