Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions G2-http3-protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
G2: gRPC over HTTP/3
----
* Author(s): [James Newton-King](https://github.com/jamesnk)
* Approver: ejona86
* Status: In review
* Implemented in: grpc-dotnet
* Last updated: 2021-08-25
* Discussion at: https://groups.google.com/g/grpc-io/c/b1dWReBGyX4

## Abstract

HTTP/3 is the third and upcoming major version of the Hypertext Transfer Protocol
used to exchange information on the World Wide Web, alongside HTTP/1.1 and HTTP/2.

This proposal is for how the gRPC protocol should run on top of the HTTP/3 protocol.

## Background

gRPC uses HTTP semantics but requires HTTP/2 for some features. HTTP/3 offers the
same capabilities as HTTP/2, enabling all gRPC scenarios, along with new benefits
offered by HTTP/3:

* Faster connection negotiation in fewer round-trips.
* Improved experience when there is connection packet loss.
* Client supports transitioning between networks.

[PROTOCOL-HTTP2.md](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)
covers gRPC's HTTP semantics, along with some content that is specific to HTTP/2.
Either this document should be generalized to include HTTP/2 and HTTP/3 information,
or a new gRPC over HTTP/3 protocol document should be created.

### Related Proposals:

n/a

## Proposal

### HTTP semantics

The shape of gRPC HTTP requests and responses are unchanged in HTTP/3. The
content in [PROTOCOL-HTTP2.md](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)
that covers requests and responses can be referred to directly, without any
duplication.

Notably, unlike gRPC-Web, the content-type of `application/grpc` is unchanged. Apps
are still communicating with gRPC, but over HTTP/3 instead of HTTP/2.

### Transport mapping

The gRPC over HTTP/2 specification [discusses HTTP2 transport mapping](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#http2-transport-mapping).
The content discussed is mostly applicable to HTTP/3.

#### Stream Identification

HTTP/3 stream IDs function largely the same as HTTP/2 stream IDs.

#### Data frames

The relationship between `DATA` frames and length prefixed messages are unchanged in HTTP/3.

#### Errors

HTTP/3 [has different error codes](https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-8.1)
from HTTP/2. HTTP/3 errors are sent via QUIC frames instead of an `RST_STREAM` HTTP frame.

HTTP/3 errors are used in three situations:

* Abruptly terminating streams
* Aborting reading of streams
* Immediately closing HTTP/3 connections

HTTP3 Code|HTTP2 Code|GRPC Code
----------|----------|-----------
H3_NO_ERROR(0x0100)|NO_ERROR(0)|INTERNAL - An explicit GRPC status of OK should have been sent but this might be used to aggressively [lameduck](https://landing.google.com/sre/sre-book/chapters/load-balancing-datacenter/#identifying-bad-tasks-flow-control-and-lame-ducks-bEs0uy) in some scenarios.
H3_GENERAL_PROTOCOL_ERROR(0x0101)|PROTOCOL_ERROR(1)|INTERNAL
H3_INTERNAL_ERROR(0x0102)|INTERNAL_ERROR(2)|INTERNAL
H3_STREAM_CREATION_ERROR(0x0103)|n/a|INTERNAL
H3_CLOSED_CRITICAL_STREAM(0x0104)|n/a|INTERNAL
H3_FRAME_UNEXPECTED(0x0105)|FRAME_SIZE_ERROR|INTERNAL
H3_FRAME_ERROR(0x0106)|FRAME_SIZE_ERROR|INTERNAL
H3_EXCESSIVE_LOAD(0x0107)|ENHANCE_YOUR_CALM|RESOURCE_EXHAUSTED ...with additional error detail provided by runtime to indicate that the exhausted resource is bandwidth.
H3_ID_ERROR(0x0108)|n/a|INTERNAL
H3_SETTINGS_ERROR(0x0109)|SETTINGS_TIMEOUT(4)|INTERNAL
H3_MISSING_SETTINGS(0x010a)|SETTINGS_TIMEOUT(4)|INTERNAL
H3_REQUEST_REJECTED(0x010b)|REFUSED_STREAM|UNAVAILABLE - Indicates that no processing occurred and the request can be retried, possibly elsewhere.
H3_REQUEST_CANCELLED(0x010c)|CANCEL(8)|Mapped to call cancellation when sent by a client.Mapped to CANCELLED when sent by a server. Note that servers should only use this mechanism when they need to cancel a call but the payload byte sequence is incomplete.
H3_REQUEST_INCOMPLETE(0x010d)|n/a|INTERNAL
H3_MESSAGE_ERROR(0x010e)|n/a|INTERNAL
H3_CONNECT_ERROR(0x010f)|CONNECT_ERROR|INTERNAL
H3_VERSION_FALLBACK(0x0110)|n/a|INTERNAL
n/a|FLOW_CONTROL_ERROR(3)|INTERNAL
n/a|STREAM_CLOSED|No mapping as there is no open stream to propagate to. Implementations should log.
n/a|COMPRESSION_ERROR|INTERNAL
n/a|INADEQUATE_SECURITY| PERMISSION_DENIED … with additional detail indicating that permission was denied as protocol is not secure enough for call.

#### Connection management

`GOAWAY` and `PING` frames exist in HTTP/3 and serve the same purpose as in HTTP/2.
One notable difference is the `GOAWAY` frame in HTTP/2 reports the last
successfully processed stream ID. In HTTP/3 the `GOAWAY` frame ID value must be greater
than the last successfully processed stream ID.

### Exceeding deadlines

When an RPC has exceeded its deadline, the server will reset the stream. In HTTP/2, a stream
is reset using the `RST_STREAM` frame. The `RST_STREAM` frame doesn't exist in HTTP/3.
Instead, this action is performed using a QUIC frame, called `RESET_STREAM`.

| | Frame | Error code | Layer
----------------------------|--------------|------------------------------|----------
Deadline exceeded HTTP/2 | RST_STREAM | CANCEL(8) | HTTP
Deadline exceeded HTTP/3 | RESET_STREAM | H3_REQUEST_CANCELLED(0x010c) | QUIC

[RESET_STREAM](https://www.rfc-editor.org/rfc/rfc9000.html#name-reset_stream-frames) abruptly
terminates sending on a stream. An important difference between HTTP/2 and
HTTP/3 is frames are received out-of-order. Because of this, a `RESET_STREAM` sent after a
completed response could still result in the response being aborted.

HTTP/3 also has the QUIC `STOP_SENDING` frame. This frame is sent by the server when a
stream's response side completes before the request side. Using `STOP_SENDING` alone isn't
appropriate for a deadline exceeded, because both stream directions should be aborted.
However, `STOP_SENDING` should be sent along with `RESET_STREAM` if the deadline is exceeded
while the request side is in-progress.

### HTTP/3 negotation

A client and server both need to support HTTP/3 for it to be used. There are two common
scenarios for establishing an HTTP/3 connection:

* gRPC client uses TLS and is configured in advance to only use HTTP/3. The client starts a
QUIC+HTTP/3 connection to server. If the server doesn't support HTTP/3 then the connection
fails.
* gRPC client uses TLS and is configured to use HTTP/2 or greater. In this case an initial
HTTP/2 call is made, server returns response with an `alt-svc` header that tells the client
that HTTP/3 is available. HTTP/2 connection is replaced with QUIC+HTTP/3 and future calls
use HTTP/3. If the server doesn't support HTTP/3 then the client continues to use HTTP/2.

HTTP/3 requires TLS and will never be used by an insecure channel.

API for configuring channel HTTP negotation behavior is up to implementations.

## Rationale

HTTP/3 is an upcoming Internet Protocol. There needs to be a standardized agreement for how
gRPC over HTTP/3 works to maintain interoperability in the gRPC eco-system.

## Implementation

A trial implementation in grpc-dotnet is underway. .NET 6 is adding preview support for
HTTP/3 to the .NET server and client. grpc-dotnet leverages that underlying HTTP/3 support.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lidizheng what about doing some python asyncio prototyping!? https://github.com/aiortc/aioquic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that building a MVP gRPC Python HTTP/3 on top of the aioquic library probably isn't that hard. Currently, gRPC Python uses gRPC Core as the transport layer, it's not that trivial to move existing code onto another transport library. I hope if we want to invest resources, we have a working architecture and aiming for long-term support.


## Open issues (if applicable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUIC always uses security (TLS) which means gRPC-over-http3 always requires certs/keys IIUC. Does it impact the gRPC API or the usage? To be addressed in this gRFC?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP/3 would never be negotated over an insecure connection.

Scenarios would be:

  1. gRPC client uses prenegotated H2C over insecure connection
  2. gRPC client uses TLS and requests only HTTP/2. Ignores alt-svc header returned from the server.
  3. gRPC client uses TLS and requests HTTP/2 or greater. In this case an initial HTTP/2 call is made, server returns response with an alt-svc header that tells the client that HTTP/3 is available. HTTP/2 connection is replaced with QUIC+HTTP/3 and future calls use HTTP/3.
  4. gRPC client uses TLS and is configured in advance to only do HTTP/3. QUIC+HTTP/3 connection is made to server.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think clients might introduce channel settings to give users the specify what protocol they want. For example:

  • RequestVersion with 2.0, 3.0.
  • RequestVersionPolicy with RequestVersionExact, RequestVersionOrGreater (allow upgrade)


n/a