From bd49c01685ccf2b857b3fe0f04236221a74d7d6d Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Sat, 8 Dec 2007 20:10:29 +0000 Subject: [PATCH] * Enable the proxy to keep connections persistent in the HTTPS case. Basicly the persistence is created by keeping the conn_rec structure created for our backend connection (whether http or https) in the connection pool. This required to adjust scoreboard.c in a way that its functions can properly deal with a NULL scoreboard handle by ignoring the call or returning an error code. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@602542 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 ++ include/ap_mmn.h | 3 +- modules/proxy/mod_proxy.h | 2 + modules/proxy/mod_proxy_http.c | 12 ++--- modules/proxy/proxy_util.c | 86 +++++++++++++++++++++++++--------- server/scoreboard.c | 12 +++++ 6 files changed, 88 insertions(+), 30 deletions(-) diff --git a/CHANGES b/CHANGES index a244320159..8e168b3d1c 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ Changes with Apache 2.3.0 [ When backported to 2.2.x, remove entry from this file ] + *) mod_proxy: Keep connections to the backend persistent in the HTTPS case. + [Ruediger Pluem] + *) rotatelogs: Improve atomicity when using -l and cleaup code. PR 44004 [Rainer Jung] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 6238a84c41..24346cb084 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -143,6 +143,7 @@ * 20071108.2 (2.3.0-dev) Add st and keep fields to struct util_ldap_connection_t * 20071108.3 (2.3.0-dev) Add API guarantee for adding connection filters * with non-NULL request_rec pointer (ap_add_*_filter*) + * 20071108.4 (2.3.0-dev) Add ap_proxy_ssl_connection_cleanup */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -150,7 +151,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20071108 #endif -#define MODULE_MAGIC_NUMBER_MINOR 3 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 4 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index da2b5a7053..27ac89f2d9 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -483,6 +483,8 @@ PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key); /* 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 *, server_rec *, apr_pool_t *); +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); PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c); PROXY_DECLARE(int) ap_proxy_conn_is_https(conn_rec *c); diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 16a557a7e4..b174af2f86 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -1824,14 +1824,10 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, backend->is_ssl = is_ssl; - /* - * TODO: Currently we cannot handle persistent SSL backend connections, - * because we recreate backend->connection for each request and thus - * try to initialize an already existing SSL connection. This does - * not work. - */ - if (is_ssl) - backend->close = 1; + + if (is_ssl) { + ap_proxy_ssl_connection_cleanup(backend, r); + } /* Step One: Determine Who To Connect To */ if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 0b1d1f300c..91f8385253 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1599,6 +1599,9 @@ static apr_status_t connection_cleanup(void *theconn) /* determine if the connection need to be closed */ if (conn->close) { apr_pool_t *p = conn->pool; + if (conn->connection) { + apr_pool_cleanup_kill(conn->pool, conn, connection_cleanup); + } apr_pool_clear(conn->pool); memset(conn, 0, sizeof(proxy_conn_rec)); conn->pool = p; @@ -1619,6 +1622,54 @@ static apr_status_t connection_cleanup(void *theconn) return APR_SUCCESS; } +static apr_status_t socket_cleanup(proxy_conn_rec *conn) +{ + if (conn->sock) { + apr_socket_close(conn->sock); + conn->sock = NULL; + } + if (conn->connection) { + apr_pool_cleanup_kill(conn->pool, conn, connection_cleanup); + conn->connection = NULL; + } + return APR_SUCCESS; +} + +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; + + /* + * If we have an existing SSL connection it might be possible that the + * server sent some SSL message we have not read so far (e.g. a SSL + * shutdown message if the server closed the keepalive connection while + * the connection was held unused in our pool). + * So ensure that if present (=> APR_NONBLOCK_READ) it is read and + * 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, + 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)) { + apr_off_t len; + + rv = apr_brigade_length(bb, 0, &len); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, + "proxy: SSL cleanup brigade contained %" + APR_OFF_T_FMT " bytes of data.", len); + } + apr_brigade_destroy(bb); + } + return APR_SUCCESS; +} + /* reslist constructor */ static apr_status_t connection_constructor(void **resource, void *params, apr_pool_t *pool) @@ -1895,11 +1946,6 @@ PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: has released connection for (%s)", proxy_function, conn->worker->hostname); - /* If there is a connection kill it's cleanup */ - if (conn->connection) { - apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup); - conn->connection = NULL; - } connection_cleanup(conn); return OK; @@ -1972,14 +2018,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, conn->hostname = apr_pstrdup(conn->pool, uri->hostname); conn->port = uri->port; } - if (conn->sock) { - apr_socket_close(conn->sock); - conn->sock = NULL; - } - if (conn->connection) { - apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup); - conn->connection = NULL; - } + socket_cleanup(conn); err = apr_sockaddr_info_get(&(conn->addr), conn->hostname, APR_UNSPEC, conn->port, 0, @@ -2131,8 +2170,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, * relatively small compared to connection lifetime */ if (!(connected = is_socket_connected(conn->sock))) { - apr_socket_close(conn->sock); - conn->sock = NULL; + socket_cleanup(conn); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: backend socket is disconnected.", proxy_function); @@ -2156,6 +2194,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, backend_addr = backend_addr->next; continue; } + conn->connection = NULL; #if !defined(TPF) && !defined(BEOS) if (worker->recv_buffer_size > 0 && @@ -2245,13 +2284,19 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, apr_sockaddr_t *backend_addr = conn->addr; int rc; apr_interval_time_t current_timeout; + apr_bucket_alloc_t *bucket_alloc; + if (conn->connection) { + return OK; + } + + bucket_alloc = apr_bucket_alloc_create(conn->pool); /* * The socket is now open, create a new backend server connection */ - conn->connection = ap_run_create_connection(c->pool, s, conn->sock, - c->id, c->sbh, - c->bucket_alloc); + conn->connection = ap_run_create_connection(conn->pool, s, conn->sock, + 0, NULL, + bucket_alloc); if (!conn->connection) { /* @@ -2263,15 +2308,14 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, "new connection to %pI (%s)", proxy_function, backend_addr, conn->hostname); /* XXX: Will be closed when proxy_conn is closed */ - apr_socket_close(conn->sock); - conn->sock = NULL; + socket_cleanup(conn); return HTTP_INTERNAL_SERVER_ERROR; } /* * register the connection cleanup to client connection * so that the connection can be closed or reused */ - apr_pool_cleanup_register(c->pool, (void *)conn, + apr_pool_cleanup_register(conn->pool, (void *)conn, connection_cleanup, apr_pool_cleanup_null); diff --git a/server/scoreboard.c b/server/scoreboard.c index 3b7b9a29fb..ae834dcd9c 100644 --- a/server/scoreboard.c +++ b/server/scoreboard.c @@ -352,6 +352,9 @@ AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r) { worker_score *ws; + if (!sb) + return; + ws = &ap_scoreboard_image->servers[sb->child_num][sb->thread_num]; #ifdef HAVE_TIMES @@ -479,6 +482,9 @@ AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, AP_DECLARE(int) ap_update_child_status(ap_sb_handle_t *sbh, int status, request_rec *r) { + if (!sbh) + return -1; + return ap_update_child_status_from_indexes(sbh->child_num, sbh->thread_num, status, r); } @@ -487,6 +493,9 @@ AP_DECLARE(void) ap_time_process_request(ap_sb_handle_t *sbh, int status) { worker_score *ws; + if (!sbh) + return; + if (sbh->child_num < 0) { return; } @@ -512,6 +521,9 @@ AP_DECLARE(worker_score *) ap_get_scoreboard_worker_from_indexes(int x, int y) AP_DECLARE(worker_score *) ap_get_scoreboard_worker(ap_sb_handle_t *sbh) { + if (!sbh) + return NULL; + return ap_get_scoreboard_worker_from_indexes(sbh->child_num, sbh->thread_num); } -- 2.40.0