Skip to content

IPIP-548: Sunset x-ipfs-path header - #548

Open
achingbrain wants to merge 6 commits into
mainfrom
ipip-548-sunset-x-ipfs-path
Open

IPIP-548: Sunset x-ipfs-path header#548
achingbrain wants to merge 6 commits into
mainfrom
ipip-548-sunset-x-ipfs-path

Conversation

@achingbrain

Copy link
Copy Markdown
Member

The x-ipfs-path header can contain characters outside of the US-ASCII character set which some clients will refuse to process.

Adding encoding rules to this header could break existing clients, instead add an ipfs-uri header that performs the same task but is a URI instead of a path so follows standard percent-encoding rules found in RFC 3986.

Futher discussion can be found in #547.

The `x-ipfs-path` header can contain characters outside of the US-ASCII
character set which some clients will refuse to process.

Adding encoding rules to this header could break existing clients,
instead add an `ipfs-uri` header that performs the same task but is a
URI instead of a path so follows standard percent-encoding rules found
in RFC 3986.

Futher discussion can be found in #547.
@achingbrain
achingbrain requested a review from lidel as a code owner August 18, 2026 11:41
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown

🚀 Build Preview on IPFS ready

  • 🔎 Commit: 01ababb
  • 🔏 CID bafybeidwjz3nqbmpprznudluazzl3tmqel66ofmsywdgfav2yzyj6qxn2i
  • 📦 Preview:

@achingbrain
achingbrain requested a review from a team as a code owner August 18, 2026 11:55
@lidel

lidel commented Aug 21, 2026

Copy link
Copy Markdown
Member

