Skip to content

Fix #6159: give early hints a destination and an off switch - #6160

Open
BalusC wants to merge 1 commit into
5.0from
issue_6159
Open

BalusC wants to merge 1 commit into
5.0from
issue_6159

Conversation

@BalusC

@BalusC BalusC commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Closes #6159

A Link preload header without an as destination never matches the request of the element, so the browser fetches every head resource again from the page. ExternalContextImpl now derives the destination from the extension of the resource: style for css, script for js, and font plus crossorigin for woff2, woff, ttf and otf. Other resources, such as images, get no hint. The FacesServlet suffix mapping, path parameters such as ;jsessionid, and the query string are stripped first.

The 103 is only sent over HTTP/2 or later. An HTTP/1.1 client or intermediary may take a 103 for the final response (RFC 8297, section 3), and browsers only act on early hints over HTTP/2 anyway. The Link headers stay on the final 200, where a CDN can still pick them up.

The new context parameter org.glassfish.mojarra.disableEarlyHints (default false) switches off both the headers and the 103. It is documented in CONTEXT-PARAMS.md.

ExternalContextImpl.normalize(String) becomes private, as nothing outside the class calls it.

Tests:

  • ExternalContextImplTest: the destination for each mapping kind, path parameters, case, null mapping, the parameter, and the 103 for each protocol.
  • Issue5746IT: no 103 over HTTP/1.1, while the 200 carries Link with as; and over HTTP/2 the browser receives a 103 with rel=preload;as= for each head resource.
  • New DisableEarlyHintsIT: no Link headers when the parameter is true.

Chrome only uses the preloads over a certificate it really trusts. This was verified by hand with a scratch CA: every head resource then reports initiatorType early-hints. Without as, or with a certificate error that is only ignored, the element fetches the resource itself. The pooled IT server has a self-signed certificate, so Issue5746IT asserts the content of the 103 instead.

🤖 Generated with Claude Opus 5.5

A Link preload header without an as destination never matches the
request of the element, so the browser fetched every head resource
again from the page. The destination now follows from the extension
of the resource: style for css, script for js, and font with
crossorigin for woff2, woff, ttf and otf. Other resources get no hint.
The FacesServlet suffix mapping, path parameters and query string are
stripped before the extension is read.

The 103 interim response is only sent over HTTP/2 or later, because an
HTTP/1.1 client or intermediary may take it for the final response
(RFC 8297, section 3). The Link headers stay on the final response.

The new org.glassfish.mojarra.disableEarlyHints context parameter
switches off both.

ExternalContextImpl.normalize(String) becomes private, as nothing
outside the class calls it.

Chrome only uses the preloads over a certificate it really trusts, not
over one whose error it was told to ignore. That was verified by hand
with a scratch CA. Issue5746IT runs on the self-signed certificate of
the pooled server, so it asserts the content of the 103 instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BalusC BalusC added this to the 5.0.0 milestone Nov 11, 2026

This branch has not been deployed

No deployments
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.

1 participant