Skip to content

Added support for link rel=compression-dictionary#11620

Open
pmeenan wants to merge 7 commits into
whatwg:mainfrom
pmeenan:dict
Open

Added support for link rel=compression-dictionary#11620
pmeenan wants to merge 7 commits into
whatwg:mainfrom
pmeenan:dict

Conversation

@pmeenan

@pmeenan pmeenan commented Sep 3, 2025

Copy link
Copy Markdown
Contributor

Add processing steps for handling the "compression-dictionary" link relation type defined in HTTP Compression Dictionary Transport.

It largely mirrors the support for prefetch but also adds a default crossorigin mode of "cors" anonymous (necessary for dictionaries to be usable in a third-party context).

Fix #11619


/index.html ( diff )
/links.html ( diff )
/references.html ( diff )
/semantics.html ( diff )

@pmeenan

pmeenan commented Sep 3, 2025

Copy link
Copy Markdown
Contributor Author

RFC is pending publication so this should wait until it has been published (any day now - final edits are complete).

Comment thread source
Comment thread source Outdated
</ol>

<p>The <span>process a link header</span> steps for this type of linked resource are to do
nothing.</p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double-checking that this is intended? https://datatracker.ietf.org/doc/draft-ietf-httpbis-compression-dictionary/ seems to imply the Link: header should work, but this mandates that in browsers it do nothing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Mistake from mirroring the prefetch behavior. Should be fixed now. The flow feels a bit weird since I merged the header and link element processing steps but need to not fire the load/error in the header side of things (made el optional to the processing). Happy for suggestions on ways to make it cleaner.

Presumably we could also treat it more like preconnect and fire-and-forget without load/error events.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the intended pattern is supposed to be like what preload does. I believe you could make that work, but I haven't double-checked...

@domenic

domenic commented Sep 4, 2025

Copy link
Copy Markdown
Member

The structure here is a bit surprising for me, in that you have HTML just do a fetch, and then do nothing with the response.

Instead, you seem to have located the response processing all in whatwg/fetch#1854. I can understand that if the goal is that there are many places that should be able to trigger that processing, e.g., if you want to be able to trigger it from fetch(). But, if HTML is the only place on the web platform that can set a "compression-dictionary" initiator, what is the point of that?

A more normal processing model would be to process the response in HTML, and not modify Fetch much. Was that considered?

@pmeenan

pmeenan commented Sep 4, 2025

Copy link
Copy Markdown
Contributor Author

The structure here is a bit surprising for me, in that you have HTML just do a fetch, and then do nothing with the response.

Instead, you seem to have located the response processing all in whatwg/fetch#1854. I can understand that if the goal is that there are many places that should be able to trigger that processing, e.g., if you want to be able to trigger it from fetch(). But, if HTML is the only place on the web platform that can set a "compression-dictionary" initiator, what is the point of that?

A more normal processing model would be to process the response in HTML, and not modify Fetch much. Was that considered?

Compression dictionaries are a transport-layer content-encoding and entirely handled within fetch. For the most part they should be completely transparent to HTML. Any HTTP response for any fetch can be stored as a compression dictionary and, usually, none of that will even be visible from HTML.

We did need a way to trigger a fetch for triggering the request of a dictionary that would not have otherwise been loaded (which will then be treated like any other response and handled entirely at the HTTP layer). preload and prefetch both would have worked fine (and can still work if someone uses them and they have the appropriate response headers) but by using a dedicated relation type we can avoid triggering fetches from clients that don't support compression dictionaries.

It also allows for adjusting the priorities and timing of the fetch independently from prefetches and preloads.

@domenic

domenic commented Sep 8, 2025

Copy link
Copy Markdown
Member

Any HTTP response for any fetch can be stored as a compression dictionary and, usually, none of that will even be visible from HTML.

Got it. I misunderstood the role of the compression-dictionary initiator. It is not required that the request initiator be set to compression-dictionary, for the response to be used as such.

In that case, I agree with the design split.

@pmeenan

pmeenan commented Nov 11, 2025

Copy link
Copy Markdown
Contributor Author

The RFC finally published so this should be ready for review now (just rebased it).

