1 #include "request.h"
2 #include "keyvalue.h"
3 #include "log.h"
4
5 #include <sys/stat.h>
6
7 #include <limits.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <ctype.h>
12
request_check_hostname(server * srv,connection * con,buffer * host)13 static int request_check_hostname(server *srv, connection *con, buffer *host) {
14 enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
15 size_t i;
16 int label_len = 0;
17 size_t host_len;
18 char *colon;
19 int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
20 int level = 0;
21
22 UNUSED(srv);
23 UNUSED(con);
24
25 /*
26 * hostport = host [ ":" port ]
27 * host = hostname | IPv4address | IPv6address
28 * hostname = *( domainlabel "." ) toplabel [ "." ]
29 * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
30 * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
31 * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
32 * IPv6address = "[" ... "]"
33 * port = *digit
34 */
35
36 /* no Host: */
37 if (!host || host->used == 0) return 0;
38
39 host_len = host->used - 1;
40
41 /* IPv6 adress */
42 if (host->ptr[0] == '[') {
43 char *c = host->ptr + 1;
44 int colon_cnt = 0;
45
46 /* check portnumber */
47 for (; *c && *c != ']'; c++) {
48 if (*c == ':') {
49 if (++colon_cnt > 7) {
50 return -1;
51 }
52 } else if (!light_isxdigit(*c) && '.' != *c) {
53 return -1;
54 }
55 }
56
57 /* missing ] */
58 if (!*c) {
59 return -1;
60 }
61
62 /* check port */
63 if (*(c+1) == ':') {
64 for (c += 2; *c; c++) {
65 if (!light_isdigit(*c)) {
66 return -1;
67 }
68 }
69 }
70 return 0;
71 }
72
73 if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
74 char *c = colon + 1;
75
76 /* check portnumber */
77 for (; *c; c++) {
78 if (!light_isdigit(*c)) return -1;
79 }
80
81 /* remove the port from the host-len */
82 host_len = colon - host->ptr;
83 }
84
85 /* Host is empty */
86 if (host_len == 0) return -1;
87
88 /* if the hostname ends in a "." strip it */
89 if (host->ptr[host_len-1] == '.') {
90 /* shift port info one left */
91 if (NULL != colon) memmove(colon-1, colon, host->used - host_len);
92 else host->ptr[host_len-1] = '\0';
93 host_len -= 1;
94 host->used -= 1;
95 }
96
97 if (host_len == 0) return -1;
98
99 /* scan from the right and skip the \0 */
100 for (i = host_len; i-- > 0; ) {
101 const char c = host->ptr[i];
102
103 switch (stage) {
104 case TOPLABEL:
105 if (c == '.') {
106 /* only switch stage, if this is not the last character */
107 if (i != host_len - 1) {
108 if (label_len == 0) {
109 return -1;
110 }
111
112 /* check the first character at right of the dot */
113 if (is_ip == 0) {
114 if (!light_isalnum(host->ptr[i+1])) {
115 return -1;
116 }
117 } else if (!light_isdigit(host->ptr[i+1])) {
118 is_ip = 0;
119 } else if ('-' == host->ptr[i+1]) {
120 return -1;
121 } else {
122 /* just digits */
123 is_ip = 1;
124 }
125
126 stage = DOMAINLABEL;
127
128 label_len = 0;
129 level++;
130 } else if (i == 0) {
131 /* just a dot and nothing else is evil */
132 return -1;
133 }
134 } else if (i == 0) {
135 /* the first character of the hostname */
136 if (!light_isalnum(c)) {
137 return -1;
138 }
139 label_len++;
140 } else {
141 if (c != '-' && !light_isalnum(c)) {
142 return -1;
143 }
144 if (is_ip == -1) {
145 if (!light_isdigit(c)) is_ip = 0;
146 }
147 label_len++;
148 }
149
150 break;
151 case DOMAINLABEL:
152 if (is_ip == 1) {
153 if (c == '.') {
154 if (label_len == 0) {
155 return -1;
156 }
157
158 label_len = 0;
159 level++;
160 } else if (!light_isdigit(c)) {
161 return -1;
162 } else {
163 label_len++;
164 }
165 } else {
166 if (c == '.') {
167 if (label_len == 0) {
168 return -1;
169 }
170
171 /* c is either - or alphanum here */
172 if ('-' == host->ptr[i+1]) {
173 return -1;
174 }
175
176 label_len = 0;
177 level++;
178 } else if (i == 0) {
179 if (!light_isalnum(c)) {
180 return -1;
181 }
182 label_len++;
183 } else {
184 if (c != '-' && !light_isalnum(c)) {
185 return -1;
186 }
187 label_len++;
188 }
189 }
190
191 break;
192 }
193 }
194
195 /* a IP has to consist of 4 parts */
196 if (is_ip == 1 && level != 3) {
197 return -1;
198 }
199
200 if (label_len == 0) {
201 return -1;
202 }
203
204 return 0;
205 }
206
207 #if 0
208 #define DUMP_HEADER
209 #endif
210
http_request_split_value(array * vals,buffer * b)211 static int http_request_split_value(array *vals, buffer *b) {
212 size_t i;
213 int state = 0;
214
215 const char *current;
216 const char *token_start = NULL, *token_end = NULL;
217 /*
218 * parse
219 *
220 * val1, val2, val3, val4
221 *
222 * into a array (more or less a explode() incl. striping of whitespaces
223 */
224
225 if (b->used == 0) return 0;
226
227 current = b->ptr;
228 for (i = 0; i < b->used; ++i, ++current) {
229 data_string *ds;
230
231 switch (state) {
232 case 0: /* find start of a token */
233 switch (*current) {
234 case ' ':
235 case '\t': /* skip white space */
236 case ',': /* skip empty token */
237 break;
238 case '\0': /* end of string */
239 return 0;
240 default:
241 /* found real data, switch to state 1 to find the end of the token */
242 token_start = token_end = current;
243 state = 1;
244 break;
245 }
246 break;
247 case 1: /* find end of token and last non white space character */
248 switch (*current) {
249 case ' ':
250 case '\t':
251 /* space - don't update token_end */
252 break;
253 case ',':
254 case '\0': /* end of string also marks the end of a token */
255 if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
256 ds = data_string_init();
257 }
258
259 buffer_copy_string_len(ds->value, token_start, token_end-token_start+1);
260 array_insert_unique(vals, (data_unset *)ds);
261
262 state = 0;
263 break;
264 default:
265 /* no white space, update token_end to include current character */
266 token_end = current;
267 break;
268 }
269 break;
270 }
271 }
272
273 return 0;
274 }
275
request_uri_is_valid_char(unsigned char c)276 static int request_uri_is_valid_char(unsigned char c) {
277 if (c <= 32) return 0;
278 if (c == 127) return 0;
279 if (c == 255) return 0;
280
281 return 1;
282 }
283
http_request_parse(server * srv,connection * con)284 int http_request_parse(server *srv, connection *con) {
285 char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
286 int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
287 char *value = NULL, *key = NULL;
288 char *reqline_host = NULL;
289 int reqline_hostlen = 0;
290
291 enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
292
293 int line = 0;
294
295 int request_line_stage = 0;
296 size_t i, first;
297
298 int done = 0;
299
300 /*
301 * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
302 * Option : "^([-a-zA-Z]+): (.+)$"
303 * End : "^$"
304 */
305
306 if (con->conf.log_request_header) {
307 log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
308 "fd:", con->fd,
309 "request-len:", con->request.request->used,
310 "\n", con->request.request);
311 }
312
313 if (con->request_count > 1 &&
314 con->request.request->ptr[0] == '\r' &&
315 con->request.request->ptr[1] == '\n') {
316 /* we are in keep-alive and might get \r\n after a previous POST request.*/
317
318 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
319 } else {
320 /* fill the local request buffer */
321 buffer_copy_string_buffer(con->parse_request, con->request.request);
322 }
323
324 keep_alive_set = 0;
325 con_length_set = 0;
326
327 /* parse the first line of the request
328 *
329 * should be:
330 *
331 * <method> <uri> <protocol>\r\n
332 * */
333 for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
334 char *cur = con->parse_request->ptr + i;
335
336 switch(*cur) {
337 case '\r':
338 if (con->parse_request->ptr[i+1] == '\n') {
339 http_method_t r;
340 char *nuri = NULL;
341 size_t j;
342
343 /* \r\n -> \0\0 */
344 con->parse_request->ptr[i] = '\0';
345 con->parse_request->ptr[i+1] = '\0';
346
347 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
348
349 if (request_line_stage != 2) {
350 con->http_status = 400;
351 con->response.keep_alive = 0;
352 con->keep_alive = 0;
353
354 if (srv->srvconf.log_request_header_on_error) {
355 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
356 log_error_write(srv, __FILE__, __LINE__, "Sb",
357 "request-header:\n",
358 con->request.request);
359 }
360 return 0;
361 }
362
363 proto = con->parse_request->ptr + first;
364
365 *(uri - 1) = '\0';
366 *(proto - 1) = '\0';
367
368 /* we got the first one :) */
369 if (-1 == (r = get_http_method_key(method))) {
370 con->http_status = 501;
371 con->response.keep_alive = 0;
372 con->keep_alive = 0;
373
374 if (srv->srvconf.log_request_header_on_error) {
375 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
376 log_error_write(srv, __FILE__, __LINE__, "Sb",
377 "request-header:\n",
378 con->request.request);
379 }
380
381 return 0;
382 }
383
384 con->request.http_method = r;
385
386 /*
387 * RFC2616 says:
388 *
389 * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
390 *
391 * */
392 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
393 char * major = proto + sizeof("HTTP/") - 1;
394 char * minor = strchr(major, '.');
395 char *err = NULL;
396 int major_num = 0, minor_num = 0;
397
398 int invalid_version = 0;
399
400 if (NULL == minor || /* no dot */
401 minor == major || /* no major */
402 *(minor + 1) == '\0' /* no minor */) {
403 invalid_version = 1;
404 } else {
405 *minor = '\0';
406 major_num = strtol(major, &err, 10);
407
408 if (*err != '\0') invalid_version = 1;
409
410 *minor++ = '.';
411 minor_num = strtol(minor, &err, 10);
412
413 if (*err != '\0') invalid_version = 1;
414 }
415
416 if (invalid_version) {
417 con->http_status = 400;
418 con->keep_alive = 0;
419
420 if (srv->srvconf.log_request_header_on_error) {
421 log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
422 log_error_write(srv, __FILE__, __LINE__, "Sb",
423 "request-header:\n",
424 con->request.request);
425 }
426 return 0;
427 }
428
429 if (major_num == 1 && minor_num == 1) {
430 con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
431 } else if (major_num == 1 && minor_num == 0) {
432 con->request.http_version = HTTP_VERSION_1_0;
433 } else {
434 con->http_status = 505;
435
436 if (srv->srvconf.log_request_header_on_error) {
437 log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
438 log_error_write(srv, __FILE__, __LINE__, "Sb",
439 "request-header:\n",
440 con->request.request);
441 }
442 return 0;
443 }
444 } else {
445 con->http_status = 400;
446 con->keep_alive = 0;
447
448 if (srv->srvconf.log_request_header_on_error) {
449 log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
450 log_error_write(srv, __FILE__, __LINE__, "Sb",
451 "request-header:\n",
452 con->request.request);
453 }
454 return 0;
455 }
456
457 if (0 == strncmp(uri, "http://", 7) &&
458 NULL != (nuri = strchr(uri + 7, '/'))) {
459 reqline_host = uri + 7;
460 reqline_hostlen = nuri - reqline_host;
461
462 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
463 } else if (0 == strncmp(uri, "https://", 8) &&
464 NULL != (nuri = strchr(uri + 8, '/'))) {
465 reqline_host = uri + 8;
466 reqline_hostlen = nuri - reqline_host;
467
468 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
469 } else {
470 /* everything looks good so far */
471 buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
472 }
473
474 /* check uri for invalid characters */
475 for (j = 0; j < con->request.uri->used - 1; j++) {
476 if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
477 unsigned char buf[2];
478 con->http_status = 400;
479 con->keep_alive = 0;
480
481 if (srv->srvconf.log_request_header_on_error) {
482 buf[0] = con->request.uri->ptr[j];
483 buf[1] = '\0';
484
485 if (con->request.uri->ptr[j] > 32 &&
486 con->request.uri->ptr[j] != 127) {
487 /* the character is printable -> print it */
488 log_error_write(srv, __FILE__, __LINE__, "ss",
489 "invalid character in URI -> 400",
490 buf);
491 } else {
492 /* a control-character, print ascii-code */
493 log_error_write(srv, __FILE__, __LINE__, "sd",
494 "invalid character in URI -> 400",
495 con->request.uri->ptr[j]);
496 }
497
498 log_error_write(srv, __FILE__, __LINE__, "Sb",
499 "request-header:\n",
500 con->request.request);
501 }
502
503 return 0;
504 }
505 }
506
507 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
508
509 con->http_status = 0;
510
511 i++;
512 line++;
513 first = i+1;
514 }
515 break;
516 case ' ':
517 switch(request_line_stage) {
518 case 0:
519 /* GET|POST|... */
520 method = con->parse_request->ptr + first;
521 first = i + 1;
522 break;
523 case 1:
524 /* /foobar/... */
525 uri = con->parse_request->ptr + first;
526 first = i + 1;
527 break;
528 default:
529 /* ERROR, one space to much */
530 con->http_status = 400;
531 con->response.keep_alive = 0;
532 con->keep_alive = 0;
533
534 if (srv->srvconf.log_request_header_on_error) {
535 log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
536 log_error_write(srv, __FILE__, __LINE__, "Sb",
537 "request-header:\n",
538 con->request.request);
539 }
540 return 0;
541 }
542
543 request_line_stage++;
544 break;
545 }
546 }
547
548 in_folding = 0;
549
550 if (con->request.uri->used == 1) {
551 con->http_status = 400;
552 con->response.keep_alive = 0;
553 con->keep_alive = 0;
554
555 if (srv->srvconf.log_request_header_on_error) {
556 log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
557 log_error_write(srv, __FILE__, __LINE__, "Sb",
558 "request-header:\n",
559 con->request.request);
560 }
561 return 0;
562 }
563
564 if (reqline_host) {
565 /* Insert as host header */
566 data_string *ds;
567
568 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
569 ds = data_string_init();
570 }
571
572 buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
573 buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen);
574 array_insert_unique(con->request.headers, (data_unset *)ds);
575 con->request.http_host = ds->value;
576 }
577
578 for (; i < con->parse_request->used && !done; i++) {
579 char *cur = con->parse_request->ptr + i;
580
581 if (is_key) {
582 size_t j;
583 int got_colon = 0;
584
585 /**
586 * 1*<any CHAR except CTLs or separators>
587 * CTLs == 0-31 + 127
588 *
589 */
590 switch(*cur) {
591 case ':':
592 is_key = 0;
593
594 value = cur + 1;
595
596 if (is_ws_after_key == 0) {
597 key_len = i - first;
598 }
599 is_ws_after_key = 0;
600
601 break;
602 case '(':
603 case ')':
604 case '<':
605 case '>':
606 case '@':
607 case ',':
608 case ';':
609 case '\\':
610 case '\"':
611 case '/':
612 case '[':
613 case ']':
614 case '?':
615 case '=':
616 case '{':
617 case '}':
618 con->http_status = 400;
619 con->keep_alive = 0;
620 con->response.keep_alive = 0;
621
622 log_error_write(srv, __FILE__, __LINE__, "sbsds",
623 "invalid character in key", con->request.request, cur, *cur, "-> 400");
624 return 0;
625 case ' ':
626 case '\t':
627 if (i == first) {
628 is_key = 0;
629 in_folding = 1;
630 value = cur;
631
632 break;
633 }
634
635
636 key_len = i - first;
637
638 /* skip every thing up to the : */
639 for (j = 1; !got_colon; j++) {
640 switch(con->parse_request->ptr[j + i]) {
641 case ' ':
642 case '\t':
643 /* skip WS */
644 continue;
645 case ':':
646 /* ok, done; handle the colon the usual way */
647
648 i += j - 1;
649 got_colon = 1;
650 is_ws_after_key = 1; /* we already know the key length */
651
652 break;
653 default:
654 /* error */
655
656 if (srv->srvconf.log_request_header_on_error) {
657 log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
658 log_error_write(srv, __FILE__, __LINE__, "Sb",
659 "request-header:\n",
660 con->request.request);
661 }
662
663 con->http_status = 400;
664 con->response.keep_alive = 0;
665 con->keep_alive = 0;
666
667 return 0;
668 }
669 }
670
671 break;
672 case '\r':
673 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
674 /* End of Header */
675 con->parse_request->ptr[i] = '\0';
676 con->parse_request->ptr[i+1] = '\0';
677
678 i++;
679
680 done = 1;
681
682 break;
683 } else {
684 if (srv->srvconf.log_request_header_on_error) {
685 log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
686 log_error_write(srv, __FILE__, __LINE__, "Sb",
687 "request-header:\n",
688 con->request.request);
689 }
690
691 con->http_status = 400;
692 con->keep_alive = 0;
693 con->response.keep_alive = 0;
694 return 0;
695 }
696 /* fall thru */
697 case 0: /* illegal characters (faster than a if () :) */
698 case 1:
699 case 2:
700 case 3:
701 case 4:
702 case 5:
703 case 6:
704 case 7:
705 case 8:
706 case 10:
707 case 11:
708 case 12:
709 case 14:
710 case 15:
711 case 16:
712 case 17:
713 case 18:
714 case 19:
715 case 20:
716 case 21:
717 case 22:
718 case 23:
719 case 24:
720 case 25:
721 case 26:
722 case 27:
723 case 28:
724 case 29:
725 case 30:
726 case 31:
727 case 127:
728 con->http_status = 400;
729 con->keep_alive = 0;
730 con->response.keep_alive = 0;
731
732 if (srv->srvconf.log_request_header_on_error) {
733 log_error_write(srv, __FILE__, __LINE__, "sbsds",
734 "CTL character in key", con->request.request, cur, *cur, "-> 400");
735
736 log_error_write(srv, __FILE__, __LINE__, "Sb",
737 "request-header:\n",
738 con->request.request);
739 }
740
741 return 0;
742 default:
743 /* ok */
744 break;
745 }
746 } else {
747 switch(*cur) {
748 case '\r':
749 if (con->parse_request->ptr[i+1] == '\n') {
750 data_string *ds = NULL;
751
752 /* End of Headerline */
753 con->parse_request->ptr[i] = '\0';
754 con->parse_request->ptr[i+1] = '\0';
755
756 if (in_folding) {
757 buffer *key_b;
758 /**
759 * we use a evil hack to handle the line-folding
760 *
761 * As array_insert_unique() deletes 'ds' in the case of a duplicate
762 * ds points somewhere and we get a evil crash. As a solution we keep the old
763 * "key" and get the current value from the hash and append us
764 *
765 * */
766
767 if (!key || !key_len) {
768 /* 400 */
769
770 if (srv->srvconf.log_request_header_on_error) {
771 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
772
773 log_error_write(srv, __FILE__, __LINE__, "Sb",
774 "request-header:\n",
775 con->request.request);
776 }
777
778
779 con->http_status = 400;
780 con->keep_alive = 0;
781 con->response.keep_alive = 0;
782 return 0;
783 }
784
785 key_b = buffer_init();
786 buffer_copy_string_len(key_b, key, key_len);
787
788 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) {
789 buffer_append_string(ds->value, value);
790 }
791
792 buffer_free(key_b);
793 } else {
794 int s_len;
795 key = con->parse_request->ptr + first;
796
797 s_len = cur - value;
798
799 /* strip trailing white-spaces */
800 for (; s_len > 0 &&
801 (value[s_len - 1] == ' ' ||
802 value[s_len - 1] == '\t'); s_len--);
803
804 value[s_len] = '\0';
805
806 if (s_len > 0) {
807 int cmp = 0;
808 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
809 ds = data_string_init();
810 }
811 buffer_copy_string_len(ds->key, key, key_len);
812 buffer_copy_string_len(ds->value, value, s_len);
813
814 /* retreive values
815 *
816 *
817 * the list of options is sorted to simplify the search
818 */
819
820 if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
821 array *vals;
822 size_t vi;
823
824 /* split on , */
825
826 vals = srv->split_vals;
827
828 array_reset(vals);
829
830 http_request_split_value(vals, ds->value);
831
832 for (vi = 0; vi < vals->used; vi++) {
833 data_string *dsv = (data_string *)vals->data[vi];
834
835 if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
836 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
837
838 break;
839 } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
840 keep_alive_set = HTTP_CONNECTION_CLOSE;
841
842 break;
843 }
844 }
845
846 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
847 char *err;
848 unsigned long int r;
849 size_t j;
850
851 if (con_length_set) {
852 con->http_status = 400;
853 con->keep_alive = 0;
854
855 if (srv->srvconf.log_request_header_on_error) {
856 log_error_write(srv, __FILE__, __LINE__, "s",
857 "duplicate Content-Length-header -> 400");
858 log_error_write(srv, __FILE__, __LINE__, "Sb",
859 "request-header:\n",
860 con->request.request);
861 }
862 array_insert_unique(con->request.headers, (data_unset *)ds);
863 return 0;
864 }
865
866 if (ds->value->used == 0) SEGFAULT();
867
868 for (j = 0; j < ds->value->used - 1; j++) {
869 char c = ds->value->ptr[j];
870 if (!isdigit((unsigned char)c)) {
871 log_error_write(srv, __FILE__, __LINE__, "sbs",
872 "content-length broken:", ds->value, "-> 400");
873
874 con->http_status = 400;
875 con->keep_alive = 0;
876
877 array_insert_unique(con->request.headers, (data_unset *)ds);
878 return 0;
879 }
880 }
881
882 r = strtoul(ds->value->ptr, &err, 10);
883
884 if (*err == '\0') {
885 con_length_set = 1;
886 con->request.content_length = r;
887 } else {
888 log_error_write(srv, __FILE__, __LINE__, "sbs",
889 "content-length broken:", ds->value, "-> 400");
890
891 con->http_status = 400;
892 con->keep_alive = 0;
893
894 array_insert_unique(con->request.headers, (data_unset *)ds);
895 return 0;
896 }
897 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
898 /* if dup, only the first one will survive */
899 if (!con->request.http_content_type) {
900 con->request.http_content_type = ds->value->ptr;
901 } else {
902 con->http_status = 400;
903 con->keep_alive = 0;
904
905 if (srv->srvconf.log_request_header_on_error) {
906 log_error_write(srv, __FILE__, __LINE__, "s",
907 "duplicate Content-Type-header -> 400");
908 log_error_write(srv, __FILE__, __LINE__, "Sb",
909 "request-header:\n",
910 con->request.request);
911 }
912 array_insert_unique(con->request.headers, (data_unset *)ds);
913 return 0;
914 }
915 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
916 /* HTTP 2616 8.2.3
917 * Expect: 100-continue
918 *
919 * -> (10.1.1) 100 (read content, process request, send final status-code)
920 * -> (10.4.18) 417 (close)
921 *
922 * (not handled at all yet, we always send 417 here)
923 *
924 * What has to be added ?
925 * 1. handling of chunked request body
926 * 2. out-of-order sending from the HTTP/1.1 100 Continue
927 * header
928 *
929 */
930
931 if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
932 con->http_status = 417;
933 con->keep_alive = 0;
934 array_insert_unique(con->request.headers, (data_unset *)ds);
935 return 0;
936 }
937 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
938 if (reqline_host) {
939 /* ignore all host: headers as we got the host in the request line */
940 ds->free((data_unset*) ds);
941 ds = NULL;
942 } else if (!con->request.http_host) {
943 con->request.http_host = ds->value;
944 } else {
945 con->http_status = 400;
946 con->keep_alive = 0;
947
948 if (srv->srvconf.log_request_header_on_error) {
949 log_error_write(srv, __FILE__, __LINE__, "s",
950 "duplicate Host-header -> 400");
951 log_error_write(srv, __FILE__, __LINE__, "Sb",
952 "request-header:\n",
953 con->request.request);
954 }
955 array_insert_unique(con->request.headers, (data_unset *)ds);
956 return 0;
957 }
958 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
959 /* Proxies sometimes send dup headers
960 * if they are the same we ignore the second
961 * if not, we raise an error */
962 if (!con->request.http_if_modified_since) {
963 con->request.http_if_modified_since = ds->value->ptr;
964 } else if (0 == strcasecmp(con->request.http_if_modified_since,
965 ds->value->ptr)) {
966 /* ignore it if they are the same */
967
968 ds->free((data_unset *)ds);
969 ds = NULL;
970 } else {
971 con->http_status = 400;
972 con->keep_alive = 0;
973
974 if (srv->srvconf.log_request_header_on_error) {
975 log_error_write(srv, __FILE__, __LINE__, "s",
976 "duplicate If-Modified-Since header -> 400");
977 log_error_write(srv, __FILE__, __LINE__, "Sb",
978 "request-header:\n",
979 con->request.request);
980 }
981 array_insert_unique(con->request.headers, (data_unset *)ds);
982 return 0;
983 }
984 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
985 /* if dup, only the first one will survive */
986 if (!con->request.http_if_none_match) {
987 con->request.http_if_none_match = ds->value->ptr;
988 } else {
989 ds->free((data_unset*) ds);
990 ds = NULL;
991 }
992 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
993 if (!con->request.http_range) {
994 /* bytes=.*-.* */
995
996 if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
997 NULL != strchr(ds->value->ptr+6, '-')) {
998
999 /* if dup, only the first one will survive */
1000 con->request.http_range = ds->value->ptr + 6;
1001 }
1002 } else {
1003 con->http_status = 400;
1004 con->keep_alive = 0;
1005
1006 if (srv->srvconf.log_request_header_on_error) {
1007 log_error_write(srv, __FILE__, __LINE__, "s",
1008 "duplicate Range-header -> 400");
1009 log_error_write(srv, __FILE__, __LINE__, "Sb",
1010 "request-header:\n",
1011 con->request.request);
1012 }
1013 array_insert_unique(con->request.headers, (data_unset *)ds);
1014 return 0;
1015 }
1016 }
1017
1018 if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
1019 } else {
1020 /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
1021 }
1022 }
1023
1024 i++;
1025 first = i+1;
1026 is_key = 1;
1027 value = NULL;
1028 #if 0
1029 /**
1030 * for Bug 1230 keep the key_len a live
1031 */
1032 key_len = 0;
1033 #endif
1034 in_folding = 0;
1035 } else {
1036 if (srv->srvconf.log_request_header_on_error) {
1037 log_error_write(srv, __FILE__, __LINE__, "sbs",
1038 "CR without LF", con->request.request, "-> 400");
1039 }
1040
1041 con->http_status = 400;
1042 con->keep_alive = 0;
1043 con->response.keep_alive = 0;
1044 return 0;
1045 }
1046 break;
1047 case ' ':
1048 case '\t':
1049 /* strip leading WS */
1050 if (value == cur) value = cur+1;
1051 default:
1052 if (*cur >= 0 && *cur < 32 && *cur != '\t') {
1053 if (srv->srvconf.log_request_header_on_error) {
1054 log_error_write(srv, __FILE__, __LINE__, "sds",
1055 "invalid char in header", (int)*cur, "-> 400");
1056 }
1057
1058 con->http_status = 400;
1059 con->keep_alive = 0;
1060
1061 return 0;
1062 }
1063 break;
1064 }
1065 }
1066 }
1067
1068 con->header_len = i;
1069
1070 /* do some post-processing */
1071
1072 if (con->request.http_version == HTTP_VERSION_1_1) {
1073 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
1074 /* no Connection-Header sent */
1075
1076 /* HTTP/1.1 -> keep-alive default TRUE */
1077 con->keep_alive = 1;
1078 } else {
1079 con->keep_alive = 0;
1080 }
1081
1082 /* RFC 2616, 14.23 */
1083 if (con->request.http_host == NULL ||
1084 buffer_is_empty(con->request.http_host)) {
1085 con->http_status = 400;
1086 con->response.keep_alive = 0;
1087 con->keep_alive = 0;
1088
1089 if (srv->srvconf.log_request_header_on_error) {
1090 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
1091 log_error_write(srv, __FILE__, __LINE__, "Sb",
1092 "request-header:\n",
1093 con->request.request);
1094 }
1095 return 0;
1096 }
1097 } else {
1098 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
1099 /* no Connection-Header sent */
1100
1101 /* HTTP/1.0 -> keep-alive default FALSE */
1102 con->keep_alive = 1;
1103 } else {
1104 con->keep_alive = 0;
1105 }
1106 }
1107
1108 /* check hostname field if it is set */
1109 if (NULL != con->request.http_host &&
1110 0 != request_check_hostname(srv, con, con->request.http_host)) {
1111
1112 if (srv->srvconf.log_request_header_on_error) {
1113 log_error_write(srv, __FILE__, __LINE__, "s",
1114 "Invalid Hostname -> 400");
1115 log_error_write(srv, __FILE__, __LINE__, "Sb",
1116 "request-header:\n",
1117 con->request.request);
1118 }
1119
1120 con->http_status = 400;
1121 con->response.keep_alive = 0;
1122 con->keep_alive = 0;
1123
1124 return 0;
1125 }
1126
1127 switch(con->request.http_method) {
1128 case HTTP_METHOD_GET:
1129 case HTTP_METHOD_HEAD:
1130 /* content-length is forbidden for those */
1131 if (con_length_set && con->request.content_length != 0) {
1132 /* content-length is missing */
1133 log_error_write(srv, __FILE__, __LINE__, "s",
1134 "GET/HEAD with content-length -> 400");
1135
1136 con->keep_alive = 0;
1137 con->http_status = 400;
1138 return 0;
1139 }
1140 break;
1141 case HTTP_METHOD_POST:
1142 /* content-length is required for them */
1143 if (!con_length_set) {
1144 /* content-length is missing */
1145 log_error_write(srv, __FILE__, __LINE__, "s",
1146 "POST-request, but content-length missing -> 411");
1147
1148 con->keep_alive = 0;
1149 con->http_status = 411;
1150 return 0;
1151
1152 }
1153 break;
1154 default:
1155 /* the may have a content-length */
1156 break;
1157 }
1158
1159
1160 /* check if we have read post data */
1161 if (con_length_set) {
1162 /* don't handle more the SSIZE_MAX bytes in content-length */
1163 if (con->request.content_length > SSIZE_MAX) {
1164 con->http_status = 413;
1165 con->keep_alive = 0;
1166
1167 log_error_write(srv, __FILE__, __LINE__, "sos",
1168 "request-size too long:", (off_t) con->request.content_length, "-> 413");
1169 return 0;
1170 }
1171
1172 /* divide by 1024 as srvconf.max_request_size is in kBytes */
1173 if (srv->srvconf.max_request_size != 0 &&
1174 (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
1175 /* the request body itself is larger then
1176 * our our max_request_size
1177 */
1178
1179 con->http_status = 413;
1180 con->keep_alive = 0;
1181
1182 log_error_write(srv, __FILE__, __LINE__, "sos",
1183 "request-size too long:", (off_t) con->request.content_length, "-> 413");
1184 return 0;
1185 }
1186
1187
1188 /* we have content */
1189 if (con->request.content_length != 0) {
1190 return 1;
1191 }
1192 }
1193
1194 return 0;
1195 }
1196
http_request_header_finished(server * srv,connection * con)1197 int http_request_header_finished(server *srv, connection *con) {
1198 UNUSED(srv);
1199
1200 if (con->request.request->used < 5) return 0;
1201
1202 if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
1203 if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
1204
1205 return 0;
1206 }
1207