|
|
a4f3a1 |
diff --git a/include/http_connection.h b/include/http_connection.h
|
|
|
a4f3a1 |
index 2192507..924ddda 100644
|
|
|
a4f3a1 |
--- a/include/http_connection.h
|
|
|
a4f3a1 |
+++ b/include/http_connection.h
|
|
|
a4f3a1 |
@@ -47,9 +47,18 @@ extern "C" {
|
|
|
a4f3a1 |
*/
|
|
|
a4f3a1 |
AP_CORE_DECLARE(void) ap_process_connection(conn_rec *c, void *csd);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+/**
|
|
|
a4f3a1 |
+ * Shutdown the connection for writing.
|
|
|
a4f3a1 |
+ * @param c The connection to shutdown
|
|
|
a4f3a1 |
+ * @param flush Whether or not to flush pending data before
|
|
|
a4f3a1 |
+ * @return APR_SUCCESS or the underlying error
|
|
|
a4f3a1 |
+ */
|
|
|
a4f3a1 |
+AP_CORE_DECLARE(apr_status_t) ap_shutdown_conn(conn_rec *c, int flush);
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
/**
|
|
|
a4f3a1 |
* Flushes all remain data in the client send buffer
|
|
|
a4f3a1 |
* @param c The connection to flush
|
|
|
a4f3a1 |
+ * @remark calls ap_shutdown_conn(c, 1)
|
|
|
a4f3a1 |
*/
|
|
|
a4f3a1 |
AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
|
|
|
a4f3a1 |
index 8be833a..6c79a1a 100644
|
|
|
a4f3a1 |
--- a/modules/proxy/proxy_util.c
|
|
|
a4f3a1 |
+++ b/modules/proxy/proxy_util.c
|
|
|
a4f3a1 |
@@ -2886,6 +2886,33 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+static apr_status_t connection_shutdown(void *theconn)
|
|
|
a4f3a1 |
+{
|
|
|
a4f3a1 |
+ proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
|
|
|
a4f3a1 |
+ conn_rec *c = conn->connection;
|
|
|
a4f3a1 |
+ if (c) {
|
|
|
a4f3a1 |
+ if (!c->aborted) {
|
|
|
a4f3a1 |
+ apr_interval_time_t saved_timeout = 0;
|
|
|
a4f3a1 |
+ apr_socket_timeout_get(conn->sock, &saved_timeout);
|
|
|
a4f3a1 |
+ if (saved_timeout) {
|
|
|
a4f3a1 |
+ apr_socket_timeout_set(conn->sock, 0);
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ (void)ap_shutdown_conn(c, 0);
|
|
|
a4f3a1 |
+ c->aborted = 1;
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ if (saved_timeout) {
|
|
|
a4f3a1 |
+ apr_socket_timeout_set(conn->sock, saved_timeout);
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02642)
|
|
|
a4f3a1 |
+ "proxy: connection shutdown");
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+ return APR_SUCCESS;
|
|
|
a4f3a1 |
+}
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
|
|
|
a4f3a1 |
proxy_conn_rec *conn,
|
|
|
a4f3a1 |
conn_rec *c,
|
|
|
a4f3a1 |
@@ -2958,6 +2985,11 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
apr_socket_timeout_set(conn->sock, current_timeout);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
+ /* Shutdown the connection before closing it (eg. SSL connections
|
|
|
a4f3a1 |
+ * need to be close-notify-ed).
|
|
|
a4f3a1 |
+ */
|
|
|
a4f3a1 |
+ apr_pool_pre_cleanup_register(conn->scpool, conn, connection_shutdown);
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
return OK;
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c
|
|
|
a4f3a1 |
index fbd701f..a8778d4 100644
|
|
|
a4f3a1 |
--- a/modules/ssl/ssl_util_ssl.c
|
|
|
a4f3a1 |
+++ b/modules/ssl/ssl_util_ssl.c
|
|
|
a4f3a1 |
@@ -166,6 +166,7 @@ int SSL_smart_shutdown(SSL *ssl)
|
|
|
a4f3a1 |
{
|
|
|
a4f3a1 |
int i;
|
|
|
a4f3a1 |
int rc;
|
|
|
a4f3a1 |
+ int flush;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
/*
|
|
|
a4f3a1 |
* Repeat the calls, because SSL_shutdown internally dispatches through a
|
|
|
a4f3a1 |
@@ -175,8 +176,20 @@ int SSL_smart_shutdown(SSL *ssl)
|
|
|
a4f3a1 |
* connection and OpenSSL cannot recognize it.
|
|
|
a4f3a1 |
*/
|
|
|
a4f3a1 |
rc = 0;
|
|
|
a4f3a1 |
+ flush = !(SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN);
|
|
|
a4f3a1 |
for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) {
|
|
|
a4f3a1 |
- if ((rc = SSL_shutdown(ssl)))
|
|
|
a4f3a1 |
+ rc = SSL_shutdown(ssl);
|
|
|
a4f3a1 |
+ if (rc >= 0 && flush && (SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN)) {
|
|
|
a4f3a1 |
+ /* Once the close notity is sent through the output filters,
|
|
|
a4f3a1 |
+ * ensure it is flushed through the socket.
|
|
|
a4f3a1 |
+ */
|
|
|
a4f3a1 |
+ if (BIO_flush(SSL_get_wbio(ssl)) <= 0) {
|
|
|
a4f3a1 |
+ rc = -1;
|
|
|
a4f3a1 |
+ break;
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+ flush = 0;
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
+ if (rc != 0)
|
|
|
a4f3a1 |
break;
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
return rc;
|
|
|
a4f3a1 |
diff --git a/server/connection.c b/server/connection.c
|
|
|
a4f3a1 |
index 6e4495f..4942c77 100644
|
|
|
a4f3a1 |
--- a/server/connection.c
|
|
|
a4f3a1 |
+++ b/server/connection.c
|
|
|
a4f3a1 |
@@ -64,22 +64,32 @@ AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c, void *csd),(c, csd),O
|
|
|
a4f3a1 |
#define MAX_SECS_TO_LINGER 30
|
|
|
a4f3a1 |
#endif
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
-AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c)
|
|
|
a4f3a1 |
+AP_CORE_DECLARE(apr_status_t) ap_shutdown_conn(conn_rec *c, int flush)
|
|
|
a4f3a1 |
{
|
|
|
a4f3a1 |
+ apr_status_t rv;
|
|
|
a4f3a1 |
apr_bucket_brigade *bb;
|
|
|
a4f3a1 |
apr_bucket *b;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
bb = apr_brigade_create(c->pool, c->bucket_alloc);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
- /* FLUSH bucket */
|
|
|
a4f3a1 |
- b = apr_bucket_flush_create(c->bucket_alloc);
|
|
|
a4f3a1 |
- APR_BRIGADE_INSERT_TAIL(bb, b);
|
|
|
a4f3a1 |
+ if (flush) {
|
|
|
a4f3a1 |
+ /* FLUSH bucket */
|
|
|
a4f3a1 |
+ b = apr_bucket_flush_create(c->bucket_alloc);
|
|
|
a4f3a1 |
+ APR_BRIGADE_INSERT_TAIL(bb, b);
|
|
|
a4f3a1 |
+ }
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
/* End Of Connection bucket */
|
|
|
a4f3a1 |
b = ap_bucket_eoc_create(c->bucket_alloc);
|
|
|
a4f3a1 |
APR_BRIGADE_INSERT_TAIL(bb, b);
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
- ap_pass_brigade(c->output_filters, bb);
|
|
|
a4f3a1 |
+ rv = ap_pass_brigade(c->output_filters, bb);
|
|
|
a4f3a1 |
+ apr_brigade_destroy(bb);
|
|
|
a4f3a1 |
+ return rv;
|
|
|
a4f3a1 |
+}
|
|
|
a4f3a1 |
+
|
|
|
a4f3a1 |
+AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c)
|
|
|
a4f3a1 |
+{
|
|
|
a4f3a1 |
+ (void)ap_shutdown_conn(c, 1);
|
|
|
a4f3a1 |
}
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
/* we now proceed to read from the client until we get EOF, or until
|
|
|
a4f3a1 |
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c
|
|
|
a4f3a1 |
index 5852685..defa109 100644
|
|
|
a4f3a1 |
--- a/server/mpm/event/event.c
|
|
|
a4f3a1 |
+++ b/server/mpm/event/event.c
|
|
|
a4f3a1 |
@@ -841,6 +841,7 @@ static int start_lingering_close_nonblocking(event_conn_state_t *cs)
|
|
|
a4f3a1 |
apr_socket_t *csd = cs->pfd.desc.s;
|
|
|
a4f3a1 |
|
|
|
a4f3a1 |
if (c->aborted
|
|
|
a4f3a1 |
+ || ap_shutdown_conn(c, 0) != APR_SUCCESS || c->aborted
|
|
|
a4f3a1 |
|| apr_socket_shutdown(csd, APR_SHUTDOWN_WRITE) != APR_SUCCESS) {
|
|
|
a4f3a1 |
apr_socket_close(csd);
|
|
|
a4f3a1 |
apr_pool_clear(cs->p);
|