You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Yann Ylavic <yl...@gmail.com> on 2016/07/27 16:09:35 UTC

Handle Upgrade forwarding (protocol switch) in mod_proxy_http

Hi,

since Upgrade is an HTTP/1 feature, I don't find it too twisted...

The primary goal would be to let the backend decide whether an Upgrade
is to be done, or otherwise continue with HTTP (still parsing the
response, filtering, caching, ...).

Currently we handle WebSocket tunneling only (in mod_proxy_wstunnel),
but it's dedicated to some configured URL(s), and if the client
chooses to not propose "Upgrade: WebSocket" on that URL(s) the request
is doomed (it falls back to the default_handler since the dedicated
scheme "ws(s)" won't be handled by anything else).

Actually mod_proxy_http has already all the state machine to handle
interim (e.g. 100-continue) and upgrade responses properly, it just
lacks the switch/tunneling to another protocol.

This what the two attached patches aim to.

The first one (mod_proxy-tunnel.patch) is to factorize all the
tunneling code(s) we currently have in proxy_connect and
proxy_wstunnel into proxy_util functions (namely
ap_proxy_tunnel_create(&tunnel, r, backconn) and
ap_proxy_tunnel_pump(tunnel, timeout)), and use them there.

The second one (mod_proxy_http-tunnel.patch) also uses them in
mod_proxy_http, where/when needed (a protocol switch is initiated by
the backend).
This is currently controlled/enabled only with "SetEnv
proxy-forward-upgrade" (we may not want to forward/tunnel Upgrades
unconditionally), it could be a ProxyUpgrade or so directive.

This is not limited to WebSocket forwarding, but it possibly would
obsolete mod_proxy_wstunnel...

WDYT?

Regards,
Yann.

Re: Handle Upgrade forwarding (protocol switch) in mod_proxy_http

Posted by Yann Ylavic <yl...@gmail.com>.
On Thu, Jul 28, 2016 at 2:33 AM, William A Rowe Jr <wr...@rowe-clan.net> wrote:
> On Jul 27, 2016 6:53 PM, "Yann Ylavic" <yl...@gmail.com> wrote:
>>
>> On Wed, Jul 27, 2016 at 8:27 PM, William A Rowe Jr <wr...@rowe-clan.net>
>> wrote:
>> >
>> > On Wed, Jul 27, 2016 at 11:09 AM, Yann Ylavic <yl...@gmail.com>
>> > wrote:
>> >>
>> >> Hi,
>> >>
>> >> since Upgrade is an HTTP/1 feature, I don't find it too twisted...
>> >>
>> >> The primary goal would be to let the backend decide whether an Upgrade
>> >> is to be done, or otherwise continue with HTTP (still parsing the
>> >> response, filtering, caching, ...).
>> >
>> >
>> > Nope... a thousand times nope...
>> >
>> > The protocol, along with a host of headers, are a hop-by-hop entities.
>> > They are not part of that discussion.
>>
>> Hmm, what's the point?
>> Can't proxies forward protocols? Don't we forward WebSocket already?
>> Do hop by hop headers prevent HTTP forwarding?
>>
>> We are talking about proxying Upgraded protocols here (once upgraded),
>> acting as a transparent/reverse proxy, when configured to, and as
>> negotiated by the client and backend.
>> Don't we do that for HTTP and other protocols already?
>
> Nope. Point-to-point is addressed by CONNECT, everything else is hop-by-hop.

Well, as usual, the proxy acts as the next hop for the client, and the
next hop for the proxy is the backend (or another proxy)?
What prevents a proxy from doing hop by hop on both sides?

For example, a proxy can play 100-continue on the client side but not
on the backend side, or play distinct 100-continue on both the client
and backend sides, or forward the "Expect: 100-continue" to the
backend (w/o reading the client's body) and the backend's "100
Continue" response before forwarding the request body and then the
final response, its choice/implementation.
Hop by hop does not mean that the protocol/feature has to stop at the
first hop, it says that it is self-contained for communicating from
one hop to next one, and that a client can't expect it to be forwarded
above the next hop (but if it works transparently, how could it
know?).

That's already what mod_proxy_wstunnel does for WebSocket, I simply
propose a more generic way (allow *any* HTTP Upgrade to be tunneled by
mod_proxy_http, at the backend's initiative, with conformant hop by
hop between the client<=>proxy and proxy<=>backend).

Below a concrete example (for the example) of what would work (better)
than today:

    CLIENT                  PROXY                   BACKEND

 GET / HTTP/1.1
 Host: proxy

                   ==>

                       GET / HTTP/1.1
                       Host: backend

                                           ==>

                                               HTTP/1.1 XXX OK
                                               [Some auth mechanism]

                                           <==

                       HTTP/1.1 XXX OK
                       [Some auth mechanism]

                   <==


    [Auth]         <=>        [HTTP]       <=>    [Auth]

                                               HTTP/1.1 302 Found
                                               Location: https://backend/ws/
                                               Set-Cookie: auth=token
                                               Upgrade: WebSocket
                                               Connection: upgrade

                                           <==

                       HTTP/1.1 302 Found
                       Location: https://proxy/ws/
                       Set-Cookie: auth=token
                       Upgrade: WebSocket
                       Connection: upgrade

                   <==

 GET /ws/ HTTP/1.1
 Host: proxy
 Upgrade: WebSocket
 Connection: upgrade
 Cookie: auth=token

                   ==>

                       GET /ws/ HTTP/1.1
                       Host: backend
                       Upgrade: WebSocket
                       Connection: upgrade
                       Cookie: auth=token

                                           ==>

                                               HTTP/1.1 101 Switching
                                               Upgrade: WebSocket
                                               Connection: upgrade

                                           <==

                       HTTP/1.1 101 Switching
                       Upgrade: WebSocket
                       Connection: upgrade

                    <==

    [WebSocket]     <=>        [TCP]       <=>    [WebSocket]


But if the client tries the below (without the Cookie), we still have
the hand on HTTP with my proposed patch, whereas with
mod_proxy_wstunnel today we'd be tunneling normal HTTP traffic:

 GET /ws/ HTTP/1.1
 Host: proxy
 Upgrade: WebSocket
 Connection: upgrade

                   ==>

                       GET /ws/ HTTP/1.1
                       Host: backend
                       Upgrade: WebSocket
                       Connection: upgrade

                                           ==>

                                               HTTP/1.1 302 Found
                                               Location: https://backend/
                                               [Go do auth there first]

                                           <==

                       HTTP/1.1 302 Found
                       Location: https://proxy/
                       [Go do auth there first]

                    <==

 [Roger, I'll do that]

Re: Handle Upgrade forwarding (protocol switch) in mod_proxy_http

Posted by William A Rowe Jr <wr...@rowe-clan.net>.
On Jul 27, 2016 6:53 PM, "Yann Ylavic" <yl...@gmail.com> wrote:
>
> On Wed, Jul 27, 2016 at 8:27 PM, William A Rowe Jr <wr...@rowe-clan.net>
wrote:
> >
> > On Wed, Jul 27, 2016 at 11:09 AM, Yann Ylavic <yl...@gmail.com>
wrote:
> >>
> >> Hi,
> >>
> >> since Upgrade is an HTTP/1 feature, I don't find it too twisted...
> >>
> >> The primary goal would be to let the backend decide whether an Upgrade
> >> is to be done, or otherwise continue with HTTP (still parsing the
> >> response, filtering, caching, ...).
> >
> >
> > Nope... a thousand times nope...
> >
> > The protocol, along with a host of headers, are a hop-by-hop entities.
> > They are not part of that discussion.
>
> Hmm, what's the point?
> Can't proxies forward protocols? Don't we forward WebSocket already?
> Do hop by hop headers prevent HTTP forwarding?
>
> We are talking about proxying Upgraded protocols here (once upgraded),
> acting as a transparent/reverse proxy, when configured to, and as
> negotiated by the client and backend.
> Don't we do that for HTTP and other protocols already?

Nope. Point-to-point is addressed by CONNECT, everything else is hop-by-hop.

Re: Handle Upgrade forwarding (protocol switch) in mod_proxy_http

Posted by Yann Ylavic <yl...@gmail.com>.
On Wed, Jul 27, 2016 at 8:27 PM, William A Rowe Jr <wr...@rowe-clan.net> wrote:
>
> On Wed, Jul 27, 2016 at 11:09 AM, Yann Ylavic <yl...@gmail.com> wrote:
>>
>> Hi,
>>
>> since Upgrade is an HTTP/1 feature, I don't find it too twisted...
>>
>> The primary goal would be to let the backend decide whether an Upgrade
>> is to be done, or otherwise continue with HTTP (still parsing the
>> response, filtering, caching, ...).
>
>
> Nope... a thousand times nope...
>
> The protocol, along with a host of headers, are a hop-by-hop entities.
> They are not part of that discussion.

Hmm, what's the point?
Can't proxies forward protocols? Don't we forward WebSocket already?
Do hop by hop headers prevent HTTP forwarding?

We are talking about proxying Upgraded protocols here (once upgraded),
acting as a transparent/reverse proxy, when configured to, and as
negotiated by the client and backend.
Don't we do that for HTTP and other protocols already?

Re: Handle Upgrade forwarding (protocol switch) in mod_proxy_http

Posted by William A Rowe Jr <wr...@rowe-clan.net>.
On Wed, Jul 27, 2016 at 1:27 PM, William A Rowe Jr <wr...@rowe-clan.net>
wrote:

>
> On Wed, Jul 27, 2016 at 11:09 AM, Yann Ylavic <yl...@gmail.com>
> wrote:
>
>> Hi,
>>
>> since Upgrade is an HTTP/1 feature, I don't find it too twisted...
>>
>> The primary goal would be to let the backend decide whether an Upgrade
>> is to be done, or otherwise continue with HTTP (still parsing the
>> response, filtering, caching, ...).
>>
>
> Nope... a thousand times nope...
>
> The protocol, along with a host of headers, are a hop-by-hop entities.
> They are not part of that discussion.
>

(However, proxy CONNECT exists for precisely this reason...)

Re: Handle Upgrade forwarding (protocol switch) in mod_proxy_http

Posted by William A Rowe Jr <wr...@rowe-clan.net>.
On Wed, Jul 27, 2016 at 11:09 AM, Yann Ylavic <yl...@gmail.com> wrote:

> Hi,
>
> since Upgrade is an HTTP/1 feature, I don't find it too twisted...
>
> The primary goal would be to let the backend decide whether an Upgrade
> is to be done, or otherwise continue with HTTP (still parsing the
> response, filtering, caching, ...).
>

Nope... a thousand times nope...

The protocol, along with a host of headers, are a hop-by-hop entities.
They are not part of that discussion.