Comment thread source
Comment thread source
that preemptively <span data-x="concept-fetch">fetching</span> and caching the specified resource
or same-site document is likely to be beneficial, as it is highly likely that the user will
be able to this resource as a compression dictionary for future
<span data-x="concept-fetch">fetches</span>. <ref>RFC9842</ref></p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ref required? We're not referencing any definition from that spec, right? (Maybe I don't understand all the ref rules and Anne can correct me).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 2 <ref>RFC9842</ref> references in the PR (both around similar language for link) and they are the only references to the compression dictionary RFC. I'm fine with removing both of them but then people would likely have to go through the fetch spec and from there to the RFC to see what compression dictionaries are.

The closest analog I could see in the code is from the img src text when it references the various bitmap formats without explicitly relying on anything in their specifications (around line 30710):

  <p class="note">The requirements above imply that images can be static bitmaps (e.g. PNGs, GIFs,
  JPEGs), single-page vector documents (single-page PDFs, XML files with an SVG document element),
  animated bitmaps (APNGs, animated GIFs), animated vector graphics (XML files with an SVG
  <span>document element</span> that use declarative SMIL animation), and so forth. However, these
  definitions preclude SVG files with script, multipage PDF files, interactive MNG files, HTML
  documents, plain text documents, and the like. <ref>PNG</ref> <ref>GIF</ref> <ref>JPEG</ref>
  <ref>PDF</ref> <ref>XML</ref> <ref>APNG</ref> <ref>SVG</ref> <ref>MNG</ref></p>

Comment thread source Outdated
Comment thread source
data-x="create link options from element">create link options</span> from <var>el</var> and
to <span>load a compression dictionary</span> given the result and <var>el</var>.</p>

<p>The <span>process a link header</span> step for this type of linked resource given a <span

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding from TPAC is that compression dictionary responses are intended to be processed almost primarily on subresource requests. But this header-processing algorithm does not run in those cases, and in fact we do not have a spec'ed processing model for subresource Link header requests. Is my understanding correct, and do we have tests for this behavior?

We haven't really had a pressing need to spec the Link header processing model on subresource requests, but if that's one of the main and expected ways of engaging with this new feature, and we have tests for it, perhaps it's important enough to invest in.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Link header is independent from the use of the dictionaries for compression and is used to trigger the loading of a stand-alone dictionary (instead of the subresource delta-compression model where a response is a dictionary itself).

The main use case envisioned is for a HTML document to trigger the loading of a dictionary that would be used in future document requests (compressing away the common HTML templates).

That said, I am sure someone would have a use case for triggering a separate dictionary request from subresources and that might be something Chrome currently allows (along with preload and preconnect) though there are ongoing discussions about how those should be handled to avoid tracking concerns.

The dictionary use case for subresource link headers should probably be included in whatever spec work we do to specify the behavior for preconnect and preload.

Right now the only WPT tests that use the Link header are for the document itself.

@pmeenan pmeenan force-pushed the dict branch 2 times, most recently from 3d454f8 to 6b1b201 Compare December 16, 2025 17:43
Comment thread source
<p>The <code data-x="rel-compression-dictionary">compression-dictionary</code> keyword indicates
that preemptively <span data-x="concept-fetch">fetching</span> and caching the specified resource
or same-site document is likely to be beneficial, as it is highly likely that the user will
be able to this resource as a compression dictionary for future

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the user will be able to this resource" => I think some verb is missing here?

Comment thread source
<code data-x="rel-compression-dictionary">compression-dictionary</code> keyword.</p>

<p>The appropriate times to <span data-x="fetch and process the linked resource">fetch and
process</span> this type of link are:</p>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, we only have one test fetch/compression-dictionary/dictionary-fetch-with-link-element.tentative.https.html for <link rel=compression-dictionary> and it only covers a simple case: a link element is created, inserted it in the doc and we check that the dictionary becomes available at some point in the future.

We should also tests that dictionary does not become available after some timeout if not all conditions are fulfilled (e.g. that if we create a link but without inserting it in the document).

