You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Graham Dumpleton <gr...@gmail.com> on 2007/11/17 06:02:32 UTC

Where is Timeout configuration directive value stored?

The function in server/core.c called for the Timeout directive is:

static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
{
    const char *err = ap_check_cmd_context(cmd,
NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);

    if (err != NULL) {
        return err;
    }

    cmd->server->timeout = apr_time_from_sec(atoi(arg));
    return NULL;
}

Ie., the Timeout directive value is stored in 'timeout' parameter of
the 'server_rec' for host context that directive appears in.

Presumably, the Timeout directive in global part of Apache
configuration would result in that being put in server_rec for main
server context.

When ap_fixup_virtual_hosts() is later run, presumably that is then
copied into vhost server_rec presuming that a vhost didn't contain its
own Timeout directive setting. Ie., that function contains:

        if (virt->timeout == 0)
            virt->timeout = main_server->timeout;

Based on that I am presuming that if either r->server-timeout or
r->connection->base_server->timeout is accessed, they should have a
non zero value corresponding to what the Timeout directive was being
set to, or the default of 300 seconds if not set, but that isn't want
I am seeing in my own handler code and instead 'timeout' is 0.

I am a bit confused at this point as mod_cgi uses:

                apr_file_pipe_timeout_set(*script_out, r->server->timeout);

but if r->server->timeout is 0, then a write would return straight
away if it blocked instead of waiting default of 300 seconds.

What am I missing? I have seen this on Apache 2.2.4 and 2.2.6 on two
different Mac OS X systems.

BTW, a long time ago, either here on modules-dev, I queried about code
in mod_cgid and whether it was correct, namely it says:

            /* Keep writing data to the child until done or too much time
             * elapses with no progress or an error occurs.
             */
            rv = apr_file_write_full(tempsock, data, len, NULL);

My concern was that this wouldn't actually ever timeout as tempsock
never had a timeout value set for it. I never got an answer at the
time

In some code I modeled on how mod_cgid was working, am now seeing
problems which suggests that not only is mod_cgid possibly broken in
not having a timeout, but one can actually deadlock the whole CGI
process and the thread in the Apache child.

I'll admit that my own code doesn't exactly mirror how the cgid
process launcher works, but the issue I see is that if a request has
POST content which is greater in size than the socket buffers can
hold, and a CGI script doesn't consume the POST content before sending
a response, also greater than the socket buffer sizes, then
cgid_handler() can block indefinitely in apr_file_write_full().

This will occur because the CGI process will in turn be blocked in
trying to send its response. It can't return until some data is read
by cgid_handler() in Apache child process, that can't happen as
reading response is only done after the POST content is sent by calls
to apr_file_write_full(). Because a 'timeout' wasn't set on tempsock
though, it will also never actually return, even after default 300
seconds, and will just deadlock.

Now, in comparing mod_cgi to mod_cgid, in mod_cgi it does make call to
set timeout on the pipe for forked process, but as shown above it uses
r->server->timeout, which keeps showing as 0 for me in my own handler
code.

Anyone like to comment on whether my analysis is correct so as to help
me understand the code and determine if mod_cgi and/or mod_cgid is
broken?

BTW, using a simple test CGI script which returns 16Kb response
without consuming POST content, and using POST with 16Kb of data
against it, I have now duplicated with CGI module what I was seeing in
my own code. Namely, the CGI script and Apache child process thread
both block indefinitely, not even recovering after timeout specified
by Timeout directive. My server for this test was configured with
static mod_cgid module.

Graham

Re: Where is Timeout configuration directive value stored?

Posted by Graham Dumpleton <gr...@gmail.com>.
Hmmm, sorted out why timeout was showing as 0. Should have just used
APR_TIME_T_FMT in the first place instead of guessing what format was
supposed to be.

Anyway, issue still stands as detailed at end of mail that mod_cgid
seems to lack setting of timeout on socket, plus the issue of deadlock
with both mod_cgi and mod_cgid. After recompiling Apache to use
mod_cgi instead of mod_cgid, showed that deadlock still occurs, but at
least for that case the timeout occurs and it recovers after period
specified by Timeout directive.

