]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
core: Write Completion (WC) bucket type.
authorYann Ylavic <ylavic@apache.org>
Tue, 29 Jun 2021 21:16:21 +0000 (21:16 +0000)
committerYann Ylavic <ylavic@apache.org>
Tue, 29 Jun 2021 21:16:21 +0000 (21:16 +0000)
A WC bucket is meant to prevent buffering/coalescing filters from retaining
data, but unlike a FLUSH bucket it won't cause the core output filter to
block trying to flush anything before.

It can be passed by async handlers which want to never block, followed by
ap_filter_should_yield() to check for pending data and eventually suspend
processing until MPM/asynchronous write completion finishes.

In this commit it's used that way by the tunneling loop of mod_proxy to
prevent SSL coaslescing.

gh: closes #200

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1891148 13f79535-47bb-0310-9956-ffa450edef68

include/ap_mmn.h
include/util_filter.h
modules/proxy/proxy_util.c
server/util_filter.c

index eccfce1e963c02d0a1c148e244d6b9dd3458d499..fee4381383a176a771f3443bcc8423ce8347a3ce 100644 (file)
  *                         ap_proxy_tunnel_conn_get_transferred() change
  *                         ap_proxy_transfer_between_connections() sent to apr_off_t *.
  * 20210531.0 (2.5.1-dev)  add conn_rec->outgoing and ap_ssl_bind_outgoing()
+ * 20210531.1 (2.5.1-dev)  Add ap_bucket_type_wc, ap_bucket_wc_make() and
+ *                         ap_bucket_wc_create() to util_filter.h
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20210531
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 0             /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 1             /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index 34264d71da998f1fe55b9708372e51ebf4806d0b..a0205a5f5cd8f355ec24fdcca6042e837bd83a74 100644 (file)
@@ -763,6 +763,30 @@ AP_DECLARE(void) ap_filter_protocol(ap_filter_t* f, unsigned int proto_flags);
 /** Filter is incompatible with "Cache-Control: no-transform" */
 #define AP_FILTER_PROTO_TRANSFORM 0x20
 
+/** Write Completion (WC) bucket */
+AP_DECLARE_DATA extern const apr_bucket_type_t ap_bucket_type_wc;
+
+/**
+ * Determine if a bucket is a Write Completion (WC) bucket
+ * @param e The bucket to inspect
+ * @return true or false
+ */
+#define AP_BUCKET_IS_WC(e) ((e)->type == &ap_bucket_type_wc)
+
+/**
+ * Make the bucket passed in a Write Completion (WC) bucket
+ * @param b The bucket to make into a WC bucket
+ * @return The new bucket, or NULL if allocation failed
+ */
+AP_DECLARE(apr_bucket *) ap_bucket_wc_make(apr_bucket *b);
+
+/**
+ * Create a bucket referring to a Write Completion (WC).
+ * @param list The freelist from which this bucket should be allocated
+ * @return The new bucket, or NULL if allocation failed
+ */
+AP_DECLARE(apr_bucket *) ap_bucket_wc_create(apr_bucket_alloc_t *list);
+
 /**
  * @}
  */
index 6b896408eafa98fe2c26b24d369d83599da69bfc..d16d47863b2bad47b52d9dc5282c293d50416ce5 100644 (file)
@@ -4412,6 +4412,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
     int flush_each = 0;
     unsigned int num_reads = 0;
     apr_off_t len;
+    apr_bucket *b;
 
     /*
      * Compat: since FLUSH_EACH is default (and zero) for legacy reasons, we
@@ -4465,7 +4466,6 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
         }
         ap_proxy_buckets_lifetime_transform(r, bb_i, bb_o);
         if (flush_each) {
-            apr_bucket *b;
             /*
              * Do not use ap_fflush here since this would cause the flush
              * bucket to be sent in a separate brigade afterwards which
@@ -4479,6 +4479,10 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
             b = apr_bucket_flush_create(bb_o->bucket_alloc);
             APR_BRIGADE_INSERT_TAIL(bb_o, b);
         }
+        else {
+            b = ap_bucket_wc_create(bb_o->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(bb_o, b);
+        }
         rv = ap_pass_brigade(c_o->output_filters, bb_o);
         apr_brigade_cleanup(bb_o);
         if (rv != APR_SUCCESS) {
@@ -4493,23 +4497,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections(
         /* Yield if the output filters stack is full? This is to avoid
          * blocking and give the caller a chance to POLLOUT async.
          */
-        if (flags & AP_PROXY_TRANSFER_YIELD_PENDING) {
-            int rc = OK;
-
-            if (!ap_filter_should_yield(c_o->output_filters)) {
-                rc = ap_filter_output_pending(c_o);
-            }
-            if (rc == OK) {
-                ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
-                              "ap_proxy_transfer_between_connections: "
-                              "yield (output pending)");
-                rv = APR_INCOMPLETE;
-                break;
-            }
-            if (rc != DECLINED) {
-                rv = AP_FILTER_ERROR;
-                break;
-            }
+        if ((flags & AP_PROXY_TRANSFER_YIELD_PENDING)
+                && ap_filter_should_yield(c_o->output_filters)) {
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+                          "ap_proxy_transfer_between_connections: "
+                          "yield (output pending)");
+            rv = APR_INCOMPLETE;
+            break;
         }
 
         /* Yield if we keep hold of the thread for too long? This gives
index e012265305c48d258a89f543e523a0d3d46e8edf..ff33bfde2110c33e19f77f24fa208b351dc07b88 100644 (file)
@@ -976,6 +976,12 @@ AP_DECLARE(apr_status_t) ap_filter_setaside_brigade(ap_filter_t *f,
              e = next) {
             next = APR_BUCKET_NEXT(e);
 
+            /* Strip WC buckets added by ap_filter_output_pending(). */
+            if (AP_BUCKET_IS_WC(e)) {
+                apr_bucket_delete(e);
+                continue;
+            }
+
             /* Opaque buckets (length == -1) are moved, so assumed to have
              * next EOR's lifetime or at least the lifetime of the connection.
              */
@@ -1268,7 +1274,10 @@ AP_DECLARE_NONSTD(int) ap_filter_output_pending(conn_rec *c)
         if (!APR_BRIGADE_EMPTY(fp->bb)) {
             ap_filter_t *f = fp->f;
             apr_status_t rv;
+            apr_bucket *b;
 
+            b = ap_bucket_wc_create(bb->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(bb, b);
             rv = ap_pass_brigade(f, bb);
             apr_brigade_cleanup(bb);
 
@@ -1279,8 +1288,7 @@ AP_DECLARE_NONSTD(int) ap_filter_output_pending(conn_rec *c)
                 break;
             }
 
-            if ((fp->bb && !APR_BRIGADE_EMPTY(fp->bb))
-                    || (f->next && ap_filter_should_yield(f->next))) {
+            if (ap_filter_should_yield(f)) {
                 rc = OK;
                 break;
             }
@@ -1391,3 +1399,41 @@ AP_DECLARE(void) ap_filter_protocol(ap_filter_t *f, unsigned int flags)
 {
     f->frec->proto_flags = flags ;
 }
+
+
+static apr_status_t wc_bucket_read(apr_bucket *b, const char **str,
+                                   apr_size_t *len, apr_read_type_e block)
+{
+    *str = NULL;
+    *len = 0;
+    return APR_SUCCESS;
+}
+
+AP_DECLARE(apr_bucket *) ap_bucket_wc_make(apr_bucket *b)
+{
+    b->length = 0;
+    b->start  = 0;
+    b->data   = NULL;
+    b->type   = &ap_bucket_type_wc;
+
+    return b;
+}
+
+AP_DECLARE(apr_bucket *) ap_bucket_wc_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 ap_bucket_wc_make(b);
+}
+
+AP_DECLARE_DATA const apr_bucket_type_t ap_bucket_type_wc = {
+    "WC", 5, APR_BUCKET_METADATA,
+    apr_bucket_destroy_noop,
+    wc_bucket_read,
+    apr_bucket_setaside_noop,
+    apr_bucket_split_notimpl,
+    apr_bucket_simple_copy
+};