Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTTP 103 Early Hints support #4860

Closed
otbutz opened this issue Jun 30, 2022 · 13 comments · Fixed by #4882
Closed

Add HTTP 103 Early Hints support #4860

otbutz opened this issue Jun 30, 2022 · 13 comments · Fixed by #4882
Labels
feature ⚙️ New feature or request

Comments

@otbutz
Copy link

otbutz commented Jun 30, 2022

RFC 8297 is only a draft, but is now supported by Chrome 103:

https://caniuse.com/mdn-http_status_103

and Mozilla also intends to support it:

https://bugzilla.mozilla.org/show_bug.cgi?id=1407355

Apache already implements it: https://httpd.apache.org/docs/2.4/howto/http2.html#earlyhints

It would be nice if caddy would add (experimental) support for it. Following the RFC recommendations, this should only be added for HTTP/2 and HTTP/3:

Therefore, a server might refrain from sending 103 (Early Hints) responses over HTTP/1.1 unless the client is known to handle informational responses correctly.

@otbutz
Copy link
Author

otbutz commented Jun 30, 2022

The very first step would be to make sure that caddy processes HTTP 103 properly while acting as a reverse proxy. That may already be the case.

@francislavoie
Copy link
Member

@dunglas has been working on adding support for early hints to the Go stdlib, I'm sure he'll follow up soon to make sure Caddy supports it sufficiently.

@francislavoie francislavoie added feature ⚙️ New feature or request upstream ⬆️ Relates to some dependency of this project labels Jun 30, 2022
@dunglas
Copy link
Collaborator

dunglas commented Jul 1, 2022

Indeed it's on my todo list. We'll have to wait for Go 1.19 first.

@bt90
Copy link
Contributor

bt90 commented Jul 24, 2022

@dunglas does this also add support for HTTP3 based connections?

@dunglas
Copy link
Collaborator

dunglas commented Aug 2, 2022

@bt90 yes! I also patched the HTTP/3 library: quic-go/quic-go#3047

@pc-erin
Copy link

pc-erin commented Aug 31, 2022

Is there any documentation on how use this feature now that it's implemented?

If we do respond 103 does that send hints but still maintain the connection for the main response?

@mholt
Copy link
Member

mholt commented Sep 1, 2022

@pc-erin HTTP 103 is for applications to emit. The only "application" Caddy really offers (at least, built-in) is the static file server; I have been considering building a feature that will parse HTML and send 103 responses accordingly (like for CSS, JS, and image resources), but maybe at a future date.

For now, this relays 103s from proxy backends down to the client.

What's your use case?

@bt90
Copy link
Contributor

bt90 commented Sep 1, 2022

Using it in a reverse proxy scenario might also be neat. Add a matcher for the main page and tell the clients to also load files X, Y and Z.

@pc-erin
Copy link

pc-erin commented Sep 1, 2022

I was working on a PHP application (which apparently doesn't support 103) and also buffers the full output, so no streaming the html head down first.

To mitigate this I thought it would be convenient to manually put some 103 hints in path handlers so that browsers could start downloading resources while PHP is building the response.

Something like:

{
  respond 103 {
    hint </css/common-styles.css>; rel=preload; as=style; nopush
    hint </js/common-scripts.js>; rel=preload; as=script; nopush
  }

  handle /page1 {
    respond 103 {
      hint </css/page1-styles.css>; rel=preload; as=style; nopush
      hint </js/page1-scripts.js>; rel=preload; as=script; nopush
    }
  }

  php_fastcgi...
}

@mholt
Copy link
Member

mholt commented Sep 1, 2022

Proposal opened at #5005

@mholt
Copy link
Member

mholt commented Sep 1, 2022

Proposal implemented in #5006 -- @pc-erin and @bt90 you may want to try it out!

@xfalcox
Copy link

xfalcox commented Sep 12, 2022

Hey @mholt,

When using 103 hints in a more conventional way, with caddy being a reverse proxy to an application that sends those responses, one useful feature is caching the 103 responses from previous requests and replying with those learned cached behaviors in newer requests. At the moment, AFAIK only Cloudflare implements this, but it can be very useful for Caddy to have something like this.

Example:

  1. User requests /index
  2. Caddy receives the request and proxies it to underlying app
  3. Underlying app runs some fast logic and responds with 103. This takes 100ms
  4. Underlying finishes building the full response. This takes 300ms

If Caddy "learns" that requests to /index get a certain 103 response, it could reply with that ASAP on step 2, making this response happen 100ms earlier, which will result in a faster browsing experience if the resources in 103 are necessary for website interactivity.

Cloudflare goes one step further, and even "learns" to 103 subsequent requests from Link headers in plain 200 responses:

Now: Turning 200 OK Link: headers into 103 Early Hints

To avoid requiring origins to emit 103 responses from their origins directly, we settled on an approach that takes advantage of something many customers already used to indicate which assets an HTML page depends on, the Link: response header.

  1. When Cloudflare gets a response from the origin, we will parse it for Link headers with preload or preconnect rel types. These rel types indicate to the browser that the asset should be loaded as soon as possible (preload), or that a connection should be established to the specified origin but no bytes should be transferred (preconnect).

  2. Cloudflare takes these headers and caches them at our edge, ready to be served as a 103 Early Hints payload.

  3. When subsequent requests come for that asset, we immediately send the browser the cached Early Hints response
    while proxying the request to the origin server to generate the full response.

  4. Cloudflare then proxies the full response from origin to the browser when it’s available.

  5. When the full response is available, it will contain Link headers (that’s how we started this whole story). We will compare the Link headers in the 200 response with the cached version to make sure that they are the most up to date. If they have changed since they’ve been cached, we will automatically purge the out-of-date Early Hints and re-cache the new ones.

Curious about your opinions on this @mholt.

@mholt
Copy link
Member

mholt commented Sep 12, 2022

@xfalcox We could do that... would require a new directive to enable it, I think. Probably best for someone to implement it as a separate plugin for now and see how popular and useful it is!

@mholt mholt removed the upstream ⬆️ Relates to some dependency of this project label Sep 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature ⚙️ New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants