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