>-----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