1
0
mirror of https://github.com/apache/httpd.git synced 2026-01-06 09:01:14 +03:00

For backends which are HTTP/1.1, do a quick test (ping)

of the "connection" via 100-Continue for reverse
proxies...

ACO and Filip Hanik also helped out with the idea...


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@986090 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jim Jagielski
2010-08-16 18:36:19 +00:00
parent abda666287
commit 87703dd78c
3 changed files with 118 additions and 43 deletions

View File

@@ -6,6 +6,10 @@ Changes with Apache 2.3.7
mod_dav, mod_cache, mod_session: Fix Handling of requests without a path
segment. PR: 49246 [Mark Drayton, Jeff Trawick]
*) mod_proxy_http: Support the 'ping' property for backend HTTP/1.1 servers
via leveraging 100-Continue as the initial "request".
[Jim Jagielski]
*) core/mod_authz_core: Introduce new access_checker_ex hook that enables
mod_authz_core to bypass authentication if access should be allowed by
IP address/env var/... [Stefan Fritsch]

View File

@@ -743,17 +743,20 @@ expressions</description>
</td></tr>
<tr><td>ping</td>
<td>0</td>
<td>Ping property tells webserver to send a <code>CPING</code>
request on ajp13 connection before forwarding a request.
The parameter is the delay in seconds to wait for the
<code>CPONG</code> reply.
This features has been added to avoid problem with hung and
busy Tomcat's and require ajp13 ping/pong support which has
been implemented on Tomcat 3.3.2+, 4.1.28+ and 5.0.13+.
<td>Ping property tells the webserver to "test" the connection to
the backend before forwarding the request. For AJP, it causes
<module>mod_proxy_ajp</module>to send a <code>CPING</code>
request on the ajp13 connection (implemented on Tomcat 3.3.2+, 4.1.28+
and 5.0.13+). For HTTP, it causes <module>mod_proxy_http</module>
to send a <code>100-Continue</code> to the backend (only valid for
HTTP/1.1 - for non HTTP/1.1 backends, this property has no
effect). In both cases the parameter is the delay in seconds to wait
for the reply.
This feature has been added to avoid problems with hung and
busy backends.
This will increase the network traffic during the normal operation
which could be an issue, but it will lower the
traffic in case some of the cluster nodes are down or busy.
Currently this has an effect only for AJP.
By adding a postfix of ms the delay can be also set in
milliseconds.
</td></tr>

View File

