3 ===================================================================
4 --- src/mod_cgi.c (.../tags/lighttpd-1.4.25)
5 +++ src/mod_cgi.c (.../branches/lighttpd-1.4.x)
9 if (pipe(from_cgi_fds)) {
10 + close(to_cgi_fds[0]);
11 + close(to_cgi_fds[1]);
12 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
15 @@ -1035,6 +1037,10 @@
18 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
19 + close(from_cgi_fds[0]);
20 + close(from_cgi_fds[1]);
21 + close(to_cgi_fds[0]);
22 + close(to_cgi_fds[1]);
27 plugin_config *s = p->config_storage[0];
30 + PATCH(execute_x_only);
32 /* skip the first, the global context */
33 for (i = 1; i < srv->config_context->used; i++) {
35 ===================================================================
36 --- src/base.h (.../tags/lighttpd-1.4.25)
37 +++ src/base.h (.../branches/lighttpd-1.4.x)
42 - buffer *ssl_error_want_reuse_buffer;
43 # ifndef OPENSSL_NO_TLSEXT
44 buffer *tlsext_server_name;
46 Index: src/mod_rewrite.c
47 ===================================================================
48 --- src/mod_rewrite.c (.../tags/lighttpd-1.4.25)
49 +++ src/mod_rewrite.c (.../branches/lighttpd-1.4.x)
51 buffer_reset(con->request.uri);
54 - for (k = 0; k < pattern_len; k++) {
55 + for (k = 0; k+1 < pattern_len; k++) {
56 if (pattern[k] == '$' || pattern[k] == '%') {
59 Index: src/connections.c
60 ===================================================================
61 --- src/connections.c (.../tags/lighttpd-1.4.25)
62 +++ src/connections.c (.../branches/lighttpd-1.4.x)
65 static int connection_handle_read_ssl(server *srv, connection *con) {
67 - int r, ssl_err, len, count = 0;
68 + int r, ssl_err, len, count = 0, read_offset, toread;
71 if (!con->conf.is_ssl) return -1;
73 - /* don't resize the buffer if we were in SSL_ERROR_WANT_* */
77 - if (!con->ssl_error_want_reuse_buffer) {
79 - buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */
80 + if (NULL != con->read_queue->last) {
81 + b = con->read_queue->last->mem;
84 + if (NULL == b || b->size - b->used < 1024) {
85 + b = chunkqueue_get_append_buffer(con->read_queue);
86 + len = SSL_pending(con->ssl);
87 + if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */
88 + buffer_prepare_copy(b, len + 1);
90 /* overwrite everything with 0 */
91 memset(b->ptr, 0, b->size);
93 - b = con->ssl_error_want_reuse_buffer;
96 - len = SSL_read(con->ssl, b->ptr, b->size - 1);
97 - con->ssl_error_want_reuse_buffer = NULL; /* reuse it only once */
98 + read_offset = (b->used > 0) ? b->used - 1 : 0;
99 + toread = b->size - 1 - read_offset;
101 + len = SSL_read(con->ssl, b->ptr + read_offset, toread);
105 + if (b->used > 0) b->used--;
107 b->ptr[b->used++] = '\0';
109 - /* we move the buffer to the chunk-queue, no need to free it */
110 + con->bytes_read += len;
112 - chunkqueue_append_buffer_weak(con->read_queue, b);
114 - con->bytes_read += len;
117 - } while (len > 0 && count < MAX_READ_LIMIT);
118 + } while (len == toread && count < MAX_READ_LIMIT);
122 @@ -234,11 +236,11 @@
123 case SSL_ERROR_WANT_READ:
124 case SSL_ERROR_WANT_WRITE:
125 con->is_readable = 0;
126 - con->ssl_error_want_reuse_buffer = b;
129 + /* the manual says we have to call SSL_read with the same arguments next time.
130 + * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
133 - /* we have to steal the buffer from the queue-queue */
135 case SSL_ERROR_SYSCALL:
137 @@ -297,16 +299,11 @@
139 connection_set_state(srv, con, CON_STATE_ERROR);
144 } else if (len == 0) {
145 con->is_readable = 0;
146 /* the other end close the connection -> KEEP-ALIVE */
154 @@ -321,26 +318,41 @@
155 static int connection_handle_read(server *srv, connection *con) {
159 + int toread, read_offset;
161 if (con->conf.is_ssl) {
162 return connection_handle_read_ssl(srv, con);
165 + b = (NULL != con->read_queue->last) ? con->read_queue->last->mem : NULL;
167 + /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
168 + * us more than 4kb is available
169 + * if FIONREAD doesn't signal a big chunk we fill the previous buffer
170 + * if it has >= 1kb free
173 - b = chunkqueue_get_append_buffer(con->read_queue);
174 - buffer_prepare_copy(b, 4 * 1024);
175 - len = recv(con->fd, b->ptr, b->size - 1, 0);
177 - if (ioctl(con->fd, FIONREAD, &toread) || toread == 0) {
178 + if (NULL == b || b->size - b->used < 1024) {
179 b = chunkqueue_get_append_buffer(con->read_queue);
180 buffer_prepare_copy(b, 4 * 1024);
183 + read_offset = (b->used == 0) ? 0 : b->used - 1;
184 + len = recv(con->fd, b->ptr + read_offset, b->size - 1 - read_offset, 0);
186 + if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
187 + if (NULL == b || b->size - b->used < 1024) {
188 + b = chunkqueue_get_append_buffer(con->read_queue);
189 + buffer_prepare_copy(b, 4 * 1024);
192 if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
193 b = chunkqueue_get_append_buffer(con->read_queue);
194 buffer_prepare_copy(b, toread + 1);
196 - len = read(con->fd, b->ptr, b->size - 1);
198 + read_offset = (b->used == 0) ? 0 : b->used - 1;
199 + len = read(con->fd, b->ptr + read_offset, b->size - 1 - read_offset);
204 con->is_readable = 0;
208 + if (b->used > 0) b->used--;
210 b->ptr[b->used++] = '\0';
212 con->bytes_read += len;
214 /* The cond_cache gets reset in response.c */
215 /* config_cond_cache_reset(srv, con); */
218 - if (con->ssl_error_want_reuse_buffer) {
219 - buffer_free(con->ssl_error_want_reuse_buffer);
220 - con->ssl_error_want_reuse_buffer = NULL;
225 con->in_error_handler = 0;
227 @@ -945,62 +951,50 @@
231 - for (c = cq->first; !last_chunk && c; c = c->next) {
232 + for (c = cq->first; c; c = c->next) {
236 b.ptr = c->mem->ptr + c->offset;
237 b.used = c->mem->used - c->offset;
238 + if (b.used > 0) b.used--; /* buffer "used" includes terminating zero */
240 - for (i = 0; !last_chunk && i < b.used; i++) {
241 + for (i = 0; i < b.used; i++) {
243 - size_t have_chars = 0;
247 - /* we have to do a 4 char lookup */
248 - have_chars = b.used - i - 1;
250 + /* chec if \n\r\n follows */
253 + const char header_end[] = "\r\n\r\n";
254 + int header_end_match_pos = 1;
256 - if (have_chars >= 4) {
257 - /* all chars are in this buffer */
258 + for ( ; cc; cc = cc->next, j = 0 ) {
260 + bb.ptr = cc->mem->ptr + cc->offset;
261 + bb.used = cc->mem->used - cc->offset;
262 + if (bb.used > 0) bb.used--; /* buffer "used" includes terminating zero */
264 - if (0 == strncmp(b.ptr + i, "\r\n\r\n", 4)) {
267 - last_offset = i + 4;
268 + for ( ; j < bb.used; j++) {
274 - chunk *lookahead_chunk = c->next;
275 - size_t missing_chars;
276 - /* looks like the following chars are not in the same chunk */
278 - missing_chars = 4 - have_chars;
280 - if (lookahead_chunk && lookahead_chunk->type == MEM_CHUNK) {
281 - /* is the chunk long enough to contain the other chars ? */
283 - if (lookahead_chunk->mem->used > missing_chars) {
284 - if (0 == strncmp(b.ptr + i, "\r\n\r\n", have_chars) &&
285 - 0 == strncmp(lookahead_chunk->mem->ptr, "\r\n\r\n" + have_chars, missing_chars)) {
287 - last_chunk = lookahead_chunk;
288 - last_offset = missing_chars;
291 + if (ch == header_end[header_end_match_pos]) {
292 + header_end_match_pos++;
293 + if (4 == header_end_match_pos) {
296 + goto found_header_end;
299 - /* a splited \r \n */
315 @@ -1140,8 +1134,15 @@
319 - b = chunkqueue_get_append_buffer(dst_cq);
320 - buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
321 + if (dst_cq->last &&
322 + dst_cq->last->type == MEM_CHUNK) {
323 + b = dst_cq->last->mem;
325 + b = chunkqueue_get_append_buffer(dst_cq);
326 + /* prepare buffer size for remaining POST data; is < 64kb */
327 + buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in + 1);
329 + buffer_append_string_len(b, c->mem->ptr + c->offset, toRead);
334 ===================================================================
335 --- src/chunk.c (.../tags/lighttpd-1.4.25)
336 +++ src/chunk.c (.../branches/lighttpd-1.4.x)
338 int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) {
341 - if (mem->used == 0) return 0;
343 c = chunkqueue_get_unused_chunk(cq);
346 Index: src/mod_proxy.c
347 ===================================================================
348 --- src/mod_proxy.c (.../tags/lighttpd-1.4.25)
349 +++ src/mod_proxy.c (.../branches/lighttpd-1.4.x)
350 @@ -1047,12 +1047,33 @@
354 - proxy_connection_close(srv, hctx);
355 - joblist_append(srv, con);
357 + hctx->host->is_disabled = 1;
358 + hctx->host->disable_ts = srv->cur_ts;
359 + log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
364 - con->http_status = 503;
365 - con->mode = DIRECT;
366 + /* disable this server */
367 + hctx->host->is_disabled = 1;
368 + hctx->host->disable_ts = srv->cur_ts;
370 + proxy_connection_close(srv, hctx);
372 + /* reset the enviroment and restart the sub-request */
373 + buffer_reset(con->physical.path);
374 + con->mode = DIRECT;
376 + joblist_append(srv, con);
378 + proxy_connection_close(srv, hctx);
379 + joblist_append(srv, con);
381 + con->mode = DIRECT;
382 + con->http_status = 503;
385 return HANDLER_FINISHED;
388 Index: src/mod_redirect.c
389 ===================================================================
390 --- src/mod_redirect.c (.../tags/lighttpd-1.4.25)
391 +++ src/mod_redirect.c (.../branches/lighttpd-1.4.x)
393 buffer_reset(p->location);
396 - for (k = 0; k < pattern_len; k++) {
397 + for (k = 0; k + 1 < pattern_len; k++) {
398 if (pattern[k] == '$' || pattern[k] == '%') {
401 Index: src/mod_fastcgi.c
402 ===================================================================
403 --- src/mod_fastcgi.c (.../tags/lighttpd-1.4.25)
404 +++ src/mod_fastcgi.c (.../branches/lighttpd-1.4.x)
405 @@ -2307,6 +2307,9 @@
407 if (NULL == (range = strchr(pos, ' '))) {
409 + if (p->conf.debug) {
410 + log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't find range after filename:", filename);
414 buffer_copy_string_len(srv->tmp_buf, filename, range - filename);
415 @@ -2338,14 +2341,24 @@
418 begin_range = strtoll(range, &rpos, 10);
419 - if (errno != 0 || begin_range < 0 || rpos == range) return 1;
420 - if ('-' != *rpos++) return 1;
421 + if (errno != 0 || begin_range < 0 || rpos == range) goto range_failed;
422 + if ('-' != *rpos++) goto range_failed;
425 end_range = strtoll(range, &rpos, 10);
426 - if (errno != 0 || end_range < 0 || rpos == range) return 1;
427 + if (errno != 0 || end_range < 0 || rpos == range) goto range_failed;
429 - if (rpos != pos) return 1;
430 + if (rpos != pos) goto range_failed;
432 + goto range_success;
435 + if (p->conf.debug) {
436 + log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't decode range after filename:", filename);
443 /* no parameters accepted */
444 Index: src/mod_accesslog.c
445 ===================================================================
446 --- src/mod_accesslog.c (.../tags/lighttpd-1.4.25)
447 +++ src/mod_accesslog.c (.../branches/lighttpd-1.4.x)
449 buffer_append_string_len(b, CONST_STR_LEN("-"));
453 + if (NULL != (ds = (data_string *)array_get_element(con->environment, p->conf.parsed_format->ptr[j]->string->ptr))) {
454 + accesslog_append_escaped(b, ds->value);
456 + buffer_append_string_len(b, CONST_STR_LEN("-"));
459 case FORMAT_FILENAME:
460 if (con->physical.path->used > 1) {
461 buffer_append_string_buffer(b, con->physical.path);
463 { 'A', FORMAT_LOCAL_ADDR },
464 { 'C', FORMAT_COOKIE },
465 { 'D', FORMAT_TIME_USED_MS },
466 - { 'e', FORMAT_ENV },
470 Index: tests/request.t
471 ===================================================================
472 --- tests/request.t (.../tags/lighttpd-1.4.25)
473 +++ tests/request.t (.../branches/lighttpd-1.4.x)
478 -use Test::More tests => 41;
479 +use Test::More tests => 42;
482 my $tf = LightyTest->new();
484 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, '-Content-Length' => '' } ];
485 ok($tf->handle_http($t) == 0, 'Status 304 has no Content-Length (#1002)');
487 +$t->{REQUEST} = ( <<EOF
488 +GET /12345.txt HTTP/1.0
489 +Host: 123.example.org
492 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain' } ];
493 +$t->{SLOWREQUEST} = 1;
494 +ok($tf->handle_http($t) == 0, 'GET, slow \\r\\n\\r\\n (#2105)');
496 ok($tf->stop_proc == 0, "Stopping lighttpd");
498 Index: tests/LightyTest.pm
499 ===================================================================
500 --- tests/LightyTest.pm (.../tags/lighttpd-1.4.25)
501 +++ tests/LightyTest.pm (.../branches/lighttpd-1.4.x)
503 kill('TERM', $pid) or return -1;
504 return -1 if ($pid != waitpid($pid, 0));
506 - diag("Process not started, nothing to stop");
507 + diag("\nProcess not started, nothing to stop");
515 - diag("Timeout while trying to connect; killing child");
516 + diag("\nTimeout while trying to connect; killing child");
517 kill('TERM', $child);
520 @@ -128,10 +128,10 @@
521 } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
522 $cmdline = "valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --log-file=valgrind ".$cmdline;
524 - # diag("starting lighttpd at :".$self->{PORT}.", cmdline: ".$cmdline );
525 + # diag("\nstarting lighttpd at :".$self->{PORT}.", cmdline: ".$cmdline );
527 if (not defined $child) {
528 - diag("Fork failed");
529 + diag("\nFork failed");
536 if (0 != $self->wait_for_port_with_proc($self->{PORT}, $child)) {
537 - diag(sprintf('The process %i is not up', $child));
538 + diag(sprintf('\nThe process %i is not up', $child));
544 my @request = $t->{REQUEST};
545 my @response = $t->{RESPONSE};
546 + my $slow = defined $t->{SLOWREQUEST};
547 my $is_debug = $ENV{"TRACE_HTTP"};
550 @@ -165,33 +166,56 @@
551 PeerPort => $self->{PORT});
553 if (not defined $remote) {
554 - diag("connect failed: $!");
555 + diag("\nconnect failed: $!");
559 $remote->autoflush(1);
561 - diag("sending request header to ".$host.":".$self->{PORT}) if $is_debug;
562 - foreach(@request) {
563 - # pipeline requests
567 + diag("\nsending request header to ".$host.":".$self->{PORT}) if $is_debug;
568 + foreach(@request) {
569 + # pipeline requests
573 - print $remote $_.$BLANK;
574 - diag("<< ".$_) if $is_debug;
575 + print $remote $_.$BLANK;
576 + diag("\n<< ".$_) if $is_debug;
578 + shutdown($remote, 1); # I've stopped writing data
580 + diag("\nsending request header to ".$host.":".$self->{PORT}) if $is_debug;
581 + foreach(@request) {
582 + # pipeline requests
588 + diag("<< ".$_."\n") if $is_debug;
589 + select(undef, undef, undef, 0.1);
590 + print $remote "\015";
591 + select(undef, undef, undef, 0.1);
592 + print $remote "\012";
593 + select(undef, undef, undef, 0.1);
594 + print $remote "\015";
595 + select(undef, undef, undef, 0.1);
596 + print $remote "\012";
597 + select(undef, undef, undef, 0.1);
601 - shutdown($remote, 1); # I've stopped writing data
602 - diag("... done") if $is_debug;
603 + diag("\n... done") if $is_debug;
607 - diag("receiving response") if $is_debug;
608 + diag("\nreceiving response") if $is_debug;
612 diag(">> ".$_) if $is_debug;
614 - diag("... done") if $is_debug;
615 + diag("\n... done") if $is_debug;
620 (my $line, $lines) = split($EOL, $lines, 2);
623 - last if(length($line) == 0);
624 + last if(!defined $line or length($line) == 0);
628 @@ -221,21 +245,21 @@
629 (my $h = $1) =~ tr/[A-Z]/[a-z]/;
631 if (defined $resp_hdr{$h}) {
632 -# diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
633 +# diag(sprintf("\nheader '%s' is duplicated: '%s' and '%s'\n",
634 # $h, $resp_hdr{$h}, $2));
635 $resp_hdr{$h} .= ', '.$2;
640 - diag(sprintf("unexpected line '%s'\n", $line));
641 + diag(sprintf("\nunexpected line '%s'", $line));
647 if (not defined($resp_line)) {
648 - diag(sprintf("empty response\n"));
649 + diag(sprintf("\nempty response"));
653 @@ -259,29 +283,29 @@
655 if ($resp_line =~ /^(HTTP\/1\.[01]) ([0-9]{3}) .+$/) {
656 if ($href->{'HTTP-Protocol'} ne $1) {
657 - diag(sprintf("proto failed: expected '%s', got '%s'\n", $href->{'HTTP-Protocol'}, $1));
658 + diag(sprintf("\nproto failed: expected '%s', got '%s'", $href->{'HTTP-Protocol'}, $1));
661 if ($href->{'HTTP-Status'} ne $2) {
662 - diag(sprintf("status failed: expected '%s', got '%s'\n", $href->{'HTTP-Status'}, $2));
663 + diag(sprintf("\nstatus failed: expected '%s', got '%s'", $href->{'HTTP-Status'}, $2));
667 - diag(sprintf("unexpected resp_line '%s'\n", $resp_line));
668 + diag(sprintf("\nunexpected resp_line '%s'", $resp_line));
672 if (defined $href->{'HTTP-Content'}) {
673 $resp_body = "" unless defined $resp_body;
674 if ($href->{'HTTP-Content'} ne $resp_body) {
675 - diag(sprintf("body failed: expected '%s', got '%s'\n", $href->{'HTTP-Content'}, $resp_body));
676 + diag(sprintf("\nbody failed: expected '%s', got '%s'", $href->{'HTTP-Content'}, $resp_body));
681 if (defined $href->{'-HTTP-Content'}) {
682 if (defined $resp_body && $resp_body ne '') {
683 - diag(sprintf("body failed: expected empty body, got '%s'\n", $resp_body));
684 + diag(sprintf("\nbody failed: expected empty body, got '%s'", $resp_body));
688 @@ -309,12 +333,12 @@
691 if (defined $resp_hdr{$k}) {
692 - diag(sprintf("header '%s' MUST not be set\n", $k));
693 + diag(sprintf("\nheader '%s' MUST not be set", $k));
697 if (not defined $resp_hdr{$k}) {
698 - diag(sprintf("required header '%s' is missing\n", $k));
699 + diag(sprintf("\nrequired header '%s' is missing", $k));
703 @@ -322,12 +346,12 @@
705 if ($href->{$_} =~ /^\/(.+)\/$/) {
706 if ($resp_hdr{$k} !~ /$1/) {
707 - diag(sprintf("response-header failed: expected '%s', got '%s', regex: %s\n",
708 + diag(sprintf("\nresponse-header failed: expected '%s', got '%s', regex: %s",
709 $href->{$_}, $resp_hdr{$k}, $1));
712 } elsif ($href->{$_} ne $resp_hdr{$k}) {
713 - diag(sprintf("response-header failed: expected '%s', got '%s'\n",
714 + diag(sprintf("\nresponse-header failed: expected '%s', got '%s'",
715 $href->{$_}, $resp_hdr{$k}));
720 # we should have sucked up everything
721 if (defined $lines) {
722 - diag(sprintf("unexpected lines '%s'\n", $lines));
723 + diag(sprintf("\nunexpected lines '%s'", $lines));
728 my ($self, $binary, $port) = @_;
730 if (not defined $child) {
731 - diag("Couldn't fork\n");
732 + diag("\nCouldn't fork");
737 exec $binary or die($?);
739 if (0 != $self->wait_for_port_with_proc($port, $child)) {
740 - diag(sprintf('The process %i is not up (port %i, %s)', $child, $port, $binary));
741 + diag(sprintf("\nThe process %i is not up (port %i, %s)", $child, $port, $binary));
745 Index: tests/run-tests.pl
746 ===================================================================
747 --- tests/run-tests.pl (.../tags/lighttpd-1.4.25)
748 +++ tests/run-tests.pl (.../branches/lighttpd-1.4.x)
754 +runtests (sort @fs);
756 ===================================================================
758 ===================================================================
760 ===================================================================
761 --- NEWS (.../tags/lighttpd-1.4.25)
762 +++ NEWS (.../branches/lighttpd-1.4.x)
769 + * Fix request parser to handle packets with splitted \r\n\r\n (fixes #2105)
770 + * Remove dependency on automake >= 1.11 with m4_ifdef check
771 + * mod_accesslog: support %e (fixes #2113, thx presbrey)
772 + * Fix mod_cgi cgi.execute-x-only option in global block
773 + * mod_fastcgi: x-sendfile2 parse error debugging
774 + * Fix mod_proxy dead host detection if connect() fails
775 + * Fix fd leaks in mod_cgi (fds not closed on pipe/fork failures, found by Rodrigo, fixes #2158, #2159)
776 + * Fix segfault with broken rewrite/redirect patterns (fixes #2140, found by crypt)
777 + * Append to previous buffer in con read (fixes #2147, found by liming, CVE-2010-0295)
779 +- 1.4.25 - 2009-11-21
780 * mod_magnet: fix pairs() for normal tables and strings (fixes #1307)
781 * mod_magnet: add traceback for printing lua errors
782 * mod_rewrite: fix compile error if compiled without pcre
783 Index: CMakeLists.txt
784 ===================================================================