Bug Summary

File:lwan-request.c
Warning:line 1264, column 21
Casting data to a larger structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

1/*
2 * lwan - simple web server
3 * Copyright (c) 2012-2014 Leandro A. F. Pereira <leandro@hardinfo.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#define _GNU_SOURCE
21#include <arpa/inet.h>
22#include <assert.h>
23#include <errno(*__errno_location ()).h>
24#include <inttypes.h>
25#include <limits.h>
26#include <stddef.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/fcntl.h>
30#include <sys/mman.h>
31#include <sys/socket.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <unistd.h>
35
36#include "lwan-private.h"
37
38#include "lwan-config.h"
39#include "lwan-http-authorize.h"
40
41enum lwan_read_finalizer {
42 FINALIZER_DONE,
43 FINALIZER_TRY_AGAIN,
44 FINALIZER_YIELD_TRY_AGAIN,
45 FINALIZER_ERROR_TOO_LARGE,
46 FINALIZER_ERROR_TIMEOUT
47};
48
49struct request_parser_helper {
50 struct lwan_value *buffer;
51 char *next_request; /* For pipelined requests */
52 struct lwan_value accept_encoding;
53 struct lwan_value if_modified_since;
54 struct lwan_value range;
55 struct lwan_value cookie;
56
57 struct lwan_value query_string;
58 struct lwan_value fragment;
59 struct lwan_value content_length;
60 struct lwan_value authorization;
61
62 struct lwan_value post_data;
63 struct lwan_value content_type;
64
65 time_t error_when_time;
66 int error_when_n_packets;
67 int urls_rewritten;
68 char connection;
69};
70
71struct proxy_header_v2 {
72 uint8_t sig[12];
73 uint8_t cmd_ver;
74 uint8_t fam;
75 uint16_t len;
76 union {
77 struct {
78 in_addr_t src_addr;
79 in_addr_t dst_addr;
80 uint16_t src_port;
81 uint16_t dst_port;
82 } ip4;
83 struct {
84 struct in6_addr src_addr;
85 struct in6_addr dst_addr;
86 uint16_t src_port;
87 uint16_t dst_port;
88 } ip6;
89 } addr;
90};
91
92static char decode_hex_digit(char ch) __attribute__((pure));
93static char *ignore_leading_whitespace(char *buffer) __attribute__((pure));
94
95
96static bool_Bool
97parse_ascii_port(char *port, unsigned short *out)
98{
99 unsigned long parsed;
100 char *end_ptr;
101
102 errno(*__errno_location ()) = 0;
103 parsed = strtoul(port, &end_ptr, 10);
104
105 if (UNLIKELY(errno != 0)__builtin_expect((((*__errno_location ()) != 0)), (0)))
106 return false0;
107
108 if (UNLIKELY(*end_ptr != '\0')__builtin_expect(((*end_ptr != '\0')), (0)))
109 return false0;
110
111 if (UNLIKELY((unsigned long)(unsigned short)parsed != parsed)__builtin_expect((((unsigned long)(unsigned short)parsed != parsed
)), (0))
)
112 return false0;
113
114 *out = htons((unsigned short)parsed);
115 return true1;
116}
117
118static char *
119strsep_char(char *strp, char delim)
120{
121 char *ptr;
122
123 if (UNLIKELY(!strp)__builtin_expect(((!strp)), (0)))
124 return NULL((void*)0);
125
126 ptr = strchr(strp, delim);
127 if (UNLIKELY(!ptr)__builtin_expect(((!ptr)), (0)))
128 return NULL((void*)0);
129
130 *ptr = '\0';
131 return ptr + 1;
132}
133
134static char *
135parse_proxy_protocol_v1(struct lwan_request *request, char *buffer)
136{
137 static const size_t line_size = 108;
138 char *end, *protocol, *src_addr, *dst_addr, *src_port, *dst_port;
139 unsigned int size;
140 struct lwan_proxy *const proxy = request->proxy;
141
142 end = memchr(buffer, '\r', line_size);
143 if (UNLIKELY(!end || end[1] != '\n')__builtin_expect(((!end || end[1] != '\n')), (0)))
144 return NULL((void*)0);
145 *end = '\0';
146 size = (unsigned int) (end + 2 - buffer);
147
148 protocol = buffer + sizeof("PROXY ") - 1;
149 src_addr = strsep_char(protocol, ' ');
150 dst_addr = strsep_char(src_addr, ' ');
151 src_port = strsep_char(dst_addr, ' ');
152 dst_port = strsep_char(src_port, ' ');
153
154 if (UNLIKELY(!dst_port)__builtin_expect(((!dst_port)), (0)))
155 return NULL((void*)0);
156
157 enum {
158 TCP4 = MULTICHAR_CONSTANT('T', 'C', 'P', '4')((int32_t)(('T') | ('C') << 8 | ('P') << 16 | ('4'
) << 24))
,
159 TCP6 = MULTICHAR_CONSTANT('T', 'C', 'P', '6')((int32_t)(('T') | ('C') << 8 | ('P') << 16 | ('6'
) << 24))
,
160 };
161
162 STRING_SWITCH(protocol)switch (string_as_int32(protocol)) {
163 case TCP4: {
164 struct sockaddr_in *from = &proxy->from.ipv4;
165 struct sockaddr_in *to = &proxy->to.ipv4;
166
167 from->sin_family = to->sin_family = AF_INET2;
168
169 if (UNLIKELY(inet_pton(AF_INET, src_addr, &from->sin_addr) <= 0)__builtin_expect(((inet_pton(2, src_addr, &from->sin_addr
) <= 0)), (0))
)
170 return NULL((void*)0);
171 if (UNLIKELY(inet_pton(AF_INET, dst_addr, &to->sin_addr) <= 0)__builtin_expect(((inet_pton(2, dst_addr, &to->sin_addr
) <= 0)), (0))
)
172 return NULL((void*)0);
173 if (UNLIKELY(!parse_ascii_port(src_port, &from->sin_port))__builtin_expect(((!parse_ascii_port(src_port, &from->
sin_port))), (0))
)
174 return NULL((void*)0);
175 if (UNLIKELY(!parse_ascii_port(dst_port, &to->sin_port))__builtin_expect(((!parse_ascii_port(dst_port, &to->sin_port
))), (0))
)
176 return NULL((void*)0);
177
178 break;
179 }
180 case TCP6: {
181 struct sockaddr_in6 *from = &proxy->from.ipv6;
182 struct sockaddr_in6 *to = &proxy->to.ipv6;
183
184 from->sin6_family = to->sin6_family = AF_INET610;
185
186 if (UNLIKELY(inet_pton(AF_INET6, src_addr, &from->sin6_addr) <= 0)__builtin_expect(((inet_pton(10, src_addr, &from->sin6_addr
) <= 0)), (0))
)
187 return NULL((void*)0);
188 if (UNLIKELY(inet_pton(AF_INET6, dst_addr, &to->sin6_addr) <= 0)__builtin_expect(((inet_pton(10, dst_addr, &to->sin6_addr
) <= 0)), (0))
)
189 return NULL((void*)0);
190 if (UNLIKELY(!parse_ascii_port(src_port, &from->sin6_port))__builtin_expect(((!parse_ascii_port(src_port, &from->
sin6_port))), (0))
)
191 return NULL((void*)0);
192 if (UNLIKELY(!parse_ascii_port(dst_port, &to->sin6_port))__builtin_expect(((!parse_ascii_port(dst_port, &to->sin6_port
))), (0))
)
193 return NULL((void*)0);
194
195 break;
196 }
197 default:
198 return NULL((void*)0);
199 }
200
201 request->flags |= REQUEST_PROXIED;
202 return buffer + size;
203}
204
205static char *
206parse_proxy_protocol_v2(struct lwan_request *request, char *buffer)
207{
208 struct proxy_header_v2 *hdr = (struct proxy_header_v2*)buffer;
209 const unsigned int proto_signature_length = 16;
210 unsigned int size;
211 struct lwan_proxy *const proxy = request->proxy;
212
213 enum {
214 LOCAL = 0x20,
215 PROXY = 0x21,
216 TCP4 = 0x11,
217 TCP6 = 0x21
218 };
219
220 size = proto_signature_length + (unsigned int)ntohs(hdr->len);
221 if (UNLIKELY(size > (unsigned int)sizeof(*hdr))__builtin_expect(((size > (unsigned int)sizeof(*hdr))), (0
))
)
222 return NULL((void*)0);
223
224 if (hdr->cmd_ver == LOCAL) {
225 struct sockaddr_in *from = &proxy->from.ipv4;
226 struct sockaddr_in *to = &proxy->to.ipv4;
227
228 from->sin_family = to->sin_family = AF_UNSPEC0;
229 } else if (hdr->cmd_ver == PROXY) {
230 if (hdr->fam == TCP4) {
231 struct sockaddr_in *from = &proxy->from.ipv4;
232 struct sockaddr_in *to = &proxy->to.ipv4;
233
234 to->sin_family = from->sin_family = AF_INET2;
235
236 from->sin_addr.s_addr = hdr->addr.ip4.src_addr;
237 from->sin_port = hdr->addr.ip4.src_port;
238
239 to->sin_addr.s_addr = hdr->addr.ip4.dst_addr;
240 to->sin_port = hdr->addr.ip4.dst_port;
241 } else if (hdr->fam == TCP6) {
242 struct sockaddr_in6 *from = &proxy->from.ipv6;
243 struct sockaddr_in6 *to = &proxy->to.ipv6;
244
245 from->sin6_family = to->sin6_family = AF_INET610;
246
247 from->sin6_addr = hdr->addr.ip6.src_addr;
248 from->sin6_port = hdr->addr.ip6.src_port;
249
250 to->sin6_addr = hdr->addr.ip6.dst_addr;
251 to->sin6_port = hdr->addr.ip6.dst_port;
252 } else {
253 return NULL((void*)0);
254 }
255 } else {
256 return NULL((void*)0);
257 }
258
259 request->flags |= REQUEST_PROXIED;
260 return buffer + size;
261}
262
263static ALWAYS_INLINEinline __attribute__((always_inline)) char *
264identify_http_method(struct lwan_request *request, char *buffer)
265{
266 enum {
267 HTTP_STR_GET = MULTICHAR_CONSTANT('G','E','T',' ')((int32_t)(('G') | ('E') << 8 | ('T') << 16 | (' '
) << 24))
,
268 HTTP_STR_HEAD = MULTICHAR_CONSTANT('H','E','A','D')((int32_t)(('H') | ('E') << 8 | ('A') << 16 | ('D'
) << 24))
,
269 HTTP_STR_POST = MULTICHAR_CONSTANT('P','O','S','T')((int32_t)(('P') | ('O') << 8 | ('S') << 16 | ('T'
) << 24))
,
270 HTTP_STR_OPTIONS = MULTICHAR_CONSTANT('O','P','T','I')((int32_t)(('O') | ('P') << 8 | ('T') << 16 | ('I'
) << 24))
,
271 HTTP_STR_DELETE = MULTICHAR_CONSTANT('D','E','L','E')((int32_t)(('D') | ('E') << 8 | ('L') << 16 | ('E'
) << 24))
,
272 };
273
274 STRING_SWITCH(buffer)switch (string_as_int32(buffer)) {
275 case HTTP_STR_GET:
276 request->flags |= REQUEST_METHOD_GET;
277 return buffer + sizeof("GET ") - 1;
278 case HTTP_STR_HEAD:
279 request->flags |= REQUEST_METHOD_HEAD;
280 return buffer + sizeof("HEAD ") - 1;
281 case HTTP_STR_POST:
282 request->flags |= REQUEST_METHOD_POST;
283 return buffer + sizeof("POST ") - 1;
284 case HTTP_STR_OPTIONS:
285 request->flags |= REQUEST_METHOD_OPTIONS;
286 return buffer + sizeof("OPTIONS ") - 1;
287 case HTTP_STR_DELETE:
288 request->flags |= REQUEST_METHOD_DELETE;
289 return buffer + sizeof("DELETE ") - 1;
290 }
291
292 return NULL((void*)0);
293}
294
295static ALWAYS_INLINEinline __attribute__((always_inline)) char
296decode_hex_digit(char ch)
297{
298 return (char)((ch <= '9') ? ch - '0' : (ch & 7) + 9);
299}
300
301static size_t
302url_decode(char *str)
303{
304 if (UNLIKELY(!str)__builtin_expect(((!str)), (0)))
305 return 0;
306
307 char *ch, *decoded;
308 for (decoded = ch = str; *ch; ch++) {
309 if (*ch == '%' && LIKELY(lwan_char_isxdigit(ch[1]) && lwan_char_isxdigit(ch[2]))__builtin_expect((!!(lwan_char_isxdigit(ch[1]) && lwan_char_isxdigit
(ch[2]))), (1))
) {
310 char tmp = (char)(decode_hex_digit(ch[1]) << 4 | decode_hex_digit(ch[2]));
311 if (UNLIKELY(!tmp)__builtin_expect(((!tmp)), (0)))
312 return 0;
313 *decoded++ = tmp;
314 ch += 2;
315 } else if (*ch == '+') {
316 *decoded++ = ' ';
317 } else {
318 *decoded++ = *ch;
319 }
320 }
321
322 *decoded = '\0';
323 return (size_t)(decoded - str);
324}
325
326static int
327key_value_compare(const void *a, const void *b)
328{
329 return strcmp(((struct lwan_key_value *)a)->key, ((struct lwan_key_value *)b)->key);
330}
331
332static void
333parse_key_values(struct lwan_request *request,
334 struct lwan_value *helper_value, struct lwan_key_value_array *array,
335 size_t (*decode_value)(char *value), const char separator)
336{
337 struct lwan_key_value *kv;
338 char *ptr = helper_value->value;
339
340 if (!helper_value->len)
341 return;
342
343 lwan_key_value_array_init(array);
344 /* Calling lwan_key_value_array_reset() twice is fine, so even if 'goto
345 * error' is executed in this function, nothing bad should happen. */
346 coro_defer(request->conn->coro, CORO_DEFER(lwan_key_value_array_reset)((void (*)(void *))(lwan_key_value_array_reset)), array);
347
348 do {
349 char *key, *value;
350
351 while (*ptr == ' ' || *ptr == separator)
352 ptr++;
353 if (UNLIKELY(*ptr == '\0')__builtin_expect(((*ptr == '\0')), (0)))
354 goto error;
355
356 key = ptr;
357 ptr = strsep_char(key, separator);
358
359 value = strsep_char(key, '=');
360 if (UNLIKELY(!value)__builtin_expect(((!value)), (0)))
361 value = "";
362 else if (UNLIKELY(!decode_value(value))__builtin_expect(((!decode_value(value))), (0)))
363 goto error;
364
365 if (UNLIKELY(!decode_value(key))__builtin_expect(((!decode_value(key))), (0)))
366 goto error;
367
368 kv = lwan_key_value_array_append(array);
369 if (UNLIKELY(!kv)__builtin_expect(((!kv)), (0)))
370 goto error;
371
372 kv->key = key;
373 kv->value = value;
374 } while (ptr);
375
376 kv = lwan_key_value_array_append(array);
377 if (UNLIKELY(!kv)__builtin_expect(((!kv)), (0)))
378 goto error;
379 kv->key = kv->value = NULL((void*)0);
380
381 lwan_key_value_array_sort(array, key_value_compare);
382
383 return;
384
385error:
386 lwan_key_value_array_reset(array);
387}
388
389static size_t
390identity_decode(char *input __attribute__((unused)))
391{
392 return 1;
393}
394
395static void
396parse_cookies(struct lwan_request *request, struct request_parser_helper *helper)
397{
398 parse_key_values(request, &helper->cookie, &request->cookies,
399 identity_decode, ';');
400}
401
402static void
403parse_query_string(struct lwan_request *request, struct request_parser_helper *helper)
404{
405 parse_key_values(request, &helper->query_string, &request->query_params,
406 url_decode, '&');
407}
408
409static void
410parse_post_data(struct lwan_request *request, struct request_parser_helper *helper)
411{
412 static const char content_type[] = "application/x-www-form-urlencoded";
413
414 request->header.body = &helper->post_data;
415 request->header.content_type = &helper->content_type;
416
417 if (helper->content_type.len < sizeof(content_type) - 1)
418 return;
419 if (UNLIKELY(strncmp(helper->content_type.value, content_type, sizeof(content_type) - 1))__builtin_expect(((strncmp(helper->content_type.value, content_type
, sizeof(content_type) - 1))), (0))
)
420 return;
421
422 parse_key_values(request, &helper->post_data, &request->post_data,
423 url_decode, '&');
424}
425
426static void
427parse_fragment_and_query(struct lwan_request *request,
428 struct request_parser_helper *helper, const char *space)
429{
430 /* Most of the time, fragments are small -- so search backwards */
431 char *fragment = memrchr(request->url.value, '#', request->url.len);
432 if (fragment) {
433 *fragment = '\0';
434 helper->fragment.value = fragment + 1;
435 helper->fragment.len = (size_t)(space - fragment - 1);
436 request->url.len -= helper->fragment.len + 1;
437 }
438
439 /* Most of the time, query string values are larger than the URL, so
440 search from the beginning */
441 char *query_string = memchr(request->url.value, '?', request->url.len);
442 if (query_string) {
443 *query_string = '\0';
444 helper->query_string.value = query_string + 1;
445 helper->query_string.len = (size_t)((fragment ? fragment : space) - query_string - 1);
446 request->url.len -= helper->query_string.len + 1;
447 }
448}
449
450static char *
451identify_http_path(struct lwan_request *request, char *buffer,
452 struct request_parser_helper *helper)
453{
454 static const size_t minimal_request_line_len = sizeof("/ HTTP/1.0") - 1;
455 char *space, *end_of_line;
456 enum {
457 HTTP_VERSION_1_0 = MULTICHAR_CONSTANT_LARGE('H','T','T','P','/','1','.','0')((int64_t)((int32_t)(('H') | ('T') << 8 | ('T') <<
16 | ('P') << 24)) | (int64_t)((int32_t)(('/') | ('1')
<< 8 | ('.') << 16 | ('0') << 24))<<
32)
,
458 HTTP_VERSION_1_1 = MULTICHAR_CONSTANT_LARGE('H','T','T','P','/','1','.','1')((int64_t)((int32_t)(('H') | ('T') << 8 | ('T') <<
16 | ('P') << 24)) | (int64_t)((int32_t)(('/') | ('1')
<< 8 | ('.') << 16 | ('1') << 24))<<
32)
,
459 };
460
461 if (UNLIKELY(*buffer != '/')__builtin_expect(((*buffer != '/')), (0)))
462 return NULL((void*)0);
463
464 end_of_line = memchr(buffer, '\r',
465 (helper->buffer->len - (size_t)(buffer - helper->buffer->value)));
466 if (UNLIKELY(!end_of_line)__builtin_expect(((!end_of_line)), (0)))
467 return NULL((void*)0);
468 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))
)
469 return NULL((void*)0);
470 *end_of_line = '\0';
471
472 space = end_of_line - sizeof("HTTP/X.X");
473
474 request->url.value = buffer;
475 request->url.len = (size_t)(space - buffer);
476 parse_fragment_and_query(request, helper, space);
477 request->original_url = request->url;
478
479 *space++ = '\0';
480
481 STRING_SWITCH_LARGE(space)switch (string_as_int64(space)) {
482 case HTTP_VERSION_1_0:
483 request->flags |= REQUEST_IS_HTTP_1_0;
484 /* fallthrough */
485 case HTTP_VERSION_1_1:
486 break;
487 default:
488 return NULL((void*)0);
489 }
490
491 return end_of_line + 1;
492}
493
494#define MATCH_HEADER(hdr) \
495 do { \
496 p += sizeof(hdr) - 1; \
497 if (UNLIKELY(p >= buffer_end)__builtin_expect(((p >= buffer_end)), (0))) /* reached the end of header blocks */ \
498 return NULL((void*)0); \
499 \
500 if (UNLIKELY(string_as_int16(p) != HTTP_HDR_COLON_SPACE)__builtin_expect(((string_as_int16(p) != HTTP_HDR_COLON_SPACE
)), (0))
) \
501 goto did_not_match; \
502 p += 2; \
503 \
504 char *end = strchr(p, '\r'); \
505 if (UNLIKELY(!end)__builtin_expect(((!end)), (0))) \
506 goto did_not_match; \
507 \
508 *end = '\0'; \
509 value = p; \
510 length = (size_t)(end - value); \
511 \
512 p = end + 1; \
513 if (UNLIKELY(*p != '\n')__builtin_expect(((*p != '\n')), (0))) \
514 goto did_not_match; \
515 } while (0)
516
517#define CASE_HEADER(hdr_const,hdr_name) \
518 case hdr_const: MATCH_HEADER(hdr_name);
519
520static char *
521parse_headers(struct request_parser_helper *helper, char *buffer, char *buffer_end)
522{
523 enum {
524 HTTP_HDR_COLON_SPACE = MULTICHAR_CONSTANT_SMALL(':', ' ')((int16_t)((':') | (' ') << 8)),
525 HTTP_HDR_REQUEST_END = MULTICHAR_CONSTANT_SMALL('\r','\n')((int16_t)(('\r') | ('\n') << 8)),
526 HTTP_HDR_ENCODING = MULTICHAR_CONSTANT_L('-','E','n','c')(((int32_t)(('-') | ('E') << 8 | ('n') << 16 | ('c'
) << 24)) | 0x20202020)
,
527 HTTP_HDR_LENGTH = MULTICHAR_CONSTANT_L('-','L','e','n')(((int32_t)(('-') | ('L') << 8 | ('e') << 16 | ('n'
) << 24)) | 0x20202020)
,
528 HTTP_HDR_TYPE = MULTICHAR_CONSTANT_L('-','T','y','p')(((int32_t)(('-') | ('T') << 8 | ('y') << 16 | ('p'
) << 24)) | 0x20202020)
,
529 HTTP_HDR_ACCEPT = MULTICHAR_CONSTANT_L('A','c','c','e')(((int32_t)(('A') | ('c') << 8 | ('c') << 16 | ('e'
) << 24)) | 0x20202020)
,
530 HTTP_HDR_AUTHORIZATION = MULTICHAR_CONSTANT_L('A','u','t','h')(((int32_t)(('A') | ('u') << 8 | ('t') << 16 | ('h'
) << 24)) | 0x20202020)
,
531 HTTP_HDR_CONNECTION = MULTICHAR_CONSTANT_L('C','o','n','n')(((int32_t)(('C') | ('o') << 8 | ('n') << 16 | ('n'
) << 24)) | 0x20202020)
,
532 HTTP_HDR_CONTENT = MULTICHAR_CONSTANT_L('C','o','n','t')(((int32_t)(('C') | ('o') << 8 | ('n') << 16 | ('t'
) << 24)) | 0x20202020)
,
533 HTTP_HDR_COOKIE = MULTICHAR_CONSTANT_L('C','o','o','k')(((int32_t)(('C') | ('o') << 8 | ('o') << 16 | ('k'
) << 24)) | 0x20202020)
,
534 HTTP_HDR_IF_MODIFIED_SINCE = MULTICHAR_CONSTANT_L('I','f','-','M')(((int32_t)(('I') | ('f') << 8 | ('-') << 16 | ('M'
) << 24)) | 0x20202020)
,
535 HTTP_HDR_RANGE = MULTICHAR_CONSTANT_L('R','a','n','g')(((int32_t)(('R') | ('a') << 8 | ('n') << 16 | ('g'
) << 24)) | 0x20202020)
536 };
537
538 for (char *p = buffer; *p; buffer = ++p) {
539 char *value;
540 size_t length;
541
542 if ((p + sizeof(int32_t)) >= buffer_end)
543 break;
544
545 STRING_SWITCH_L(p)switch (string_as_int32(p) | 0x20202020) {
546 case HTTP_HDR_ACCEPT:
547 p += sizeof("Accept") - 1;
548
549 STRING_SWITCH_L(p)switch (string_as_int32(p) | 0x20202020) {
550 CASE_HEADER(HTTP_HDR_ENCODING, "-Encoding")
551 helper->accept_encoding.value = value;
552 helper->accept_encoding.len = length;
553 break;
554 }
555 break;
556 CASE_HEADER(HTTP_HDR_AUTHORIZATION, "Authorization")
557 helper->authorization.value = value;
558 helper->authorization.len = length;
559 break;
560 CASE_HEADER(HTTP_HDR_CONNECTION, "Connection")
561 helper->connection = (*value | 0x20);
562 break;
563 case HTTP_HDR_CONTENT:
564 p += sizeof("Content") - 1;
565
566 STRING_SWITCH_L(p)switch (string_as_int32(p) | 0x20202020) {
567 CASE_HEADER(HTTP_HDR_TYPE, "-Type")
568 helper->content_type.value = value;
569 helper->content_type.len = length;
570 break;
571 CASE_HEADER(HTTP_HDR_LENGTH, "-Length")
572 helper->content_length.value = value;
573 helper->content_length.len = length;
574 break;
575 }
576 break;
577 CASE_HEADER(HTTP_HDR_COOKIE, "Cookie")
578 helper->cookie.value = value;
579 helper->cookie.len = length;
580 break;
581 CASE_HEADER(HTTP_HDR_IF_MODIFIED_SINCE, "If-Modified-Since")
582 helper->if_modified_since.value = value;
583 helper->if_modified_since.len = length;
584 break;
585 CASE_HEADER(HTTP_HDR_RANGE, "Range")
586 helper->range.value = value;
587 helper->range.len = length;
588 break;
589 default:
590 STRING_SWITCH_SMALL(p)switch (string_as_int16(p)) {
591 case HTTP_HDR_REQUEST_END:
592 *p = '\0';
593 helper->next_request = p + sizeof("\r\n") - 1;
594 return p;
595 }
596 }
597did_not_match:
598 p = memchr(p, '\n', (size_t)(buffer_end - p));
599 if (!p)
600 break;
601 }
602
603 return buffer;
604}
605
606#undef CASE_HEADER
607#undef MATCH_HEADER
608
609static void
610parse_if_modified_since(struct lwan_request *request, struct request_parser_helper *helper)
611{
612 if (UNLIKELY(!helper->if_modified_since.len)__builtin_expect(((!helper->if_modified_since.len)), (0)))
613 return;
614
615 struct tm t;
616 char *processed = strptime(helper->if_modified_since.value,
617 "%a, %d %b %Y %H:%M:%S GMT", &t);
618
619 if (UNLIKELY(!processed)__builtin_expect(((!processed)), (0)))
620 return;
621 if (UNLIKELY(*processed)__builtin_expect(((*processed)), (0)))
622 return;
623
624 request->header.if_modified_since = timegm(&t);
625}
626
627static void
628parse_range(struct lwan_request *request, struct request_parser_helper *helper)
629{
630 if (UNLIKELY(helper->range.len <= (sizeof("bytes=") - 1))__builtin_expect(((helper->range.len <= (sizeof("bytes="
) - 1))), (0))
)
631 return;
632
633 char *range = helper->range.value;
634 if (UNLIKELY(strncmp(range, "bytes=", sizeof("bytes=") - 1))__builtin_expect(((strncmp(range, "bytes=", sizeof("bytes=") -
1))), (0))
)
635 return;
636
637 range += sizeof("bytes=") - 1;
638 off_t from, to;
639
640 if (sscanf(range, "%"SCNu64"l" "u""-%"SCNu64"l" "u", &from, &to) == 2) {
641 request->header.range.from = from;
642 request->header.range.to = to;
643 } else if (sscanf(range, "-%"SCNu64"l" "u", &to) == 1) {
644 request->header.range.from = 0;
645 request->header.range.to = to;
646 } else if (sscanf(range, "%"SCNu64"l" "u""-", &from) == 1) {
647 request->header.range.from = from;
648 request->header.range.to = -1;
649 } else {
650 request->header.range.from = -1;
651 request->header.range.to = -1;
652 }
653}
654
655static void
656parse_accept_encoding(struct lwan_request *request, struct request_parser_helper *helper)
657{
658 if (!helper->accept_encoding.len)
659 return;
660
661 enum {
662 ENCODING_DEFL1 = MULTICHAR_CONSTANT('d','e','f','l')((int32_t)(('d') | ('e') << 8 | ('f') << 16 | ('l'
) << 24))
,
663 ENCODING_DEFL2 = MULTICHAR_CONSTANT(' ','d','e','f')((int32_t)((' ') | ('d') << 8 | ('e') << 16 | ('f'
) << 24))
,
664 ENCODING_GZIP1 = MULTICHAR_CONSTANT('g','z','i','p')((int32_t)(('g') | ('z') << 8 | ('i') << 16 | ('p'
) << 24))
,
665 ENCODING_GZIP2 = MULTICHAR_CONSTANT(' ','g','z','i')((int32_t)((' ') | ('g') << 8 | ('z') << 16 | ('i'
) << 24))
666 };
667
668 for (char *p = helper->accept_encoding.value; p && *p; p++) {
669 STRING_SWITCH(p)switch (string_as_int32(p)) {
670 case ENCODING_DEFL1:
671 case ENCODING_DEFL2:
672 request->flags |= REQUEST_ACCEPT_DEFLATE;
673 break;
674 case ENCODING_GZIP1:
675 case ENCODING_GZIP2:
676 request->flags |= REQUEST_ACCEPT_GZIP;
677 break;
678 }
679
680 if (!(p = strchr(p, ',')))
681 break;
682 }
683}
684
685static ALWAYS_INLINEinline __attribute__((always_inline)) char *
686ignore_leading_whitespace(char *buffer)
687{
688 while (*buffer && lwan_char_isspace(*buffer))
689 buffer++;
690 return buffer;
691}
692
693static ALWAYS_INLINEinline __attribute__((always_inline)) void
694compute_keep_alive_flag(struct lwan_request *request, struct request_parser_helper *helper)
695{
696 bool_Bool is_keep_alive;
697 if (request->flags & REQUEST_IS_HTTP_1_0)
698 is_keep_alive = (helper->connection == 'k');
699 else
700 is_keep_alive = (helper->connection != 'c');
701 if (is_keep_alive)
702 request->conn->flags |= CONN_KEEP_ALIVE;
703 else
704 request->conn->flags &= ~CONN_KEEP_ALIVE;
705}
706
707static enum lwan_http_status read_from_request_socket(struct lwan_request *request,
708 struct lwan_value *buffer, struct request_parser_helper *helper, const size_t buffer_size,
709 enum lwan_read_finalizer (*finalizer)(size_t total_read, size_t buffer_size, struct request_parser_helper *helper, int n_packets))
710{
711 ssize_t n;
712 size_t total_read = 0;
713 int n_packets = 0;
714
715 if (helper->next_request) {
716 buffer->len -= (size_t)(helper->next_request - buffer->value);
717 /* FIXME: This memmove() could be eventually removed if a better
718 * stucture were used for the request buffer. */
719 memmove(buffer->value, helper->next_request, buffer->len);
720 total_read = buffer->len;
721 goto try_to_finalize;
722 }
723
724 for (; ; n_packets++) {
725 n = read(request->fd, buffer->value + total_read,
726 (size_t)(buffer_size - total_read));
727 /* Client has shutdown orderly, nothing else to do; kill coro */
728 if (UNLIKELY(n == 0)__builtin_expect(((n == 0)), (0))) {
729 coro_yield(request->conn->coro, CONN_CORO_ABORT);
730 __builtin_unreachable();
731 }
732
733 if (UNLIKELY(n < 0)__builtin_expect(((n < 0)), (0))) {
734 switch (errno(*__errno_location ())) {
735 case EAGAIN11:
736 case EINTR4:
737yield_and_read_again:
738 request->conn->flags |= CONN_MUST_READ;
739 coro_yield(request->conn->coro, CONN_CORO_MAY_RESUME);
740 continue;
741 }
742
743 /* Unexpected error before reading anything */
744 if (UNLIKELY(!total_read)__builtin_expect(((!total_read)), (0)))
745 return HTTP_BAD_REQUEST;
746
747 /* Unexpected error, kill coro */
748 coro_yield(request->conn->coro, CONN_CORO_ABORT);
749 __builtin_unreachable();
750 }
751
752 total_read += (size_t)n;
753 buffer->len = (size_t)total_read;
754
755try_to_finalize:
756 switch (finalizer(total_read, buffer_size, helper, n_packets)) {
757 case FINALIZER_DONE:
758 request->conn->flags &= ~CONN_MUST_READ;
759 buffer->value[buffer->len] = '\0';
760 return HTTP_OK;
761 case FINALIZER_TRY_AGAIN:
762 continue;
763 case FINALIZER_YIELD_TRY_AGAIN:
764 goto yield_and_read_again;
765 case FINALIZER_ERROR_TOO_LARGE:
766 return HTTP_TOO_LARGE;
767 case FINALIZER_ERROR_TIMEOUT:
768 return HTTP_TIMEOUT;
769 }
770 }
771
772 /* Shouldn't reach here. */
773 coro_yield(request->conn->coro, CONN_CORO_ABORT);
774 __builtin_unreachable();
775 return HTTP_INTERNAL_ERROR;
776}
777
778static enum lwan_read_finalizer read_request_finalizer(size_t total_read,
779 size_t buffer_size, struct request_parser_helper *helper, int n_packets)
780{
781 /* 16 packets should be enough to read a request (without the body, as
782 * is the case for POST requests). This yields a timeout error to avoid
783 * clients being intentionally slow and hogging the server. */
784 if (UNLIKELY(n_packets > helper->error_when_n_packets)__builtin_expect(((n_packets > helper->error_when_n_packets
)), (0))
)
785 return FINALIZER_ERROR_TIMEOUT;
786
787 if (UNLIKELY(total_read < 4)__builtin_expect(((total_read < 4)), (0)))
788 return FINALIZER_YIELD_TRY_AGAIN;
789
790 if (UNLIKELY(total_read == buffer_size)__builtin_expect(((total_read == buffer_size)), (0)))
791 return FINALIZER_ERROR_TOO_LARGE;
792
793 if (LIKELY(helper->next_request)__builtin_expect((!!(helper->next_request)), (1))) {
794 helper->next_request = NULL((void*)0);
795 return FINALIZER_DONE;
796 }
797
798 /* FIXME: Would saving the location of CRLFCRLF be useful? Maybe
799 * parse_headers() could benefit from this information? How would it
800 * compare to helper->next_request? */
801 if (LIKELY(memmem(helper->buffer->value, helper->buffer->len, "\r\n\r\n", 4))__builtin_expect((!!(memmem(helper->buffer->value, helper
->buffer->len, "\r\n\r\n", 4))), (1))
)
802 return FINALIZER_DONE;
803
804 return FINALIZER_TRY_AGAIN;
805}
806
807static ALWAYS_INLINEinline __attribute__((always_inline)) enum lwan_http_status
808read_request(struct lwan_request *request, struct request_parser_helper *helper)
809{
810 return read_from_request_socket(request, helper->buffer, helper,
811 DEFAULT_BUFFER_SIZE4096, read_request_finalizer);
812}
813
814static enum lwan_read_finalizer post_data_finalizer(size_t total_read,
815 size_t buffer_size, struct request_parser_helper *helper, int n_packets)
816{
817 if (buffer_size == total_read)
818 return FINALIZER_DONE;
819
820 /* For POST requests, the body can be larger, and due to small MTUs on
821 * most ethernet connections, responding with a timeout solely based on
822 * number of packets doesn't work. Use keepalive timeout instead. */
823 if (UNLIKELY(time(NULL) > helper->error_when_time)__builtin_expect(((time(((void*)0)) > helper->error_when_time
)), (0))
)
824 return FINALIZER_ERROR_TIMEOUT;
825
826 /* In addition to time, also estimate the number of packets based on an
827 * usual MTU value and the request body size. */
828 if (UNLIKELY(n_packets > helper->error_when_n_packets)__builtin_expect(((n_packets > helper->error_when_n_packets
)), (0))
)
829 return FINALIZER_ERROR_TIMEOUT;
830
831 return FINALIZER_TRY_AGAIN;
832}
833
834static ALWAYS_INLINEinline __attribute__((always_inline)) int max(int a, int b)
835{
836 return (a > b) ? a : b;
837}
838
839static ALWAYS_INLINEinline __attribute__((always_inline)) int calculate_n_packets(size_t total)
840{
841 /* 740 = 1480 (a common MTU) / 2, so that Lwan'll optimistically error out
842 * after ~2x number of expected packets to fully read the request body.*/
843 return max(1, (int)(total / 740));
844}
845
846static const char *
847get_abs_path_env(const char *var)
848{
849 const char *ret = secure_getenv(var);
850 return (ret && *ret == '/') ? ret : NULL((void*)0);
851}
852
853static const char *
854get_temp_dir(void)
855{
856 struct stat st;
857 const char *tmpdir;
858
859 tmpdir = get_abs_path_env("TMPDIR");
860 if (tmpdir)
861 return tmpdir;
862
863 tmpdir = get_abs_path_env("TMP");
864 if (tmpdir)
865 return tmpdir;
866
867 tmpdir = get_abs_path_env("TEMP");
868 if (tmpdir)
869 return tmpdir;
870
871 if (!stat("/tmp", &st) && S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
872 return "/tmp";
873
874 if (!stat("/var/tmp", &st) && S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
875 return "/var/tmp";
876
877 return NULL((void*)0);
878}
879
880static int
881create_temp_file(void)
882{
883 char template[PATH_MAX4096];
884 const char *tmpdir;
885 mode_t prev_mask;
886 int ret;
887
888 tmpdir = get_temp_dir();
889 if (UNLIKELY(!tmpdir)__builtin_expect(((!tmpdir)), (0)))
890 return -ENOENT2;
891
892#if defined(O_TMPFILE(020000000 | 0200000))
893 int fd = open(tmpdir, O_TMPFILE(020000000 | 0200000) | O_RDWR02 | O_EXCL0200 | O_CLOEXEC02000000,
894 S_IRUSR0400 | S_IWUSR0200);
895 if (LIKELY(fd >= 0)__builtin_expect((!!(fd >= 0)), (1)))
896 return fd;
897#endif
898
899 ret = snprintf(template, sizeof(template), "%s/lwanXXXXXX", tmpdir);
900 if (UNLIKELY(ret < 0 || ret >= (int)sizeof(template))__builtin_expect(((ret < 0 || ret >= (int)sizeof(template
))), (0))
)
901 return -EOVERFLOW75;
902
903 prev_mask = umask_for_tmpfile(S_IRUSR | S_IWUSR)({ (void)(0400 | 0200); 0U; });
904 ret = mkostemp(template, O_CLOEXEC02000000);
905 umask_for_tmpfile(prev_mask)({ (void)(prev_mask); 0U; });
906
907 if (LIKELY(ret >= 0)__builtin_expect((!!(ret >= 0)), (1)))
908 unlink(template);
909
910 return ret;
911}
912
913struct file_backed_buffer {
914 void *ptr;
915 size_t size;
916};
917
918static void
919free_post_buffer(void *data)
920{
921 struct file_backed_buffer *buf = data;
922
923 munmap(buf->ptr, buf->size);
924 free(buf);
925}
926
927static void*
928alloc_post_buffer(struct coro *coro, size_t size, bool_Bool allow_file)
929{
930 struct file_backed_buffer *buf;
931 void *ptr;
932 int fd;
933
934 if (LIKELY(size < 1<<20)__builtin_expect((!!(size < 1<<20)), (1))) {
935 ptr = coro_malloc(coro, size);
936
937 if (LIKELY(ptr)__builtin_expect((!!(ptr)), (1)))
938 return ptr;
939 }
940
941 if (UNLIKELY(!allow_file)__builtin_expect(((!allow_file)), (0)))
942 return NULL((void*)0);
943
944 fd = create_temp_file();
945 if (UNLIKELY(fd < 0)__builtin_expect(((fd < 0)), (0)))
946 return NULL((void*)0);
947
948 if (UNLIKELY(ftruncate(fd, (off_t)size) < 0)__builtin_expect(((ftruncate(fd, (off_t)size) < 0)), (0))) {
949 close(fd);
950 return NULL((void*)0);
951 }
952
953 ptr = mmap(NULL((void*)0), size, PROT_READ0x1 | PROT_WRITE0x2, MAP_PRIVATE0x02, fd, 0);
954 close(fd);
955 if (UNLIKELY(ptr == MAP_FAILED)__builtin_expect(((ptr == ((void *) -1))), (0)))
956 return NULL((void*)0);
957
958 buf = coro_malloc_full(coro, sizeof(*buf), free_post_buffer);
959 if (UNLIKELY(!buf)__builtin_expect(((!buf)), (0))) {
960 munmap(ptr, size);
961 return NULL((void*)0);
962 }
963
964 buf->ptr = ptr;
965 buf->size = size;
966 return ptr;
967}
968
969static enum lwan_http_status
970read_post_data(struct lwan_request *request, struct request_parser_helper *helper)
971{
972 /* Holy indirection, Batman! */
973 struct lwan_config *config = &request->conn->thread->lwan->config;
974 const size_t max_post_data_size = config->max_post_data_size;
975 char *new_buffer;
976 long parsed_size;
977
978 if (UNLIKELY(!helper->content_length.value)__builtin_expect(((!helper->content_length.value)), (0)))
979 return HTTP_BAD_REQUEST;
980 parsed_size = parse_long(helper->content_length.value, -1);
981 if (UNLIKELY(parsed_size < 0)__builtin_expect(((parsed_size < 0)), (0)))
982 return HTTP_BAD_REQUEST;
983 if (UNLIKELY(parsed_size >= (long)max_post_data_size)__builtin_expect(((parsed_size >= (long)max_post_data_size
)), (0))
)
984 return HTTP_TOO_LARGE;
985
986 size_t post_data_size = (size_t)parsed_size;
987 size_t have;
988 if (!helper->next_request) {
989 have = 0;
990 } else {
991 char *buffer_end = helper->buffer->value + helper->buffer->len;
992 have = (size_t)(ptrdiff_t)(buffer_end - helper->next_request);
993
994 if (have >= post_data_size) {
995 helper->post_data.value = helper->next_request;
996 helper->post_data.len = post_data_size;
997 helper->next_request += post_data_size;
998 return HTTP_OK;
999 }
1000 }
1001
1002 new_buffer = alloc_post_buffer(request->conn->coro, post_data_size + 1,
1003 config->allow_post_temp_file);
1004 if (UNLIKELY(!new_buffer)__builtin_expect(((!new_buffer)), (0)))
1005 return HTTP_INTERNAL_ERROR;
1006
1007 helper->post_data.value = new_buffer;
1008 helper->post_data.len = post_data_size;
1009 if (have)
1010 new_buffer = mempcpy(new_buffer, helper->next_request, have);
1011 helper->next_request = NULL((void*)0);
1012
1013 helper->error_when_time = time(NULL((void*)0)) + request->conn->thread->lwan->config.keep_alive_timeout;
1014 helper->error_when_n_packets = calculate_n_packets(post_data_size);
1015
1016 struct lwan_value buffer = { .value = new_buffer, .len = post_data_size - have };
1017 return read_from_request_socket(request, &buffer, helper, buffer.len,
1018 post_data_finalizer);
1019}
1020
1021static char *
1022parse_proxy_protocol(struct lwan_request *request, char *buffer)
1023{
1024 enum {
1025 HTTP_PROXY_VER1 = MULTICHAR_CONSTANT('P','R','O','X')((int32_t)(('P') | ('R') << 8 | ('O') << 16 | ('X'
) << 24))
,
1026 HTTP_PROXY_VER2 = MULTICHAR_CONSTANT('\x0D','\x0A','\x0D','\x0A')((int32_t)(('\x0D') | ('\x0A') << 8 | ('\x0D') <<
16 | ('\x0A') << 24))
,
1027 };
1028
1029 STRING_SWITCH(buffer)switch (string_as_int32(buffer)) {
1030 case HTTP_PROXY_VER1:
1031 return parse_proxy_protocol_v1(request, buffer);
1032 case HTTP_PROXY_VER2:
1033 return parse_proxy_protocol_v2(request, buffer);
1034 }
1035
1036 return buffer;
1037}
1038
1039static enum lwan_http_status
1040parse_http_request(struct lwan_request *request, struct request_parser_helper *helper)
1041{
1042 char *buffer = helper->buffer->value;
1043
1044 if (request->flags & REQUEST_ALLOW_PROXY_REQS) {
1045 /* REQUEST_ALLOW_PROXY_REQS will be cleared in lwan_process_request() */
1046
1047 buffer = parse_proxy_protocol(request, buffer);
1048 if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0)))
1049 return HTTP_BAD_REQUEST;
1050 }
1051
1052 buffer = ignore_leading_whitespace(buffer);
1053
1054 char *path = identify_http_method(request, buffer);
1055 if (UNLIKELY(!path)__builtin_expect(((!path)), (0)))
1056 return HTTP_NOT_ALLOWED;
1057
1058 buffer = identify_http_path(request, path, helper);
1059 if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0)))
1060 return HTTP_BAD_REQUEST;
1061
1062 buffer = parse_headers(helper, buffer, helper->buffer->value + helper->buffer->len);
1063 if (UNLIKELY(!buffer)__builtin_expect(((!buffer)), (0)))
1064 return HTTP_BAD_REQUEST;
1065
1066 size_t decoded_len = url_decode(request->url.value);
1067 if (UNLIKELY(!decoded_len)__builtin_expect(((!decoded_len)), (0)))
1068 return HTTP_BAD_REQUEST;
1069 request->original_url.len = request->url.len = decoded_len;
1070
1071 compute_keep_alive_flag(request, helper);
1072
1073 return HTTP_OK;
1074}
1075
1076static enum lwan_http_status
1077prepare_for_response(struct lwan_url_map *url_map,
1078 struct lwan_request *request,
1079 struct request_parser_helper *helper)
1080{
1081 request->url.value += url_map->prefix_len;
1082 request->url.len -= url_map->prefix_len;
1083
1084 if (url_map->flags & HANDLER_MUST_AUTHORIZE) {
1085 if (!lwan_http_authorize(request,
1086 &helper->authorization,
1087 url_map->authorization.realm,
1088 url_map->authorization.password_file))
1089 return HTTP_NOT_AUTHORIZED;
1090 }
1091
1092 if (url_map->flags & HANDLER_PARSE_QUERY_STRING)
1093 parse_query_string(request, helper);
1094
1095 if (url_map->flags & HANDLER_PARSE_IF_MODIFIED_SINCE)
1096 parse_if_modified_since(request, helper);
1097
1098 if (url_map->flags & HANDLER_PARSE_RANGE)
1099 parse_range(request, helper);
1100
1101 if (url_map->flags & HANDLER_PARSE_ACCEPT_ENCODING)
1102 parse_accept_encoding(request, helper);
1103
1104 if (url_map->flags & HANDLER_PARSE_COOKIES)
1105 parse_cookies(request, helper);
1106
1107 if (url_map->flags & HANDLER_REMOVE_LEADING_SLASH) {
1108 while (*request->url.value == '/' && request->url.len > 0) {
1109 ++request->url.value;
1110 --request->url.len;
1111 }
1112 }
1113
1114 if (lwan_request_get_method(request) == REQUEST_METHOD_POST) {
1115 enum lwan_http_status status;
1116
1117 if (!(url_map->flags & HANDLER_PARSE_POST_DATA)) {
1118 /* FIXME: Discard POST data here? If a POST request is sent
1119 * to a handler that is not supposed to handle a POST request,
1120 * the next request in the pipeline will fail because the
1121 * body of the previous request will be used as the next
1122 * request itself. */
1123 return HTTP_NOT_ALLOWED;
1124 }
1125
1126 status = read_post_data(request, helper);
1127 if (UNLIKELY(status != HTTP_OK)__builtin_expect(((status != HTTP_OK)), (0)))
1128 return status;
1129
1130 parse_post_data(request, helper);
1131 }
1132
1133 return HTTP_OK;
1134}
1135
1136static bool_Bool
1137handle_rewrite(struct lwan_request *request, struct request_parser_helper *helper)
1138{
1139 request->flags &= ~RESPONSE_URL_REWRITTEN;
1140
1141 parse_fragment_and_query(request, helper,
1142 request->url.value + request->url.len);
1143
1144 helper->urls_rewritten++;
1145 if (UNLIKELY(helper->urls_rewritten > 4)__builtin_expect(((helper->urls_rewritten > 4)), (0))) {
1146 lwan_default_response(request, HTTP_INTERNAL_ERROR);
1147 return false0;
1148 }
1149
1150 return true1;
1151}
1152
1153char *
1154lwan_process_request(struct lwan *l, struct lwan_request *request,
1155 struct lwan_value *buffer, char *next_request)
1156{
1157 enum lwan_http_status status;
1158 struct lwan_url_map *url_map;
1159
1160 struct request_parser_helper helper = {
1161 .buffer = buffer,
1162 .next_request = next_request,
1163 .error_when_n_packets = calculate_n_packets(DEFAULT_BUFFER_SIZE4096)
1164 };
1165
1166 status = read_request(request, &helper);
1167 if (UNLIKELY(status != HTTP_OK)__builtin_expect(((status != HTTP_OK)), (0))) {
1168 /* This request was bad, but maybe there's a good one in the
1169 * pipeline. */
1170 if (status == HTTP_BAD_REQUEST && helper.next_request)
1171 goto out;
1172
1173 /* Response here can be: HTTP_TOO_LARGE, HTTP_BAD_REQUEST (without
1174 * next request), or HTTP_TIMEOUT. Nothing to do, just abort the
1175 * coroutine. */
1176 lwan_default_response(request, status);
1177 coro_yield(request->conn->coro, CONN_CORO_ABORT);
1178 __builtin_unreachable();
1179 }
1180
1181 status = parse_http_request(request, &helper);
1182 if (UNLIKELY(status != HTTP_OK)__builtin_expect(((status != HTTP_OK)), (0))) {
1183 lwan_default_response(request, status);
1184 goto out;
1185 }
1186
1187lookup_again:
1188 url_map = lwan_trie_lookup_prefix(&l->url_map_trie, request->url.value);
1189 if (UNLIKELY(!url_map)__builtin_expect(((!url_map)), (0))) {
1190 lwan_default_response(request, HTTP_NOT_FOUND);
1191 goto out;
1192 }
1193
1194 status = prepare_for_response(url_map, request, &helper);
1195 if (UNLIKELY(status != HTTP_OK)__builtin_expect(((status != HTTP_OK)), (0))) {
1196 lwan_default_response(request, status);
1197 goto out;
1198 }
1199
1200 status = url_map->handler(request, &request->response, url_map->data);
1201 if (UNLIKELY(url_map->flags & HANDLER_CAN_REWRITE_URL)__builtin_expect(((url_map->flags & HANDLER_CAN_REWRITE_URL
)), (0))
) {
1202 if (request->flags & RESPONSE_URL_REWRITTEN) {
1203 if (LIKELY(handle_rewrite(request, &helper))__builtin_expect((!!(handle_rewrite(request, &helper))), (
1))
)
1204 goto lookup_again;
1205 goto out;
1206 }
1207 }
1208
1209 lwan_response(request, status);
1210
1211out:
1212 return helper.next_request;
1213}
1214
1215static inline void *
1216value_lookup(const struct lwan_key_value_array *array, const char *key)
1217{
1218 const struct lwan_array *la = (const struct lwan_array *)array;
1219
1220 if (LIKELY(la->elements)__builtin_expect((!!(la->elements)), (1))) {
1221 struct lwan_key_value k = { .key = (char *)key };
1222 struct lwan_key_value *entry;
1223
1224 entry = bsearch(&k, la->base, la->elements - 1, sizeof(k), key_value_compare);
1225 if (LIKELY(entry)__builtin_expect((!!(entry)), (1)))
1226 return entry->value;
1227 }
1228
1229 return NULL((void*)0);
1230}
1231
1232const char *
1233lwan_request_get_query_param(struct lwan_request *request, const char *key)
1234{
1235 return value_lookup(&request->query_params, key);
1236}
1237
1238const char *
1239lwan_request_get_post_param(struct lwan_request *request, const char *key)
1240{
1241 return value_lookup(&request->post_data, key);
1242}
1243
1244const char *
1245lwan_request_get_cookie(struct lwan_request *request, const char *key)
1246{
1247 return value_lookup(&request->cookies, key);
1248}
1249
1250ALWAYS_INLINEinline __attribute__((always_inline)) int
1251lwan_connection_get_fd(const struct lwan *lwan, const struct lwan_connection *conn)
1252{
1253 return (int)(ptrdiff_t)(conn - lwan->conns);
1254}
1255
1256const char *
1257lwan_request_get_remote_address(struct lwan_request *request,
1258 char buffer[static INET6_ADDRSTRLEN46])
1259{
1260 struct sockaddr_storage non_proxied_addr = { .ss_family = AF_UNSPEC0 };
1261 struct sockaddr_storage *sock_addr;
1262
1263 if (request->flags & REQUEST_PROXIED) {
1264 sock_addr = (struct sockaddr_storage *)&request->proxy->from;
Casting data to a larger structure type and accessing a field can lead to memory access errors or data corruption
1265
1266 if (UNLIKELY(sock_addr->ss_family == AF_UNSPEC)__builtin_expect(((sock_addr->ss_family == 0)), (0)))
1267 return memcpy(buffer, "*unspecified*", sizeof("*unspecified*"));
1268 } else {
1269 socklen_t sock_len = sizeof(non_proxied_addr);
1270
1271 sock_addr = &non_proxied_addr;
1272
1273 if (UNLIKELY(getpeername(request->fd,__builtin_expect(((getpeername(request->fd, (struct sockaddr
*) sock_addr, &sock_len) < 0)), (0))
1274 (struct sockaddr *) sock_addr,__builtin_expect(((getpeername(request->fd, (struct sockaddr
*) sock_addr, &sock_len) < 0)), (0))
1275 &sock_len) < 0)__builtin_expect(((getpeername(request->fd, (struct sockaddr
*) sock_addr, &sock_len) < 0)), (0))
)
1276 return NULL((void*)0);
1277 }
1278
1279 if (sock_addr->ss_family == AF_INET2)
1280 return inet_ntop(AF_INET2,
1281 &((struct sockaddr_in *) sock_addr)->sin_addr,
1282 buffer, INET6_ADDRSTRLEN46);
1283
1284 return inet_ntop(AF_INET610,
1285 &((struct sockaddr_in6 *) sock_addr)->sin6_addr,
1286 buffer, INET6_ADDRSTRLEN46);
1287}