8000 early hint functionality by pjebs · Pull Request #1996 · valyala/fasthttp · GitHub
[go: up one dir, main page]

Skip to content

early hint functionality #1996

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

Merged
merged 1 commit into from
Apr 21, 2025
Merged

early hint functionality #1996

merged 1 commit into from
Apr 21, 2025

Conversation

pjebs
Copy link
Contributor
@pjebs pjebs commented Apr 16, 2025

Draft of Early Hints functionality.

Fixes: #1992

@pjebs pjebs mentioned this pull request Apr 16, 2025
Copy link
Collaborator
@erikdubbelboer erikdubbelboer left a comment

Choose a reason for hiding this comment

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

The hints map[string]string prevents me from generating for example these headers:

Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style

Can you also add a test case that shows the Early Hints response and makes sure the normal response after it also works fine.

@pjebs
Copy link
Contributor Author
pjebs commented Apr 20, 2025

The hints map[string]string prevents me from generating for example these headers:

Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style

Can you also add a test case that shows the Early Hints response and makes sure the normal response after it also works fine.

ctx.EarlyHints(map[string]string{
    "https://fonts.google.com": "rel=preconnect",
    "/main.css": "rel=preload; as=style",
    "/common.js": "rel=preload; as=script",
    "/experimental.3eab3290.css": "rel=preload; as=style", // <===== You wouldn't normally early hint this one because it's not stable
}) 

@erikdubbelboer
Copy link
Collaborator

I'm wondering if this is the best API. Another way might be that this function has no arguments and just sends the headers set in the response already and then resets them. Not sure if an Early Hints response can also have other headers?

@pjebs
Copy link
Contributor Author
pjebs commented Apr 20, 2025

I'm wondering if this is the best API. Another way might be that this function has no arguments and just sends the headers set in the response already and then resets them. Not sure if an Early Hints response can also have other headers?

The point of early hints is that the Link Headers are sent before the processing of the full response.
In some cases, the full response may take "considerable" time to determine what the headers are and then write them to Response.

Also the early hint links are not necessarily the same as the final response links. It is usually a smaller subset (i.e. link resources that are stable such as perhaps overall sites css c.f a particular page's css that developer's may change regularly).

If the function didn't take arguments as to what the early hints are, I would need to waste time iterating over the currently set headers to determine which ones are eligible as valid early hints.

This is also similar to the API of node.js: https://github.com/nodejs/node/pull/44180/files (except I made it into a map instead of a slice)

@pjebs
Copy link
Contributor Author
pjebs commented Apr 20, 2025

@erikdubbelboer Is there a sample test that I can use as a template that tests something similar?

@erikdubbelboer
Copy link
8000
Collaborator

The API I was thinking of is just:

ctx.Response.Header.Add("Link", "...")
ctx.EarlyHints()

Which then only send the Link header and not any other header that might already have been set.

This design is more in line with what we already have and makes it easier to have no memory allocations.

For an example of a test you can take the 100 continue test:

func TestServerExpect100Continue(t *testing.T) {

@pjebs
Copy link
Contributor Author
pjebs commented Apr 20, 2025

The API I was thinking of is just:

ctx.Response.Header.Add("Link", "...")
ctx.EarlyHints()

Which then only send the Link header and not any other header that might already have been set.

This design is more in line with what we already have and makes it easier to have no memory allocations.

For an example of a test you can take the 100 continue test:

func TestServerExpect100Continue(t *testing.T) {

But I still have to iterate over the headers to determine if the header is a Link (I.e by doing a comparison). That is slower.

There is no guarantee the developer will only add Links to header before calling EarlyHints.

@erikdubbelboer
Copy link
Collaborator

The amount of headers will be so low that its probably around the same speed as the map. A map makes it really hard not to generate garbage which would make that much slower.

@pjebs
Copy link
Contributor Author
pjebs commented Apr 20, 2025

@erikdubbelboer Done

@pjebs pjebs requested a review from erikdubbelboer April 20, 2025 09:28
@pjebs
Copy link
Contributor Author
pjebs commented Apr 21, 2025
8000

@erikdubbelboer Done

@pjebs pjebs requested a review from erikdubbelboer April 21, 2025 05:05
Copy link
Collaborator
@erikdubbelboer erikdubbelboer left a comment

Choose a reason for hiding this comment

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

Sorry, 2 more changes.

  1. Can you make the function return an error so all the nolint:errcheck can go away and can instead be turned into error returns. Also check the error returned by Flush and defer the releaseWriter so it also gets released on error.
  2. Can you add a simple example to the documentation of the function.

@pjebs pjebs requested a review from erikdubbelboer April 21, 2025 09:18
@pjebs
Copy link
Contributor Author
pjebs commented Apr 21, 2025

Tests are flaky.

@erikdubbelboer erikdubbelboer merged commit a05560d into valyala:master Apr 21, 2025
11 checks passed
@erikdubbelboer
Copy link
Collaborator

Thanks! I'll tag a release tomorrow.

@pjebs pjebs deleted the early-hints branch April 21, 2025 11:18
@pjebs
Copy link
Contributor Author
pjebs commented Apr 22, 2025

What's the difference between c.Conn() and using that compared to acquire/release?

@erikdubbelboer
Copy link
Collaborator

Conn() returns the raw connection. Writing directly to it could cause each Write() to be a separate TCP packet. The writer is buffered and will send everything in a single packet on Flush().

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.

Support HTTP Early Hints
2 participants
0