According to the description of the ProxyTimeout directive, this
is the expected behavior:
> This directive allows a user to specifiy a timeout on proxy requests.
> This is useful when you have a slow/buggy appserver which hangs, and
> you would rather just return a timeout and fail gracefully instead
> of waiting however long it takes the server to return.
However, this is not what occurs. The ProxyTimeout is only used
to obtain the connection to the 'origin server'; when it actually
sends the proxied request and waits for the response, the value of
the Timeout directive is used.
Unfortunately, mod_proxy uses a core function called 'pre_connection'
after the connection has been made (despite the 'pre' in the function
name :D) and therein lies the problem. That code only has access to
the server config, not the modules configs, and it resets the timeout
to the value of the Timeout directive.
My fix is to reset the timeout *after* the call to pre_connection if
this directive is set.
I also added new functionality allowing a special environment
variable ("proxy-timeout") to be set to overload the directive for
more fine-grained control. This would allow the following:
ProxyTimeout 15
RewriteRule ^/proxy/(.*)$ http://someotherserver.com/$1
RewriteRule ^/quick/(.*)$ http://someotherserver.com/$1 \
[E=proxy-timeout:5]
RewriteRule ^/slow/(.*)$ http://someotherserver.com/$1 \
[E=proxy-timeout:30]
This allows three different proxies timeouts to the same origin
server (someotherserver.com) based on the URL to the forward
proxy.
Attached is my patch to 2.0.63 to the proxy_http.c file in
modules/proxy.
Thanks,
Ron
--- modules/proxy/proxy_http.c.orig 2007-09-04 15:33:45.000000000 -0400
+++ modules/proxy/proxy_http.c 2008-02-04 14:57:21.000000000 -0500
@@ -379,6 +379,36 @@
"proxy: HTTP: pre_connection setup failed (%d)",
rc);
return rc;
+ } else {
+ // that pre_connection code sets the socket timeout as
+ // the value of Timeout which is the timeout of the
+ // original request; by the time that is hit, our client
+ // has already been given a timeout
+ //
+ // instead, we'll look to see if an env var, proxy-timeout,
+ // has been set: if so, we use it; otherwise, we use
+ // the setting for ProxyTimeout (if set); (otherwise, we
+ // will stick with the value of Timeout.)
+ const char* tbl_timeout;
+ apr_interval_time_t timeout = (conf->timeout_set) ?
+ conf->timeout : 0;
+
+ tbl_timeout = apr_table_get(r->subprocess_env, "proxy-timeout");
+ if (tbl_timeout == NULL) {
+ tbl_timeout = apr_table_get(r->notes, "proxy-timeout");
+ }
+ if (tbl_timeout != NULL) {
+ int int_timeout = atoi(tbl_timeout);
+ if (int_timeout > 0) {
+ timeout = apr_time_from_sec(int_timeout);
+ }
+ }
+ if (timeout > 0) {
+ apr_socket_timeout_set(p_conn->sock, timeout);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: setting request timeout (%d)", timeout);
+ }
+
}
}
return OK;