From: Stefan Eissing Date: Mon, 24 Oct 2016 10:06:41 +0000 (+0000) Subject: Merge of r1750392,r1750412,r1750416,r1750474,r1750494,r1750508 from trunk: X-Git-Tag: 2.4.24~176 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a3d85555d430e1a6218c83bdadc01bd7466f0ca;p=thirdparty%2Fapache%2Fhttpd.git Merge of r1750392,r1750412,r1750416,r1750474,r1750494,r1750508 from trunk: mod_proxy_{http,ajp,fcgi}: don't reuse backend connections with data available before the request is sent. PR 57832. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1766372 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index af2f77dcbc5..fb02e16103d 100644 --- a/CHANGES +++ b/CHANGES @@ -66,6 +66,9 @@ Changes with Apache 2.4.24 *) core: CVE-2016-5387: Mitigate [f]cgi "httpoxy" issues. [Dominic Scheirlinck , Yann Ylavic] + *) mod_proxy_{http,ajp,fcgi}: don't reuse backend connections with data + available before the request is sent. PR 57832. [Yann Ylavic] + *) mod_proxy_balancer: Prevent redirect loops between workers within a balancer by limiting the number of redirects to the number balancer members. PR 59864 [Ruediger Pluem] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 01878cdef3d..a4feabc1446 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -482,6 +482,11 @@ * dav_finish_multistatus, dav_send_multistatus, * dav_handle_err, dav_failed_proppatch, * dav_success_proppatch. + * 20120211.64 (2.4.24-dev) Add ap_proxy_check_backend(), and tmp_bb to struct + * proxy_conn_rec. + * 20120211.65 (2.4.24-dev) Add ap_check_pipeline(). + * 20120211.66 (2.4.24-dev) Rename ap_proxy_check_backend() to + * ap_proxy_check_connection(). */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -489,7 +494,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 63 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 66 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_request.h b/include/http_request.h index 4d0109adfc5..0013d39fa66 100644 --- a/include/http_request.h +++ b/include/http_request.h @@ -337,6 +337,21 @@ void ap_process_async_request(request_rec *r); */ AP_DECLARE(void) ap_die(int type, request_rec *r); +/** + * Check whether a connection is still established and has data available, + * optionnaly consuming blank lines ([CR]LF). + * @param c The current connection + * @param bb The brigade to filter + * @param max_blank_lines Max number of blank lines to consume, or zero + * to consider them as data (single read). + * @return APR_SUCCESS: connection established with data available, + * APR_EAGAIN: connection established and empty, + * APR_NOTFOUND: too much blank lines, + * APR_E*: connection/general error. + */ +AP_DECLARE(apr_status_t) ap_check_pipeline(conn_rec *c, apr_bucket_brigade *bb, + unsigned int max_blank_lines); + /* Hooks */ /** diff --git a/modules/http/http_request.c b/modules/http/http_request.c index 5b2c1e8a0c7..9ce7b8b3298 100644 --- a/modules/http/http_request.c +++ b/modules/http/http_request.c @@ -228,41 +228,51 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) ap_die_r(type, r, r->status); } -static void check_pipeline(conn_rec *c, apr_bucket_brigade *bb) +AP_DECLARE(apr_status_t) ap_check_pipeline(conn_rec *c, apr_bucket_brigade *bb, + unsigned int max_blank_lines) { - apr_status_t rv; - int num_blank_lines = DEFAULT_LIMIT_BLANK_LINES; + apr_status_t rv = APR_EOF; ap_input_mode_t mode = AP_MODE_SPECULATIVE; + unsigned int num_blank_lines = 0; apr_size_t cr = 0; char buf[2]; - c->data_in_input_filters = 0; while (c->keepalive != AP_CONN_CLOSE && !c->aborted) { apr_size_t len = cr + 1; apr_brigade_cleanup(bb); rv = ap_get_brigade(c->input_filters, bb, mode, APR_NONBLOCK_READ, len); - if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(bb)) { - /* - * Error or empty brigade: There is no data present in the input - * filter - */ + if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(bb) || !max_blank_lines) { if (mode == AP_MODE_READBYTES) { /* Unexpected error, stop with this connection */ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(02967) "Can't consume pipelined empty lines"); c->keepalive = AP_CONN_CLOSE; + rv = APR_EGENERAL; + } + else if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(bb)) { + if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) { + /* Pipe is dead */ + c->keepalive = AP_CONN_CLOSE; + } + else { + /* Pipe is up and empty */ + rv = APR_EAGAIN; + } + } + else { + apr_off_t n = 0; + /* Single read asked, (non-meta-)data available? */ + rv = apr_brigade_length(bb, 0, &n); + if (rv == APR_SUCCESS && n <= 0) { + rv = APR_EAGAIN; + } } break; } - /* Ignore trailing blank lines (which must not be interpreted as - * pipelined requests) up to the limit, otherwise we would block - * on the next read without flushing data, and hence possibly delay - * pending response(s) until the next/real request comes in or the - * keepalive timeout expires. - */ + /* Lookup and consume blank lines */ rv = apr_brigade_flatten(bb, buf, &len); if (rv != APR_SUCCESS || len != cr + 1) { int log_level; @@ -270,14 +280,15 @@ static void check_pipeline(conn_rec *c, apr_bucket_brigade *bb) /* Unexpected error, stop with this connection */ c->keepalive = AP_CONN_CLOSE; log_level = APLOG_ERR; + rv = APR_EGENERAL; } else { /* Let outside (non-speculative/blocking) read determine * where this possible failure comes from (metadata, - * morphed EOF socket => empty bucket? debug only here). + * morphed EOF socket, ...). Debug only here. */ - c->data_in_input_filters = 1; log_level = APLOG_DEBUG; + rv = APR_SUCCESS; } ap_log_cerror(APLOG_MARK, log_level, rv, c, APLOGNO(02968) "Can't check pipelined data"); @@ -285,40 +296,47 @@ static void check_pipeline(conn_rec *c, apr_bucket_brigade *bb) } if (mode == AP_MODE_READBYTES) { + /* [CR]LF consumed, try next */ mode = AP_MODE_SPECULATIVE; cr = 0; } else if (cr) { AP_DEBUG_ASSERT(len == 2 && buf[0] == APR_ASCII_CR); if (buf[1] == APR_ASCII_LF) { + /* consume this CRLF */ mode = AP_MODE_READBYTES; - num_blank_lines--; + num_blank_lines++; } else { - c->data_in_input_filters = 1; + /* CR(?!LF) is data */ break; } } else { if (buf[0] == APR_ASCII_LF) { + /* consume this LF */ mode = AP_MODE_READBYTES; - num_blank_lines--; + num_blank_lines++; } else if (buf[0] == APR_ASCII_CR) { cr = 1; } else { - c->data_in_input_filters = 1; + /* Not [CR]LF, some data */ break; } } - /* Enough blank lines with this connection? - * Stop and don't recycle it. - */ - if (num_blank_lines < 0) { + if (num_blank_lines > max_blank_lines) { + /* Enough blank lines with this connection, + * stop and don't recycle it. + */ c->keepalive = AP_CONN_CLOSE; + rv = APR_NOTFOUND; + break; } } + + return rv; } @@ -327,6 +345,7 @@ AP_DECLARE(void) ap_process_request_after_handler(request_rec *r) apr_bucket_brigade *bb; apr_bucket *b; conn_rec *c = r->connection; + apr_status_t rv; /* Send an EOR bucket through the output filter chain. When * this bucket is destroyed, the request will be logged and @@ -351,8 +370,15 @@ AP_DECLARE(void) ap_process_request_after_handler(request_rec *r) * already by the EOR bucket's cleanup function. */ - check_pipeline(c, bb); + /* Check pipeline consuming blank lines, they must not be interpreted as + * the next pipelined request, otherwise we would block on the next read + * without flushing data, and hence possibly delay pending response(s) + * until the next/real request comes in or the keepalive timeout expires. + */ + rv = ap_check_pipeline(c, bb, DEFAULT_LIMIT_BLANK_LINES); + c->data_in_input_filters = (rv == APR_SUCCESS); apr_brigade_destroy(bb); + if (c->cs) c->cs->state = (c->aborted) ? CONN_STATE_LINGER : CONN_STATE_WRITE_COMPLETION; diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index db4da70b47c..281a77650c9 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -271,6 +271,10 @@ typedef struct { unsigned int inreslist:1; /* connection in apr_reslist? */ const char *uds_path; /* Unix domain socket path */ const char *ssl_hostname;/* Hostname (SNI) in use by SSL connection */ + apr_bucket_brigade *tmp_bb;/* Temporary brigade created with the connection + * and its scpool/bucket_alloc (NULL before), + * must be left cleaned when used (locally). + */ } proxy_conn_rec; typedef struct { @@ -632,6 +636,7 @@ PROXY_DECLARE(int) ap_proxy_checkproxyblock2(request_rec *r, proxy_server_conf * PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r); /* DEPRECATED (will be replaced with ap_proxy_connect_backend */ PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, request_rec *); +/* DEPRECATED (will be replaced with ap_proxy_check_connection */ PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn, request_rec *r); PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c); @@ -916,6 +921,28 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function, proxy_conn_rec *conn, server_rec *s); + +#define PROXY_CHECK_CONN_EMPTY (1 << 0) +/** + * Check a connection to the backend + * @param scheme calling proxy scheme (http, ajp, ...) + * @param conn acquired connection + * @param server current server record + * @param max_blank_lines how many blank lines to consume, + * or zero for none (considered data) + * @param flags PROXY_CHECK_* bitmask + * @return APR_SUCCESS: connection established, + * APR_ENOTEMPTY: connection established with data, + * APR_ENOSOCKET: not connected, + * APR_EINVAL: worker in error state (unusable), + * other: connection closed/aborted (remotely) + */ +PROXY_DECLARE(apr_status_t) ap_proxy_check_connection(const char *scheme, + proxy_conn_rec *conn, + server_rec *server, + unsigned max_blank_lines, + int flags); + /** * Make a connection to the backend * @param proxy_function calling proxy scheme (http, ajp, ...) diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index ef9f247a616..051724e559d 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -769,7 +769,10 @@ static int proxy_ajp_handler(request_rec *r, proxy_worker *worker, break; /* Step Two: Make the Connection */ - if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) { + if (ap_proxy_check_connection(scheme, backend, r->server, 0, + PROXY_CHECK_CONN_EMPTY) + && ap_proxy_connect_backend(scheme, backend, worker, + r->server)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00896) "failed to make connection to backend: %s", backend->hostname); diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index a11757c5a72..76d381bc2a2 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -953,7 +953,10 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, } /* Step Two: Make the Connection */ - if (ap_proxy_connect_backend(FCGI_SCHEME, backend, worker, r->server)) { + if (ap_proxy_check_connection(FCGI_SCHEME, backend, r->server, 0, + PROXY_CHECK_CONN_EMPTY) + && ap_proxy_connect_backend(FCGI_SCHEME, backend, worker, + r->server)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01079) "failed to make connection to backend: %s", backend->hostname); diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index de8b8c802c3..d343aa7be71 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -1188,7 +1188,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, const char *buf; char keepchar; apr_bucket *e; - apr_bucket_brigade *bb, *tmp_bb; + apr_bucket_brigade *bb; apr_bucket_brigade *pass_bb; int len, backasswards; int interim_response = 0; /* non-zero whilst interim 1xx responses @@ -1244,16 +1244,17 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, backend->r->proxyreq = PROXYREQ_RESPONSE; apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu", origin->local_addr->port)); - tmp_bb = apr_brigade_create(p, c->bucket_alloc); do { apr_status_t rc; apr_brigade_cleanup(bb); - rc = ap_proxygetline(tmp_bb, buffer, sizeof(buffer), backend->r, 0, &len); + rc = ap_proxygetline(backend->tmp_bb, buffer, sizeof(buffer), + backend->r, 0, &len); if (len == 0) { /* handle one potential stray CRLF */ - rc = ap_proxygetline(tmp_bb, buffer, sizeof(buffer), backend->r, 0, &len); + rc = ap_proxygetline(backend->tmp_bb, buffer, sizeof(buffer), + backend->r, 0, &len); } if (len <= 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(01102) @@ -1908,13 +1909,8 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, worker, r->server)) != OK) goto cleanup; - backend->is_ssl = is_ssl; - if (is_ssl) { - ap_proxy_ssl_connection_cleanup(backend, r); - } - /* * In the case that we are handling a reverse proxy connection and this * is not a request that is coming over an already kept alive connection @@ -1939,7 +1935,10 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, break; /* Step Two: Make the Connection */ - if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { + if (ap_proxy_check_connection(proxy_function, backend, r->server, 1, + PROXY_CHECK_CONN_EMPTY) + && ap_proxy_connect_backend(proxy_function, backend, worker, + r->server)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114) "HTTP: failed to make connection to backend: %s", backend->hostname); diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 66ba17a0b6a..6444b6899e3 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1305,6 +1305,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balance static void socket_cleanup(proxy_conn_rec *conn) { conn->sock = NULL; + conn->tmp_bb = NULL; conn->connection = NULL; conn->ssl_hostname = NULL; apr_pool_clear(conn->scpool); @@ -1405,10 +1406,10 @@ static apr_status_t connection_cleanup(void *theconn) return APR_SUCCESS; } +/* DEPRECATED */ PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn, request_rec *r) { - apr_bucket_brigade *bb; apr_status_t rv; /* @@ -1420,22 +1421,21 @@ PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn * processed. We don't expect any data to be in the returned brigade. */ if (conn->sock && conn->connection) { - bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); - rv = ap_get_brigade(conn->connection->input_filters, bb, + rv = ap_get_brigade(conn->connection->input_filters, conn->tmp_bb, AP_MODE_READBYTES, APR_NONBLOCK_READ, HUGE_STRING_LEN); - if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) { - socket_cleanup(conn); - } - if (!APR_BRIGADE_EMPTY(bb)) { + if (!APR_BRIGADE_EMPTY(conn->tmp_bb)) { apr_off_t len; - rv = apr_brigade_length(bb, 0, &len); + rv = apr_brigade_length(conn->tmp_bb, 0, &len); ap_log_rerror(APLOG_MARK, APLOG_TRACE3, rv, r, "SSL cleanup brigade contained %" APR_OFF_T_FMT " bytes of data.", len); + apr_brigade_cleanup(conn->tmp_bb); + } + if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) { + socket_cleanup(conn); } - apr_brigade_destroy(bb); } return APR_SUCCESS; } @@ -2638,13 +2638,103 @@ PROXY_DECLARE(apr_status_t) ap_proxy_connect_uds(apr_socket_t *sock, #endif } +PROXY_DECLARE(apr_status_t) ap_proxy_check_connection(const char *scheme, + proxy_conn_rec *conn, + server_rec *server, + unsigned max_blank_lines, + int flags) +{ + apr_status_t rv = APR_SUCCESS; + proxy_worker *worker = conn->worker; + + if (!PROXY_WORKER_IS_USABLE(worker)) { + /* + * The worker is in error likely done by a different thread / process + * e.g. for a timeout or bad status. We should respect this and should + * not continue with a connection via this worker even if we got one. + */ + rv = APR_EINVAL; + } + else if (conn->connection) { + /* We have a conn_rec, check the full filter stack for things like + * SSL alert/shutdown, filters aside data... + */ + rv = ap_check_pipeline(conn->connection, conn->tmp_bb, + max_blank_lines); + apr_brigade_cleanup(conn->tmp_bb); + if (rv == APR_SUCCESS) { + /* Some data available, the caller might not want them. */ + if (flags & PROXY_CHECK_CONN_EMPTY) { + rv = APR_ENOTEMPTY; + } + } + else if (APR_STATUS_IS_EAGAIN(rv)) { + /* Filter chain is OK and empty, yet we can't determine from + * ap_check_pipeline (actually ap_core_input_filter) whether + * an empty non-blocking read is EAGAIN or EOF on the socket + * side (it's always SUCCESS), so check it explicitely here. + */ + if (ap_proxy_is_socket_connected(conn->sock)) { + rv = APR_SUCCESS; + } + else { + rv = APR_EPIPE; + } + } + } + else if (conn->sock) { + /* For modules working with sockets directly, check it. */ + if (!ap_proxy_is_socket_connected(conn->sock)) { + rv = APR_EPIPE; + } + } + else { + rv = APR_ENOSOCKET; + } + + if (rv == APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, server, + "%s: reusing backend connection %pI<>%pI", + scheme, conn->connection->local_addr, + conn->connection->client_addr); + } + else if (conn->sock) { + /* This clears conn->scpool (and associated data), so backup and + * restore any ssl_hostname for this connection set earlier by + * ap_proxy_determine_connection(). + */ + char ssl_hostname[PROXY_WORKER_RFC1035_NAME_SIZE]; + if (rv == APR_EINVAL + || !conn->ssl_hostname + || PROXY_STRNCPY(ssl_hostname, conn->ssl_hostname)) { + ssl_hostname[0] = '\0'; + } + + socket_cleanup(conn); + if (rv != APR_ENOTEMPTY) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, APLOGNO(00951) + "%s: backend socket is disconnected.", scheme); + } + else { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, server, APLOGNO(03408) + "%s: reusable backend connection is not empty: " + "forcibly closed", scheme); + } + + if (ssl_hostname[0]) { + conn->ssl_hostname = apr_pstrdup(conn->scpool, ssl_hostname); + } + } + + return rv; +} + PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, server_rec *s) { apr_status_t rv; - int connected = 0; int loglevel; apr_sockaddr_t *backend_addr = conn->addr; /* the local address to use for the outgoing connection */ @@ -2654,29 +2744,12 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); - if (conn->sock) { - if (!(connected = ap_proxy_is_socket_connected(conn->sock))) { - /* This clears conn->scpool (and associated data), so backup and - * restore any ssl_hostname for this connection set earlier by - * ap_proxy_determine_connection(). - */ - char ssl_hostname[PROXY_WORKER_RFC1035_NAME_SIZE]; - if (!conn->ssl_hostname || PROXY_STRNCPY(ssl_hostname, - conn->ssl_hostname)) { - ssl_hostname[0] = '\0'; - } - - socket_cleanup(conn); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00951) - "%s: backend socket is disconnected.", - proxy_function); - - if (ssl_hostname[0]) { - conn->ssl_hostname = apr_pstrdup(conn->scpool, ssl_hostname); - } - } + rv = ap_proxy_check_connection(proxy_function, conn, s, 0, 0); + if (rv == APR_EINVAL) { + return DECLINED; } - while ((backend_addr || conn->uds_path) && !connected) { + + while (rv != APR_SUCCESS && (backend_addr || conn->uds_path)) { #if APR_HAVE_SYS_UN_H if (conn->uds_path) { @@ -2848,9 +2921,8 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, } } } - - connected = 1; } + if (PROXY_WORKER_IS_USABLE(worker)) { /* * Put the entire worker to error state if @@ -2858,7 +2930,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, * Although some connections may be alive * no further connections to the worker could be made */ - if (!connected) { + if (rv != APR_SUCCESS) { if (!(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) { worker->s->error_time = apr_time_now(); worker->s->status |= PROXY_WORKER_IN_ERROR; @@ -2879,7 +2951,6 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, worker->s->error_time = 0; worker->s->retries = 0; } - return connected ? OK : DECLINED; } else { /* @@ -2887,11 +2958,13 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, * e.g. for a timeout or bad status. We should respect this and should * not continue with a connection via this worker even if we got one. */ - if (connected) { + if (rv == APR_SUCCESS) { socket_cleanup(conn); } - return DECLINED; + rv = APR_EINVAL; } + + return rv == APR_SUCCESS ? OK : DECLINED; } static apr_status_t connection_shutdown(void *theconn) @@ -2936,6 +3009,7 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, } bucket_alloc = apr_bucket_alloc_create(conn->scpool); + conn->tmp_bb = apr_brigade_create(conn->scpool, bucket_alloc); /* * The socket is now open, create a new backend server connection */