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

caddyhttp: Support respond with HTTP 103 Early Hints #5006

Merged
merged 2 commits into from
Sep 5, 2022
Merged

Conversation

mholt
Copy link
Member

@mholt mholt commented Sep 1, 2022

This adds support for early hints in the static_response handler.

It implements my initial proposal. If accepted, it closes #5005.

A practical Caddyfile example, assuming that the endpoints behind /heavy-pages/ take a while to load on the backend:

@hint {
	protocol http2+
	path     /heavy-pages/*
}
route @hint {
	header  Link "</style.css>; rel=preload; as=style"
	header  Link "</script.js>; rel=preload; as=script"
	respond 103
}
reverse_proxy ...

(The HTTP/2 requirement is to try to protect old, incompatible clients. It is optional if your clients are modern or you don't care.)

Early hints are best used when the final response may not be ready for a while (a "while" being, perhaps, 2-3 RTTs, so still on the order of ms).

I had considered an implementation that automatically dispatches early hints from our file_server since we can parse HTML and get an idea of the subresources before sending the whole document to the client. However, by the time we've parsed the HTML, we might as well be streaming it to the client anyway, and they can read the <head> of the HTML document and start requesting its subresources. Even if we cached the result of parsing the HTML, it's probably still faster to just send it to the client without hints.

Anyway, this seems simple enough and I'm inclined to merge it in after a few more tests.

This adds support for early hints in the static_response handler.
@mholt mholt added the feature ⚙️ New feature or request label Sep 1, 2022
@mholt mholt added this to the v2.6.0-beta.1 milestone Sep 1, 2022
@otbutz
Copy link

otbutz commented Sep 2, 2022

The requirement to explicitly protect it with protocol http2+ sounds like a potential footgun? Almost every client supports HTTP/2, so it would be hard to detect if someone forgets to add it as only half-assed HTTP/1.x clients would be affected.

@otbutz
Copy link

otbutz commented Sep 2, 2022

Could we safely drop 103 responses on a HTTP/1.x connection instead?

Citing the RFC:

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.

As we have no idea about the capabilities of the client, we should drop them.

@mholt
Copy link
Member Author

mholt commented Sep 2, 2022

The requirement to explicitly protect it with protocol http2+ sounds like a potential footgun? Almost every client supports HTTP/2, so it would be hard to detect if someone forgets to add it as only half-assed HTTP/1.x clients would be affected.

Good point, I personally think that part is optional, I'm just showing a "best practice" that I read from the Internet 🙃 (IIRC it's even recommended in the spec).

So yeah, protocol enforcement is optional if you don't care about or have old clients. Making it as simple as:

route /heavy-pages/* {
	header  Link "</style.css>; rel=preload; as=style"
	header  Link "</script.js>; rel=preload; as=script"
	respond 103
}
reverse_proxy ...

Could we safely drop 103 responses on a HTTP/1.x connection instead?

We could, but what if the HTTP/1.x client can handle informational responses? Then there's no good way to make it happen. (I could imagine cases where modern clients use HTTP/1.1, for example over plaintext HTTP on an internal network.)

@otbutz
Copy link

otbutz commented Sep 5, 2022

We could, but what if the HTTP/1.x client can handle informational responses?

HTTP 103 is purely informative. You just don't get the performance benefit, so to speak.

Or as the spec puts it:

Aside from performance optimizations, such evaluation of the 103
(Early Hints) response's header fields MUST NOT affect how the final
response is processed
. A client MUST NOT interpret the 103 (Early
Hints) response header fields as if they applied to the informational
response itself (e.g., as metadata about the 103 (Early Hints)
response).

I would wager that the proportion of clients that would correctly process early hints without supporting HTTP/2 is very small. Breaking old quirky HTTP/1.x implementations is far more likely.

I could imagine cases where modern clients use HTTP/1.1, for example over plaintext HTTP on an internal network.

An internal network would have low latency which doesn't really benefit from early hints.

We could add an i-know-what-im-doing-just-enable-it option though :)

@otbutz
Copy link

otbutz commented Sep 5, 2022

It's even worse if caddy is acting as a reverse proxy. The backend might have some logic in place to avoid sending early hints if it detects a HTTP/1.x client. Since the backend communication may be using HTTP/2, this kind of detection is broken. We would need some kind of X-Forwarded-* header to provide the backend with the protocol level of the client. I fear that such a header doesn't exist yet.

To paraphrase it: any backend which uses HTTP 103 responses is likely to break older clients if we blindly pipe through early hints

@mholt
Copy link
Member Author

mholt commented Sep 5, 2022

Breaking old quirky HTTP/1.x implementations is far more likely.

I look forward to finding out if that's the case -- we'll try it in a beta and can adjust if needed.

An internal network would have low latency which doesn't really benefit from early hints.

Network latency is not the issue (if it were, you wouldn't want Early Hints which requires 1 extra RTT -- you'd want Push) - the problem is CPU latency. Backends that take a lot of time generating the response. For example a long DB query or similar.

It's even worse if caddy is acting as a reverse proxy. The backend might have some logic in place to avoid sending early hints if it detects a HTTP/1.x client. Since the backend communication may be using HTTP/2, this kind of detection is broken.

Good point, and I would also be interested in learning how many of those are out there.

I like the way you think! I also like the idea of finding out how many broken clients are out there and how often this actually appears in the wild.

Since there is a very simple way to disable the "hopeful" behavior of 103 Early Hints (by using the protocol matcher with http2+), I think it's probably fine to roll this out, especially in a pre-release for now.

Your concerns and points are very valid and correct. I am mainly curious how widespread that behavior is, and beta is the time to find out!

@francislavoie francislavoie changed the title caddyhttp: Support sending HTTP 103 Early Hints caddyhttp: Support respond with HTTP 103 Early Hints Sep 5, 2022
@mholt mholt merged commit ca4fae6 into master Sep 5, 2022
@francislavoie francislavoie deleted the earlyhints branch September 5, 2022 19:50
@mholt mholt modified the milestones: v2.6.0-beta.1, v2.6.0 Sep 13, 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 this pull request may close these issues.

Originate HTTP 103 Early Hints
3 participants