@@ -669,7 +669,7 @@ static int spool_reqbody_cl(apr_pool_t *p,
static
int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
proxy_conn_rec *p_conn, conn_rec *origin,
proxy_conn_rec *p_conn, proxy_worker *worker,
proxy_server_conf *conf,
apr_uri_t *uri,
char *url, char *server_portstr)
@@ -694,6 +694,8 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
int force10, rv;
apr_table_t *headers_in_copy;
proxy_dir_conf *dconf;
conn_rec *origin = p_conn->connection;
int do_100_continue;
dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
header_brigade = apr_brigade_create(p, origin->bucket_alloc);
@@ -702,6 +704,11 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
* Send the HTTP/1.1 request to the remote server
*/
do_100_continue = (worker->ping_timeout_set
&& !r->header_only
&& (PROXYREQ_REVERSE == r->proxyreq)
&& !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0")));
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
/*
* According to RFC 2616 8.2.3 we are not allowed to forward an
@@ -791,6 +798,14 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
);
}
/* Use HTTP/1.1 100-Continue as quick "HTTP ping" test
* to backend
*/
if (do_100_continue) {
apr_table_mergen(r->headers_in, "Expect", "100-Continue");
r->expecting_100 = 1;
}
/* X-Forwarded-*: handling
*
* XXX Privacy Note:
@@ -1350,7 +1365,7 @@ apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec
static
apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
proxy_conn_rec *backend,
conn_rec *origin,
proxy_worker *worker,
proxy_server_conf *conf,
char *server_portstr) {
conn_rec *c = r->connection;
@@ -1375,9 +1390,32 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
int proxy_status = OK;
const char *original_status_line = r->status_line;
const char *proxy_status_line = NULL;
conn_rec *origin = backend->connection;
apr_interval_time_t old_timeout = 0;
int do_100_continue;
do_100_continue = (worker->ping_timeout_set
&& !r->header_only
&& (PROXYREQ_REVERSE == r->proxyreq)
&& !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0")));
bb = apr_brigade_create(p, c->bucket_alloc);
pass_bb = apr_brigade_create(p, c->bucket_alloc);
/* Setup for 100-Continue timeout if appropriate */
if (do_100_continue) {
apr_socket_timeout_get(backend->sock, &old_timeout);
if (worker->ping_timeout != old_timeout) {
apr_status_t rc;
rc = apr_socket_timeout_set(backend->sock, worker->ping_timeout);
if (rc != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server,
"proxy: could not set 100-Continue timeout");
}
}
}
/* Get response from the remote server, and pass it up the
* filter chain
@@ -1406,6 +1444,9 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
if (APR_STATUS_IS_TIMEUP(rc)) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"proxy: read timeout");
if (do_100_continue) {
return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, "Timeout on 100-Continue");
}
}
/*
* If we are a reverse proxy request shutdown the connection
@@ -1641,6 +1682,12 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
if (ap_is_HTTP_INFO(proxy_status)) {
interim_response++;
/* Reset to old timeout iff we've adjusted it */
if (do_100_continue
&& (r->status == HTTP_CONTINUE)
&& (worker->ping_timeout != old_timeout)) {
apr_socket_timeout_set(backend->sock, old_timeout);
}
}
else {
interim_response = 0;
@@ -1923,6 +1970,7 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
proxy_conn_rec *backend = NULL;
int is_ssl = 0;
conn_rec *c = r->connection;
int retry = 0;
/*
* Use a shorter-lived pool to reduce memory usage
* and avoid a memory leak
@@ -1990,48 +2038,68 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
backend->close = 1;
}
/* Step One: Determine Who To Connect To */
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend,
uri, &url, proxyname,
while (retry < 2) {
char *locurl = url;
/* Step One: Determine Who To Connect To */
if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend,
uri, &locurl, proxyname,
proxyport, server_portstr,
sizeof(server_portstr))) != OK)
goto cleanup;
break;
/* Step Two: Make the Connection */
if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
status = HTTP_SERVICE_UNAVAILABLE;
goto cleanup;
}
/* Step Two: Make the Connection */
if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: HTTP: failed to make connection to backend: %s",
backend->hostname);
status = HTTP_SERVICE_UNAVAILABLE;
break;
}
/* Step Three: Create conn_rec */
if (!backend->connection) {
if ((status = ap_proxy_connection_create(proxy_function, backend,
c, r->server)) != OK)
goto cleanup;
/*
* On SSL connections set a note on the connection what CN is
* requested, such that mod_ssl can check if it is requested to do
* so.
/* Step Three: Create conn_rec */
if (!backend->connection) {
if ((status = ap_proxy_connection_create(proxy_function, backend,
c, r->server)) != OK)
break;
/*
* On SSL connections set a note on the connection what CN is
* requested, such that mod_ssl can check if it is requested to do
* so.
*/
if (is_ssl) {
apr_table_set(backend->connection->notes, "proxy-request-hostname",
uri->hostname);
}
}
/* Step Four: Send the Request
* On the off-chance that we forced a 100-Continue as a
* kinda HTTP ping test, allow for retries
*/
if (is_ssl) {
apr_table_set(backend->connection->notes, "proxy-request-hostname",
uri->hostname);
if ((status = ap_proxy_http_request(p, r, backend, worker,
conf, uri, locurl, server_portstr)) != OK) {
if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->ping_timeout_set) {
backend->close = 1;
ap_log_error(APLOG_MARK, APLOG_INFO, status, r->server,
"proxy: HTTP: 100-Continue failed to %pI (%s)",
worker->cp->addr, worker->hostname);
retry++;
continue;
} else {
break;
}
}
/* Step Five: Receive the Response... Fall thru to cleanup */
status = ap_proxy_http_process_response(p, r, backend, worker,
conf, server_portstr);
break;
}
/* Step Four: Send the Request */
if ((status = ap_proxy_http_request(p, r, backend, backend->connection,
conf, uri, url, server_portstr)) != OK)
goto cleanup;
/* Step Five: Receive the Response */
if ((status = ap_proxy_http_process_response(p, r, backend,
backend->connection,
conf, server_portstr)) != OK)
goto cleanup;
/* Step Six: Clean Up */
cleanup:
if (backend) {
if (status != OK)