Subject: Handling H3_REQUEST_REJECTED

From: Geoffrey Kizer <[email-masked]>
Date: Wed, 1 Sep 2021 23:37:51 +0000

It is often unclear what action an HTTP3 client should take when it receives H3_REQUEST_REJECTED.

>From the standard:

When the server cancels a request without performing any application processing, the request is considered "rejected." The server SHOULD abort its response stream with the error code H3_REQUEST_REJECTED. In this context, "processed" means that some data from the stream was passed to some higher layer of software that might have taken some action as a result. The client can treat requests rejected by the server as though they had never been sent at all, thereby allowing them to be retried later.

So when a client receives H3_REQUEST_REJECTED, it *can* retry the request. But it is often not clear *how* to retry the request, because the client has no information about *why* the request was rejected, nor about the circumstances under which retrying the request might succeed instead of simply being rejected again.

If the client has already received a GOAWAY on the connection, then it seems reasonable to conclude that the request was rejected because the connection is going away, and the client should retry the request on another connection.

But if the client hasn't received a GOAWAY on the connection, then it is not clear what to do.

One possibility is that the connection is going away, but the client has not received or processed the GOAWAY message yet. In fact, this seems quite likely, since the standard states that upon sending GOAWAY, a server should reject requests that the GOAWAY has indicated will not be handled. Since there is no guaranteed ordering across receipt and processing of the GOAWAY message and the request rejections, the latter will be processed before the former in some cases. In this case, retrying on the current connection is pointless and wasteful since the retry will simply be rejected again.

Another possibility is described in the standard: An intermediary can choose to map an HTTP2 REFUSED_STREAM error to HTTP3 H3_REQUEST_REJECTED. (Presumably it could do something similar with HTTP/1.1 requests as well.) In this case, retrying the request immediately on the current connection (or any valid connection) is often the right action to take, since it allows the intermediary to determine if and how to forward the request so that it will not be rejected again.

It seems like there are many other possibilities as well, given the broad definition of H3_REQUEST_REJECTED. For example, the physical server itself may be shutting down, but other connections to the same endpoint (but different physical servers) may still be available to process the request. Or, the server may be temporarily unavailable, but is expected to be available again after some period of time. Without some information about why the request was rejected, the client cannot choose an appropriate retry strategy.

Is there any guidance about how a client should handle H3_REQUEST_REJECTED in general?

Could/should the standard be enhanced to provide more information about why a request was rejected, to allow a client to choose a better retry strategy?

Thanks
Geoff