Subject: Standard for upgrading based on URL?

From: Felipe Gasper <[email-masked]>
Date: Tue, 12 Oct 2021 13:28:40 -0400

Hello,

	Is there any way, per currently-published standards, to upgrade a TLS connection from HTTP/1 to H2 based on its URL? e.g.:

https://example.com/http1   <-- served via HTTP/1

https://example.com/http2   <-- served via HTTP/3

	This is possible with non-TLS via normal HTTP upgrades but doesn’t appear to be possible via the ALPN approach mandated for TLS-secured HTTP/2 connections. It seems strange that there would be no way to do over TLS what’s easy to do in plain text. What am I missing?

	Thank you!

-FG

---

From: Ben Schwartz <[email-masked]>
Date: Tue, 12 Oct 2021 16:05:34 -0400

Clients generally upgrade to HTTP/2 automatically based on the ALPN process
in the TLS handshake.  Do you mean HTTP/3?

On Tue, Oct 12, 2021 at 1:30 PM Felipe Gasper <[email-masked]>
wrote:

> Hello,
>
>         Is there any way, per currently-published standards, to upgrade a
> TLS connection from HTTP/1 to H2 based on its URL? e.g.:
>
>         This is possible with non-TLS via normal HTTP upgrades but doesn’t
> appear to be possible via the ALPN approach mandated for TLS-secured HTTP/2
> connections. It seems strange that there would be no way to do over TLS
> what’s easy to do in plain text. What am I missing?
>
>         Thank you!
>
> -FG
>

---

From: Nick Harper <[email-masked]>
Date: Tue, 12 Oct 2021 13:15:18 -0700

Upgrading a connection from HTTP/1 to HTTP/3 isn't possible since they use
different underlying transports (TCP vs QUIC).

What would be the use case for starting a TLS connection using HTTP/1 and
then later upgrading to HTTP/2, instead of always using HTTP/2 on the
connection? The in-band upgrade mechanism provided for h2c only exists so
that a client without prior knowledge can use h2c; a similar mechanism
isn't needed for h2 (over TLS) because the signal that HTTP/2 is supported
is carried in ALPN.

On Tue, Oct 12, 2021 at 1:09 PM Ben Schwartz <[email-masked]> wrote:

> Clients generally upgrade to HTTP/2 automatically based on the ALPN
> process in the TLS handshake.  Do you mean HTTP/3?
>
>>         This is possible with non-TLS via normal HTTP upgrades but
>> doesn’t appear to be possible via the ALPN approach mandated for
>> TLS-secured HTTP/2 connections. It seems strange that there would be no way
>> to do over TLS what’s easy to do in plain text. What am I missing?
>>
>>         Thank you!
>>
>> -FG
>>
>

---

From: Felipe Gasper <[email-masked]>
Date: Tue, 12 Oct 2021 16:38:21 -0400

> On Oct 12, 2021, at 4:15 PM, Nick Harper <[email-masked]> wrote:
> 
> Upgrading a connection from HTTP/1 to HTTP/3 isn't possible since they use different underlying transports (TCP vs QUIC).

Oops! Sorry, I meant upgrading to H2.

> What would be the use case for starting a TLS connection using HTTP/1 and then later upgrading to HTTP/2, instead of always using HTTP/2 on the connection? The in-band upgrade mechanism provided for h2c only exists so that a client without prior knowledge can use h2c; a similar mechanism isn't needed for h2 (over TLS) because the signal that HTTP/2 is supported is carried in ALPN.

We have an application server that only serves H1 right now. We’d like to be able to add new endpoints using H2 without having to rewrite the entire thing.

So:

https://ourapp.com/legacy-endpoint    <--- We’d like not to rewrite this (for now).

https://ourapp.com/new-endpoint       <--- We’d like to write this in H2.

The in-band upgrade mechanism for h2c trivially allows this since the URL is part of the client’s first sent line, but it doesn’t seem like the ALPN-based negotiation can allow that … or is there some way for the client to send the URL during the TLS handshake?

Thank you!

-FG

---

From: Lucas Pardue <[email-masked]>
Date: Tue, 12 Oct 2021 21:51:36 +0100

Hi Felipe,

On Tue, 12 Oct 2021, 21:40 Felipe Gasper, <[email-masked]> wrote:

> > Upgrading a connection from HTTP/1 to HTTP/3 isn't possible since they
> use different underlying transports (TCP vs QUIC).
>
> > What would be the use case for starting a TLS connection using HTTP/1
> and then later upgrading to HTTP/2, instead of always using HTTP/2 on the
> We have an application server that only serves H1 right now. We’d like to
> be able to add new endpoints using H2 without having to rewrite the entire
> thing.

> The in-band upgrade mechanism for h2c trivially allows this since the URL
> is part of the client’s first sent line, but it doesn’t seem like the
> ALPN-based negotiation can allow that … or is there some way for the client
> to send the URL during the TLS handshake?
>

An alternative approach that is a proven effective strategy is to insert
something like a reverse proxy, load balancer or CDN in front of your
legacy servers. That way clients would talk H2 to all endpoints (as they
see it) but you would handle the dispatching of requests to different
servers with different capabilities yourself. That would let you stay fully
in control of migration without any hard to solve coordination challenges
with the actual clients.