(I'll be adding some extra ipip-0548-test-fixtures.zip)

lidel added 2 commits August 21, 2026 03:51
Build the Ipfs-Uri header on the ipfs-uri and ipns-uri specs instead
of restating their canonical forms, and pin down what a second
implementation needs to emit byte-identical values:

- content path: decode request segments once, %2F is a separator
- strict RFC 3986 percent-encoding, with %2E / %2E%2E for dot segments
- DNSLink authority converts to A-labels or the header is omitted
- header also sent on redirects and errors, capped at 8192 bytes,
  exposed for CORS
- X-Ipfs-Path is legacy-only and MUST be omitted for non-ASCII paths
Make the IPIP lean on the URI specs and give implementers testable
fixtures per AGENTS.md:

- cite ipfs-uri and ipns-uri as the base of the design
- fixture table covers all 15 files of the tricky-filenames dir; the
  CAR is attached to the PR and the root is pinned as
  ipip-548_test-fixtures
- add gateway-conformance dir-with-percent-encoded-filename.car as a
  second fixture that catches raw URL path passthrough
- status back to proposal, point relatedIssues at discussion #547
lidel added a commit to ipfs/boxo that referenced this pull request Aug 21, 2026
Implement the Ipfs-Uri response header from ipfs/specs#548: a
canonical ipfs:// or ipns:// URI for the requested content path,
safe in an HTTP field value for any UnixFS file name.

- authority in canonical form: base32 CIDv1, base36 IPNS name
  keeping its multicodec, lowercase A-label DNSLink; header omitted
  when the root cannot be normalized
- every path segment percent-encoded over the RFC 3986 unreserved
  set with uppercase hex; "." and ".." emitted as %2E / %2E%2E
- sent on deserialized, redirect, and error responses up to 8192
  bytes, and exposed via default Access-Control-Expose-Headers
- X-Ipfs-Path no longer sent by default; restore via
  Config.DeprecatedXIpfsPath + Headers.WithDeprecatedXIpfsPath,
  still omitted for bytes invalid in a field value
- CI runs gateway-conformance from ipfs/gateway-conformance#301
  until a release with the IPIP-548 tests ships
lidel added a commit to ipfs/gateway-conformance that referenced this pull request Aug 21, 2026
Cover the Ipfs-Uri response header from ipfs/specs#548 and the
deprecation of X-Ipfs-Path, one request per failure class:

- canonical percent-encoded segments: delimiters, platform-encoder
  gaps (!'()*~), 4-byte UTF-8; full byte-level vectors live in the
  IPIP-0548 fixtures table
- request-spelling independence over
  dir-with-percent-encoded-filename.car: raw sub-delims and
  lowercase hex must yield the same canonical value
- decode-once normalization (%2F, %2E, dot segments), nested
  trailing slashes, query exclusion on alternate formats, redirects
- authority normalization: CIDv0 and legacy base58 peer IDs
- X-Ipfs-Path must be omitted for non-ASCII paths and unchanged
  when present for ASCII-safe ones; existing expectations move to
  Ipfs-Uri, raw block tests drop the header expectation, CORS
  expects Ipfs-Uri exposed
- DNSLink hosts get an ipns:// assertion in the dnslink suite
lidel added a commit to ipfs/boxo that referenced this pull request Aug 21, 2026
Implement the Ipfs-Uri response header from ipfs/specs#548: a
canonical ipfs:// or ipns:// URI for the requested content path,
safe in an HTTP field value for any UnixFS file name.

- authority in canonical form: base32 CIDv1, base36 IPNS name
  keeping its multicodec, lowercase A-label DNSLink; header omitted
  when the root cannot be normalized
- every path segment percent-encoded over the RFC 3986 unreserved
  set with uppercase hex; "." and ".." emitted as %2E / %2E%2E
- sent on deserialized, redirect, and error responses up to 8192
  bytes, and exposed via default Access-Control-Expose-Headers
- X-Ipfs-Path no longer sent by default; restore via
  Config.DeprecatedXIpfsPath + Headers.WithDeprecatedXIpfsPath,
  still omitted for bytes invalid in a field value
- CI runs gateway-conformance from ipfs/gateway-conformance#301
  until a release with the IPIP-548 tests ships
@lidel

lidel commented Aug 21, 2026

Copy link
Copy Markdown
Member

Thanks @achingbrain for kicking this off, Ipfs-Uri closes a real gap.

The header hid more edge cases than expected (./.. segments, %2F, names that already look percent-encoded, DNSLink IDNs, legacy base58 peer IDs), so I pushed clarifications here (9d187a6, 99afeee): the Ipfs-Uri section now builds on the ipfs:// / ipns:// URI specs and pins the exact serialization, X-Ipfs-Path is legacy-only and omitted when the content path is not ASCII-safe, and the fixtures table covers names across nine alphabets (CAR in the zip above).

Remaining before ratification:

Both implementations follow the spec as closely as possible; push back or relax if any of it feels too pedantic. I'm also leaning toward dropping x-ipfs-path by default and keeping it opt-in (as boxo does): the raw value is unsafe anyway. PTAL

lidel added a commit to ipfs/gateway-conformance that referenced this pull request Aug 22, 2026
Cover the Ipfs-Uri response header from ipfs/specs#548 and the
deprecation of X-Ipfs-Path, one request per failure class:

- canonical percent-encoded segments: delimiters, platform-encoder
  gaps (!'()*~), 4-byte UTF-8; full byte-level vectors live in the
  IPIP-0548 fixtures table
- request-spelling independence over
  dir-with-percent-encoded-filename.car: raw sub-delims and
  lowercase hex must yield the same canonical value
- decode-once normalization (%2F, %2E, dot segments), nested
  trailing slashes, query exclusion on alternate formats, redirects
- a hand-built fixture with a link literally named "a/b.txt" proves
  such an entry is not path-addressable: %2F always decodes to a
  separator, so the nested b.txt wins under every request spelling
- authority normalization: CIDv0 and legacy base58 peer IDs
- X-Ipfs-Path must be omitted for non-ASCII paths and unchanged
  when present for ASCII-safe ones; existing expectations move to
  Ipfs-Uri, raw block tests drop the header expectation, CORS
  expects Ipfs-Uri exposed
- DNSLink hosts get an ipns:// assertion in the dnslink suite
lidel added a commit to ipfs/boxo that referenced this pull request Aug 22, 2026
Implement the Ipfs-Uri response header from ipfs/specs#548: a
canonical ipfs:// or ipns:// URI for the requested content path,
safe in an HTTP field value for any UnixFS file name.

- authority in canonical form: base32 CIDv1, base36 IPNS name
  keeping its multicodec, lowercase A-label DNSLink; header omitted
  when the root cannot be normalized
- every path segment percent-encoded over the RFC 3986 unreserved
  set with uppercase hex; "." and ".." emitted as %2E / %2E%2E
- sent on deserialized, redirect, and error responses up to 8192
  bytes, and exposed via default Access-Control-Expose-Headers
- X-Ipfs-Path no longer sent by default; restore via
  Config.DeprecatedXIpfsPath + Headers.WithDeprecatedXIpfsPath,
  still omitted for bytes invalid in a field value
- CI runs gateway-conformance from ipfs/gateway-conformance#301
  until a release with the IPIP-548 tests ships
lidel added a commit to ipfs/gateway-conformance that referenced this pull request Aug 22, 2026
Cover the Ipfs-Uri response header from ipfs/specs#548 and the
deprecation of X-Ipfs-Path, one request per failure class:

- canonical percent-encoded segments: delimiters, platform-encoder
  gaps (!'()*~), 4-byte UTF-8; full byte-level vectors live in the
  IPIP-0548 fixtures table
- request-spelling independence over
  dir-with-percent-encoded-filename.car: raw sub-delims and
  lowercase hex must yield the same canonical value
- decode-once normalization (%2F, %2E, dot segments), nested
  trailing slashes, query exclusion on alternate formats, redirects
- a hand-built fixture with a link literally named "a/b.txt" proves
  such an entry is not path-addressable: %2F always decodes to a
  separator, so the nested b.txt wins under every request spelling
- authority normalization: CIDv0 and legacy base58 peer IDs
- X-Ipfs-Path must be omitted for non-ASCII paths and unchanged
  when present for ASCII-safe ones; existing expectations move to
  Ipfs-Uri, raw block tests drop the header expectation, CORS
  expects Ipfs-Uri exposed
- DNSLink hosts get an ipns:// assertion in the dnslink suite
lidel added a commit to ipfs/boxo that referenced this pull request Aug 22, 2026
Implement the Ipfs-Uri response header from ipfs/specs#548: a
canonical ipfs:// or ipns:// URI for the requested content path,
safe in an HTTP field value for any UnixFS file name.

- authority in canonical form: base32 CIDv1, base36 IPNS name
  keeping its multicodec, lowercase A-label DNSLink; header omitted
  when the root cannot be normalized
- every path segment percent-encoded over the RFC 3986 unreserved
  set with uppercase hex; "." and ".." emitted as %2E / %2E%2E
- sent on deserialized, redirect, and error responses up to 8192
  bytes, and exposed via default Access-Control-Expose-Headers
- X-Ipfs-Path no longer sent by default; restore via
  Config.DeprecatedXIpfsPath + Headers.WithDeprecatedXIpfsPath,
  still omitted for bytes invalid in a field value
- CI runs gateway-conformance from ipfs/gateway-conformance#301
  until a release with the IPIP-548 tests ships
A dag-pb link name may contain a slash at the byte level, but no
content path can address it. Make every relevant spec say so:

- unixfs: names containing "/" join the restricted names list, and
  the path escaping section defines the HTTP gateway and URI behavior
  while leaving other contexts unspecified
- path-gateway: spell out the consequence next to the %2F rule
- ipip-0548: record the previously-undefined escaping gap in the
  design rationale, and reference the conformance fixture that proves
  a slash-named link resolves to the nested file under every request
  spelling

Refs ipfs/helia-verified-fetch#376 (comment)
@lidel
lidel force-pushed the ipip-548-sunset-x-ipfs-path branch from 8e17877 to 01ababb Compare August 22, 2026 12:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants