[mod_status] page refresh option (fixes #2170)
[lighttpd.git] / src / request.c
blob08047b5547afc2f0e3edbb964ec9e5635ef0ff4e
1 #include "first.h"
3 #include "request.h"
4 #include "keyvalue.h"
5 #include "log.h"
7 #include <sys/stat.h>
9 #include <limits.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <ctype.h>
15 static int request_check_hostname(server *srv, connection *con, buffer *host) {
16 enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
17 size_t i;
18 int label_len = 0;
19 size_t host_len;
20 char *colon;
21 int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
22 int level = 0;
24 UNUSED(srv);
25 UNUSED(con);
28 * hostport = host [ ":" port ]
29 * host = hostname | IPv4address | IPv6address
30 * hostname = *( domainlabel "." ) toplabel [ "." ]
31 * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
32 * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
33 * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
34 * IPv6address = "[" ... "]"
35 * port = *digit
38 /* no Host: */
39 if (buffer_is_empty(host)) return 0;
41 host_len = buffer_string_length(host);
43 /* IPv6 adress */
44 if (host->ptr[0] == '[') {
45 char *c = host->ptr + 1;
46 int colon_cnt = 0;
48 /* check the address inside [...] */
49 for (; *c && *c != ']'; c++) {
50 if (*c == ':') {
51 if (++colon_cnt > 7) {
52 return -1;
54 } else if (!light_isxdigit(*c) && '.' != *c) {
55 return -1;
59 /* missing ] */
60 if (!*c) {
61 return -1;
64 /* check port */
65 if (*(c+1) == ':') {
66 for (c += 2; *c; c++) {
67 if (!light_isdigit(*c)) {
68 return -1;
72 else if ('\0' != *(c+1)) {
73 /* only a port is allowed to follow [...] */
74 return -1;
76 return 0;
79 if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
80 char *c = colon + 1;
82 /* check portnumber */
83 for (; *c; c++) {
84 if (!light_isdigit(*c)) return -1;
87 /* remove the port from the host-len */
88 host_len = colon - host->ptr;
91 /* Host is empty */
92 if (host_len == 0) return -1;
94 /* if the hostname ends in a "." strip it */
95 if (host->ptr[host_len-1] == '.') {
96 /* shift port info one left */
97 if (NULL != colon) memmove(colon-1, colon, buffer_string_length(host) - host_len);
98 buffer_string_set_length(host, buffer_string_length(host) - 1);
99 host_len -= 1;
102 if (host_len == 0) return -1;
104 /* scan from the right and skip the \0 */
105 for (i = host_len; i-- > 0; ) {
106 const char c = host->ptr[i];
108 switch (stage) {
109 case TOPLABEL:
110 if (c == '.') {
111 /* only switch stage, if this is not the last character */
112 if (i != host_len - 1) {
113 if (label_len == 0) {
114 return -1;
117 /* check the first character at right of the dot */
118 if (is_ip == 0) {
119 if (!light_isalnum(host->ptr[i+1])) {
120 return -1;
122 } else if (!light_isdigit(host->ptr[i+1])) {
123 is_ip = 0;
124 } else if ('-' == host->ptr[i+1]) {
125 return -1;
126 } else {
127 /* just digits */
128 is_ip = 1;
131 stage = DOMAINLABEL;
133 label_len = 0;
134 level++;
135 } else if (i == 0) {
136 /* just a dot and nothing else is evil */
137 return -1;
139 } else if (i == 0) {
140 /* the first character of the hostname */
141 if (!light_isalnum(c)) {
142 return -1;
144 label_len++;
145 } else {
146 if (c != '-' && !light_isalnum(c)) {
147 return -1;
149 if (is_ip == -1) {
150 if (!light_isdigit(c)) is_ip = 0;
152 label_len++;
155 break;
156 case DOMAINLABEL:
157 if (is_ip == 1) {
158 if (c == '.') {
159 if (label_len == 0) {
160 return -1;
163 label_len = 0;
164 level++;
165 } else if (!light_isdigit(c)) {
166 return -1;
167 } else {
168 label_len++;
170 } else {
171 if (c == '.') {
172 if (label_len == 0) {
173 return -1;
176 /* c is either - or alphanum here */
177 if ('-' == host->ptr[i+1]) {
178 return -1;
181 label_len = 0;
182 level++;
183 } else if (i == 0) {
184 if (!light_isalnum(c)) {
185 return -1;
187 label_len++;
188 } else {
189 if (c != '-' && !light_isalnum(c)) {
190 return -1;
192 label_len++;
196 break;
200 /* a IP has to consist of 4 parts */
201 if (is_ip == 1 && level != 3) {
202 return -1;
205 if (label_len == 0) {
206 return -1;
209 return 0;
212 #if 0
213 #define DUMP_HEADER
214 #endif
216 static int http_request_split_value(array *vals, buffer *b) {
217 size_t i, len;
218 int state = 0;
220 const char *current;
221 const char *token_start = NULL, *token_end = NULL;
223 * parse
225 * val1, val2, val3, val4
227 * into a array (more or less a explode() incl. striping of whitespaces
230 if (buffer_string_is_empty(b)) return 0;
232 current = b->ptr;
233 len = buffer_string_length(b);
234 for (i = 0; i <= len; ++i, ++current) {
235 data_string *ds;
237 switch (state) {
238 case 0: /* find start of a token */
239 switch (*current) {
240 case ' ':
241 case '\t': /* skip white space */
242 case ',': /* skip empty token */
243 break;
244 case '\0': /* end of string */
245 return 0;
246 default:
247 /* found real data, switch to state 1 to find the end of the token */
248 token_start = token_end = current;
249 state = 1;
250 break;
252 break;
253 case 1: /* find end of token and last non white space character */
254 switch (*current) {
255 case ' ':
256 case '\t':
257 /* space - don't update token_end */
258 break;
259 case ',':
260 case '\0': /* end of string also marks the end of a token */
261 if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
262 ds = data_string_init();
265 buffer_copy_string_len(ds->value, token_start, token_end-token_start+1);
266 array_insert_unique(vals, (data_unset *)ds);
268 state = 0;
269 break;
270 default:
271 /* no white space, update token_end to include current character */
272 token_end = current;
273 break;
275 break;
279 return 0;
282 static int request_uri_is_valid_char(unsigned char c) {
283 if (c <= 32) return 0;
284 if (c == 127) return 0;
285 if (c == 255) return 0;
287 return 1;
290 int http_request_parse(server *srv, connection *con) {
291 char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
292 int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
293 char *value = NULL, *key = NULL;
294 char *reqline_host = NULL;
295 int reqline_hostlen = 0;
297 enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
299 int line = 0;
301 int request_line_stage = 0;
302 size_t i, first, ilen;
304 int done = 0;
307 * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
308 * Option : "^([-a-zA-Z]+): (.+)$"
309 * End : "^$"
312 if (con->conf.log_request_header) {
313 log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
314 "fd:", con->fd,
315 "request-len:", buffer_string_length(con->request.request),
316 "\n", con->request.request);
319 if (con->request_count > 1 &&
320 con->request.request->ptr[0] == '\r' &&
321 con->request.request->ptr[1] == '\n') {
322 /* we are in keep-alive and might get \r\n after a previous POST request.*/
324 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, buffer_string_length(con->request.request) - 2);
325 } else {
326 /* fill the local request buffer */
327 buffer_copy_buffer(con->parse_request, con->request.request);
330 keep_alive_set = 0;
331 con_length_set = 0;
333 /* parse the first line of the request
335 * should be:
337 * <method> <uri> <protocol>\r\n
338 * */
339 ilen = buffer_string_length(con->parse_request);
340 for (i = 0, first = 0; i < ilen && line == 0; i++) {
341 switch(con->parse_request->ptr[i]) {
342 case '\r':
343 if (con->parse_request->ptr[i+1] == '\n') {
344 http_method_t r;
345 char *nuri = NULL;
346 size_t j, jlen;
348 /* \r\n -> \0\0 */
349 con->parse_request->ptr[i] = '\0';
350 con->parse_request->ptr[i+1] = '\0';
352 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
354 if (request_line_stage != 2) {
355 con->http_status = 400;
356 con->response.keep_alive = 0;
357 con->keep_alive = 0;
359 if (srv->srvconf.log_request_header_on_error) {
360 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
361 log_error_write(srv, __FILE__, __LINE__, "Sb",
362 "request-header:\n",
363 con->request.request);
365 return 0;
368 proto = con->parse_request->ptr + first;
370 *(uri - 1) = '\0';
371 *(proto - 1) = '\0';
373 /* we got the first one :) */
374 if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) {
375 con->http_status = 501;
376 con->response.keep_alive = 0;
377 con->keep_alive = 0;
379 if (srv->srvconf.log_request_header_on_error) {
380 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
381 log_error_write(srv, __FILE__, __LINE__, "Sb",
382 "request-header:\n",
383 con->request.request);
386 return 0;
389 con->request.http_method = r;
392 * RFC2616 says:
394 * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
396 * */
397 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
398 char * major = proto + sizeof("HTTP/") - 1;
399 char * minor = strchr(major, '.');
400 char *err = NULL;
401 int major_num = 0, minor_num = 0;
403 int invalid_version = 0;
405 if (NULL == minor || /* no dot */
406 minor == major || /* no major */
407 *(minor + 1) == '\0' /* no minor */) {
408 invalid_version = 1;
409 } else {
410 *minor = '\0';
411 major_num = strtol(major, &err, 10);
413 if (*err != '\0') invalid_version = 1;
415 *minor++ = '.';
416 minor_num = strtol(minor, &err, 10);
418 if (*err != '\0') invalid_version = 1;
421 if (invalid_version) {
422 con->http_status = 400;
423 con->keep_alive = 0;
425 if (srv->srvconf.log_request_header_on_error) {
426 log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
427 log_error_write(srv, __FILE__, __LINE__, "Sb",
428 "request-header:\n",
429 con->request.request);
431 return 0;
434 if (major_num == 1 && minor_num == 1) {
435 con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
436 } else if (major_num == 1 && minor_num == 0) {
437 con->request.http_version = HTTP_VERSION_1_0;
438 } else {
439 con->http_status = 505;
441 if (srv->srvconf.log_request_header_on_error) {
442 log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
443 log_error_write(srv, __FILE__, __LINE__, "Sb",
444 "request-header:\n",
445 con->request.request);
447 return 0;
449 } else {
450 con->http_status = 400;
451 con->keep_alive = 0;
453 if (srv->srvconf.log_request_header_on_error) {
454 log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
455 log_error_write(srv, __FILE__, __LINE__, "Sb",
456 "request-header:\n",
457 con->request.request);
459 return 0;
462 if (0 == strncmp(uri, "http://", 7) &&
463 NULL != (nuri = strchr(uri + 7, '/'))) {
464 reqline_host = uri + 7;
465 reqline_hostlen = nuri - reqline_host;
467 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
468 } else if (0 == strncmp(uri, "https://", 8) &&
469 NULL != (nuri = strchr(uri + 8, '/'))) {
470 reqline_host = uri + 8;
471 reqline_hostlen = nuri - reqline_host;
473 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
474 } else {
475 /* everything looks good so far */
476 buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
479 /* check uri for invalid characters */
480 jlen = buffer_string_length(con->request.uri);
481 for (j = 0; j < jlen; j++) {
482 if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
483 unsigned char buf[2];
484 con->http_status = 400;
485 con->keep_alive = 0;
487 if (srv->srvconf.log_request_header_on_error) {
488 buf[0] = con->request.uri->ptr[j];
489 buf[1] = '\0';
491 if (con->request.uri->ptr[j] > 32 &&
492 con->request.uri->ptr[j] != 127) {
493 /* the character is printable -> print it */
494 log_error_write(srv, __FILE__, __LINE__, "ss",
495 "invalid character in URI -> 400",
496 buf);
497 } else {
498 /* a control-character, print ascii-code */
499 log_error_write(srv, __FILE__, __LINE__, "sd",
500 "invalid character in URI -> 400",
501 con->request.uri->ptr[j]);
504 log_error_write(srv, __FILE__, __LINE__, "Sb",
505 "request-header:\n",
506 con->request.request);
509 return 0;
513 buffer_copy_buffer(con->request.orig_uri, con->request.uri);
515 con->http_status = 0;
517 i++;
518 line++;
519 first = i+1;
521 break;
522 case ' ':
523 switch(request_line_stage) {
524 case 0:
525 /* GET|POST|... */
526 method = con->parse_request->ptr + first;
527 first = i + 1;
528 break;
529 case 1:
530 /* /foobar/... */
531 uri = con->parse_request->ptr + first;
532 first = i + 1;
533 break;
534 default:
535 /* ERROR, one space to much */
536 con->http_status = 400;
537 con->response.keep_alive = 0;
538 con->keep_alive = 0;
540 if (srv->srvconf.log_request_header_on_error) {
541 log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
542 log_error_write(srv, __FILE__, __LINE__, "Sb",
543 "request-header:\n",
544 con->request.request);
546 return 0;
549 request_line_stage++;
550 break;
554 in_folding = 0;
556 if (buffer_string_is_empty(con->request.uri)) {
557 con->http_status = 400;
558 con->response.keep_alive = 0;
559 con->keep_alive = 0;
561 if (srv->srvconf.log_request_header_on_error) {
562 log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
563 log_error_write(srv, __FILE__, __LINE__, "Sb",
564 "request-header:\n",
565 con->request.request);
567 return 0;
570 if (reqline_host) {
571 /* Insert as host header */
572 data_string *ds;
574 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
575 ds = data_string_init();
578 buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
579 buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen);
580 array_insert_unique(con->request.headers, (data_unset *)ds);
581 con->request.http_host = ds->value;
584 for (; i <= ilen && !done; i++) {
585 char *cur = con->parse_request->ptr + i;
587 if (is_key) {
588 size_t j;
589 int got_colon = 0;
592 * 1*<any CHAR except CTLs or separators>
593 * CTLs == 0-31 + 127, CHAR = 7-bit ascii (0..127)
596 switch(*cur) {
597 case ':':
598 is_key = 0;
600 value = cur + 1;
602 if (is_ws_after_key == 0) {
603 key_len = i - first;
605 is_ws_after_key = 0;
607 break;
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 case '{':
623 case '}':
624 con->http_status = 400;
625 con->keep_alive = 0;
626 con->response.keep_alive = 0;
628 if (srv->srvconf.log_request_header_on_error) {
629 log_error_write(srv, __FILE__, __LINE__, "sbsds",
630 "invalid character in key", con->request.request, cur, *cur, "-> 400");
632 log_error_write(srv, __FILE__, __LINE__, "Sb",
633 "request-header:\n",
634 con->request.request);
636 return 0;
637 case ' ':
638 case '\t':
639 if (i == first) {
640 is_key = 0;
641 in_folding = 1;
642 value = cur;
644 break;
648 key_len = i - first;
650 /* skip every thing up to the : */
651 for (j = 1; !got_colon; j++) {
652 switch(con->parse_request->ptr[j + i]) {
653 case ' ':
654 case '\t':
655 /* skip WS */
656 continue;
657 case ':':
658 /* ok, done; handle the colon the usual way */
660 i += j - 1;
661 got_colon = 1;
662 is_ws_after_key = 1; /* we already know the key length */
664 break;
665 default:
666 /* error */
668 if (srv->srvconf.log_request_header_on_error) {
669 log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
670 log_error_write(srv, __FILE__, __LINE__, "Sb",
671 "request-header:\n",
672 con->request.request);
675 con->http_status = 400;
676 con->response.keep_alive = 0;
677 con->keep_alive = 0;
679 return 0;
683 break;
684 case '\r':
685 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
686 /* End of Header */
687 con->parse_request->ptr[i] = '\0';
688 con->parse_request->ptr[i+1] = '\0';
690 i++;
692 done = 1;
693 } else {
694 if (srv->srvconf.log_request_header_on_error) {
695 log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
696 log_error_write(srv, __FILE__, __LINE__, "Sb",
697 "request-header:\n",
698 con->request.request);
701 con->http_status = 400;
702 con->keep_alive = 0;
703 con->response.keep_alive = 0;
704 return 0;
706 break;
707 default:
708 if (*cur < 32 || ((unsigned char)*cur) >= 127) {
709 con->http_status = 400;
710 con->keep_alive = 0;
711 con->response.keep_alive = 0;
713 if (srv->srvconf.log_request_header_on_error) {
714 log_error_write(srv, __FILE__, __LINE__, "sbsds",
715 "invalid character in key", con->request.request, cur, *cur, "-> 400");
717 log_error_write(srv, __FILE__, __LINE__, "Sb",
718 "request-header:\n",
719 con->request.request);
722 return 0;
724 /* ok */
725 break;
727 } else {
728 switch(*cur) {
729 case '\r':
730 if (con->parse_request->ptr[i+1] == '\n') {
731 data_string *ds = NULL;
733 /* End of Headerline */
734 con->parse_request->ptr[i] = '\0';
735 con->parse_request->ptr[i+1] = '\0';
737 if (in_folding) {
738 buffer *key_b;
740 * we use a evil hack to handle the line-folding
742 * As array_insert_unique() deletes 'ds' in the case of a duplicate
743 * ds points somewhere and we get a evil crash. As a solution we keep the old
744 * "key" and get the current value from the hash and append us
746 * */
748 if (!key || !key_len) {
749 /* 400 */
751 if (srv->srvconf.log_request_header_on_error) {
752 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
754 log_error_write(srv, __FILE__, __LINE__, "Sb",
755 "request-header:\n",
756 con->request.request);
760 con->http_status = 400;
761 con->keep_alive = 0;
762 con->response.keep_alive = 0;
763 return 0;
766 key_b = buffer_init();
767 buffer_copy_string_len(key_b, key, key_len);
769 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) {
770 buffer_append_string(ds->value, value);
773 buffer_free(key_b);
774 } else {
775 int s_len;
776 key = con->parse_request->ptr + first;
778 s_len = cur - value;
780 /* strip trailing white-spaces */
781 for (; s_len > 0 &&
782 (value[s_len - 1] == ' ' ||
783 value[s_len - 1] == '\t'); s_len--);
785 value[s_len] = '\0';
787 if (s_len > 0) {
788 int cmp = 0;
789 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
790 ds = data_string_init();
792 buffer_copy_string_len(ds->key, key, key_len);
793 buffer_copy_string_len(ds->value, value, s_len);
795 /* retreive values
798 * the list of options is sorted to simplify the search
801 if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
802 array *vals;
803 size_t vi;
805 /* split on , */
807 vals = srv->split_vals;
809 array_reset(vals);
811 http_request_split_value(vals, ds->value);
813 for (vi = 0; vi < vals->used; vi++) {
814 data_string *dsv = (data_string *)vals->data[vi];
816 if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
817 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
819 break;
820 } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
821 keep_alive_set = HTTP_CONNECTION_CLOSE;
823 break;
827 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
828 char *err;
829 unsigned long int r;
830 size_t j, jlen;
832 if (con_length_set) {
833 con->http_status = 400;
834 con->keep_alive = 0;
836 if (srv->srvconf.log_request_header_on_error) {
837 log_error_write(srv, __FILE__, __LINE__, "s",
838 "duplicate Content-Length-header -> 400");
839 log_error_write(srv, __FILE__, __LINE__, "Sb",
840 "request-header:\n",
841 con->request.request);
843 array_insert_unique(con->request.headers, (data_unset *)ds);
844 return 0;
847 jlen = buffer_string_length(ds->value);
848 for (j = 0; j < jlen; j++) {
849 char c = ds->value->ptr[j];
850 if (!isdigit((unsigned char)c)) {
851 log_error_write(srv, __FILE__, __LINE__, "sbs",
852 "content-length broken:", ds->value, "-> 400");
854 con->http_status = 400;
855 con->keep_alive = 0;
857 array_insert_unique(con->request.headers, (data_unset *)ds);
858 return 0;
862 r = strtoul(ds->value->ptr, &err, 10);
864 if (*err == '\0') {
865 con_length_set = 1;
866 con->request.content_length = r;
867 } else {
868 log_error_write(srv, __FILE__, __LINE__, "sbs",
869 "content-length broken:", ds->value, "-> 400");
871 con->http_status = 400;
872 con->keep_alive = 0;
874 array_insert_unique(con->request.headers, (data_unset *)ds);
875 return 0;
877 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
878 /* if dup, only the first one will survive */
879 if (!con->request.http_content_type) {
880 con->request.http_content_type = ds->value->ptr;
881 } else {
882 con->http_status = 400;
883 con->keep_alive = 0;
885 if (srv->srvconf.log_request_header_on_error) {
886 log_error_write(srv, __FILE__, __LINE__, "s",
887 "duplicate Content-Type-header -> 400");
888 log_error_write(srv, __FILE__, __LINE__, "Sb",
889 "request-header:\n",
890 con->request.request);
892 array_insert_unique(con->request.headers, (data_unset *)ds);
893 return 0;
895 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
896 /* HTTP 2616 8.2.3
897 * Expect: 100-continue
899 * -> (10.1.1) 100 (read content, process request, send final status-code)
900 * -> (10.4.18) 417 (close)
902 * (not handled at all yet, we always send 417 here)
904 * What has to be added ?
905 * 1. handling of chunked request body
906 * 2. out-of-order sending from the HTTP/1.1 100 Continue
907 * header
911 if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
912 con->http_status = 417;
913 con->keep_alive = 0;
914 array_insert_unique(con->request.headers, (data_unset *)ds);
915 return 0;
917 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
918 if (reqline_host) {
919 /* ignore all host: headers as we got the host in the request line */
920 ds->free((data_unset*) ds);
921 ds = NULL;
922 } else if (!con->request.http_host) {
923 con->request.http_host = ds->value;
924 } else {
925 con->http_status = 400;
926 con->keep_alive = 0;
928 if (srv->srvconf.log_request_header_on_error) {
929 log_error_write(srv, __FILE__, __LINE__, "s",
930 "duplicate Host-header -> 400");
931 log_error_write(srv, __FILE__, __LINE__, "Sb",
932 "request-header:\n",
933 con->request.request);
935 array_insert_unique(con->request.headers, (data_unset *)ds);
936 return 0;
938 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
939 /* Proxies sometimes send dup headers
940 * if they are the same we ignore the second
941 * if not, we raise an error */
942 if (!con->request.http_if_modified_since) {
943 con->request.http_if_modified_since = ds->value->ptr;
944 } else if (0 == strcasecmp(con->request.http_if_modified_since,
945 ds->value->ptr)) {
946 /* ignore it if they are the same */
948 ds->free((data_unset *)ds);
949 ds = NULL;
950 } else {
951 con->http_status = 400;
952 con->keep_alive = 0;
954 if (srv->srvconf.log_request_header_on_error) {
955 log_error_write(srv, __FILE__, __LINE__, "s",
956 "duplicate If-Modified-Since header -> 400");
957 log_error_write(srv, __FILE__, __LINE__, "Sb",
958 "request-header:\n",
959 con->request.request);
961 array_insert_unique(con->request.headers, (data_unset *)ds);
962 return 0;
964 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
965 /* if dup, only the first one will survive */
966 if (!con->request.http_if_none_match) {
967 con->request.http_if_none_match = ds->value->ptr;
968 } else {
969 ds->free((data_unset*) ds);
970 ds = NULL;
972 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
973 if (!con->request.http_range) {
974 /* bytes=.*-.* */
976 if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
977 NULL != strchr(ds->value->ptr+6, '-')) {
979 /* if dup, only the first one will survive */
980 con->request.http_range = ds->value->ptr + 6;
982 } else {
983 con->http_status = 400;
984 con->keep_alive = 0;
986 if (srv->srvconf.log_request_header_on_error) {
987 log_error_write(srv, __FILE__, __LINE__, "s",
988 "duplicate Range-header -> 400");
989 log_error_write(srv, __FILE__, __LINE__, "Sb",
990 "request-header:\n",
991 con->request.request);
993 array_insert_unique(con->request.headers, (data_unset *)ds);
994 return 0;
998 if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
999 } else {
1000 /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
1004 i++;
1005 first = i+1;
1006 is_key = 1;
1007 value = NULL;
1008 #if 0
1010 * for Bug 1230 keep the key_len a live
1012 key_len = 0;
1013 #endif
1014 in_folding = 0;
1015 } else {
1016 if (srv->srvconf.log_request_header_on_error) {
1017 log_error_write(srv, __FILE__, __LINE__, "sbs",
1018 "CR without LF", con->request.request, "-> 400");
1021 con->http_status = 400;
1022 con->keep_alive = 0;
1023 con->response.keep_alive = 0;
1024 return 0;
1026 break;
1027 case ' ':
1028 case '\t':
1029 /* strip leading WS */
1030 if (value == cur) value = cur+1;
1031 /* fallthrough */
1032 default:
1033 if (*cur >= 0 && *cur < 32 && *cur != '\t') {
1034 if (srv->srvconf.log_request_header_on_error) {
1035 log_error_write(srv, __FILE__, __LINE__, "sds",
1036 "invalid char in header", (int)*cur, "-> 400");
1039 con->http_status = 400;
1040 con->keep_alive = 0;
1042 return 0;
1044 break;
1049 con->header_len = i;
1051 /* do some post-processing */
1053 if (con->request.http_version == HTTP_VERSION_1_1) {
1054 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
1055 /* no Connection-Header sent */
1057 /* HTTP/1.1 -> keep-alive default TRUE */
1058 con->keep_alive = 1;
1059 } else {
1060 con->keep_alive = 0;
1063 /* RFC 2616, 14.23 */
1064 if (con->request.http_host == NULL ||
1065 buffer_string_is_empty(con->request.http_host)) {
1066 con->http_status = 400;
1067 con->response.keep_alive = 0;
1068 con->keep_alive = 0;
1070 if (srv->srvconf.log_request_header_on_error) {
1071 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
1072 log_error_write(srv, __FILE__, __LINE__, "Sb",
1073 "request-header:\n",
1074 con->request.request);
1076 return 0;
1078 } else {
1079 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
1080 /* no Connection-Header sent */
1082 /* HTTP/1.0 -> keep-alive default FALSE */
1083 con->keep_alive = 1;
1084 } else {
1085 con->keep_alive = 0;
1089 /* check hostname field if it is set */
1090 if (NULL != con->request.http_host &&
1091 0 != request_check_hostname(srv, con, con->request.http_host)) {
1093 if (srv->srvconf.log_request_header_on_error) {
1094 log_error_write(srv, __FILE__, __LINE__, "s",
1095 "Invalid Hostname -> 400");
1096 log_error_write(srv, __FILE__, __LINE__, "Sb",
1097 "request-header:\n",
1098 con->request.request);
1101 con->http_status = 400;
1102 con->response.keep_alive = 0;
1103 con->keep_alive = 0;
1105 return 0;
1108 switch(con->request.http_method) {
1109 case HTTP_METHOD_GET:
1110 case HTTP_METHOD_HEAD:
1111 /* content-length is forbidden for those */
1112 if (con_length_set && con->request.content_length != 0) {
1113 /* content-length is missing */
1114 log_error_write(srv, __FILE__, __LINE__, "s",
1115 "GET/HEAD with content-length -> 400");
1117 con->keep_alive = 0;
1118 con->http_status = 400;
1119 return 0;
1121 break;
1122 case HTTP_METHOD_POST:
1123 /* content-length is required for them */
1124 if (!con_length_set) {
1125 /* content-length is missing */
1126 log_error_write(srv, __FILE__, __LINE__, "s",
1127 "POST-request, but content-length missing -> 411");
1129 con->keep_alive = 0;
1130 con->http_status = 411;
1131 return 0;
1134 break;
1135 default:
1136 /* require Content-Length if request contains request body */
1137 if (array_get_element(con->request.headers, "Transfer-Encoding")) {
1138 /* presence of Transfer-Encoding in request headers requires "chunked"
1139 * be final encoding in HTTP/1.1. Return 411 Length Required as
1140 * lighttpd does not support request input transfer-encodings */
1141 con->keep_alive = 0;
1142 con->http_status = 411; /* 411 Length Required */
1143 return 0;
1145 break;
1149 /* check if we have read post data */
1150 if (con_length_set) {
1151 /* don't handle more the SSIZE_MAX bytes in content-length */
1152 if (con->request.content_length > SSIZE_MAX) {
1153 con->http_status = 413;
1154 con->keep_alive = 0;
1156 log_error_write(srv, __FILE__, __LINE__, "sos",
1157 "request-size too long:", (off_t) con->request.content_length, "-> 413");
1158 return 0;
1161 /* divide by 1024 as srvconf.max_request_size is in kBytes */
1162 if (srv->srvconf.max_request_size != 0 &&
1163 (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
1164 /* the request body itself is larger then
1165 * our our max_request_size
1168 con->http_status = 413;
1169 con->keep_alive = 0;
1171 log_error_write(srv, __FILE__, __LINE__, "sos",
1172 "request-size too long:", (off_t) con->request.content_length, "-> 413");
1173 return 0;
1177 /* we have content */
1178 if (con->request.content_length != 0) {
1179 return 1;
1183 return 0;
1186 int http_request_header_finished(server *srv, connection *con) {
1187 UNUSED(srv);
1189 if (buffer_string_length(con->request.request) < 4) return 0;
1191 if (0 == memcmp(con->request.request->ptr + buffer_string_length(con->request.request) - 4, CONST_STR_LEN("\r\n\r\n"))) return 1;
1192 if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
1194 return 0;