mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
mod_proxy, mod_proxy_http: Connection headers must be stripped on the way
in and out, support an optional function to handle this. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1482075 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -428,6 +428,7 @@
|
||||
* ap_condition_if_none_match(),
|
||||
* ap_condition_if_modified_since(),
|
||||
* ap_condition_if_range()
|
||||
* 20121222.13 (2.5.0-dev) Add ap_proxy_clear_connection()
|
||||
*/
|
||||
|
||||
#define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
|
||||
@@ -435,7 +436,7 @@
|
||||
#ifndef MODULE_MAGIC_NUMBER_MAJOR
|
||||
#define MODULE_MAGIC_NUMBER_MAJOR 20121222
|
||||
#endif
|
||||
#define MODULE_MAGIC_NUMBER_MINOR 12 /* 0...n */
|
||||
#define MODULE_MAGIC_NUMBER_MINOR 13 /* 0...n */
|
||||
|
||||
/**
|
||||
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
|
||||
|
@@ -961,6 +961,16 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
|
||||
conn_rec *origin, apr_bucket_brigade *bb,
|
||||
int flush);
|
||||
|
||||
/**
|
||||
* Clear the headers referenced by the Connection header from the given
|
||||
* table, and remove the Connection header.
|
||||
* @param r request
|
||||
* @param headers table of headers to clear
|
||||
* @return 1 if "close" was present, 0 otherwise.
|
||||
*/
|
||||
APR_DECLARE_OPTIONAL_FN(int, ap_proxy_clear_connection,
|
||||
(request_rec *r, apr_table_t *headers));
|
||||
|
||||
#define PROXY_LBMETHOD "proxylbmethod"
|
||||
|
||||
/* The number of dynamic workers that can be added when reconfiguring.
|
||||
|
@@ -21,6 +21,9 @@
|
||||
|
||||
module AP_MODULE_DECLARE_DATA proxy_http_module;
|
||||
|
||||
static int (*ap_proxy_clear_connection_fn)(request_rec *r, apr_table_t *headers) =
|
||||
NULL;
|
||||
|
||||
static apr_status_t ap_proxy_http_cleanup(const char *scheme,
|
||||
request_rec *r,
|
||||
proxy_conn_rec *backend);
|
||||
@@ -178,33 +181,7 @@ static apr_table_t *ap_proxy_clean_warnings(apr_pool_t *p, apr_table_t *headers)
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
static int clear_conn_headers(void *data, const char *key, const char *val)
|
||||
{
|
||||
apr_table_t *headers = ((header_dptr*)data)->table;
|
||||
apr_pool_t *pool = ((header_dptr*)data)->pool;
|
||||
const char *name;
|
||||
char *next = apr_pstrdup(pool, val);
|
||||
while (*next) {
|
||||
name = next;
|
||||
while (*next && !apr_isspace(*next) && (*next != ',')) {
|
||||
++next;
|
||||
}
|
||||
while (*next && (apr_isspace(*next) || (*next == ','))) {
|
||||
*next++ = '\0';
|
||||
}
|
||||
apr_table_unset(headers, name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
|
||||
{
|
||||
header_dptr x;
|
||||
x.pool = p;
|
||||
x.table = headers;
|
||||
apr_table_unset(headers, "Proxy-Connection");
|
||||
apr_table_do(clear_conn_headers, &x, headers, "Connection", NULL);
|
||||
apr_table_unset(headers, "Connection");
|
||||
}
|
||||
|
||||
static void add_te_chunked(apr_pool_t *p,
|
||||
apr_bucket_alloc_t *bucket_alloc,
|
||||
apr_bucket_brigade *header_brigade)
|
||||
@@ -1491,11 +1468,10 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
|
||||
* ap_http_filter to know where to end.
|
||||
*/
|
||||
te = apr_table_get(r->headers_out, "Transfer-Encoding");
|
||||
|
||||
/* strip connection listed hop-by-hop headers from response */
|
||||
if (ap_find_token(p, apr_table_get(r->headers_out, "Connection"),
|
||||
"close"))
|
||||
backend->close = 1;
|
||||
ap_proxy_clear_connection(p, r->headers_out);
|
||||
backend->close = ap_proxy_clear_connection_fn(r, r->headers_out);
|
||||
|
||||
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
|
||||
ap_set_content_type(r, apr_pstrdup(p, buf));
|
||||
}
|
||||
@@ -1507,6 +1483,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
|
||||
for (i=0; hop_by_hop_hdrs[i]; ++i) {
|
||||
apr_table_unset(r->headers_out, hop_by_hop_hdrs[i]);
|
||||
}
|
||||
|
||||
/* Delete warnings with wrong date */
|
||||
r->headers_out = ap_proxy_clean_warnings(p, r->headers_out);
|
||||
|
||||
@@ -2031,8 +2008,34 @@ cleanup:
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* post_config hook: */
|
||||
static int proxy_http_post_config(apr_pool_t *pconf, apr_pool_t *plog,
|
||||
apr_pool_t *ptemp, server_rec *s)
|
||||
{
|
||||
|
||||
/* proxy_http_post_config() will be called twice during startup. So, don't
|
||||
* set up the static data the 1st time through. */
|
||||
if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (!ap_proxy_clear_connection_fn) {
|
||||
ap_proxy_clear_connection_fn =
|
||||
APR_RETRIEVE_OPTIONAL_FN(ap_proxy_clear_connection);
|
||||
if (!ap_proxy_clear_connection_fn) {
|
||||
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO()
|
||||
"mod_proxy must be loaded for mod_proxy_http");
|
||||
return !OK;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void ap_proxy_http_register_hook(apr_pool_t *p)
|
||||
{
|
||||
ap_hook_post_config(proxy_http_post_config, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
proxy_hook_scheme_handler(proxy_http_handler, NULL, NULL, APR_HOOK_FIRST);
|
||||
proxy_hook_canon_handler(proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);
|
||||
warn_rx = ap_pregcomp(p, "[0-9]{3}[ \t]+[^ \t]+[ \t]+\"[^\"]*\"([ \t]+\"([^\"]+)\")?", 0);
|
||||
|
@@ -2969,45 +2969,71 @@ PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_prov
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void proxy_util_register_hooks(apr_pool_t *p)
|
||||
{
|
||||
APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker);
|
||||
}
|
||||
|
||||
/* Clear all connection-based headers from the incoming headers table */
|
||||
typedef struct header_dptr {
|
||||
typedef struct header_connection {
|
||||
apr_pool_t *pool;
|
||||
apr_table_t *table;
|
||||
apr_time_t time;
|
||||
} header_dptr;
|
||||
apr_array_header_t *array;
|
||||
const char *first;
|
||||
unsigned int closed:1;
|
||||
} header_connection;
|
||||
|
||||
static int clear_conn_headers(void *data, const char *key, const char *val)
|
||||
static int find_conn_headers(void *data, const char *key, const char *val)
|
||||
{
|
||||
apr_table_t *headers = ((header_dptr*)data)->table;
|
||||
apr_pool_t *pool = ((header_dptr*)data)->pool;
|
||||
header_connection *x = data;
|
||||
const char *name;
|
||||
char *next = apr_pstrdup(pool, val);
|
||||
while (*next) {
|
||||
name = next;
|
||||
while (*next && !apr_isspace(*next) && (*next != ',')) {
|
||||
++next;
|
||||
|
||||
name = ap_get_token(x->pool, &val, 0);
|
||||
while (name && *name) {
|
||||
if (!strcasecmp(name, "close")) {
|
||||
x->closed = 1;
|
||||
}
|
||||
while (*next && (apr_isspace(*next) || (*next == ','))) {
|
||||
*next++ = '\0';
|
||||
if (!x->first) {
|
||||
x->first = name;
|
||||
}
|
||||
apr_table_unset(headers, name);
|
||||
else {
|
||||
if (!x->array) {
|
||||
x->array = apr_array_make(x->pool, 4, sizeof(char *));
|
||||
}
|
||||
const char **elt = apr_array_push(x->array);
|
||||
*elt = name;
|
||||
}
|
||||
while (*val == ',') {
|
||||
++val;
|
||||
}
|
||||
name = ap_get_token(x->pool, &val, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void proxy_clear_connection(request_rec *r, apr_table_t *headers)
|
||||
/**
|
||||
* Remove all headers referred to by the Connection header.
|
||||
*/
|
||||
PROXY_DECLARE(int) ap_proxy_clear_connection(request_rec *r,
|
||||
apr_table_t *headers)
|
||||
{
|
||||
header_dptr x;
|
||||
const char **name;
|
||||
header_connection x;
|
||||
|
||||
x.pool = r->pool;
|
||||
x.table = headers;
|
||||
x.array = NULL;
|
||||
x.first = NULL;
|
||||
x.closed = 0;
|
||||
|
||||
apr_table_unset(headers, "Proxy-Connection");
|
||||
apr_table_do(clear_conn_headers, &x, r->headers_in, "Connection", NULL);
|
||||
|
||||
apr_table_do(find_conn_headers, &x, headers, "Connection", NULL);
|
||||
if (x.first) {
|
||||
/* fast path - no memory allocated for one header */
|
||||
apr_table_unset(headers, "Connection");
|
||||
apr_table_unset(headers, x.first);
|
||||
}
|
||||
if (x.array) {
|
||||
/* two or more headers */
|
||||
while ((name = apr_array_pop(x.array))) {
|
||||
apr_table_unset(headers, *name);
|
||||
}
|
||||
}
|
||||
|
||||
return x.closed;
|
||||
}
|
||||
|
||||
PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
@@ -3194,7 +3220,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
|
||||
* apr is compiled with APR_POOL_DEBUG.
|
||||
*/
|
||||
headers_in_copy = apr_table_copy(r->pool, r->headers_in);
|
||||
proxy_clear_connection(r, headers_in_copy);
|
||||
ap_proxy_clear_connection(r, headers_in_copy);
|
||||
/* send request headers */
|
||||
headers_in_array = apr_table_elts(headers_in_copy);
|
||||
headers_in = (const apr_table_entry_t *) headers_in_array->elts;
|
||||
@@ -3299,3 +3325,9 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
|
||||
apr_brigade_cleanup(bb);
|
||||
return OK;
|
||||
}
|
||||
|
||||
void proxy_util_register_hooks(apr_pool_t *p)
|
||||
{
|
||||
APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker);
|
||||
APR_REGISTER_OPTIONAL_FN(ap_proxy_clear_connection);
|
||||
}
|
||||
|
Reference in New Issue
Block a user