CORS Implementation - #3002
CORS Implementation#3002
Conversation
ab8be3b to
235f9ea
Compare
|
Not ready yet, just want CI to start running on this branch. |
karlseguin
left a comment
There was a problem hiding this comment.
- I ran the demo tests, and there wasn't 1 OPTIONS request.
- The singleflight is nice, but it might have been a mistake to land it with this PR. It introduces bugs not related to CORS. I'd consider landing Singlelight first.
- Without caching CORS responses, this seems like it could hurt performance more than initially anticipated.
| return raw[0..authority_end]; | ||
| } | ||
|
|
||
| pub fn isSameOrigin(url: [:0]const u8, origin: [:0]const u8) bool { |
There was a problem hiding this comment.
Frame.isSameOrigin should use this (there's a comment there that assumes Protocols are equal, but I'm not sure why that's true).
| owned.credentials = try arena.dupeZ(u8, c); | ||
| } | ||
|
|
||
| if (req.authored_headers.len > 0) { |
There was a problem hiding this comment.
The callsite dupes these in call_arena, and then we dupe it again in transfer.arena. We should rework headers before landing this.Request.headers is a micro-optimization which put the headers in a curl-friendly list from the get go. It was always questionable, and if we're going to iterate + dupe + iterate + dupe, I think it would both be cleaner and more efficient to:
1 - A single header list
2 - The header has a authored: bool flag
3 - The caller sets the headers after newRequest is called so that transfer.arena is available
There was a problem hiding this comment.
Done in #3118
I want to work on referrer policy, and I'll have the same issue.
| .GET, .HEAD => false, | ||
| else => true, | ||
| }; | ||
| if (!is_cross_origin and !is_unsafe_method) { |
There was a problem hiding this comment.
There's two different types of double negative going on here. They can all be eliminated.
const is_same_origin = URL.isSameOrigin(req.cookie_origin, req.url);
const is_safe_method = switch (req.method) {
.GET, .HEAD => true,
else => false,
};
if (is_same_origin and is_safe_method) {
return;
}| switch (res) { | ||
| .queued => { | ||
| // joined inflight fetch so release it. | ||
| client.arena_pool.release(arena); |
There was a problem hiding this comment.
I think there's a UAF bug in SingleFlight (1) related to this, BUT, as-is there's no reason to even acquire the arena in this case.
(1) Commented in SingleFlight.enter
| const lp = @import("lightpanda"); | ||
|
|
||
| const http = @import("http.zig"); | ||
| const Request = @import("../browser/webapi/net/Request.zig"); |
Adding headers to an HTTP request was a bit awkward due to my desire to avoid having an intermediate representation (e.g. an ArrayList(Header)). Going straight to a curl slist avoids double-copying the headers (first to Zig, then to curl). But the CORS work (lightpanda-io#3002) showcases that this micro-optimization simply isn't worth it, since it needs that intermediate representation anyways. And, this change isn't just for CORS. Headers have been a silly pain in the past like unclear ownership, and messy APIs used in _a lot_ of places (WebBotAuth, WebSocket, Fetch, ...) This new approach stores headers on the transfer in an ArrayList. The API is: ``` const transfer = try client.newRequest(.{...}, owner); { errdefer transfer.deinit(); try transfer.addHeader("Over", "9000", .{}); } try transfer.submit(); ``` This: 1 - Eliminates ambiguity about errdefer cleanup responsibility 2 - Eliminates a bunch of stringZ concat that Frame, Config, CDP were doing 3 - Transfer.arena is now available for headers
5e1c6dd to
4eb88c0
Compare
|
Redid a lot of the implementation of the CorsGate. I'm happier with this one. I purposefully omitted the It is currently disabled by default behind an |
|
As far as I can see, chrome sends the pre-flight request each time... It doesn't use any cache. |
It does if the response includes a access-control-max-age header |
| \\ --obey-robots | ||
| \\ Fetches and obeys robots.txt of the target page. | ||
| \\ Defaults to false. | ||
| \\ --obey-cors |
There was a problem hiding this comment.
Should be above --obey-robots
|
i started to review / test this, but I ran into a couple show-stoppers.
Doesn't seem right. |
|
2 is fixed. It was blocking some scripts that are meant to be processed as w.r.t 1, I'm not sure how it would panic on a preflight deny? It just sets allowed as false and will resolve following the same path as preflight accepts and just resolve the requests as blocked. |
|
as a follow up, I ran it against the |
|
use the wptrunner in the demo project to run /cors/. It'll crash. |
|
I always run it with |
karlseguin
left a comment
There was a problem hiding this comment.
A redirect to a different origin doesn't trigger a CORS check. It might be worth looking at how redirects are handled holistically, or maybe there's a simple / clean fix for CORS.
But, for now, I'm less worried about places where CORS doesn't block where it should, but rather places where CORS blocks when it shouldn't (since that can break existing use-cases). There's ~4 different ways that can happen, all commented inline.
| .url = "http://example.com/", | ||
| .cookie_jar = null, | ||
| .cookie_origin = "", | ||
| .origin = "", |
There was a problem hiding this comment.
A bit more correct to pass null for all these tests. I don't think you'll ever get a "" origin in the code.
| try transfer.materializeResponse(msg.conn, .{}); | ||
|
|
||
| // Validate the headers for the response with CORS. | ||
| if (transfer._cors_cross_origin) { |
There was a problem hiding this comment.
There are some references online to how this behaves with a 304, but I couldn't find anything official in the spec. There's at least a few mentions that a 304 doesn't have to (or maybe shouldn't) include CORS headers and they should come from the cached value. /cors/304.htm is currently 0/4 which tells me we're doing it wrong.
There was a problem hiding this comment.
Yeah, the WPT tests also seem to want it to resolve the CORS status from the HTTP cache.
|
No caching |
|
Shouldn't EDIT: it seems we also should check |
3275163 to
7dc3257
Compare
This adds a CORS implementation as experimental feature for now.
Enable it with
--experimental-feature corsfix #2015