Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] Proxy from H2 to 1.1

On Thu, Jul 30, 2020 at 4:33 PM Simone Bordet <sbordet@xxxxxxxxxxx> wrote:
>
> Hi,

Hey, Simone. Thanks for bearing with me even though my message was so confusing. Let me try to clarify.

> On Thu, Jul 30, 2020 at 11:47 AM Travis Spencer
> <travis.spencer@xxxxxxxxx> wrote:
> >
> > We are trying to add H2 support to our server that embeds Jetty. This
> > works perfectly except in the case where we proxy to downstream
> > services. For a couple routes, we forward to an HTTP (not HTTPS)
> > server and a server that doesn't support H2. In these cases, the proxy
> > request fails since non-SSL with H2 isn't supported by the one origin
> > server and the other only accepts 1.1.
> >
> > So, my question is, how in our AsyncProxyServlet subclass should we
> > specify that the proxy requests should use HTTP 1.1 and not H2? ATM,
> > the proxied request seems to always use whatever version the client
> > used when communicating with the proxy servlet.
>
> I am not sure I understand.

A picture's worth a 1000 words, so here's a diagram:

                        +-----------------------------+
                        |                             |
                        |    +--------------------+   |
       H2 for various   |    |                    |   |
       non-proxied cases|    |                    |   |
               +-------------+  Jetty Web server  |   |
                        |    |                    |   |                   +-----------------+
                        |    |                    |   |      HTTP 1.1     |                 |
                        |    +--------------------+   |      without SSL  |     Origin      |
       H2 that proxies  |                             |           +-------+     server      |
       to an HTTP 1.1   |    +--------------------+   |           ^       |       1         |
       server without   |    |                    |   |           |       +-----------------+
       SSL     +-------------+                    +---------------+
                        |    | Jetty Proxy Server |   |
                        |    |                    |   |
               +-------------+                    +---------------+       +-----------------+
                        |    +--------------------+   |           v       |     Origin      |
       H2 that proxies  |                             |           +-------+     server      |
       to an HTTP 1.1   |           Our Server        |       HTTP 1.1    |        2        |
       server with SSL  |                             |       with SSL    |                 |
                        +-----------------------------+                   +-----------------+



(In case the fonts get screwed up you can find a copy of that diagram here: https://drive.google.com/file/d/1Ks8AsjeKHcSUyL7qVtjenkputtsqJZPZ/view?usp=sharing)

> You have a server that is both a server (i.e. it answers requests
> directly) and a proxy (i.e. it uses AsyncProxyServlet to forward to
> other servers that only support HTTP/1.1).

Yes, exactly.

> AsyncProxyServlet will create an instance of HttpClient with (by
> default) the HTTP/1.1 transport.
> So every proxied request will be sent as HTTP/1.1.
>
> Therefore it is already the case that all proxied requests use HTTP/1.1.

That's not what I'm seeing, in the logs at least. I think the logged info is correct too because the origin servers (both of them) are giving me errors, and the only thing I've changed is H2 support on the proxy.

> > When access the downstream HTTP 1.1 server, the client and proxy
> > request looks like this:
> >
> > MyGoodTransparentProxyServlet:70 474713221 rewriting:
> > https://localhost:5555/mygood-api ->
> > https://remote.example.com:443/some-other-good-api
>
> Uh? You said the other server was not using HTTPS?

One is HTTP and one is HTTPS.

> > HttpRequest[GET /some-other-good-api HTTP/2.0]@8c22593

See, Simone, how the proxy uses H2 as well and not 1.1?

> > accept-language: en-US,en;q=0.5
> > content-type: application/json
> > cache-control: no-cache
> > pragma: no-cache
> > accept: application/json, text/plain, */*
> > X-Forwarded-For: 0:0:0:0:0:0:0:1
> > X-Forwarded-Proto: https
> > X-Forwarded-Host: localhost:5555
> > X-Forwarded-Server: 0:0:0:0:0:0:0:1
> > Via: 2.0 Y762xIGev8Am
> >
> > Note the Via header as well. I could not call addProxyHeaders in my
> > subclass anymore because that calls addViaHeader, which seems to have
> > a few bugs in it:
> >
> > * HTTP is used when RFC 7230 says it shouldn't be except when the
> > protocol isn't HTTP (there's no MUST on this, but, in section 5.7.1,
> > it says "For brevity, the protocol-name is omitted when the received
> > protocol is HTTP.")
>
> Don't understand? The protocol *is* HTTP.

Yep, and my read of the RFC is that the protocol string should be omitted in that case. If it were something else, like I don't know what, GRPC or something, then it should be included. For HTTP though, it shouldn't. The example in that section is helpful in this regard:

Via: 1.0 fred, 1.1 p.example.net
See, no HTTP. The example isn't normative, but I think it helps show what I'm trying to point out.

>
> > * "null" is used if ViaHost isn't configured. Instead, a pseudonym
> > should be used
>
> Where is "null"?

null is what AsyncProxyServlet usually sends when AbstractProxyServlet's viaHost is called after addViaHeader is invoked unless the viaHost initial servlet parameter is specified.

Here's an example of the default Via that's created when my subclass calls org.eclipse.jetty.proxy.AbstractProxyServlet#addProxyHeaders:

Via: http/1.1 null

The http/1.1 is hardcoded (which is wrong IINM, since I connected via H2) and the host is not a pseudonym and not the actual host.

> > * The protocol version is hard coded to be 1.1 when, in my case at
> > least, it should be 2.0.
>
> Uh? But you said you want to use HTTP/1.1.

The protocol that should be added isn't the one of the proxy. It's the one of the client. I could be totally wrong, but the wording and examples in RFC 7230 section 5.7.1 lead me to this conclusion. Perhaps I'm reading the wrong RFC or just misunderstanding it.


Back to the top