https://redmine.lighttpd.net/https://redmine.lighttpd.net/favicon.ico?13667327412017-10-12T06:36:56Zlighty labsLighttpd - Bug #2827: POST to mod_cgi sometimes hangshttps://redmine.lighttpd.net/issues/2827?journal_id=111262017-10-12T06:36:56Zgstrauss
<ul><li><strong>Status</strong> changed from <i>New</i> to <i>Patch Pending</i></li><li><strong>Target version</strong> changed from <i>1.4.x</i> to <i>1.4.46</i></li></ul><p>Technically speaking, CGI should check (and validate) CONTENT_LENGTH before reading input, and should read CONTENT_LENGTH of input, instead of reading until EOF.</p>
<p>Still, you have quite thoroughly described an edge case in lighttpd which should be fixed. The easiest fix is to move the call to fdevent_sched_run() to be outside that conditional block. lighttpd will still wait 1 second if no new events arrive, but will then proceed as expected.</p>
<p>While I could add some logic so that lighttpd polls for events immediately (instant timeout) if there are pending fds to be closed, closes the fds pending close, and then polls for a longer timeout, I think the simple fix is sufficient, and if you do not want to wait 1 second for your CGI to continue, then you should follow the CGI spec and use CONTENT_LENGTH.</p>
<p><a class="external" href="https://tools.ietf.org/html/rfc3875">https://tools.ietf.org/html/rfc3875</a><br /><pre>
4.2. Request Message-Body
[...]
A request-body is supplied with the request if the CONTENT_LENGTH is
not NULL. The server MUST make at least that many bytes available
for the script to read. The server MAY signal an end-of-file
condition after CONTENT_LENGTH bytes have been read or it MAY supply
extension data. Therefore, the script MUST NOT attempt to read more
than CONTENT_LENGTH bytes, even if more data is available. However,
it is not obliged to read any of the data.
</pre></p> Lighttpd - Bug #2827: POST to mod_cgi sometimes hangshttps://redmine.lighttpd.net/issues/2827?journal_id=111272017-10-12T06:48:37Zgstrauss
<ul></ul><pre>
--- a/src/server.c
+++ b/src/server.c
@@ -2085,13 +2085,14 @@ static int server_main (server * const srv, int argc, char **argv) {
(*handler)(srv, context, revents);
}
} while (--n > 0);
- fdevent_sched_run(srv, srv->ev);
} else if (n < 0 && errno != EINTR) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"fdevent_poll failed:",
strerror(errno));
}
+ if (n >= 0) fdevent_sched_run(srv, srv->ev);
+
for (ndx = 0; ndx < srv->joblist->used; ndx++) {
connection *con = srv->joblist->ptr[ndx];
connection_state_machine(srv, con);
</pre> Lighttpd - Bug #2827: POST to mod_cgi sometimes hangshttps://redmine.lighttpd.net/issues/2827?journal_id=111282017-10-12T20:40:06Zdavidm
<ul></ul><p>Wouldn't it be better to do fdevent_sched_run() unconditionally? Otherwise, if epoll_wait() gets interrupted by a signal, we wouldn't call fdevent_sched_run() even though there might be pending work from the connection_state_machine(), right?</p> Lighttpd - Bug #2827: POST to mod_cgi sometimes hangshttps://redmine.lighttpd.net/issues/2827?journal_id=111292017-10-14T18:51:25Zgstrauss
<ul></ul><blockquote>
<p>Wouldn't it be better to do fdevent_sched_run() unconditionally?</p>
</blockquote>
<p>Not if there are things intended to be sent to the kernel which were interrupted before being sent to the kernel. (This might not be entirely relevant in this call to poll, but is relevant in other event loops I have written elsewhere.)</p>
<blockquote>
<p>Otherwise, if epoll_wait() gets interrupted by a signal, we wouldn't call fdevent_sched_run() even though there might be pending work from the connection_state_machine(), right?</p>
</blockquote>
<p>This code is in a loop. If interrupted, it will be tried again on the next loop. On any busy system, there should be actual fd events ready before interrupts, and on mostly idle systems, there is unlikely to be a large number of syscall interrupts (without fd events) which might interrupt the loop many times before it completes at least once (with either an event or a 1 second timeout without any event).</p>
<p>I have already pointed out that the root cause of your problem is the insecure CGI script which does not follow the CGI standard and might read an arbitrarily large amount of data.</p> Lighttpd - Bug #2827: POST to mod_cgi sometimes hangshttps://redmine.lighttpd.net/issues/2827?journal_id=111312017-10-15T08:05:05Zgstrauss
<ul><li><strong>Status</strong> changed from <i>Patch Pending</i> to <i>Fixed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li></ul><p>Applied in changeset <a class="changeset" title="[core] handle fds pending close after poll timeout (fixes #2827) handle fds pending close whethe..." href="https://redmine.lighttpd.net/projects/lighttpd/repository/14/revisions/8ed588ce32b96d4e9ca2f495defa4897e46497d3">8ed588ce32b96d4e9ca2f495defa4897e46497d3</a>.</p> Lighttpd - Bug #2827: POST to mod_cgi sometimes hangshttps://redmine.lighttpd.net/issues/2827?journal_id=111332017-10-16T05:42:32Zstbuehler
<ul></ul><p>Why not just set the timeout to 1 (ms) when there are close requests pending (e.g. in <code>fdevent_poll</code>)? Also why is <code>fdevent_sched_run</code> called in <code>fdevent_libev_poll</code> ?</p> Lighttpd - Bug #2827: POST to mod_cgi sometimes hangshttps://redmine.lighttpd.net/issues/2827?journal_id=111342017-10-16T06:01:21Zgstrauss
<ul></ul><blockquote>
<p>Also why is fdevent_sched_run called in fdevent_libev_poll ?</p>
</blockquote>
<p>See <a class="changeset" title="[core] fix fd leak when using libev (fixes #2761) server.event-handler = "libev" would leak fds ..." href="https://redmine.lighttpd.net/projects/lighttpd/repository/14/revisions/eb37615a47de85a53909225706cb9240652c704a">eb37615a</a></p>