diff --git a/IPIP/0332-gateway-error-handling.md b/IPIP/0332-gateway-error-handling.md new file mode 100644 index 000000000..91b51f60c --- /dev/null +++ b/IPIP/0332-gateway-error-handling.md @@ -0,0 +1,72 @@ +# IPIP 0000: Streaming Error Handling in HTTP Gateways + +- Start Date: 2022-10-12 +- Related Issues: + - [ipfs/kubo/pull/9333](https://github.com/ipfs/kubo/pull/9333) + - [mdn/browser-compat-data/issues/14703](https://github.com/mdn/browser-compat-data/issues/14703) + +## Summary + +Ensure streaming error handling in web gateways is clear and consistent. + +## Motivation + +Web gateways provide different functionalities where users can download files. +The download of this files is streamed from the server to the client using HTTP. +However, there is no good way of presenting to the client an error that happens +during the stream. + +For example, if during the download of a TAR file, the server detects some error +and is not able to continue, the user can get a valid, yet incomplete TAR. However, +the user will not know that the TAR is incomplete. By introducing consistent error +handling, the server attempts to notify the user. + +## Detailed design + +If the server encounters an error before streaming the contents to the client, +the server must fail with the respective `4xx` or `5xx` HTTP status code (no change). + +If the server encounters an error while streaming the contents, the server must +force-close the HTTP stream to the user. This way, the user will receive a +network error, making it clear that the downloaded file is not valid. +In addition, the server must set an header `X-On-Error: reset` to indicate that +connection will be reset if an error occurs. + +The client can opt-out of this behavior by sending a `X-Error-Behavior: trailer`. +In that case, the server will not force-close the HTTP stream. Instead, the server +will send the trailing header `X-Stream-Error` header with the error message. + +## Test fixtures + +There are no relevant test fixures for this IPIP. + +## Design rationale + +Before starting to stream the body of the response, the server is able to set +an HTTP status code for the error. However, after the HTTP headers are set +and the body started being streamed, there are no clear ways in the HTTP +specification to show an error. Since the gateway is browser-first, it is +important to show an error and avoid users receiving an incomplete file. +Therefore, the server can force-close the HTTP stream, leading to a network +error. This tells the user that an error happened. + +### User benefit + +The user will know that an error happened while receiving the file. Otherwise, +the user might receive incomplete, but still valid, files that could be mistaken +but the real file. + +### Compatibility + +This RFC is backwards compatible. + +### Alternatives + +Using [`Trailer`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer) HTTP headers +was considered. However, trailer headers are [not supported in browsers](https://github.com/mdn/browser-compat-data/issues/14703). +In addition, even if trailer headers were supported in browsers, there is no clear +standard for which header would be used to indicate errors. + +### Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/http-gateways/PATH_GATEWAY.md b/http-gateways/PATH_GATEWAY.md index 33c581fa9..c77312629 100644 --- a/http-gateways/PATH_GATEWAY.md +++ b/http-gateways/PATH_GATEWAY.md @@ -41,6 +41,7 @@ where client prefers to perform all validation locally. - [`Accept` (request header)](#accept-request-header) - [`Range` (request header)](#range-request-header) - [`Service-Worker` (request header)](#service-worker-request-header) + - [`X-Error-Behavior` (request header)](#x-error-behavior-request-header) - [Request Query Parameters](#request-query-parameters) - [`filename` (request query parameter)](#filename-request-query-parameter) - [`download` (request query parameter)](#download-request-query-parameter) @@ -74,6 +75,8 @@ where client prefers to perform all validation locally. - [`X-Ipfs-Roots` (response header)](#x-ipfs-roots-response-header) - [`X-Content-Type-Options` (response header)](#x-content-type-options-response-header) - [`X-Trace-Id` (response header)](#x-trace-id-response-header) + - [`X-On-Error` (response header)](#x-on-error-response-header) + - [`X-Stream-Error` (response header)](#x-stream-error-response-header) - [Response Payload](#response-payload) - [Appendix: notes for implementers](#appendix-notes-for-implementers) - [Content resolution](#content-resolution) @@ -83,6 +86,7 @@ where client prefers to perform all validation locally. - [Best practices for HTTP caching](#best-practices-for-http-caching) - [Denylists](#denylists) - [Generated HTML with directory index](#generated-html-with-directory-index) + - [Streaming errors](#streaming-errors) # HTTP API @@ -217,6 +221,17 @@ Gateway should refuse attempts to register a service worker for entire Requests to these paths with `Service-Worker: script` MUST be denied by returning HTTP 400 Bad Request error. +### `X-Error-Behavior` (request header) + +Clients can request a different behavior when errors occur during an HTTP +stream. The possible values, and behaviors are defined as follows: + +- `reset` (default): resets the HTTP stream. +- `trailer`: a trailer header [`X-Stream-Error`](#x-stream-error-response-header) will +be sent with the error message. + +See the [streaming errors](#streaming-errors) section for more information. + ## Request Query Parameters All query parameters are optional. @@ -582,6 +597,17 @@ unique identifier to help in debugging errors and performance issues. A good practice is to always return it with HTTP error [status codes](#response-status-codes) >=`400`. +### `X-On-Error` (response header) + +Returned on streaming requests to indicate the server behavior in case an error happens. +The header can have the value `reset`, or `trailer`. See the [streaming errors](#streaming-errors) +section for more information. + +### `X-Stream-Error` (response header) + +Returned if the client set [`X-Error-Behavior`](#x-error-behavior-request-header) to `trailer`. This trailing header will +contain the error message that occurred while streaming a file. + ## Response Payload Data sent with HTTP response depends on the type of requested IPFS resource: @@ -705,3 +731,13 @@ The usual optimizations involve: limiting the cost of a single page load. - The downside of this approach is that it will always be slower than skipping child block resolution. + +## Streaming errors + +To avoid users receiving an incomplete, yet valid, files, the gateway MUST +close the HTTP stream if an error occurs while streaming a file to the client. +This can be done via the following mechanisms: + +- Sending a `FIN` (close) frame for HTTP/1.1 +- Sending a `RST_STREAM` (reset stream) frame for HTTP/2 +- Sending a `CANCEL_PUSH` frame for HTTP/3, see RFC9114 section A.2.5.3.