]> git.pld-linux.org Git - packages/lighttpd.git/blob - a9e131..df8e4f.patch
use-after-free header unfolding fix
[packages/lighttpd.git] / a9e131..df8e4f.patch
1 From: =?UTF-8?Q?Stefan_B=c3=bchler?= <stbuehler@web.de>
2 To: lighttpd-announce@lists.lighttpd.net
3 Message-ID: <8cbf0c87-1037-8f70-aa24-b2f14c95170d@web.de>
4 Date: Sun, 26 Aug 2018 19:06:30 +0200
5 Subject: use-after-free bug in header folding
6
7 Hi,
8
9 Or Peles reported some use-after-free scenarios related to header 
10 folding (continuing a header value on a whitespace indented line).
11
12 The fix required some preparation and therefor consists of a series of 4 
13 patches, see git:
14
15 https://git.lighttpd.net/lighttpd/lighttpd1.4.git/log/?qt=range&q=a9e131..df8e4f&showmsg=1
16
17 There are currently no plans for a new release.
18
19 cheers,
20 Stefan
21
22 diff --git a/src/request.c b/src/request.c
23 index 213a87e1..e94d8591 100644
24 --- a/src/request.c
25 +++ b/src/request.c
26 @@ -408,26 +408,179 @@ static int request_uri_is_valid_char(unsigned char c) {
27         return 1;
28  }
29  
30 -static int http_request_missing_CR_before_LF(server *srv, connection *con) {
31 +static void http_request_missing_CR_before_LF(server *srv, connection *con) {
32         if (srv->srvconf.log_request_header_on_error) {
33                 log_error_write(srv, __FILE__, __LINE__, "s", "missing CR before LF in header -> 400");
34                 log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request);
35         }
36 +}
37  
38 -       con->http_status = 400;
39 -       con->keep_alive = 0;
40 -       con->response.keep_alive = 0;
41 +enum keep_alive_set {
42 +       HTTP_CONNECTION_UNSET,
43 +       HTTP_CONNECTION_KEEPALIVE,
44 +       HTTP_CONNECTION_CLOSE,
45 +};
46 +
47 +typedef struct {
48 +       enum keep_alive_set keep_alive_set;
49 +       char con_length_set;
50 +       char *reqline_host;
51 +       int reqline_hostlen;
52 +} parse_header_state;
53 +
54 +static void init_parse_header_state(parse_header_state* state) {
55 +       state->keep_alive_set = HTTP_CONNECTION_UNSET;
56 +       state->con_length_set = 0;
57 +       state->reqline_host = NULL;
58 +       state->reqline_hostlen = 0;
59 +}
60 +
61 +/* add a header to the list of headers; certain headers are also parsed in this state.
62 + *
63 + * Also might drop a header if deemed unnecessary/broken.
64 + *
65 + * returns 0 on error
66 + */
67 +static int parse_single_header(server *srv, connection *con, parse_header_state *state, data_string *ds) {
68 +       int cmp = 0;
69 +
70 +       /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
71 +       if (buffer_string_is_empty(ds->value)) {
72 +               goto drop_header;
73 +       }
74 +
75 +       /* retreive values
76 +        *
77 +        *
78 +        * the list of options is sorted to simplify the search
79 +        */
80 +
81 +       if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
82 +               array *vals;
83 +               size_t vi;
84 +
85 +               /* split on , */
86 +
87 +               vals = srv->split_vals;
88 +
89 +               array_reset(vals);
90 +
91 +               http_request_split_value(vals, ds->value);
92 +
93 +               for (vi = 0; vi < vals->used; vi++) {
94 +                       data_string *dsv = (data_string *)vals->data[vi];
95 +
96 +                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
97 +                               state->keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
98 +
99 +                               break;
100 +                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
101 +                               state->keep_alive_set = HTTP_CONNECTION_CLOSE;
102 +
103 +                               break;
104 +                       }
105 +               }
106 +
107 +       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
108 +               char *err;
109 +               off_t r;
110 +
111 +               if (state->con_length_set) {
112 +                       if (srv->srvconf.log_request_header_on_error) {
113 +                               log_error_write(srv, __FILE__, __LINE__, "s",
114 +                                               "duplicate Content-Length-header -> 400");
115 +                               log_error_write(srv, __FILE__, __LINE__, "Sb",
116 +                                               "request-header:\n",
117 +                                               con->request.request);
118 +                       }
119 +                       goto invalid_header;
120 +               }
121 +
122 +               r = strtoll(ds->value->ptr, &err, 10);
123 +
124 +               if (*err == '\0' && r >= 0) {
125 +                       state->con_length_set = 1;
126 +                       con->request.content_length = r;
127 +               } else {
128 +                       log_error_write(srv, __FILE__, __LINE__, "sbs",
129 +                                       "content-length broken:", ds->value, "-> 400");
130 +                       goto invalid_header;
131 +               }
132 +       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
133 +               /* if dup, only the first one will survive */
134 +               if (!con->request.http_content_type) {
135 +                       con->request.http_content_type = ds->value->ptr;
136 +               } else {
137 +                       if (srv->srvconf.log_request_header_on_error) {
138 +                               log_error_write(srv, __FILE__, __LINE__, "s",
139 +                                               "duplicate Content-Type-header -> 400");
140 +                               log_error_write(srv, __FILE__, __LINE__, "Sb",
141 +                                               "request-header:\n",
142 +                                               con->request.request);
143 +                       }
144 +                       goto invalid_header;
145 +               }
146 +       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
147 +               if (state->reqline_host) {
148 +                       /* ignore all host: headers as we got the host in the request line */
149 +                       goto drop_header;
150 +               } else if (!con->request.http_host) {
151 +                       con->request.http_host = ds->value;
152 +               } else {
153 +                       if (srv->srvconf.log_request_header_on_error) {
154 +                               log_error_write(srv, __FILE__, __LINE__, "s",
155 +                                               "duplicate Host-header -> 400");
156 +                               log_error_write(srv, __FILE__, __LINE__, "Sb",
157 +                                               "request-header:\n",
158 +                                               con->request.request);
159 +                       }
160 +                       goto invalid_header;
161 +               }
162 +       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
163 +               /* Proxies sometimes send dup headers
164 +                * if they are the same we ignore the second
165 +                * if not, we raise an error */
166 +               if (!con->request.http_if_modified_since) {
167 +                       con->request.http_if_modified_since = ds->value->ptr;
168 +               } else if (0 == strcasecmp(con->request.http_if_modified_since, ds->value->ptr)) {
169 +                       /* ignore it if they are the same */
170 +                       goto drop_header;
171 +               } else {
172 +                       if (srv->srvconf.log_request_header_on_error) {
173 +                               log_error_write(srv, __FILE__, __LINE__, "s",
174 +                                               "duplicate If-Modified-Since header -> 400");
175 +                               log_error_write(srv, __FILE__, __LINE__, "Sb",
176 +                                               "request-header:\n",
177 +                                               con->request.request);
178 +                       }
179 +                       goto invalid_header;
180 +               }
181 +       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
182 +               /* if dup, only the first one will survive */
183 +               if (!con->request.http_if_none_match) {
184 +                       con->request.http_if_none_match = ds->value->ptr;
185 +               } else {
186 +                       goto drop_header;
187 +               }
188 +       }
189 +
190 +       array_insert_unique(con->request.headers, (data_unset *)ds);
191 +       return 1;
192 +
193 +drop_header:
194 +       ds->free((data_unset *)ds);
195 +       return 1;
196 +
197 +invalid_header:
198 +       ds->free((data_unset *)ds);
199         return 0;
200  }
201  
202  int http_request_parse(server *srv, connection *con) {
203 -       char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
204 +       char *uri = NULL, *proto = NULL, *method = NULL;
205         int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
206         char *value = NULL, *key = NULL;
207 -       char *reqline_host = NULL;
208 -       int reqline_hostlen = 0;
209 -
210 -       enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
211 +       data_string *current_header = NULL;
212  
213         int line = 0;
214  
215 @@ -437,6 +590,9 @@ int http_request_parse(server *srv, connection *con) {
216         int done = 0;
217         const unsigned int http_header_strict = (con->conf.http_parseopts & HTTP_PARSEOPT_HEADER_STRICT);
218  
219 +       parse_header_state state;
220 +       init_parse_header_state(&state);
221 +
222         /*
223          * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
224          * Option : "^([-a-zA-Z]+): (.+)$"
225 @@ -457,9 +613,7 @@ int http_request_parse(server *srv, connection *con) {
226  
227               #ifdef __COVERITY__
228                 if (buffer_string_length(con->request.request) < 2) {
229 -                       con->keep_alive = 0;
230 -                       con->http_status = 400;
231 -                       return 0;
232 +                       goto failure;
233                 }
234               #endif
235                 /* coverity[overflow_sink : FALSE] */
236 @@ -467,12 +621,13 @@ int http_request_parse(server *srv, connection *con) {
237         } else if (con->request_count > 0 &&
238             con->request.request->ptr[1] == '\n') {
239                 /* we are in keep-alive and might get \n after a previous POST request.*/
240 -               if (http_header_strict) return http_request_missing_CR_before_LF(srv, con);
241 +               if (http_header_strict) {
242 +                       http_request_missing_CR_before_LF(srv, con);
243 +                       goto failure;
244 +               }
245               #ifdef __COVERITY__
246                 if (buffer_string_length(con->request.request) < 1) {
247 -                       con->keep_alive = 0;
248 -                       con->http_status = 400;
249 -                       return 0;
250 +                       goto failure;
251                 }
252               #endif
253                 /* coverity[overflow_sink : FALSE] */
254 @@ -482,9 +637,6 @@ int http_request_parse(server *srv, connection *con) {
255                 buffer_copy_buffer(con->parse_request, con->request.request);
256         }
257  
258 -       keep_alive_set = 0;
259 -       con_length_set = 0;
260 -
261         /* parse the first line of the request
262          *
263          * should be:
264 @@ -510,22 +662,19 @@ int http_request_parse(server *srv, connection *con) {
265                                         con->parse_request->ptr[i] = '\0';
266                                         ++i;
267                                 } else if (http_header_strict) { /* '\n' */
268 -                                       return http_request_missing_CR_before_LF(srv, con);
269 +                                       http_request_missing_CR_before_LF(srv, con);
270 +                                       goto failure;
271                                 }
272                                 con->parse_request->ptr[i] = '\0';
273  
274                                 if (request_line_stage != 2) {
275 -                                       con->http_status = 400;
276 -                                       con->response.keep_alive = 0;
277 -                                       con->keep_alive = 0;
278 -
279                                         if (srv->srvconf.log_request_header_on_error) {
280                                                 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
281                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
282                                                                 "request-header:\n",
283                                                                 con->request.request);
284                                         }
285 -                                       return 0;
286 +                                       goto failure;
287                                 }
288  
289                                 proto = con->parse_request->ptr + first;
290 @@ -536,8 +685,6 @@ int http_request_parse(server *srv, connection *con) {
291                                 /* we got the first one :) */
292                                 if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) {
293                                         con->http_status = 501;
294 -                                       con->response.keep_alive = 0;
295 -                                       con->keep_alive = 0;
296  
297                                         if (srv->srvconf.log_request_header_on_error) {
298                                                 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
299 @@ -546,7 +693,7 @@ int http_request_parse(server *srv, connection *con) {
300                                                                 con->request.request);
301                                         }
302  
303 -                                       return 0;
304 +                                       goto failure;
305                                 }
306  
307                                 con->request.http_method = r;
308 @@ -582,16 +729,13 @@ int http_request_parse(server *srv, connection *con) {
309                                         }
310  
311                                         if (invalid_version) {
312 -                                               con->http_status = 400;
313 -                                               con->keep_alive = 0;
314 -
315                                                 if (srv->srvconf.log_request_header_on_error) {
316                                                         log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
317                                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
318                                                                         "request-header:\n",
319                                                                         con->request.request);
320                                                 }
321 -                                               return 0;
322 +                                               goto failure;
323                                         }
324  
325                                         if (major_num == 1 && minor_num == 1) {
326 @@ -607,19 +751,16 @@ int http_request_parse(server *srv, connection *con) {
327                                                                         "request-header:\n",
328                                                                         con->request.request);
329                                                 }
330 -                                               return 0;
331 +                                               goto failure;
332                                         }
333                                 } else {
334 -                                       con->http_status = 400;
335 -                                       con->keep_alive = 0;
336 -
337                                         if (srv->srvconf.log_request_header_on_error) {
338                                                 log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
339                                                 log_error_write(srv, __FILE__, __LINE__, "Sb",
340                                                                 "request-header:\n",
341                                                                 con->request.request);
342                                         }
343 -                                       return 0;
344 +                                       goto failure;
345                                 }
346  
347                                 if (*uri == '/') {
348 @@ -627,14 +768,14 @@ int http_request_parse(server *srv, connection *con) {
349                                         buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
350                                 } else if (0 == strncasecmp(uri, "http://", 7) &&
351                                     NULL != (nuri = strchr(uri + 7, '/'))) {
352 -                                       reqline_host = uri + 7;
353 -                                       reqline_hostlen = nuri - reqline_host;
354 +                                       state.reqline_host = uri + 7;
355 +                                       state.reqline_hostlen = nuri - state.reqline_host;
356  
357                                         buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
358                                 } else if (0 == strncasecmp(uri, "https://", 8) &&
359                                     NULL != (nuri = strchr(uri + 8, '/'))) {
360 -                                       reqline_host = uri + 8;
361 -                                       reqline_hostlen = nuri - reqline_host;
362 +                                       state.reqline_host = uri + 8;
363 +                                       state.reqline_hostlen = nuri - state.reqline_host;
364  
365                                         buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
366                                 } else if (!http_header_strict
367 @@ -643,10 +784,8 @@ int http_request_parse(server *srv, connection *con) {
368                                         /* everything looks good so far */
369                                         buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
370                                 } else {
371 -                                       con->http_status = 400;
372 -                                       con->keep_alive = 0;
373                                         log_error_write(srv, __FILE__, __LINE__, "ss", "request-URI parse error -> 400 for:", uri);
374 -                                       return 0;
375 +                                       goto failure;
376                                 }
377  
378                                 /* check uri for invalid characters */
379 @@ -660,33 +799,30 @@ int http_request_parse(server *srv, connection *con) {
380                                         j = (NULL == z) ? jlen : (size_t)(z - con->request.uri->ptr);
381                                 }
382                                 if (j < jlen) {
383 -                                               con->http_status = 400;
384 -                                               con->keep_alive = 0;
385 -
386 -                                               if (srv->srvconf.log_request_header_on_error) {
387 -                                                       unsigned char buf[2];
388 -                                                       buf[0] = con->request.uri->ptr[j];
389 -                                                       buf[1] = '\0';
390 -
391 -                                                       if (con->request.uri->ptr[j] > 32 &&
392 -                                                           con->request.uri->ptr[j] != 127) {
393 -                                                               /* the character is printable -> print it */
394 -                                                               log_error_write(srv, __FILE__, __LINE__, "ss",
395 -                                                                               "invalid character in URI -> 400",
396 -                                                                               buf);
397 -                                                       } else {
398 -                                                               /* a control-character, print ascii-code */
399 -                                                               log_error_write(srv, __FILE__, __LINE__, "sd",
400 -                                                                               "invalid character in URI -> 400",
401 -                                                                               con->request.uri->ptr[j]);
402 -                                                       }
403 -
404 -                                                       log_error_write(srv, __FILE__, __LINE__, "Sb",
405 -                                                                       "request-header:\n",
406 -                                                                       con->request.request);
407 +                                       if (srv->srvconf.log_request_header_on_error) {
408 +                                               unsigned char buf[2];
409 +                                               buf[0] = con->request.uri->ptr[j];
410 +                                               buf[1] = '\0';
411 +
412 +                                               if (con->request.uri->ptr[j] > 32 &&
413 +                                                       con->request.uri->ptr[j] != 127) {
414 +                                                       /* the character is printable -> print it */
415 +                                                       log_error_write(srv, __FILE__, __LINE__, "ss",
416 +                                                                       "invalid character in URI -> 400",
417 +                                                                       buf);
418 +                                               } else {
419 +                                                       /* a control-character, print ascii-code */
420 +                                                       log_error_write(srv, __FILE__, __LINE__, "sd",
421 +                                                                       "invalid character in URI -> 400",
422 +                                                                       con->request.uri->ptr[j]);
423                                                 }
424  
425 -                                               return 0;
426 +                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
427 +                                                               "request-header:\n",
428 +                                                               con->request.request);
429 +                                       }
430 +
431 +                                       goto failure;
432                                 }
433  
434                                 buffer_copy_buffer(con->request.orig_uri, con->request.uri);
435 @@ -711,17 +847,13 @@ int http_request_parse(server *srv, connection *con) {
436                                 break;
437                         default:
438                                 /* ERROR, one space to much */
439 -                               con->http_status = 400;
440 -                               con->response.keep_alive = 0;
441 -                               con->keep_alive = 0;
442 -
443                                 if (srv->srvconf.log_request_header_on_error) {
444                                         log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
445                                         log_error_write(srv, __FILE__, __LINE__, "Sb",
446                                                         "request-header:\n",
447                                                         con->request.request);
448                                 }
449 -                               return 0;
450 +                               goto failure;
451                         }
452  
453                         request_line_stage++;
454 @@ -732,20 +864,16 @@ int http_request_parse(server *srv, connection *con) {
455         in_folding = 0;
456  
457         if (buffer_string_is_empty(con->request.uri)) {
458 -               con->http_status = 400;
459 -               con->response.keep_alive = 0;
460 -               con->keep_alive = 0;
461 -
462                 if (srv->srvconf.log_request_header_on_error) {
463                         log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
464                         log_error_write(srv, __FILE__, __LINE__, "Sb",
465                                                         "request-header:\n",
466                                                         con->request.request);
467                 }
468 -               return 0;
469 +               goto failure;
470         }
471  
472 -       if (reqline_host) {
473 +       if (state.reqline_host) {
474                 /* Insert as host header */
475                 data_string *ds;
476  
477 @@ -754,7 +882,7 @@ int http_request_parse(server *srv, connection *con) {
478                 }
479  
480                 buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
481 -               buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen);
482 +               buffer_copy_string_len(ds->value, state.reqline_host, state.reqline_hostlen);
483                 array_insert_unique(con->request.headers, (data_unset *)ds);
484                 con->request.http_host = ds->value;
485         }
486 @@ -799,10 +927,6 @@ int http_request_parse(server *srv, connection *con) {
487                         case '=':
488                         case '{':
489                         case '}':
490 -                               con->http_status = 400;
491 -                               con->keep_alive = 0;
492 -                               con->response.keep_alive = 0;
493 -
494                                 if (srv->srvconf.log_request_header_on_error) {
495                                         log_error_write(srv, __FILE__, __LINE__, "sbsds",
496                                                 "invalid character in key", con->request.request, cur, *cur, "-> 400");
497 @@ -811,7 +935,7 @@ int http_request_parse(server *srv, connection *con) {
498                                                 "request-header:\n",
499                                                 con->request.request);
500                                 }
501 -                               return 0;
502 +                               goto failure;
503                         case ' ':
504                         case '\t':
505                                 if (i == first) {
506 @@ -850,11 +974,7 @@ int http_request_parse(server *srv, connection *con) {
507                                                                 con->request.request);
508                                                 }
509  
510 -                                               con->http_status = 400;
511 -                                               con->response.keep_alive = 0;
512 -                                               con->keep_alive = 0;
513 -
514 -                                               return 0;
515 +                                               goto failure;
516                                         }
517                                 }
518  
519 @@ -876,15 +996,13 @@ int http_request_parse(server *srv, connection *con) {
520                                                         con->request.request);
521                                         }
522  
523 -                                       con->http_status = 400;
524 -                                       con->keep_alive = 0;
525 -                                       con->response.keep_alive = 0;
526 -                                       return 0;
527 +                                       goto failure;
528                                 }
529                                 break;
530                         case '\n':
531                                 if (http_header_strict) {
532 -                                       return http_request_missing_CR_before_LF(srv, con);
533 +                                       http_request_missing_CR_before_LF(srv, con);
534 +                                       goto failure;
535                                 } else if (i == first) {
536                                         con->parse_request->ptr[i] = '\0';
537                                         done = 1;
538 @@ -893,10 +1011,6 @@ int http_request_parse(server *srv, connection *con) {
539                                 /* fall through */
540                         default:
541                                 if (http_header_strict ? (*cur < 32 || ((unsigned char)*cur) >= 127) : *cur == '\0') {
542 -                                       con->http_status = 400;
543 -                                       con->keep_alive = 0;
544 -                                       con->response.keep_alive = 0;
545 -
546                                         if (srv->srvconf.log_request_header_on_error) {
547                                                 log_error_write(srv, __FILE__, __LINE__, "sbsds",
548                                                         "invalid character in key", con->request.request, cur, *cur, "-> 400");
549 @@ -906,7 +1020,7 @@ int http_request_parse(server *srv, connection *con) {
550                                                         con->request.request);
551                                         }
552  
553 -                                       return 0;
554 +                                       goto failure;
555                                 }
556                                 /* ok */
557                                 break;
558 @@ -916,9 +1030,13 @@ int http_request_parse(server *srv, connection *con) {
559                         case '\r':
560                         case '\n':
561                                 if (*cur == '\n' || con->parse_request->ptr[i+1] == '\n') {
562 -                                       data_string *ds = NULL;
563 +                                       int value_len;
564 +
565                                         if (*cur == '\n') {
566 -                                               if (http_header_strict) return http_request_missing_CR_before_LF(srv, con);
567 +                                               if (http_header_strict) {
568 +                                                       http_request_missing_CR_before_LF(srv, con);
569 +                                                       goto failure;
570 +                                               }
571                                         } else { /* (con->parse_request->ptr[i+1] == '\n') */
572                                                 con->parse_request->ptr[i] = '\0';
573                                                 ++i;
574 @@ -927,17 +1045,15 @@ int http_request_parse(server *srv, connection *con) {
575                                         /* End of Headerline */
576                                         con->parse_request->ptr[i] = '\0';
577  
578 +                                       value_len = cur - value;
579 +
580 +                                       /* strip trailing white-spaces */
581 +                                       while (value_len > 0 && (value[value_len - 1] == ' ' || value[value_len - 1] == '\t')) {
582 +                                               --value_len;
583 +                                       }
584 +
585                                         if (in_folding) {
586 -                                               /**
587 -                                                * we use a evil hack to handle the line-folding
588 -                                                * 
589 -                                                * As array_insert_unique() deletes 'ds' in the case of a duplicate
590 -                                                * ds points somewhere and we get a evil crash. As a solution we keep the old
591 -                                                * "key" and get the current value from the hash and append us
592 -                                                *
593 -                                                * */
594 -
595 -                                               if (!key || !key_len) {
596 +                                               if (!current_header) {
597                                                         /* 400 */
598  
599                                                         if (srv->srvconf.log_request_header_on_error) {
600 @@ -948,193 +1064,35 @@ int http_request_parse(server *srv, connection *con) {
601                                                                         con->request.request);
602                                                         }
603  
604 -
605 -                                                       con->http_status = 400;
606 -                                                       con->keep_alive = 0;
607 -                                                       con->response.keep_alive = 0;
608 -                                                       return 0;
609 +                                                       goto failure;
610                                                 }
611  
612 -                                               if (NULL != (ds = (data_string *)array_get_element_klen(con->request.headers, key, key_len))) {
613 -                                                       buffer_append_string(ds->value, value);
614 -                                               }
615 +                                               buffer_append_string_len(current_header->value, value, value_len);
616                                         } else {
617 -                                               int s_len;
618 -                                               key = con->parse_request->ptr + first;
619 -
620 -                                               s_len = cur - value;
621 -
622 -                                               /* strip trailing white-spaces */
623 -                                               for (; s_len > 0 && 
624 -                                                               (value[s_len - 1] == ' ' || 
625 -                                                                value[s_len - 1] == '\t'); s_len--);
626 -
627 -                                               value[s_len] = '\0';
628 -
629 -                                               if (s_len > 0) {
630 -                                                       int cmp = 0;
631 -                                                       if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
632 -                                                               ds = data_string_init();
633 -                                                       }
634 -                                                       buffer_copy_string_len(ds->key, key, key_len);
635 -                                                       buffer_copy_string_len(ds->value, value, s_len);
636 -
637 -                                                       /* retreive values
638 -                                                        *
639 -                                                        *
640 -                                                        * the list of options is sorted to simplify the search
641 -                                                        */
642 -
643 -                                                       if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
644 -                                                               array *vals;
645 -                                                               size_t vi;
646 -
647 -                                                               /* split on , */
648 -
649 -                                                               vals = srv->split_vals;
650 -
651 -                                                               array_reset(vals);
652 -
653 -                                                               http_request_split_value(vals, ds->value);
654 -
655 -                                                               for (vi = 0; vi < vals->used; vi++) {
656 -                                                                       data_string *dsv = (data_string *)vals->data[vi];
657 -
658 -                                                                       if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
659 -                                                                               keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
660 -
661 -                                                                               break;
662 -                                                                       } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
663 -                                                                               keep_alive_set = HTTP_CONNECTION_CLOSE;
664 -
665 -                                                                               break;
666 -                                                                       }
667 -                                                               }
668 -
669 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
670 -                                                               char *err;
671 -                                                               off_t r;
672 -
673 -                                                               if (con_length_set) {
674 -                                                                       con->http_status = 400;
675 -                                                                       con->keep_alive = 0;
676 -
677 -                                                                       if (srv->srvconf.log_request_header_on_error) {
678 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
679 -                                                                                               "duplicate Content-Length-header -> 400");
680 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
681 -                                                                                               "request-header:\n",
682 -                                                                                               con->request.request);
683 -                                                                       }
684 -                                                                       array_insert_unique(con->request.headers, (data_unset *)ds);
685 -                                                                       return 0;
686 -                                                               }
687 -
688 -                                                               r = strtoll(ds->value->ptr, &err, 10);
689 -
690 -                                                               if (*err == '\0' && r >= 0) {
691 -                                                                       con_length_set = 1;
692 -                                                                       con->request.content_length = r;
693 -                                                               } else {
694 -                                                                       log_error_write(srv, __FILE__, __LINE__, "sbs",
695 -                                                                                       "content-length broken:", ds->value, "-> 400");
696 -
697 -                                                                       con->http_status = 400;
698 -                                                                       con->keep_alive = 0;
699 -
700 -                                                                       array_insert_unique(con->request.headers, (data_unset *)ds);
701 -                                                                       return 0;
702 -                                                               }
703 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
704 -                                                               /* if dup, only the first one will survive */
705 -                                                               if (!con->request.http_content_type) {
706 -                                                                       con->request.http_content_type = ds->value->ptr;
707 -                                                               } else {
708 -                                                                       con->http_status = 400;
709 -                                                                       con->keep_alive = 0;
710 -
711 -                                                                       if (srv->srvconf.log_request_header_on_error) {
712 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
713 -                                                                                               "duplicate Content-Type-header -> 400");
714 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
715 -                                                                                               "request-header:\n",
716 -                                                                                               con->request.request);
717 -                                                                       }
718 -                                                                       array_insert_unique(con->request.headers, (data_unset *)ds);
719 -                                                                       return 0;
720 -                                                               }
721 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
722 -                                                               if (reqline_host) {
723 -                                                                       /* ignore all host: headers as we got the host in the request line */
724 -                                                                       ds->free((data_unset*) ds);
725 -                                                                       ds = NULL;
726 -                                                               } else if (!con->request.http_host) {
727 -                                                                       con->request.http_host = ds->value;
728 -                                                               } else {
729 -                                                                       con->http_status = 400;
730 -                                                                       con->keep_alive = 0;
731 -
732 -                                                                       if (srv->srvconf.log_request_header_on_error) {
733 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
734 -                                                                                               "duplicate Host-header -> 400");
735 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
736 -                                                                                               "request-header:\n",
737 -                                                                                               con->request.request);
738 -                                                                       }
739 -                                                                       array_insert_unique(con->request.headers, (data_unset *)ds);
740 -                                                                       return 0;
741 -                                                               }
742 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
743 -                                                               /* Proxies sometimes send dup headers
744 -                                                                * if they are the same we ignore the second
745 -                                                                * if not, we raise an error */
746 -                                                               if (!con->request.http_if_modified_since) {
747 -                                                                       con->request.http_if_modified_since = ds->value->ptr;
748 -                                                               } else if (0 == strcasecmp(con->request.http_if_modified_since,
749 -                                                                                       ds->value->ptr)) {
750 -                                                                       /* ignore it if they are the same */
751 -
752 -                                                                       ds->free((data_unset *)ds);
753 -                                                                       ds = NULL;
754 -                                                               } else {
755 -                                                                       con->http_status = 400;
756 -                                                                       con->keep_alive = 0;
757 -
758 -                                                                       if (srv->srvconf.log_request_header_on_error) {
759 -                                                                               log_error_write(srv, __FILE__, __LINE__, "s",
760 -                                                                                               "duplicate If-Modified-Since header -> 400");
761 -                                                                               log_error_write(srv, __FILE__, __LINE__, "Sb",
762 -                                                                                               "request-header:\n",
763 -                                                                                               con->request.request);
764 -                                                                       }
765 -                                                                       array_insert_unique(con->request.headers, (data_unset *)ds);
766 -                                                                       return 0;
767 -                                                               }
768 -                                                       } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
769 -                                                               /* if dup, only the first one will survive */
770 -                                                               if (!con->request.http_if_none_match) {
771 -                                                                       con->request.http_if_none_match = ds->value->ptr;
772 -                                                               } else {
773 -                                                                       ds->free((data_unset*) ds);
774 -                                                                       ds = NULL;
775 -                                                               }
776 +                                               /* process previous header */
777 +                                               if (current_header) {
778 +                                                       data_string *ds = current_header;
779 +                                                       current_header = NULL;
780 +                                                       if (!parse_single_header(srv, con, &state, ds)) {
781 +                                                               /* parse_single_header should already have logged it */
782 +                                                               goto failure;
783                                                         }
784 +                                               }
785  
786 -                                                       if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
787 -                                               } else {
788 -                                                       /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
789 +                                               key = con->parse_request->ptr + first;
790 +
791 +                                               if (NULL == (current_header = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
792 +                                                       current_header = data_string_init();
793                                                 }
794 +
795 +                                               buffer_copy_string_len(current_header->key, key, key_len);
796 +                                               buffer_copy_string_len(current_header->value, value, value_len);
797                                         }
798  
799                                         first = i+1;
800                                         is_key = 1;
801                                         value = NULL;
802 -#if 0
803 -                                       /**
804 -                                        * for Bug 1230 keep the key_len a live
805 -                                        */
806                                         key_len = 0; 
807 -#endif
808                                         in_folding = 0;
809                                 } else {
810                                         if (srv->srvconf.log_request_header_on_error) {
811 @@ -1142,10 +1100,7 @@ int http_request_parse(server *srv, connection *con) {
812                                                                 "CR without LF", con->request.request, "-> 400");
813                                         }
814  
815 -                                       con->http_status = 400;
816 -                                       con->keep_alive = 0;
817 -                                       con->response.keep_alive = 0;
818 -                                       return 0;
819 +                                       goto failure;
820                                 }
821                                 break;
822                         case ' ':
823 @@ -1160,22 +1115,29 @@ int http_request_parse(server *srv, connection *con) {
824                                                                 "invalid char in header", (int)*cur, "-> 400");
825                                         }
826  
827 -                                       con->http_status = 400;
828 -                                       con->keep_alive = 0;
829 -
830 -                                       return 0;
831 +                                       goto failure;
832                                 }
833                                 break;
834                         }
835                 }
836         }
837  
838 +       /* process last header */
839 +       if (current_header) {
840 +               data_string* ds = current_header;
841 +               current_header = NULL;
842 +               if (!parse_single_header(srv, con, &state, ds)) {
843 +                       /* parse_single_header should already have logged it */
844 +                       goto failure;
845 +               }
846 +       }
847 +
848         con->header_len = i;
849  
850         /* do some post-processing */
851  
852         if (con->request.http_version == HTTP_VERSION_1_1) {
853 -               if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
854 +               if (state.keep_alive_set != HTTP_CONNECTION_CLOSE) {
855                         /* no Connection-Header sent */
856  
857                         /* HTTP/1.1 -> keep-alive default TRUE */
858 @@ -1187,9 +1149,6 @@ int http_request_parse(server *srv, connection *con) {
859                 /* RFC 2616, 14.23 */
860                 if (con->request.http_host == NULL ||
861                     buffer_string_is_empty(con->request.http_host)) {
862 -                       con->http_status = 400;
863 -                       con->response.keep_alive = 0;
864 -                       con->keep_alive = 0;
865  
866                         if (srv->srvconf.log_request_header_on_error) {
867                                 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
868 @@ -1197,10 +1156,10 @@ int http_request_parse(server *srv, connection *con) {
869                                                 "request-header:\n",
870                                                 con->request.request);
871                         }
872 -                       return 0;
873 +                       goto failure;
874                 }
875         } else {
876 -               if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
877 +               if (state.keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
878                         /* no Connection-Header sent */
879  
880                         /* HTTP/1.0 -> keep-alive default FALSE  */
881 @@ -1222,11 +1181,7 @@ int http_request_parse(server *srv, connection *con) {
882                                         con->request.request);
883                 }
884  
885 -               con->http_status = 400;
886 -               con->response.keep_alive = 0;
887 -               con->keep_alive = 0;
888 -
889 -               return 0;
890 +               goto failure;
891         }
892  
893         {
894 @@ -1235,24 +1190,21 @@ int http_request_parse(server *srv, connection *con) {
895                         if (con->request.http_version == HTTP_VERSION_1_0) {
896                                 log_error_write(srv, __FILE__, __LINE__, "s",
897                                                 "HTTP/1.0 with Transfer-Encoding (bad HTTP/1.0 proxy?) -> 400");
898 -                               con->keep_alive = 0;
899 -                               con->http_status = 400; /* Bad Request */
900 -                               return 0;
901 +                               goto failure;
902                         }
903  
904                         if (0 != strcasecmp(ds->value->ptr, "chunked")) {
905                                 /* Transfer-Encoding might contain additional encodings,
906                                  * which are not currently supported by lighttpd */
907 -                               con->keep_alive = 0;
908                                 con->http_status = 501; /* Not Implemented */
909 -                               return 0;
910 +                               goto failure;
911                         }
912  
913                         /* reset value for Transfer-Encoding, a hop-by-hop header,
914                          * which must not be blindly forwarded to backends */
915                         buffer_reset(ds->value); /* headers with empty values are ignored */
916  
917 -                       con_length_set = 1;
918 +                       state.con_length_set = 1;
919                         con->request.content_length = -1;
920  
921                         /*(note: ignore whether or not Content-Length was provided)*/
922 @@ -1265,27 +1217,23 @@ int http_request_parse(server *srv, connection *con) {
923         case HTTP_METHOD_GET:
924         case HTTP_METHOD_HEAD:
925                 /* content-length is forbidden for those */
926 -               if (con_length_set && con->request.content_length != 0) {
927 +               if (state.con_length_set && con->request.content_length != 0) {
928                         /* content-length is missing */
929                         log_error_write(srv, __FILE__, __LINE__, "s",
930                                         "GET/HEAD with content-length -> 400");
931  
932 -                       con->keep_alive = 0;
933 -                       con->http_status = 400;
934 -                       return 0;
935 +                       goto failure;
936                 }
937                 break;
938         case HTTP_METHOD_POST:
939                 /* content-length is required for them */
940 -               if (!con_length_set) {
941 +               if (!state.con_length_set) {
942                         /* content-length is missing */
943                         log_error_write(srv, __FILE__, __LINE__, "s",
944                                         "POST-request, but content-length missing -> 411");
945  
946 -                       con->keep_alive = 0;
947                         con->http_status = 411;
948 -                       return 0;
949 -
950 +                       goto failure;
951                 }
952                 break;
953         default:
954 @@ -1294,12 +1242,21 @@ int http_request_parse(server *srv, connection *con) {
955  
956  
957         /* check if we have read post data */
958 -       if (con_length_set) {
959 +       if (state.con_length_set) {
960                 /* we have content */
961                 if (con->request.content_length != 0) {
962                         return 1;
963                 }
964         }
965  
966 +       return 0;
967 +
968 +failure:
969 +       if (current_header) current_header->free((data_unset *)current_header);
970 +
971 +       con->keep_alive = 0;
972 +       con->response.keep_alive = 0;
973 +       if (!con->http_status) con->http_status = 400;
974 +
975         return 0;
976  }
This page took 0.269867 seconds and 3 git commands to generate.