Bug #2197
closedlighttpd stalls when reading fragmented ssl requests
Description
Hello.
Since switching from lighttpd 1.4.22 to lighttpd 1.4.26, lighttpd sometimes doesn't respond to some requests, which results in the browser showing only a white page and getting a timeout after a certain time.
After some investigations I found out that lighttpd doesn't even handle the request and hangs in the "READ" state, waiting for more header lines to arrive:
2010-05-11 13:23:09: (log.c.166) server started 2010-05-11 13:23:10: (connections.c.1372) state at start 6 req-start 2010-05-11 13:23:10: (connections.c.1384) state for fd 6 req-start 2010-05-11 13:23:10: (connections.c.1635) state for fd 6 read 2010-05-11 13:23:10: (connections.c.1778) state at exit: 6 read 2010-05-11 13:23:10: (connections.c.1372) state at start 6 read 2010-05-11 13:23:10: (connections.c.1635) state for fd 6 read 2010-05-11 13:23:10: (connections.c.1778) state at exit: 6 read 2010-05-11 13:23:10: (connections.c.1372) state at start 6 read 2010-05-11 13:23:10: (connections.c.1635) state for fd 6 read 2010-05-11 13:23:10: (connections.c.1778) state at exit: 6 read 2010-05-11 13:23:10: (connections.c.1372) state at start 6 read 2010-05-11 13:23:10: (connections.c.1635) state for fd 6 read 2010-05-11 13:23:10: (connections.c.1778) state at exit: 6 read 2010-05-11 13:23:10: (connections.c.1372) state at start 6 read 2010-05-11 13:23:10: (connections.c.1635) state for fd 6 read 2010-05-11 13:23:10: (connections.c.1778) state at exit: 6 read
The problem can be relatively simple reproduced using the newest lighttpd-checkout (revision 2724) independently of the OpenSSL version. When sending a HTTP request header within a single packet, everything works fine, when sending each header line independently, the webserver stops to respond.
The following CLI-PHP code is able to evoke the problem:
<?php //If data gets send in the intermediate mode, lighttpd doesn't response when using SSL define(INTERMEDIATE, true); function write_socket($sock, $line, &$request) { $request .= $line; if (INTERMEDIATE) write_socket_flush($sock, $request); } function write_socket_flush($sock, &$request) { fwrite($sock, $request); $request = ''; } $sock = fsockopen("ssl://10.44.44.63", 443); if ($sock) { echo("Sending request\n"); $request = ""; write_socket($sock, "GET / HTTP/1.1\r\n", $request); write_socket($sock, "Host: 10.44.44.63\r\n", $request); write_socket($sock, "Connection: close\r\n", $request); write_socket($sock, "\r\n", $request); if (!INTERMEDIATE) write_socket_flush($sock, $request); echo("Listening\n"); $response = ""; while (!feof($sock)) { $response .= fread($sock, 2048); } echo($response); fclose($sock); }
Summary:
Responding to headers which are fragmented across multiple TCP-Packets doesn't work on a SSL connection in the in 1.4.26 and in the 1.4.x checkout. It worked until version 1.4.25.
Thanks,
Andreas
Files
Updated by andreas_stoe over 14 years ago
- % Done changed from 0 to 50
I found out that there was one change in connections.c which appeared strange to me: In connection_handle_read_ssl:235 (revision 2724) you wrote
} while (len == toread && count < MAX_READ_LIMIT);
This actually makes no sense (to me): len is set to the count of bytes that have been read from the SSL socket and toread is the count of bytes which was ought to be read, wheras toread may be restricted to the count of bytes available in the current read buffer. As this value might be smaller than the actual bytes pending on the SSL socket, len == toread doesn't say anything about whether all data has been read from the socket.
The line
} while (len > 0 && count < MAX_READ_LIMIT);
from version 1.4.25 made more sense to me, as data is read from the SSL-Socket until SSL_read returns an error or no data is available.
Please inform me, whether my "fix" makes sense or whether this destroys any feature I've been too blind to see.
Andreas
PS: I forgot to mention explicitly, that this small patch fixes the problem described above.
Updated by stbuehler over 14 years ago
The idea is, that if one read resulted in less bytes than possible the internal ssl buffer should be empty; we don't care whether the kernel buffer is "empty", as we get another fdevent in that case and can continue to read later.
But i guess it looks like this doesn't work.
Updated by stbuehler over 14 years ago
Updated by stbuehler over 14 years ago
- Status changed from New to Fixed
- % Done changed from 50 to 100
Applied in changeset r2729.
Also available in: Atom