Annotation of embedaddon/lighttpd/src/request.c, revision 1.1.1.1
1.1 misho 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 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:
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:
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:
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 (HTTP_METHOD_UNSET == (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, CHAR = 7-bit ascii (0..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: if (srv->srvconf.log_request_header_on_error) {
623: log_error_write(srv, __FILE__, __LINE__, "sbsds",
624: "invalid character in key", con->request.request, cur, *cur, "-> 400");
625:
626: log_error_write(srv, __FILE__, __LINE__, "Sb",
627: "request-header:\n",
628: con->request.request);
629: }
630: return 0;
631: case ' ':
632: case '\t':
633: if (i == first) {
634: is_key = 0;
635: in_folding = 1;
636: value = cur;
637:
638: break;
639: }
640:
641:
642: key_len = i - first;
643:
644: /* skip every thing up to the : */
645: for (j = 1; !got_colon; j++) {
646: switch(con->parse_request->ptr[j + i]) {
647: case ' ':
648: case '\t':
649: /* skip WS */
650: continue;
651: case ':':
652: /* ok, done; handle the colon the usual way */
653:
654: i += j - 1;
655: got_colon = 1;
656: is_ws_after_key = 1; /* we already know the key length */
657:
658: break;
659: default:
660: /* error */
661:
662: if (srv->srvconf.log_request_header_on_error) {
663: log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
664: log_error_write(srv, __FILE__, __LINE__, "Sb",
665: "request-header:\n",
666: con->request.request);
667: }
668:
669: con->http_status = 400;
670: con->response.keep_alive = 0;
671: con->keep_alive = 0;
672:
673: return 0;
674: }
675: }
676:
677: break;
678: case '\r':
679: if (con->parse_request->ptr[i+1] == '\n' && i == first) {
680: /* End of Header */
681: con->parse_request->ptr[i] = '\0';
682: con->parse_request->ptr[i+1] = '\0';
683:
684: i++;
685:
686: done = 1;
687: } else {
688: if (srv->srvconf.log_request_header_on_error) {
689: log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
690: log_error_write(srv, __FILE__, __LINE__, "Sb",
691: "request-header:\n",
692: con->request.request);
693: }
694:
695: con->http_status = 400;
696: con->keep_alive = 0;
697: con->response.keep_alive = 0;
698: return 0;
699: }
700: break;
701: default:
702: if (*cur < 32 || ((unsigned char)*cur) >= 127) {
703: con->http_status = 400;
704: con->keep_alive = 0;
705: con->response.keep_alive = 0;
706:
707: if (srv->srvconf.log_request_header_on_error) {
708: log_error_write(srv, __FILE__, __LINE__, "sbsds",
709: "invalid character in key", con->request.request, cur, *cur, "-> 400");
710:
711: log_error_write(srv, __FILE__, __LINE__, "Sb",
712: "request-header:\n",
713: con->request.request);
714: }
715:
716: return 0;
717: }
718: /* ok */
719: break;
720: }
721: } else {
722: switch(*cur) {
723: case '\r':
724: if (con->parse_request->ptr[i+1] == '\n') {
725: data_string *ds = NULL;
726:
727: /* End of Headerline */
728: con->parse_request->ptr[i] = '\0';
729: con->parse_request->ptr[i+1] = '\0';
730:
731: if (in_folding) {
732: buffer *key_b;
733: /**
734: * we use a evil hack to handle the line-folding
735: *
736: * As array_insert_unique() deletes 'ds' in the case of a duplicate
737: * ds points somewhere and we get a evil crash. As a solution we keep the old
738: * "key" and get the current value from the hash and append us
739: *
740: * */
741:
742: if (!key || !key_len) {
743: /* 400 */
744:
745: if (srv->srvconf.log_request_header_on_error) {
746: log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
747:
748: log_error_write(srv, __FILE__, __LINE__, "Sb",
749: "request-header:\n",
750: con->request.request);
751: }
752:
753:
754: con->http_status = 400;
755: con->keep_alive = 0;
756: con->response.keep_alive = 0;
757: return 0;
758: }
759:
760: key_b = buffer_init();
761: buffer_copy_string_len(key_b, key, key_len);
762:
763: if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) {
764: buffer_append_string(ds->value, value);
765: }
766:
767: buffer_free(key_b);
768: } else {
769: int s_len;
770: key = con->parse_request->ptr + first;
771:
772: s_len = cur - value;
773:
774: /* strip trailing white-spaces */
775: for (; s_len > 0 &&
776: (value[s_len - 1] == ' ' ||
777: value[s_len - 1] == '\t'); s_len--);
778:
779: value[s_len] = '\0';
780:
781: if (s_len > 0) {
782: int cmp = 0;
783: if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
784: ds = data_string_init();
785: }
786: buffer_copy_string_len(ds->key, key, key_len);
787: buffer_copy_string_len(ds->value, value, s_len);
788:
789: /* retreive values
790: *
791: *
792: * the list of options is sorted to simplify the search
793: */
794:
795: if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
796: array *vals;
797: size_t vi;
798:
799: /* split on , */
800:
801: vals = srv->split_vals;
802:
803: array_reset(vals);
804:
805: http_request_split_value(vals, ds->value);
806:
807: for (vi = 0; vi < vals->used; vi++) {
808: data_string *dsv = (data_string *)vals->data[vi];
809:
810: if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
811: keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
812:
813: break;
814: } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
815: keep_alive_set = HTTP_CONNECTION_CLOSE;
816:
817: break;
818: }
819: }
820:
821: } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
822: char *err;
823: unsigned long int r;
824: size_t j;
825:
826: if (con_length_set) {
827: con->http_status = 400;
828: con->keep_alive = 0;
829:
830: if (srv->srvconf.log_request_header_on_error) {
831: log_error_write(srv, __FILE__, __LINE__, "s",
832: "duplicate Content-Length-header -> 400");
833: log_error_write(srv, __FILE__, __LINE__, "Sb",
834: "request-header:\n",
835: con->request.request);
836: }
837: array_insert_unique(con->request.headers, (data_unset *)ds);
838: return 0;
839: }
840:
841: if (ds->value->used == 0) SEGFAULT();
842:
843: for (j = 0; j < ds->value->used - 1; j++) {
844: char c = ds->value->ptr[j];
845: if (!isdigit((unsigned char)c)) {
846: log_error_write(srv, __FILE__, __LINE__, "sbs",
847: "content-length broken:", ds->value, "-> 400");
848:
849: con->http_status = 400;
850: con->keep_alive = 0;
851:
852: array_insert_unique(con->request.headers, (data_unset *)ds);
853: return 0;
854: }
855: }
856:
857: r = strtoul(ds->value->ptr, &err, 10);
858:
859: if (*err == '\0') {
860: con_length_set = 1;
861: con->request.content_length = r;
862: } else {
863: log_error_write(srv, __FILE__, __LINE__, "sbs",
864: "content-length broken:", ds->value, "-> 400");
865:
866: con->http_status = 400;
867: con->keep_alive = 0;
868:
869: array_insert_unique(con->request.headers, (data_unset *)ds);
870: return 0;
871: }
872: } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
873: /* if dup, only the first one will survive */
874: if (!con->request.http_content_type) {
875: con->request.http_content_type = ds->value->ptr;
876: } else {
877: con->http_status = 400;
878: con->keep_alive = 0;
879:
880: if (srv->srvconf.log_request_header_on_error) {
881: log_error_write(srv, __FILE__, __LINE__, "s",
882: "duplicate Content-Type-header -> 400");
883: log_error_write(srv, __FILE__, __LINE__, "Sb",
884: "request-header:\n",
885: con->request.request);
886: }
887: array_insert_unique(con->request.headers, (data_unset *)ds);
888: return 0;
889: }
890: } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
891: /* HTTP 2616 8.2.3
892: * Expect: 100-continue
893: *
894: * -> (10.1.1) 100 (read content, process request, send final status-code)
895: * -> (10.4.18) 417 (close)
896: *
897: * (not handled at all yet, we always send 417 here)
898: *
899: * What has to be added ?
900: * 1. handling of chunked request body
901: * 2. out-of-order sending from the HTTP/1.1 100 Continue
902: * header
903: *
904: */
905:
906: if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
907: con->http_status = 417;
908: con->keep_alive = 0;
909: array_insert_unique(con->request.headers, (data_unset *)ds);
910: return 0;
911: }
912: } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
913: if (reqline_host) {
914: /* ignore all host: headers as we got the host in the request line */
915: ds->free((data_unset*) ds);
916: ds = NULL;
917: } else if (!con->request.http_host) {
918: con->request.http_host = ds->value;
919: } else {
920: con->http_status = 400;
921: con->keep_alive = 0;
922:
923: if (srv->srvconf.log_request_header_on_error) {
924: log_error_write(srv, __FILE__, __LINE__, "s",
925: "duplicate Host-header -> 400");
926: log_error_write(srv, __FILE__, __LINE__, "Sb",
927: "request-header:\n",
928: con->request.request);
929: }
930: array_insert_unique(con->request.headers, (data_unset *)ds);
931: return 0;
932: }
933: } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
934: /* Proxies sometimes send dup headers
935: * if they are the same we ignore the second
936: * if not, we raise an error */
937: if (!con->request.http_if_modified_since) {
938: con->request.http_if_modified_since = ds->value->ptr;
939: } else if (0 == strcasecmp(con->request.http_if_modified_since,
940: ds->value->ptr)) {
941: /* ignore it if they are the same */
942:
943: ds->free((data_unset *)ds);
944: ds = NULL;
945: } else {
946: con->http_status = 400;
947: con->keep_alive = 0;
948:
949: if (srv->srvconf.log_request_header_on_error) {
950: log_error_write(srv, __FILE__, __LINE__, "s",
951: "duplicate If-Modified-Since header -> 400");
952: log_error_write(srv, __FILE__, __LINE__, "Sb",
953: "request-header:\n",
954: con->request.request);
955: }
956: array_insert_unique(con->request.headers, (data_unset *)ds);
957: return 0;
958: }
959: } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
960: /* if dup, only the first one will survive */
961: if (!con->request.http_if_none_match) {
962: con->request.http_if_none_match = ds->value->ptr;
963: } else {
964: ds->free((data_unset*) ds);
965: ds = NULL;
966: }
967: } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
968: if (!con->request.http_range) {
969: /* bytes=.*-.* */
970:
971: if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
972: NULL != strchr(ds->value->ptr+6, '-')) {
973:
974: /* if dup, only the first one will survive */
975: con->request.http_range = ds->value->ptr + 6;
976: }
977: } else {
978: con->http_status = 400;
979: con->keep_alive = 0;
980:
981: if (srv->srvconf.log_request_header_on_error) {
982: log_error_write(srv, __FILE__, __LINE__, "s",
983: "duplicate Range-header -> 400");
984: log_error_write(srv, __FILE__, __LINE__, "Sb",
985: "request-header:\n",
986: con->request.request);
987: }
988: array_insert_unique(con->request.headers, (data_unset *)ds);
989: return 0;
990: }
991: }
992:
993: if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
994: } else {
995: /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
996: }
997: }
998:
999: i++;
1000: first = i+1;
1001: is_key = 1;
1002: value = NULL;
1003: #if 0
1004: /**
1005: * for Bug 1230 keep the key_len a live
1006: */
1007: key_len = 0;
1008: #endif
1009: in_folding = 0;
1010: } else {
1011: if (srv->srvconf.log_request_header_on_error) {
1012: log_error_write(srv, __FILE__, __LINE__, "sbs",
1013: "CR without LF", con->request.request, "-> 400");
1014: }
1015:
1016: con->http_status = 400;
1017: con->keep_alive = 0;
1018: con->response.keep_alive = 0;
1019: return 0;
1020: }
1021: break;
1022: case ' ':
1023: case '\t':
1024: /* strip leading WS */
1025: if (value == cur) value = cur+1;
1026: default:
1027: if (*cur >= 0 && *cur < 32 && *cur != '\t') {
1028: if (srv->srvconf.log_request_header_on_error) {
1029: log_error_write(srv, __FILE__, __LINE__, "sds",
1030: "invalid char in header", (int)*cur, "-> 400");
1031: }
1032:
1033: con->http_status = 400;
1034: con->keep_alive = 0;
1035:
1036: return 0;
1037: }
1038: break;
1039: }
1040: }
1041: }
1042:
1043: con->header_len = i;
1044:
1045: /* do some post-processing */
1046:
1047: if (con->request.http_version == HTTP_VERSION_1_1) {
1048: if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
1049: /* no Connection-Header sent */
1050:
1051: /* HTTP/1.1 -> keep-alive default TRUE */
1052: con->keep_alive = 1;
1053: } else {
1054: con->keep_alive = 0;
1055: }
1056:
1057: /* RFC 2616, 14.23 */
1058: if (con->request.http_host == NULL ||
1059: buffer_is_empty(con->request.http_host)) {
1060: con->http_status = 400;
1061: con->response.keep_alive = 0;
1062: con->keep_alive = 0;
1063:
1064: if (srv->srvconf.log_request_header_on_error) {
1065: log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
1066: log_error_write(srv, __FILE__, __LINE__, "Sb",
1067: "request-header:\n",
1068: con->request.request);
1069: }
1070: return 0;
1071: }
1072: } else {
1073: if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
1074: /* no Connection-Header sent */
1075:
1076: /* HTTP/1.0 -> keep-alive default FALSE */
1077: con->keep_alive = 1;
1078: } else {
1079: con->keep_alive = 0;
1080: }
1081: }
1082:
1083: /* check hostname field if it is set */
1084: if (NULL != con->request.http_host &&
1085: 0 != request_check_hostname(srv, con, con->request.http_host)) {
1086:
1087: if (srv->srvconf.log_request_header_on_error) {
1088: log_error_write(srv, __FILE__, __LINE__, "s",
1089: "Invalid Hostname -> 400");
1090: log_error_write(srv, __FILE__, __LINE__, "Sb",
1091: "request-header:\n",
1092: con->request.request);
1093: }
1094:
1095: con->http_status = 400;
1096: con->response.keep_alive = 0;
1097: con->keep_alive = 0;
1098:
1099: return 0;
1100: }
1101:
1102: switch(con->request.http_method) {
1103: case HTTP_METHOD_GET:
1104: case HTTP_METHOD_HEAD:
1105: /* content-length is forbidden for those */
1106: if (con_length_set && con->request.content_length != 0) {
1107: /* content-length is missing */
1108: log_error_write(srv, __FILE__, __LINE__, "s",
1109: "GET/HEAD with content-length -> 400");
1110:
1111: con->keep_alive = 0;
1112: con->http_status = 400;
1113: return 0;
1114: }
1115: break;
1116: case HTTP_METHOD_POST:
1117: /* content-length is required for them */
1118: if (!con_length_set) {
1119: /* content-length is missing */
1120: log_error_write(srv, __FILE__, __LINE__, "s",
1121: "POST-request, but content-length missing -> 411");
1122:
1123: con->keep_alive = 0;
1124: con->http_status = 411;
1125: return 0;
1126:
1127: }
1128: break;
1129: default:
1130: /* the may have a content-length */
1131: break;
1132: }
1133:
1134:
1135: /* check if we have read post data */
1136: if (con_length_set) {
1137: /* don't handle more the SSIZE_MAX bytes in content-length */
1138: if (con->request.content_length > SSIZE_MAX) {
1139: con->http_status = 413;
1140: con->keep_alive = 0;
1141:
1142: log_error_write(srv, __FILE__, __LINE__, "sos",
1143: "request-size too long:", (off_t) con->request.content_length, "-> 413");
1144: return 0;
1145: }
1146:
1147: /* divide by 1024 as srvconf.max_request_size is in kBytes */
1148: if (srv->srvconf.max_request_size != 0 &&
1149: (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
1150: /* the request body itself is larger then
1151: * our our max_request_size
1152: */
1153:
1154: con->http_status = 413;
1155: con->keep_alive = 0;
1156:
1157: log_error_write(srv, __FILE__, __LINE__, "sos",
1158: "request-size too long:", (off_t) con->request.content_length, "-> 413");
1159: return 0;
1160: }
1161:
1162:
1163: /* we have content */
1164: if (con->request.content_length != 0) {
1165: return 1;
1166: }
1167: }
1168:
1169: return 0;
1170: }
1171:
1172: int http_request_header_finished(server *srv, connection *con) {
1173: UNUSED(srv);
1174:
1175: if (con->request.request->used < 5) return 0;
1176:
1177: if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
1178: if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
1179:
1180: return 0;
1181: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>