-
Notifications
You must be signed in to change notification settings - Fork 236
IPIP-402: Partial CAR Support on Trustless Gateways #402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 16 commits
dd84771
6f7f7b3
aeff21c
b5eca27
c68f06a
1fc8915
98191b5
a6bfb2c
78e81e0
bfb5d3c
0639715
56786ff
61d1088
e1af6e4
f5f33ff
4ebbb96
e3c36f3
0953cb6
ffb1550
584098d
917efb9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,7 +4,7 @@ description: > | |||||||||||||||||||||||||
| Trustless Gateways are a minimal subset of Path Gateways that allow light IPFS | ||||||||||||||||||||||||||
| clients to retrieve data behind a CID and verify its integrity without delegating any | ||||||||||||||||||||||||||
| trust to the gateway itself. | ||||||||||||||||||||||||||
| date: 2023-03-30 | ||||||||||||||||||||||||||
| date: 2023-06-20 | ||||||||||||||||||||||||||
| maturity: reliable | ||||||||||||||||||||||||||
| editors: | ||||||||||||||||||||||||||
| - name: Marcin Rataj | ||||||||||||||||||||||||||
|
|
@@ -17,25 +17,33 @@ tags: ['httpGateways', 'lowLevelHttpGateways'] | |||||||||||||||||||||||||
| order: 1 | ||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Trustless Gateway is a minimal _subset_ of :cite[path-gateway] | ||||||||||||||||||||||||||
| Trustless Gateway is a _subset_ of :cite[path-gateway] | ||||||||||||||||||||||||||
| that allows light IPFS clients to retrieve data behind a CID and verify its | ||||||||||||||||||||||||||
| integrity without delegating any trust to the gateway itself. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The minimal implementation means: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - data is requested by CID, only supported path is `/ipfs/{cid}` | ||||||||||||||||||||||||||
| - no path traversal or recursive resolution, no UnixFS/IPLD decoding server-side | ||||||||||||||||||||||||||
| - response type is always fully verifiable: client can decide between a raw block or a CAR stream | ||||||||||||||||||||||||||
| - no UnixFS/IPLD deserialization | ||||||||||||||||||||||||||
| - for CAR files: | ||||||||||||||||||||||||||
| - the behavior is identical to :cite[path-gateway] | ||||||||||||||||||||||||||
| - for raw blocks: | ||||||||||||||||||||||||||
| - data is requested by CID, only supported path is `/ipfs/{cid}` | ||||||||||||||||||||||||||
| - no path traversal or recursive resolution | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # HTTP API | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| A subset of "HTTP API" of :cite[path-gateway]. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## `GET /ipfs/{cid}[?{params}]` | ||||||||||||||||||||||||||
| ## `GET /ipfs/{cid}[/{path}][?{params}]` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Downloads data at specified CID. | ||||||||||||||||||||||||||
| Downloads verifiable data for the specified **immutable** content path. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## `HEAD /ipfs/{cid}[?{params}]` | ||||||||||||||||||||||||||
| Optional `path` is permitted for requests that specify CAR format (`application/vnd.ipld.car`). | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| For RAW requests, only `GET /ipfs/{cid}[?{params}]` is supported. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## `HEAD /ipfs/{cid}[/{path}][?{params}]` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Same as GET, but does not return any payload. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -45,13 +53,13 @@ Downloads data at specified IPNS Key. Verifiable :cite[ipns-record] can be reque | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## `HEAD /ipns/{key}[?{params}]` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| same as GET, but does not return any payload. | ||||||||||||||||||||||||||
| Same as GET, but does not return any payload. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
lidel marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
| # HTTP Request | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Same as in :cite[path-gateway], but with limited number of supported response types. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## HTTP Request Headers | ||||||||||||||||||||||||||
| ## Request Headers | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### `Accept` (request header) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -67,12 +75,162 @@ Below response types SHOULD to be supported: | |||||||||||||||||||||||||
| Gateway SHOULD return HTTP 400 Bad Request when running in strict trustless | ||||||||||||||||||||||||||
| mode (no deserialized responses) and `Accept` header is missing. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Request Query Parameters | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### :dfn[dag-scope] (request query parameter) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Optional, `dag-scope=(block|entity|all)` with default value `all`, only available for CAR requests. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Describes the shape of the DAG fetched the terminus of the specified path whose blocks | ||||||||||||||||||||||||||
| are included in the returned CAR file after the blocks required to traverse | ||||||||||||||||||||||||||
| path segments. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - `block` - Only the root block at the end of the path is returned after blocks | ||||||||||||||||||||||||||
| required to verify the specified path segments. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - `entity` - For queries that traverse UnixFS data, `entity` roughly means return | ||||||||||||||||||||||||||
| blocks needed to verify the terminating element of the requested content path. | ||||||||||||||||||||||||||
| For UnixFS, all the blocks needed to read an entire UnixFS file, or enumerate a UnixFS directory. | ||||||||||||||||||||||||||
| For all queries that reference non-UnixFS data, `entity` is equivalent to `block` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - `all` - Transmit the entire contiguous DAG that begins at the end of the path | ||||||||||||||||||||||||||
| query, after blocks required to verify path segments | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| When present, returned `Etag` must include unique prefix based on the passed scope type. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### :dfn[entity-bytes] (request query parameter) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The optional `entity-bytes=from:to` parameter is available only for CAR | ||||||||||||||||||||||||||
| requests. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| It implies `dag-scope=entity` and serves as a trustless equivalent of an HTTP | ||||||||||||||||||||||||||
| Range Request. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| When the terminating entity at the end of the specified content path: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - can be interpreted as a continuous array of bytes (such as a UnixFS file), a | ||||||||||||||||||||||||||
| Gateway MUST return only the minimal set of blocks necessary to verify the | ||||||||||||||||||||||||||
| specified byte range of that entity. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - cannot be interpreted as a continuous array of bytes (such as a DAG-CBOR/JSON | ||||||||||||||||||||||||||
| map or UnixFS directory), the parameter MUST be ignored, and the request is | ||||||||||||||||||||||||||
| equivalent to `dag-scope=entity`. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Allowed values for `from` and `to` follow a subset of section 14.1.2 from | ||||||||||||||||||||||||||
| :cite[rfc9110], where they are defined as offset integers that limit the | ||||||||||||||||||||||||||
| returned blocks to only those necessary to satisfy the range `[from,to]`: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - `from` value gives the byte-offset of the first byte in a range. | ||||||||||||||||||||||||||
| - `to` value gives the byte-offset of the last byte in the range; | ||||||||||||||||||||||||||
| that is, the byte positions specified are inclusive. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The following additional values are supported: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - `*` can be substituted for end-of-file | ||||||||||||||||||||||||||
| - `entity-bytes=0:*` is the entire file (a verifiable version of HTTP request for `Range: 0-`) | ||||||||||||||||||||||||||
| - Negative numbers can be used for referring to bytes from the end of a file | ||||||||||||||||||||||||||
lidel marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
| - `entity-bytes=-1024:*` is the last 1024 bytes of a file | ||||||||||||||||||||||||||
| (verifiable version of HTTP request for `Range: -1024`) | ||||||||||||||||||||||||||
| - It is also permissible (unlike with HTTP Range Requests) to ask for the | ||||||||||||||||||||||||||
| range of 500 bytes from the beginning of the file to 1000 bytes from the | ||||||||||||||||||||||||||
| end: `entity-bytes=499:-1000` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh look! Real-world use proving this problem: ipfs/js-ipfs-unixfs#335 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rvagg dag-pb TSize has nothing to do with AFAIK the only thing TSize is potentially used by for anyone in the context of the HTTP Gateway API is in the context of the trusted component of the API and giving rough estimates of file/directory sizes in directory HTMLs when the gateway doesn't want to use resources to grab the first block of each directory element to figure out if it's a file/directory and for files what the specs/src/http-gateways/path-gateway.md Line 682 in add659b
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, different value, same problem though; the value is encoded by the producer of the blocks and has to be implicitly trusted to get the right byte range There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, the issue with malformed graphs still exists along with the trust problems you mentioned. It shows up here, but it also likely belongs as an implementers note on the trusted gateway spec as well. I was just calling out that:
Edit: Also, IIUC because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added It is the same class of problems as "I do trust data match the CID i requested, but where do I get trusted CIDs from?" – IMO beyond the scope of this IPIP. |
||||||||||||||||||||||||||
| A Gateway MUST augment the returned `Etag` based on the passed `entity-bytes`. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| A Gateway SHOULD return an HTTP 400 Bad Request error when the requested range | ||||||||||||||||||||||||||
| cannot be parsed as valid offset positions. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| In more nuanced error scenarios, a Gateway MUST return a valid CAR response | ||||||||||||||||||||||||||
| that includes enough blocks for the client to understand why the requested | ||||||||||||||||||||||||||
| `entity-bytes` was incorrect or why only a part of the requested byte range was | ||||||||||||||||||||||||||
| returned: | ||||||||||||||||||||||||||
lidel marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - If the requested `entity-bytes` resolves to a range that partially falls | ||||||||||||||||||||||||||
| outside of the entity's byte range, the response MUST include the subset of | ||||||||||||||||||||||||||
| blocks within the entity's bytes. | ||||||||||||||||||||||||||
| - This allows clients to request valid ranges of the entity without needing | ||||||||||||||||||||||||||
| to know its total size beforehand, and it does not require the Gateway to | ||||||||||||||||||||||||||
| buffer the entire entity before returning the response. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - If the requested `entity-bytes` resolves to a zero-length range or falls | ||||||||||||||||||||||||||
| fully outside of the entity's bytes, the response is equivalent to | ||||||||||||||||||||||||||
| `dag-scope=block`. | ||||||||||||||||||||||||||
| - This allows client to produce a meaningful error (e.g, in case of UnixFS, | ||||||||||||||||||||||||||
| leverage `Data.blocksizes` information present in the root `dag-pb` block). | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # HTTP Response | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Below MUST be implemented **in addition** to "HTTP Response" of :cite[path-gateway]. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## HTTP Response Headers | ||||||||||||||||||||||||||
| ## Response Headers | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### `Content-Type` (response header) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| MUST be returned and include additional format-specific parameters when possible. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| If a CAR stream was requested, the response MUST include the parameter specifying CAR version. | ||||||||||||||||||||||||||
| For example: `Content-Type: application/vnd.ipld.car; version=1` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### `Content-Disposition` (response header) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| MUST be returned and set to `attachment` to ensure requested bytes are not rendered by a web browser. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Response Payload | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Block Response | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| An opaque bytes matching the requested block CID | ||||||||||||||||||||||||||
| ([application/vnd.ipld.raw](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw)). | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The Body hash MUST match the Multihash from the requested CID. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### CAR Response | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| A CAR stream for the requested | ||||||||||||||||||||||||||
| [application/vnd.ipld.car](https://www.iana.org/assignments/media-types/application/vnd.ipld.car) | ||||||||||||||||||||||||||
| content type, path and optional `dag-scope` and `entity-bytes` URL parameters. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #### CAR version | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Value returned in | ||||||||||||||||||||||||||
| [`CarV1Header.version`](https://ipld.io/specs/transport/car/carv1/#header) | ||||||||||||||||||||||||||
| field MUST match the `version` parameter returned in `Content-Type` header. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #### CAR roots | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The behavior associated with the | ||||||||||||||||||||||||||
| [`CarV1Header.roots`](https://ipld.io/specs/transport/car/carv1/#header) field | ||||||||||||||||||||||||||
| is not currently specified. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Clients MAY ignore it. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| :::issue | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| As of 2023-06-20, the behavior of the `roots` CAR field remains an [unresolved item within the CARv1 specification](https://web.archive.org/web/20230328013837/https://ipld.io/specs/transport/car/carv1/#unresolved-items). | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ::: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #### CAR determinism | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The default CAR header and block order in a CAR response is not specified and is non-deterministic. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Clients MUST NOT assume that CAR responses are deterministic (byte-for-byte identical) across different gateways. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Clients MUST NOT assume that CAR includes CIDs and their blocks in the same order across different gateways. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| :::issue | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| In controlled environments, clients MAY choose to rely on undocumented CAR determinism, | ||||||||||||||||||||||||||
| subject to the agreement of the following conditions between the client and the | ||||||||||||||||||||||||||
| gateway: | ||||||||||||||||||||||||||
| - CAR version | ||||||||||||||||||||||||||
| - content of [`CarV1Header.roots`](https://ipld.io/specs/transport/car/carv1/#header) field | ||||||||||||||||||||||||||
| - order of blocks | ||||||||||||||||||||||||||
| - status of duplicate blocks | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| In the future, there may be an introduction of a convention to indicate aspects | ||||||||||||||||||||||||||
| of determinism in CAR responses. Please refer to | ||||||||||||||||||||||||||
| [IPIP-412](https://github.com/ipfs/specs/pull/412) for potential developments | ||||||||||||||||||||||||||
| in this area. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ::: | ||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.