Skip to content

feat(gateway): IPIP-548 Ipfs-Uri response header - #1209

Merged
lidel merged 6 commits into
mainfrom
ipip-548-ipfs-uri
Aug 27, 2026
Merged

feat(gateway): IPIP-548 Ipfs-Uri response header#1209
lidel merged 6 commits into
mainfrom
ipip-548-ipfs-uri

Conversation

@lidel

@lidel lidel commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Problem

X-Ipfs-Path cannot carry every UnixFS file name: bytes outside visible ASCII are invalid in HTTP field values1, so a path like /ipfs/{cid}/łódź.txt reaches clients garbled or silently altered. ipfs/specs#548 deprecates the header in favor of Ipfs-Uri, a percent-encoded ipfs:// / ipns:// URI that survives any file name.

Fix

  • emit Ipfs-Uri per IPIP-548: Sunset x-ipfs-path header specs#548: canonical authority (base32 CIDv1, base36 IPNS name, A-label DNSLink), strict percent-encoding of every path segment, sent on deserialized, redirect, and error responses, exposed for CORS
  • stop sending X-Ipfs-Path by default; Config.DeprecatedXIpfsPath plus Headers.WithDeprecatedXIpfsPath restore it for legacy consumers, still omitted when the path has unsafe bytes
  • covered by feat: tests for IPIP-548 Ipfs-Uri header gateway-conformance#301; CI pins that branch until a release ships (TODO in the workflow)

Tests

All pass, Sharness can be ignored here, it pass in Kubo using conformance and boxo/gateway from this PR:

Footnotes

  1. RFC 9110, section 5.5: field values are limited to HTAB, SP, and visible ASCII.

@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.00000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.33%. Comparing base (25b1db8) to head (8ed1938).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
gateway/handler.go 90.32% 3 Missing and 3 partials ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1209      +/-   ##
==========================================
+ Coverage   64.18%   64.33%   +0.14%     
==========================================
  Files         269      269              
  Lines       27193    27258      +65     
==========================================
+ Hits        17455    17536      +81     
+ Misses       8024     8010      -14     
+ Partials     1714     1712       -2     
Files with missing lines Coverage Δ
gateway/gateway.go 79.22% <ø> (ø)
gateway/headers.go 100.00% <100.00%> (ø)
gateway/handler.go 82.65% <90.32%> (+2.17%) ⬆️

... and 13 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@lidel
lidel force-pushed the ipip-548-ipfs-uri branch 2 times, most recently from 5e24c4e to b52d029 Compare August 21, 2026 02:56
@lidel
lidel marked this pull request as ready for review August 21, 2026 03:35
@lidel
lidel requested a review from a team as a code owner August 21, 2026 03:35
@lidel
lidel force-pushed the ipip-548-ipfs-uri branch from b52d029 to fd861e7 Compare August 22, 2026 12:34
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 force-pushed the ipip-548-ipfs-uri branch from fd861e7 to 37cbbdd Compare August 22, 2026 12:35
lidel added 2 commits August 24, 2026 01:20
Per IPIP-548 only dotted DNSLink names become an ipns:// authority:
example.local works, examplenodot never does.

Refs ipfs/helia-verified-fetch#376 (comment)
Use the conformance tests from ipfs/gateway-conformance#301 at its
latest commit, which adds the dot-less DNSLink Ipfs-Uri tests.
@lidel

lidel commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

The red sharness is the usual cross-repo dance: it runs kubo master's sharness, which still expects X-Ipfs-Path. ipfs/kubo#11437 updates it and is fully green against this branch, so main goes green once that lands. Fine to merge.

@lidel
lidel merged commit 63cae36 into main Aug 27, 2026
31 of 33 checks passed
lidel added a commit to ipfs/kubo that referenced this pull request Aug 27, 2026
* feat: Ipfs-Uri gateway header (IPIP-548)

Bump boxo to the IPIP-548 implementation (ipfs/boxo#1209): gateway
responses carry a canonical percent-encoded Ipfs-Uri header and stop
sending the deprecated X-Ipfs-Path, which cannot represent every
UnixFS file name.

- sharness: CORS expects Ipfs-Uri exposed, X-Ipfs-Path gone
- gateway-conformance CI pinned to the IPIP-548 test suite
  (ipfs/gateway-conformance#301) until a release ships
- reverse-proxy doc and v0.44 changelog updated

Refs ipfs/specs#548

* feat: opt-in Gateway.DeprecatedXIpfsPath

Expose boxo's opt-in for the legacy X-Ipfs-Path response header as a
kubo config flag, default off. Unsafe: the legacy value cannot
represent every UnixFS file name, so it must only be used to
facilitate migration to Ipfs-Uri, and even when enabled the header
is still skipped when the value would include non-ASCII byte
sequences.

Refs ipfs/specs#548

* ci: bump gateway-conformance pin

* ci: gateway-conformance v0.14

* chore: boxo with IPIP-548 from boxo/main

* docs: Ipfs-Uri changelog in v0.43.1

* docs: assemble v0.43.1 changelog

Move the v0.44 highlights and dependency lines into a new v0.43.1
section, and add the missing entry for owner-only key exports
(#11428). v0.44.md returns to an empty skeleton.

* docs: note boxo v0.42.2 fixes in v0.43.1
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.

2 participants