From: Ruediger Pluem Date: Thu, 4 Feb 2016 13:41:19 +0000 (+0000) Subject: * Introduce ap_proxy_transfer_between_connections X-Git-Tag: 2.5.0-alpha~2210 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fbf68524d3f4e3bfa4e707b853fef89c8c6ca827;p=apache * Introduce ap_proxy_transfer_between_connections git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1728478 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 3f4ee651cb..09671af22c 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -1175,6 +1175,39 @@ PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r, apr_bucket_brigade *from, apr_bucket_brigade *to); +/* + * Sends all data that can be read non blocking from the input filter chain of + * c_i and send it down the output filter chain of c_o. For reading it uses + * the bucket brigade bb_i which should be created from the bucket allocator + * associated with c_i. For sending through the output filter chain it uses + * the bucket brigade bb_o which should be created from the bucket allocator + * associated with c_o. In order to get the buckets from bb_i to bb_o + * ap_proxy_buckets_lifetime_transform is used. + * + * @param r request_rec of the actual request. Used for logging purposes + * @param c_i inbound connection conn_rec + * @param c_o outbound connection conn_rec + * @param bb_i bucket brigade for pulling data from the inbound connection + * @param bb_o bucket brigade for sending data through the outbound connection + * @param name string for logging from where data was pulled + * @param sent if not NULL will be set to 1 if data was sent through c_o + * @param bsize maximum amount of data pulled in one iteration from c_i + * @param after if set flush data on c_o only once after the loop + * @return apr_status_t of the operation. Could be any error returned from + * either the input filter chain of c_i or the output filter chain + * of c_o. APR_EPIPE if the outgoing connection was aborted. + */ +PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections( + request_rec *r, + conn_rec *c_i, + conn_rec *c_o, + apr_bucket_brigade *bb_i, + apr_bucket_brigade *bb_o, + const char *name, + int *sent, + apr_off_t bsize, + int after); + extern module PROXY_DECLARE_DATA proxy_module; #endif /*MOD_PROXY_H*/ diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 35e67f40d0..92e0c9cd7a 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -3735,6 +3735,90 @@ PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r, return rv; } +PROXY_DECLARE(apr_status_t) ap_proxy_transfer_between_connections( + request_rec *r, + conn_rec *c_i, + conn_rec *c_o, + apr_bucket_brigade *bb_i, + apr_bucket_brigade *bb_o, + const char *name, + int *sent, + apr_off_t bsize, + int after) +{ + apr_status_t rv; +#ifdef DEBUGGING + apr_off_t len; +#endif + + do { + apr_brigade_cleanup(bb_i); + rv = ap_get_brigade(c_i->input_filters, bb_i, AP_MODE_READBYTES, + APR_NONBLOCK_READ, bsize); + if (rv == APR_SUCCESS) { + if (c_o->aborted) { + return APR_EPIPE; + } + if (APR_BRIGADE_EMPTY(bb_i)) { + break; + } +#ifdef DEBUGGING + len = -1; + apr_brigade_length(bb_i, 0, &len); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO() + "ap_proxy_transfer_between_connections: " + "read %" APR_OFF_T_FMT + " bytes from %s", len, name); +#endif + if (sent) { + *sent = 1; + } + ap_proxy_buckets_lifetime_transform(r, bb_i, bb_o); + if (!after) { + 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 + * causes some filters to set aside the buckets from the first + * brigade and process them when the flush arrives in the second + * brigade. As set asides of our transformed buckets involve + * memory copying we try to avoid this. If we have the flush + * bucket in the first brigade they directly process the + * buckets without setting them aside. + */ + b = apr_bucket_flush_create(bb_o->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb_o, b); + } + rv = ap_pass_brigade(c_o->output_filters, bb_o); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO() + "ap_proxy_transfer_between_connections: " + "error on %s - ap_pass_brigade", + name); + } + } else if (!APR_STATUS_IS_EAGAIN(rv) && !APR_STATUS_IS_EOF(rv)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO() + "ap_proxy_transfer_between_connections: " + "error on %s - ap_get_brigade", + name); + } + } while (rv == APR_SUCCESS); + + if (after) { + ap_fflush(c_o->output_filters, bb_o); + } + + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, rv, r, + "ap_proxy_transfer_between_connections complete"); + + if (APR_STATUS_IS_EAGAIN(rv)) { + rv = APR_SUCCESS; + } + + return rv; +} + void proxy_util_register_hooks(apr_pool_t *p) { APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker);