>-----Original Message-----
>From: Joe Orton [mailto:[EMAIL PROTECTED]
[SNIP]
>
>This is just back to what we had patches for already: doing an SSL
>shutdown on any EOF bucket, right? Which is not right since you get an
>EOS after each HTTP response, not at the end of the connection.
>
>Hence the need for a new bucket type to represent end-of-connection
>differently from EOS.
>
>(the test case for that is to see if you can send two requests on a
>single SSL connection)
Okay - since I've not played much with buckets, here's my first attempt at getting
something to work - please let me know if it's okay.
Logic:
-> When ap_flush_conn() is called (always before apr_socket_close()), create a EOC
bucket and pass it on
-> In the SSL (output) filter, invoke SSL_shutdown but don't free the SSL context as
it's required for the flush that happens later
-> ssl_filter_io_shutdown() takes a extra flag for freeing the SSL context (when a EOC
is received, it just sends the SSL_shutdown but doesn't do the free)
Patch:
-------------------------------------------------------------------------------
NEW FILE: apr-util/buckets/apr_buckets_eoc.c
-------------------------------------------------------------------------------
#include "apr_buckets.h"
static apr_status_t eoc_bucket_read(apr_bucket *b, const char **str,
apr_size_t *len, apr_read_type_e block)
{
*str = NULL;
*len = 0;
return APR_SUCCESS;
}
APU_DECLARE(apr_bucket *) apr_bucket_eoc_make(apr_bucket *b)
{
b->length = 0;
b->start = 0;
b->data = NULL;
b->type = &apr_bucket_type_eoc;
return b;
}
APU_DECLARE(apr_bucket *) apr_bucket_eoc_create(apr_bucket_alloc_t *list)
{
apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
APR_BUCKET_INIT(b);
b->free = apr_bucket_free;
b->list = list;
return apr_bucket_eoc_make(b);
}
APU_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_eoc = {
"EOC", 5, APR_BUCKET_METADATA,
apr_bucket_destroy_noop,
eoc_bucket_read,
apr_bucket_setaside_noop,
apr_bucket_split_notimpl,
apr_bucket_simple_copy
};
-------------------------------------------------------------------------------
END of apr_buckets_eoc.c
-------------------------------------------------------------------------------
Index: apr-util/include/apr_buckets.h
===================================================================
RCS file: /home/cvspublic/apr-util/include/apr_buckets.h,v
retrieving revision 1.156
diff -u -r1.156 apr_buckets.h
--- apr_buckets.h 13 Feb 2004 09:55:26 -0000 1.156
+++ apr_buckets.h 24 Feb 2004 17:46:31 -0000
@@ -453,6 +453,12 @@
*/
#define APR_BUCKET_IS_FLUSH(e) ((e)->type == &apr_bucket_type_flush)
/**
+ * Determine if a bucket is an End Of Connection (EOC) bucket
+ * @param e The bucket to inspect
+ * @return true or false
+ */
+#define APR_BUCKET_IS_EOC(e) ((e)->type == &apr_bucket_type_eoc)
+/**
* Determine if a bucket is an EOS bucket
* @param e The bucket to inspect
* @return true or false
@@ -1056,6 +1062,11 @@
*/
APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_flush;
/**
+ * The End Of Connection (EOC) bucket type. This signifies that the
+ * connection will be closed.
+ */
+APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_eoc;
+/**
* The EOS bucket type. This signifies that there will be no more data, ever.
* All filters MUST send all data to the next filter when they receive a
* bucket of this type
@@ -1202,6 +1213,21 @@
* other code should call apr_bucket_foo_create. All the initialization
* functions change nothing if they fail.
*/
+
+/**
+ * Create an End of Connection (EOC) bucket. This indicates that the
+ * connection will be closed.
+ * @param list The freelist from which this bucket should be allocated
+ * @return The new bucket, or NULL if allocation failed
+ */
+APU_DECLARE(apr_bucket *) apr_bucket_eoc_create(apr_bucket_alloc_t *list);
+
+/**
+ * Make the bucket passed in an End Of Connection (EOC) bucket.
+ * @param b The bucket to make into an EOC bucket
+ * @return The new bucket, or NULL if allocation failed
+ */
+APU_DECLARE(apr_bucket *) apr_bucket_eoc_make(apr_bucket *b);
/**
* Create an End of Stream bucket. This indicates that there is no more data
Index: httpd-2.0/server/connection.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/connection.c,v
retrieving revision 1.111
diff -u -r1.111 connection.c
--- server/connection.c 1 Jan 2004 13:26:23 -0000 1.111
+++ server/connection.c 24 Feb 2004 17:24:27 -0000
@@ -108,10 +108,23 @@
#define MAX_SECS_TO_LINGER 30
#endif
+AP_CORE_DECLARE(void) ap_end_connection(conn_rec *c)
+{
+ apr_bucket_brigade *bb;
+ apr_bucket *b;
+
+ bb = apr_brigade_create(c->pool, c->bucket_alloc);
+ b = apr_bucket_eoc_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ ap_pass_brigade(c->output_filters, bb);
+}
+
AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c)
{
apr_bucket_brigade *bb;
apr_bucket *b;
+
+ ap_end_connection(c);
bb = apr_brigade_create(c->pool, c->bucket_alloc);
b = apr_bucket_flush_create(c->bucket_alloc);
Index: httpd-2.0/modules/ssl/ssl_engine_io.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/ssl/ssl_engine_io.c,v
retrieving revision 1.117
diff -u -r1.117 ssl_engine_io.c
--- modules/ssl/ssl_engine_io.c 9 Feb 2004 20:29:22 -0000 1.117
+++ modules/ssl/ssl_engine_io.c 24 Feb 2004 17:24:44 -0000
@@ -872,7 +872,8 @@
*/
static apr_status_t ssl_filter_io_shutdown(ssl_filter_ctx_t *filter_ctx,
conn_rec *c,
- int abortive)
+ int abortive,
+ int shutdown_flag)
{
SSL *ssl = filter_ctx->pssl;
const char *type = "";
@@ -951,6 +952,9 @@
SSL_set_shutdown(ssl, shutdown_type);
SSL_smart_shutdown(ssl);
+ if (!shutdown_flag)
+ return APR_SUCCESS;
+
/* and finally log the fact that we've closed the connection */
if (c->base_server->loglevel >= APLOG_INFO) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server,
@@ -990,7 +994,7 @@
}
c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl);
- if ((ret = ssl_filter_io_shutdown(filter_ctx, c, 0)) != APR_SUCCESS) {
+ if ((ret = ssl_filter_io_shutdown(filter_ctx, c, 0, 1)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_INFO, ret, NULL,
"SSL filter error shutting down I/O");
}
@@ -1025,7 +1029,7 @@
c->base_server,
"SSL Proxy connect failed");
ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
- return ssl_filter_io_shutdown(filter_ctx, c, 1);
+ return ssl_filter_io_shutdown(filter_ctx, c, 1, 1);
}
return APR_SUCCESS;
@@ -1089,7 +1093,7 @@
inctx->rc = APR_EGENERAL;
}
- return ssl_filter_io_shutdown(filter_ctx, c, 1);
+ return ssl_filter_io_shutdown(filter_ctx, c, 1, 1);
}
/*
@@ -1130,7 +1134,7 @@
error ? error : "unknown");
ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
- return ssl_filter_io_shutdown(filter_ctx, c, 1);
+ return ssl_filter_io_shutdown(filter_ctx, c, 1, 1);
}
}
@@ -1155,7 +1159,7 @@
ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server,
"No acceptable peer certificate available");
- return ssl_filter_io_shutdown(filter_ctx, c, 1);
+ return ssl_filter_io_shutdown(filter_ctx, c, 1, 1);
}
return APR_SUCCESS;
@@ -1369,7 +1373,8 @@
/* If it is a flush or EOS, we need to pass this down.
* These types do not require translation by OpenSSL.
*/
- if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {
+ if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket) ||
+ APR_BUCKET_IS_EOC(bucket)) {
if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) {
status = outctx->rc;
break;
@@ -1387,6 +1392,10 @@
return status;
}
break;
+ }
+ else if (APR_BUCKET_IS_EOC(bucket)) {
+ ssl_filter_io_shutdown(filter_ctx, f->c, 0, 0);
+ apr_bucket_delete(bucket);
}
else {
/* bio_filter_out_flush() already passed down a flush bucket