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

Reply via email to