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 Last-Event-ID to CORS-safelisted headers #49257

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

rexxars
Copy link
Contributor

@rexxars rexxars commented Nov 19, 2024

The EventSource API does not run any preflight request when specifying the Last-Event-ID header, and so fetch requests should also allow this header to be set manually.

See issue whatwg/fetch#568 for more information and PR whatwg/fetch#1788 for changes to the specification

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

I think we also need an actual cross-origin EventSource test where the ID gets set to a value that doesn't match the requirements.

fetch/api/cors/resources/not-cors-safelisted.json Outdated Show resolved Hide resolved
The EventSource API does _not_ run any preflight request when specifying
the `Last-Event-ID` header, and so `fetch` requests should also allow
this header to be set manually.

See whatwg/fetch#568 for more information
@rexxars rexxars force-pushed the fetch-cors-safelist-last-event-id branch from 746a146 to 79c1fed Compare November 20, 2024 21:55
@rexxars
Copy link
Contributor Author

rexxars commented Nov 20, 2024

I think we also need an actual cross-origin EventSource test where the ID gets set to a value that doesn't match the requirements.

Makes sense - added in c80e8b3

@rexxars rexxars force-pushed the fetch-cors-safelist-last-event-id branch from 79c1fed to c80e8b3 Compare November 20, 2024 22:12
@rexxars rexxars requested a review from annevk November 21, 2024 23:05
Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

Thanks, this looks pretty good to me. Any reason it's marked as draft?

eventsource/eventsource-cross-origin-preflight.window.js Outdated Show resolved Hide resolved
cors/cors-safelisted-request-header.any.js Outdated Show resolved Hide resolved
eventsource/eventsource-cross-origin-preflight.window.js Outdated Show resolved Hide resolved
eventsource/resources/cors-unsafe-last-event-id.py Outdated Show resolved Hide resolved
@rexxars
Copy link
Contributor Author

rexxars commented Nov 26, 2024

Thanks, this looks pretty good to me. Any reason it's marked as draft?

I wasn't sure if the spec changes had to be approved/merged before making this ready for review. I'll mark it as ready now, assuming based on your comment that this is acceptable.

Comment on lines +27 to +29
// 2. Will emit either `success` or `failure` event. We expect `success`,
// which is the case if `last-event-id` is set to the same value as received above,
// and a preflight request has been sent for the unsafe `last-event-id` headers.
Copy link
Member

Choose a reason for hiding this comment

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

Wait shouldn't this be open and error events?

Copy link
Contributor Author

@rexxars rexxars Nov 26, 2024

Choose a reason for hiding this comment

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

Hmm, the way I read the spec/ask here is that if the last-event-id header contains any "unsafe bytes", AND the request is going cross-origin, then we should do a preflight request that contains access-control-request-headers: last-event-id. If the server then responds with access-control-allow-headers: last-event-id, we are okay to send the "unsafe" value to the server. If the server does not respond to the preflight request with that header, it will fail the request. Can you confirm if this is the intended behavior, and if it is not correct, outline what the correct behavior is?

As for the use of success/failure: We could theoretically send back a 400 or something if the preflight wasn't run (thus triggering the error event), but the EventSource API purposely gives very little information on errors (basically nothing at all). If we use the generic error event, it's hard/harder to then detect why the request failed - it could be because of an HTTP error code, because the stream ended (and triggered a reconnect), because the network is down, because of CORS issues etc. I prefer to handle things more explicitly - by sending named events for success/failure we'll have access to the data field and can use that in the error output, eg "expected preflight, did not get one" or "got , expected ". I find it both helps implementers figure out what is going wrong, as well as anyone reading the text/fixture, as the different cases are more explicitly called out.

source.addEventListener('success', this.step_func_done());
source.addEventListener('failure', this.step_func_done((evt) => {
assert_unreached(evt.data);
}));
Copy link
Member

Choose a reason for hiding this comment

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

You can also use this.assert_unreached though I don't think you can output event.data in that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As mentioned in the above comment - I prefer to give a helpful error message when possible to help implementers understand which part of the test is failing, which is why I went for the variant where we can provide a message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants