You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by yl...@apache.org on 2021/09/24 15:52:51 UTC

svn commit: r1893603 - in /httpd/httpd/trunk: changes-entries/tunnel_forward_hook.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.c modules/proxy/mod_proxy.h modules/proxy/proxy_util.c

Author: ylavic
Date: Fri Sep 24 15:52:50 2021
New Revision: 1893603

URL: http://svn.apache.org/viewvc?rev=1893603&view=rev
Log:
mod_proxy: Add tunnel_forward hook.

* modules/proxy/mod_proxy.h, modules/proxy/mod_proxy.c:
  Declare/implement the hook.

* modules/proxy/proxy_util.c(proxy_transfer):
  Run tunnel_forward hooks when called by the tunneling loop.
  Simpler input/output brigade cleanup on exit.


Added:
    httpd/httpd/trunk/changes-entries/tunnel_forward_hook.txt
Modified:
    httpd/httpd/trunk/docs/log-message-tags/next-number
    httpd/httpd/trunk/modules/proxy/mod_proxy.c
    httpd/httpd/trunk/modules/proxy/mod_proxy.h
    httpd/httpd/trunk/modules/proxy/proxy_util.c

Added: httpd/httpd/trunk/changes-entries/tunnel_forward_hook.txt
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/changes-entries/tunnel_forward_hook.txt?rev=1893603&view=auto
==============================================================================
--- httpd/httpd/trunk/changes-entries/tunnel_forward_hook.txt (added)
+++ httpd/httpd/trunk/changes-entries/tunnel_forward_hook.txt Fri Sep 24 15:52:50 2021
@@ -0,0 +1,2 @@
+  *) mod_proxy: New tunnel_forward hooking mechanism allowing modules to handle
+     Upgrade(d) protocols data.  [Yann Ylavic]
\ No newline at end of file

Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1893603&r1=1893602&r2=1893603&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
+++ httpd/httpd/trunk/docs/log-message-tags/next-number Fri Sep 24 15:52:50 2021
@@ -1 +1 @@
-10295
+10297

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.c?rev=1893603&r1=1893602&r2=1893603&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.c Fri Sep 24 15:52:50 2021
@@ -3474,6 +3474,7 @@ APR_HOOK_STRUCT(
     APR_HOOK_LINK(post_request)
     APR_HOOK_LINK(request_status)
     APR_HOOK_LINK(check_trans)
+    APR_HOOK_LINK(tunnel_forward)
 )
 
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, scheme_handler,
@@ -3517,3 +3518,9 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(prox
 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, detach_backend,
                                     (request_rec *r, proxy_conn_rec *backend),
                                     (r, backend), OK, DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(proxy, PROXY, int, tunnel_forward,
+                                    (proxy_tunnel_rec *tunnel,
+                                     conn_rec *c_i, conn_rec *c_o,
+                                     apr_bucket_brigade *bb),
+                                    (tunnel, c_i, c_o, bb),
+                                    OK, DECLINED)

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.h?rev=1893603&r1=1893602&r2=1893603&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.h (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.h Fri Sep 24 15:52:50 2021
@@ -1400,6 +1400,24 @@ PROXY_DECLARE(apr_off_t) ap_proxy_tunnel
                                 const proxy_tunnel_conn_t *tc);
 
 /**
+ * Tunnel forwarding hook
+ * Called for every brigade forwarded by a tunnel from/to the client to/from
+ * the origin. Each hook receives incoming buckets in bb and produces outgoing
+ * buckets in the same bb, much like an output filter.
+ * @param tunnel   the tunnel
+ * @param c        the connection the data are going to
+ * @param bb       the incoming data
+ * @return         OK/DECLINED to pass to the next hooks, DONE to not pass to
+ *                 the next hooks, an HTTP_ error on failure.
+ * @note A hook must not return DONE unless it consumes/sets-aside *all* the
+ *       incoming buckets, and it must produce (non-meta-)data buckets only.
+ */
+PROXY_DECLARE_OPTIONAL_HOOK(proxy, PROXY, int, tunnel_forward,
+                            (proxy_tunnel_rec *tunnel,
+                             conn_rec *c_i, conn_rec *c_o,
+                             apr_bucket_brigade *bb))
+
+/**
  * Clear the headers referenced by the Connection header from the given
  * table, and remove the Connection header.
  * @param r request

Modified: httpd/httpd/trunk/modules/proxy/proxy_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c?rev=1893603&r1=1893602&r2=1893603&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/proxy_util.c (original)
+++ httpd/httpd/trunk/modules/proxy/proxy_util.c Fri Sep 24 15:52:50 2021
@@ -4531,7 +4531,8 @@ static apr_status_t proxy_transfer(reque
                                    apr_off_t bsize,
                                    int flags,
                                    apr_off_t *bytes_in,
-                                   apr_off_t *bytes_out)
+                                   apr_off_t *bytes_out,
+                                   proxy_tunnel_rec *tunnel)
 {
     apr_status_t rv;
     int flush_each = 0;
@@ -4557,8 +4558,7 @@ static apr_status_t proxy_transfer(reque
         if (rv != APR_SUCCESS) {
             if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) {
                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(03308)
-                              "proxy_transfer: error on %s - ap_get_brigade",
-                              name);
+                              "proxy_transfer: can't get data from %s", name);
                 if (rv == APR_INCOMPLETE) {
                     /* Don't return APR_INCOMPLETE, it'd mean "should yield"
                      * for the caller, while it means "incomplete body" here
@@ -4569,25 +4569,62 @@ static apr_status_t proxy_transfer(reque
             }
             break;
         }
-
         if (c_o->aborted) {
-            apr_brigade_cleanup(bb_i);
-            flags &= ~AP_PROXY_TRANSFER_FLUSH_AFTER;
             rv = APR_EPIPE;
             break;
         }
         if (APR_BRIGADE_EMPTY(bb_i)) {
             break;
         }
+
         len = -1;
         apr_brigade_length(bb_i, 0, &len);
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03306)
-                      "proxy_transfer: read %" APR_OFF_T_FMT " bytes "
-                      "of %s", len, name);
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+                      "proxy_transfer: got %" APR_OFF_T_FMT " bytes "
+                      "from %s", len, name);
         if (bytes_in && len > 0) {
             *bytes_in += len;
         }
-        ap_proxy_buckets_lifetime_transform(r, bb_i, bb_o);
+
+        rv = ap_proxy_buckets_lifetime_transform(r, bb_i, bb_o);
+        if (rv != APR_SUCCESS) {
+            break;
+        }
+
+        if (tunnel) {
+            int rc = proxy_run_tunnel_forward(tunnel, c_i, c_o, bb_o);
+            if (rc != OK && rc != DONE) {
+                if (!ap_is_HTTP_ERROR(rc)) {
+                    /* SUSPENDED is not allowed for now */
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10295)
+                                  "proxy: %s: invalid status %d returned by "
+                                  "tunnel forward hooks", tunnel->scheme, rc);
+                }
+                rv = APR_EGENERAL;
+                break;
+            }
+            if (APR_BRIGADE_EMPTY(bb_o)) {
+                /* Buckets retained by the hooks, next. */
+                continue;
+            }
+            if (rc == DONE) {
+                /* DONE with data is invalid because it'd mean that the next
+                 * hooks wouldn't have a chance to see the data, hence no hook
+                 * would be able to retain data.
+                 */
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10296)
+                              "proxy: %s: invalid return value from tunnel "
+                              " forward hook", tunnel->scheme);
+                rv = APR_EGENERAL;
+                break;
+            }
+
+            len = -1;
+            apr_brigade_length(bb_o, 0, &len);
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+                          "proxy_transfer: forward %" APR_OFF_T_FMT " bytes "
+                          "from %s", len, name);
+        }
         if (bytes_out && len > 0) {
             *bytes_out += len;
         }
@@ -4612,14 +4649,14 @@ static apr_status_t proxy_transfer(reque
             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) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(03307)
-                          "proxy_transfer: error on %s - ap_pass_brigade",
-                          name);
+                          "proxy_transfer: can't pass %" APR_OFF_T_FMT
+                          " bytes from %s", len, name);
             flags &= ~AP_PROXY_TRANSFER_FLUSH_AFTER;
             break;
         }
+        apr_brigade_cleanup(bb_o);
 
         /* Yield if the output filters stack is full? This is to avoid
          * blocking and give the caller a chance to POLLOUT async.
@@ -4644,11 +4681,14 @@ static apr_status_t proxy_transfer(reque
         }
     }
 
-    if (flags & AP_PROXY_TRANSFER_FLUSH_AFTER) {
+    /* bb_o first to avoid protential dangling buckets (transient) */
+    apr_brigade_cleanup(bb_o);
+    apr_brigade_cleanup(bb_i);
+
+    if ((flags & AP_PROXY_TRANSFER_FLUSH_AFTER) && !c_o->aborted) {
         ap_fflush(c_o->output_filters, bb_o);
         apr_brigade_cleanup(bb_o);
     }
-    apr_brigade_cleanup(bb_i);
 
     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r,
                   "proxy_transfer complete (%s %pI)",
@@ -4675,7 +4715,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_tra
 {
     apr_off_t bytes_out = 0;
     apr_status_t rv = proxy_transfer(r, c_i, c_o, bb_i, bb_o, name, bsize,
-                                     flags, NULL, &bytes_out);
+                                     flags, NULL, &bytes_out, NULL);
     if (sent && bytes_out > 0) {
         *sent = 1;
     }
@@ -4853,7 +4893,8 @@ static int proxy_tunnel_transfer(proxy_t
                         in->name, tunnel->read_buf_size,
                         AP_PROXY_TRANSFER_YIELD_PENDING |
                         AP_PROXY_TRANSFER_YIELD_MAX_READS,
-                        &in->bytes_in, &out->bytes_out);
+                        &in->bytes_in, &out->bytes_out,
+                        tunnel);
     if (rv != APR_SUCCESS) {
         if (APR_STATUS_IS_INCOMPLETE(rv)) {
             /* Pause POLLIN while waiting for POLLOUT on the other