Bug 1807268 - Re-enable verifyShowClipboardSuggestionsToggleTest UI test r=jajohnson
[gecko.git] / netwerk / docs / early_hints.md
blob6390365072a5d48594c0014dc820c7967ba8e204
1 # Early Hints
3 [Early Hints](https://html.spec.whatwg.org/multipage/semantics.html#early-hints) is an informational HTTP status code allowing server to send headers likely to appear in the final response before sending the final response.
4 This is used to send [Link headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link) to start `preconnect`s and `preload`s.
6 This document is about the implementation details of Early Hints in Firefox.
7 We focus on the `preload` feature, as it is the main feature interacting with classes.
8 For Early Hint `preconnect` the Early Hints specific code is rather small and only touches the code path on [`103 Early Hints` responses](#early-hints-response-on-main-document-load).
10 ```{mermaid}
11 sequenceDiagram
12     participant F as Firefox
13     participant S as Server
14     autonumber
15     F->>+S: Main document Request: GET /
16     S-->>F: 103 Early Hints Response
17     note over F: Firefox starts<br/>hinted requests
18     note over S: Server Think Time
19     S->>-F: 200 OK final response
20 ```
22 Early Hints benefits originate from leveraging Server Think Time.
23 The duration between response (2) and (3) arriving is the theoretical maximal benefit Early Hints can have.
24 The server think time can originate from creating dynamic content by interacting with databases or more commonly when proxying the request to a different server.
26 ```{contents}
27 :local:
28 :depth: 1
29 ```
31 ## `103 Early Hints` Response on Main Document Load
33 On `103 Early Hints` response the `nsHttpChannel` handling main document load passes the link header and a few more from the `103 Early Hints` response to the `EarlyHintsService`
35 When receiving a `103 Early Hints` response, the `nsHttpChannel` forwards the `Link` headers in the `103 Early Hints` response to the `EarlyHintsService`
36 When the `DocumentLoadListener` receives a cross-origin redirect, it cancels all preloads in progress.
38 ```{note}
39 Only the first `103 Early Hints` response is processed.
40 The remaining `103 Early Hints` responses are ignored, even after same-origin redirects.
41 When we receive cross origin redirects, all ongoing Early Hint preload requests are cancelled.
42 ```
44 ```{mermaid}
45 graph TD
46     MainChannel[nsHttpChannel]
47     EHS[EarlyHintsService]
48     EHC[EarlyHintPreconnect]
49     EHP[EarlyHintPreloader]
50     PreloadChannel[nsIChannel]
51     PCL[ParentChannelListener]
53     MainChannel
54       -- "nsIEarlyHintsObserver::EarlyHint(LinkHeader, Csp, RefererPolicy)<br/>via DocumentLoadListener"
55       --> EHS
56     EHS
57         -- "rel=preconnect"
58         --> EHC
59     EHS -->|"rel=preload<br/>via OngoingEarlyHints"| EHP
60     EHP -->|"CSP checks then AsyncOpen"| PreloadChannel
61     PreloadChannel -->|mListener| PCL
62     PCL -->|mNextListener| EHP
63 ```
65 ## Main document Final Response
67 On the final response the `DocumentLoadListener` retrieves the list of link headers from the `EarlyHintsService`.
68 As a side effect, the `EarlyHintPreloader` also starts a 10s timer to cancel itself if the content process doesn't connect to the `EarlyHintPreloader`.
69 The timeout shouldn't occur in normal circumstances, because the content process connects to that `EarlyHintPreloader` immediately.
70 The timeout currently only occurs when:
72 - the main response has different CSP requirements disallowing the load ([Bug 1815884](https://bugzilla.mozilla.org/show_bug.cgi?id=1815884)),
73 - the main response has COEP headers disallowing the load ([Bug 1806403](https://bugzilla.mozilla.org/show_bug.cgi?id=1806403)),
74 - the user reloads a website and the image/css is already in the image/css-cache ([Bug 1815884](https://bugzilla.mozilla.org/show_bug.cgi?id=1815884)),
75 - the tab gets closed before the connect happens or possibly other corner cases.
77 ```{mermaid}
78 graph TD
79     DLL[DocumentLoadListener]
80     EHP[EarlyHintPreloader]
81     PS[PreloadService]
82     EHR[EarlyHintsRegistrar]
83     Timer[nsITimer]
85     DLL
86         -- "(1)<br/>GetAllPreloads(newCspRequirements)<br/> via EarlyHintsService and OngoingEarlyHints"
87         --> EHP
88     EHP -->|"Start timer to cancel on<br/>ParentConnectTimeout<br/>after 10s"| Timer
89     EHP -->|"Register(earlyHintPreloaderId)"| EHR
90     Timer -->|"RefPtr"| EHP
91     EHR -->|"RefPtr"| EHP
92     DLL
93         -- "(2)<br/>Send to content process via IPC<br/>List of Links+earlyHintPreloaderId"
94         --> PS
95 ```
97 ## Preload request from Content process
99 The Child process parses Link headers from the `103 Early Hints` response first and then from the main document response.
100 Preloads from the Link headers of the `103 Early Hints` response have an `earlyHintPreloadId` assigned to them.
101 The Preloader sets this `earlyHintPreloaderId` on the channel doing the preload before calling `AsyncOpen`.
102 The `HttpChannelParent` looks for the `earlyHintPreloaderId` in `AsyncOpen` and connects to the `EarlyHintPreloader` via the `EarlyHintRegistrar` instead of doing a network request.
104 ```{mermaid}
105 graph TD
106     PS[PreloadService]
107     Preloader["FetchPreloader<br/>FontPreloader<br/>imgLoader<br/>ScriptLoader<br/>StyleLoader"]
108     Parent["HttpChannelParent"]
109     EHR["EarlyHintRegistrar"]
110     EHP["EarlyHintPreloader"]
112     PS -- "PreloadLinkHeader" --> Preloader
113     Preloader -- "NewChannel<br/>SetEarlyHintPreloaderId<br/>AsyncOpen" --> Parent
114     Parent -- "EarlyHintRegistrar::OnParentReady(this, earlyHintPreloaderId)" --> EHR
115     EHR -- "OnParentConnect" --> EHP
118 ## Early Hint Preload request
120 The `EarlyHintPreloader` follows HTTP 3xx redirects and always sets the request header `X-Moz: early hint`.
122 ## Early Hint Preload response
124 When the `EarlyHintPreloader` received the `OnStartRequest` it forwards all `nsIRequestObserver` functions to the `HttpChannelParent` as soon as it knows which `HttpChannelParent` to forward the `nsIRequestObserver` functions to.
126 ```{mermaid}
127 graph TD
128     OPC["EHP::OnParentConnect"]
129     OSR["EHP::OnStartRequest"]
130     Invoke["Invoke StreamListenerFunctions"]
131     End(("&shy;"))
133     OPC -- "CancelTimer" --> Invoke
134     OSR -- "Suspend Channel if called<br/>before OnParentReady" --> Invoke
135     Invoke -- "Resume Channel if suspended<br/>Forward OSR+ODA+OSR<br/>Set Listener of ParentChanelListener to HttpChannelParent" --> End
138 ## Final setup
140 In the end all the remaining `OnDataAvailable` and `OnStopRequest` calls are passed down this call chain from `nsIChannel` to the preloader.
142 ```{mermaid}
143 graph TD
144     Channel[nsIChannel]
145     PCL[ParentChannelListener]
146     HCP[HttpChanelParent]
147     HCC[HttpChannelChild]
148     Preloader[FetchPreloader/imgLoader/...]
150     Channel -- "mListener" --> PCL
151     PCL -- "mNextListener" --> HCP
152     HCP -- "mChannel" --> Channel
153     HCP -- "..." --> HCC
154     HCC -- "..." --> HCP
155     HCC -- "mListener" --> Preloader
156     Preloader -- "mChannel" --> HCC