On 11/3/19 4:48 PM, yla...@apache.org wrote:
> Author: ylavic
> Date: Sun Nov  3 15:48:53 2019
> New Revision: 1869338
> 
> URL: http://svn.apache.org/viewvc?rev=1869338&view=rev
> Log:
> mod_proxy: factorize mod_proxy_{connect,wstunnel} tunneling code in 
> proxy_util.
> 
> This commit adds struct proxy_tunnel_rec that contains the fields needed for a
> poll() loop through the filters chains, plus functions 
> ap_proxy_tunnel_create()
> and ap_proxy_tunnel_run() to respectively initialize a tunnel and (re)start 
> it.
>  
> Proxy connect and wstunnel modules now make use of this new API to avoid
> duplicating logic and code.
> 
> Modified:
>     httpd/httpd/trunk/CHANGES
>     httpd/httpd/trunk/docs/log-message-tags/next-number
>     httpd/httpd/trunk/include/ap_mmn.h
>     httpd/httpd/trunk/modules/proxy/mod_proxy.h
>     httpd/httpd/trunk/modules/proxy/mod_proxy_connect.c
>     httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c
>     httpd/httpd/trunk/modules/proxy/proxy_util.c
> 

> Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_connect.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_connect.c?rev=1869338&r1=1869337&r2=1869338&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/proxy/mod_proxy_connect.c (original)
> +++ httpd/httpd/trunk/modules/proxy/mod_proxy_connect.c Sun Nov  3 15:48:53 
> 2019

> @@ -364,83 +333,25 @@ static int proxy_connect_handler(request
>       * Handle two way transfer of data over the socket (this is a tunnel).
>       */
>  
> -    /* we are now acting as a tunnel - the input/output filter stacks should
> -     * not contain any non-connection filters.
> -     */
> -    r->output_filters = c->output_filters;
> -    r->proto_output_filters = c->output_filters;
> -    r->input_filters = c->input_filters;
> -    r->proto_input_filters = c->input_filters;
> -/*    r->sent_bodyct = 1;*/
> -
> -    do { /* Loop until done (one side closes the connection, or an error) */
> -        rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled);
> -        if (rv != APR_SUCCESS) {
> -            if (APR_STATUS_IS_EINTR(rv)) {
> -                continue;
> -            }
> -            apr_socket_close(sock);
> -            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01023) 
> "error apr_poll()");
> -            return HTTP_INTERNAL_SERVER_ERROR;
> -        }
> -
> -        ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO(01024)
> -                      "woke from poll(), i=%d", pollcnt);
> +    /* r->sent_bodyct = 1; */
>  
> -        for (pi = 0; pi < pollcnt; pi++) {
> -            const apr_pollfd_t *cur = &signalled[pi];
> -
> -            if (cur->desc.s == sock) {
> -                pollevent = cur->rtnevents;
> -                if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
> -                    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, 
> APLOGNO(01025)
> -                                  "backend was readable");
> -                    done |= ap_proxy_transfer_between_connections(r, 
> backconn,
> -                                                                  c, bb_back,
> -                                                                  bb_front,
> -                                                                  "backend", 
> NULL,
> -                                                                  
> CONN_BLKSZ, 1)
> -                                                                 != 
> APR_SUCCESS;
> -                }
> -                else if (pollevent & APR_POLLERR) {
> -                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01026)
> -                                  "err on backend connection");
> -                    backconn->aborted = 1;
> -                    done = 1;
> -                }
> -            }
> -            else if (cur->desc.s == client_socket) {
> -                pollevent = cur->rtnevents;
> -                if (pollevent & (APR_POLLIN | APR_POLLHUP)) {
> -                    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, 
> APLOGNO(01027)
> -                                  "client was readable");
> -                    done |= ap_proxy_transfer_between_connections(r, c,
> -                                                                  backconn,
> -                                                                  bb_front,
> -                                                                  bb_back,
> -                                                                  "client",
> -                                                                  NULL,
> -                                                                  
> CONN_BLKSZ, 1)
> -                                                                 != 
> APR_SUCCESS;
> -                }
> -                else if (pollevent & APR_POLLERR) {
> -                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02827)
> -                                  "err on client connection");
> -                    c->aborted = 1;
> -                    done = 1;
> -                }
> -            }
> -            else {
> -                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01028)
> -                              "unknown socket in pollset");
> -                done = 1;
> -            }
> +    rv = ap_proxy_tunnel_create(&tunnel, r, backconn);
> +    if (rv != APR_SUCCESS) {
> +        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10208)
> +                      "can't create tunnel for %pI (%s)",
> +                      nexthop, connectname);
> +        return HTTP_INTERNAL_SERVER_ERROR;
> +    }
>  
> +    rc = ap_proxy_tunnel_run(tunnel);
> +    if (ap_is_HTTP_ERROR(rc)) {
> +        /* Don't send an error page if we sent data already */
> +        if (proxyport && !tunnel->replied) {
> +            return rc;
>          }
> -    } while (!done);
> -
> -    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
> -                  "finished with poll() - cleaning up");
> +        /* Custom log may need this, still */
> +        r->status = rc;

I have some lively discussions outside this forum on the consequences the above 
line has.
In fact this means that even though we replied to the client with a 200 on its 
CONNECT request we might log a different status
code if something goes wrong during the tunneling. In contrast to this we don't 
do this for other other methods e.g. GET or POST:
Once we sent the status code to the client we do not log a different one should 
something go wrong while delivering the response.
Removing r->status = rc is IMHO enough to align the behavior again.

Thoughts?

Regards

Rüdiger

Reply via email to