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