Is it just accepted that CGI scripts will always just consume all
their input, or that when they don't they will not generate a response
more than socket buffer size?

Graham

On 17/11/2007, Graham Dumpleton <gr...@gmail.com> wrote:
> The function in server/core.c called for the Timeout directive is:
>
> static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
> {
>     const char *err = ap_check_cmd_context(cmd,
> NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
>
>     if (err != NULL) {
>         return err;
>     }
>
>     cmd->server->timeout = apr_time_from_sec(atoi(arg));
>     return NULL;
> }
>
> Ie., the Timeout directive value is stored in 'timeout' parameter of
> the 'server_rec' for host context that directive appears in.
>
> Presumably, the Timeout directive in global part of Apache
> configuration would result in that being put in server_rec for main
> server context.
>
> When ap_fixup_virtual_hosts() is later run, presumably that is then
> copied into vhost server_rec presuming that a vhost didn't contain its
> own Timeout directive setting. Ie., that function contains:
>
>         if (virt->timeout == 0)
>             virt->timeout = main_server->timeout;
>
> Based on that I am presuming that if either r->server-timeout or
> r->connection->base_server->timeout is accessed, they should have a
> non zero value corresponding to what the Timeout directive was being
> set to, or the default of 300 seconds if not set, but that isn't want
> I am seeing in my own handler code and instead 'timeout' is 0.
>
> I am a bit confused at this point as mod_cgi uses:
>
>                 apr_file_pipe_timeout_set(*script_out, r->server->timeout);
>
> but if r->server->timeout is 0, then a write would return straight
> away if it blocked instead of waiting default of 300 seconds.
>
> What am I missing? I have seen this on Apache 2.2.4 and 2.2.6 on two
> different Mac OS X systems.
>
> BTW, a long time ago, either here on modules-dev, I queried about code
> in mod_cgid and whether it was correct, namely it says:
>
>             /* Keep writing data to the child until done or too much time
>              * elapses with no progress or an error occurs.
>              */
>             rv = apr_file_write_full(tempsock, data, len, NULL);
>
> My concern was that this wouldn't actually ever timeout as tempsock
> never had a timeout value set for it. I never got an answer at the
> time
>
> In some code I modeled on how mod_cgid was working, am now seeing
> problems which suggests that not only is mod_cgid possibly broken in
> not having a timeout, but one can actually deadlock the whole CGI
> process and the thread in the Apache child.
>
> I'll admit that my own code doesn't exactly mirror how the cgid
> process launcher works, but the issue I see is that if a request has
> POST content which is greater in size than the socket buffers can
> hold, and a CGI script doesn't consume the POST content before sending
> a response, also greater than the socket buffer sizes, then
> cgid_handler() can block indefinitely in apr_file_write_full().
>
> This will occur because the CGI process will in turn be blocked in
> trying to send its response. It can't return until some data is read
> by cgid_handler() in Apache child process, that can't happen as
> reading response is only done after the POST content is sent by calls
> to apr_file_write_full(). Because a 'timeout' wasn't set on tempsock
> though, it will also never actually return, even after default 300
> seconds, and will just deadlock.
>
> Now, in comparing mod_cgi to mod_cgid, in mod_cgi it does make call to
> set timeout on the pipe for forked process, but as shown above it uses
> r->server->timeout, which keeps showing as 0 for me in my own handler
> code.
>
> Anyone like to comment on whether my analysis is correct so as to help
> me understand the code and determine if mod_cgi and/or mod_cgid is
> broken?
>
> BTW, using a simple test CGI script which returns 16Kb response
> without consuming POST content, and using POST with 16Kb of data
> against it, I have now duplicated with CGI module what I was seeing in
> my own code. Namely, the CGI script and Apache child process thread
> both block indefinitely, not even recovering after timeout specified
> by Timeout directive. My server for this test was configured with
> static mod_cgid module.
>
> Graham
>