It would also be interesting to check load cancellation or update (e.g. the attribute href attribute is removed or modified before the fetch started) but I suspect that will require a way to be sure a load hasn't started.

Comment thread source

<ul>
<li><p>When the <span>external resource link</span> is created on a <code>link</code> element
that is already <span>browsing-context connected</span>.</p></li>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that correspond to a <link rel="compression-dictionary"> that is already present in the doc (not dynamically inserted)? If so it does not seem to be covered by the tests.

Comment thread source
that is already <span>browsing-context connected</span>.</p></li>

<li><p>When the <span>external resource link</span>'s <code>link</code> element <span>becomes
browsing-context connected</span>.</p></li>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the case covered by the test, but maybe we should also check that, before the insertion, dictionary does not become available.

Comment thread source

<li><p>When the <code data-x="attr-link-href">href</code> attribute of the <code>link</code>
element of an <span>external resource link</span> that is already <span>browsing-context
connected</span> is changed.</p></li>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be covered by existing tests.

Comment thread source
<div algorithm>
<p>The <span>fetch and process the linked resource</span> steps for this type of linked resource,
given a <code>link</code> element <var>el</var>, are to <span
data-x="create link options from element">create link options</span> from <var>el</var> and

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I guess there is a bunch of options to be tested here: https://html.spec.whatwg.org/#create-link-options-from-element ; dictionary-fetch-with-link-element.tentative.https.html seems quite limited with only a test for crossorigin=anonymous (which is also default).

Comment thread source

<p>The <span>process a link header</span> step for this type of linked resource given a <span
data-x="link processing options">link processing options</span> <var>options</var> are to
<span>load a compression dictionary</span> given <var>options</var>.</p>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I don't see a lot of options tested for dictionary-fetch-with-link-header.tentative.https.html

Comment thread source
data-x="event-error">error</code> at <var>el</var>.</p></li>

<li><p>Otherwise, if <var>el</var> is set, <span data-x="concept-event-fire">fire an event</span>
named <code data-x="event-load">load</code> at <var>el</var>.</p></li>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please add WPT tests for these two events? (for both Link header and element).

Comment thread source
<li><p>The user agent should <span data-x="concept-fetch">fetch</span> <var>request</var>, with
<i data-x="processResponseConsumeBody">processResponseConsumeBody</i> set to
<var>processCompressionDictionaryResponse</var>. User agents may delay the fetching of
<var>request</var> to prioritize other requests that are necessary for the current document.</p></li>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this is based on "prefetch", but I believe the spec should clarify the timing for <link rel=compression-dictionary>.

From whatwg/fetch#1854 (comment) I understand we need to wait a browser's idle period (which I guess can be verified with https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback for browsers that support it, or otherwise a double requestAnimationFrame) and (maybe) until the document load event was already dispatched.

Again, it would be nice to have some tests that verify we don't trigger the load before these conditions are met. Perhaps the events from the previous sections would be useful for that purpose.

Regarding Link header, I understand these conditions do not apply. I suspect we'd prefer to handle preconnect and preload before, but https://html.spec.whatwg.org/#process-link-headers does not seem to indicate a preferred order.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pmeenan shared info privately based on Chromium's code, basically:

  • For Link header handling of compressed-dictionary is deferred after the document load completes.
  • For Link element, this is done asap as described here (when browsing-context connected etc).
  • For both Link header and element, this is done by pushing the fetches into a task queue, which are executed only when the browser's main thread becomes idle.

In one comment above, the case of subresources was mentioned. It seems Chromium handles them a bit differently, as Link header for them is allowed before the load completes when they are not coming from the memory cache: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/loader/preload_helper.cc;l=252;drc=88330e24edafaacd0d2f012282526e096a90b33a

Comment thread source
data-x="create link options from element">create link options</span> from <var>el</var> and
to <span>load a compression dictionary</span> given the result and <var>el</var>.</p>

<p>The <span>process a link header</span> step for this type of linked resource given a <span

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this is also used by https://html.spec.whatwg.org/#process-link-headers

(I guess the use case is even less important, but technically we should have WPT test for that too)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Add support for <link rel=compression-dictionary ...>

4 participants