Cheers
Lucas

---

From: David Benjamin <[email-masked]>
Date: Tue, 12 Oct 2021 16:58:11 -0400

> to send the URL during the TLS handshake?

No, something like this wouldn't really work for what HTTP/2 is trying to
do in the first place. One of the biggest benefits of newer protocols like
HTTP/2 and HTTP/3 is better use of the network via connection reuse. That
means that switching protocols on a request-by-request basis doesn't really
work. As a client, once a suitable HTTP/2 or HTTP/3 connection is
available, incoming requests will go to that connection. If clients probed
the server with a new connection first, we'd negate all the benefits.

The in-band upgrade didn't give you this property either. (The in-band
upgrade is getting removed in http2bis because no one implemented it, so
I'm guessing you haven't tested this?) Even if it is initiated by something
URL-triggered, the end result is an HTTP/2 connection. So, suppose you hit
/new-endpoint and upgraded to HTTP/2. The client now has an HTTP/2
connection available, so when you go to hit /legacy-endpoint, it would
reuse that HTTP/2 connection rather than making a new one. Your HTTP/2
server continues to be responsible for /legacy-endpoint.

If porting the legacy endpoints to the new application server is difficult,
I think the best solution is for your HTTP/2 frontend to forward the legacy
endpoints to the old application server, while speaking HTTP/2 to the
client. This lets you apply the benefits of HTTP/2 across your entire
origin.

David

---

From: Felipe Gasper <[email-masked]>
Date: Tue, 12 Oct 2021 19:59:02 -0400

> On Oct 12, 2021, at 4:58 PM, David Benjamin <[email-masked]> wrote:
> 
> On Tue, Oct 12, 2021 at 4:40 PM Felipe Gasper <[email-masked]> wrote:
> 
> No, something like this wouldn't really work for what HTTP/2 is trying to do in the first place. One of the biggest benefits of newer protocols like HTTP/2 and HTTP/3 is better use of the network via connection reuse. That means that switching protocols on a request-by-request basis doesn't really work. As a client, once a suitable HTTP/2 or HTTP/3 connection is available, incoming requests will go to that connection. If clients probed the server with a new connection first, we'd negate all the benefits.
> 
> The in-band upgrade didn't give you this property either. (The in-band upgrade is getting removed in http2bis because no one implemented it, so I'm guessing you haven't tested this?) Even if it is initiated by something URL-triggered, the end result is an HTTP/2 connection. So, suppose you hit /new-endpoint and upgraded to HTTP/2. The client now has an HTTP/2 connection available, so when you go to hit /legacy-endpoint, it would reuse that HTTP/2 connection rather than making a new one. Your HTTP/2 server continues to be responsible for /legacy-endpoint.
> 
> If porting the legacy endpoints to the new application server is difficult, I think the best solution is for your HTTP/2 frontend to forward the legacy endpoints to the old application server, while speaking HTTP/2 to the client. This lets you apply the benefits of HTTP/2 across your entire origin.

That makes all the sense in the world. Thank you for explaining.

cheers,
-Felipe Gasper

---

From: "Martin Thomson" <[email-masked]>
Date: Wed, 13 Oct 2021 11:21:37 +1100

If you really do need multiple protocols and you can't tolerate in-line negotiation (I can't imagine why), new names might help.  So rather than ourapp.example/new and ourapp.example/old you might deploy h2 to new.ourapp.example.  In general, I'd think of that as a trial only, because HTTP/2 should ultimately deploy right alongside HTTP/1.1 for all URLs on your primary server.

Mike Bishop has done some thinking about how you might serve different parts of your content with different servers (and therefore also different protocols, though that was not his thinking).  See https://www.ietf.org/archive/id/draft-bishop-httpbis-distributed-origin-00.html for more.  If you are intent on exploring that space, know that you would be breaking totally new ground, with all the risks associated with that.

On Wed, Oct 13, 2021, at 07:58, David Benjamin wrote:
> No, something like this wouldn't really work for what HTTP/2 is trying 
> to do in the first place. One of the biggest benefits of newer 
> protocols like HTTP/2 and HTTP/3 is better use of the network via 
> connection reuse. That means that switching protocols on a 
> request-by-request basis doesn't really work. As a client, once a 
> suitable HTTP/2 or HTTP/3 connection is available, incoming requests 
> will go to that connection. If clients probed the server with a new 
> connection first, we'd negate all the benefits.
>
> upgrade is getting removed in http2bis because no one implemented it, 
> so I'm guessing you haven't tested this?) Even if it is initiated by 
> something URL-triggered, the end result is an HTTP/2 connection. So, 
> suppose you hit /new-endpoint and upgraded to HTTP/2. The client now 
> has an HTTP/2 connection available, so when you go to hit 
> /legacy-endpoint, it would reuse that HTTP/2 connection rather than 
> making a new one. Your HTTP/2 server continues to be responsible for 
> /legacy-endpoint.
>
> If porting the legacy endpoints to the new application server is 
> difficult, I think the best solution is for your HTTP/2 frontend to 
> forward the legacy endpoints to the old application server, while 
> speaking HTTP/2 to the client. This lets you apply the benefits of 
> HTTP/2 across your entire origin.
>
> David