fix more WPT test edge cases for preflight cache

This commit is contained in:
Muki Kiboigo committed 2026-09-13 14:52:25 -07:00
1 parent 5347ad181b
commit 2147566981
2 files changed
+26 -27

No files matched your search

+19 -20
View File
@@ -217,19 +217,17 @@ pub fn check(self: *CorsGate, transfer: *Transfer) !Result {
return .allowed;
}
if (try URL.getOrigin(transfer.arena.allocator(), req.url)) |target| {
if (self.network.cors_store.get(.{ .origin = origin, .target = target })) |cached| {
const authored = try collectAuthoredHeaders(transfer, transfer.arena.allocator());
if (CorsStore.covers(cached, req.method, req.credentials_mode == .include, authored.items)) {
log.debug(.cors, "cross origin", .{
.url = req.url,
.origin = origin,
.preflight = false,
.cached = true,
});
lp.metrics.cors_check.incr(.cached);
return .allowed;
}
if (self.network.cors_store.get(.{ .origin = origin, .target = req.url })) |cached| {
const authored = try collectAuthoredHeaders(transfer, transfer.arena.allocator());
if (CorsStore.covers(cached, req.method, req.credentials_mode == .include, authored.items)) {
log.debug(.cors, "cross origin", .{
.url = req.url,
.origin = origin,
.preflight = false,
.cached = true,
});
lp.metrics.cors_check.incr(.cached);
return .allowed;
}
}
@@ -295,7 +293,6 @@ const CorsPreflightContext = struct {
key: []const u8,
url: [:0]const u8,
origin: []const u8,
target: []const u8,
method: http.Method,
request_headers: []const []const u8,
wants_credentials: bool,
@@ -393,9 +390,13 @@ const CorsPreflightContext = struct {
}
fn cacheGrant(self: *CorsPreflightContext, acam: ?[]const u8, acah: ?[]const u8, acma: ?[]const u8) !void {
if (self.target.len == 0) return;
if (self.url.len == 0) return;
const max_age_s: u64 = if (acma) |v| std.fmt.parseUnsigned(u64, v, 10) catch return else return;
const max_age_s: u64 = blk: {
const v = acma orelse break :blk 5;
if (v.len == 0) break :blk 5;
break :blk std.fmt.parseUnsigned(u64, v, 10) catch return;
};
if (max_age_s == 0) return;
const capped_s: u64 = @min(max_age_s, 7200);
@@ -426,14 +427,14 @@ const CorsPreflightContext = struct {
}
try self.gate.network.cors_store.put(
.{ .origin = self.origin, .target = self.target },
.{ .origin = self.origin, .target = self.url },
.{
.credentials = self.wants_credentials,
.methods_wildcard = methods_wildcard,
.methods = methods,
.headers_wildcard = headers_wildcard,
.headers = owned_headers,
.expires_at = lp.datetime.timestamp(.real) + capped_ms,
.expires_at = lp.datetime.milliTimestamp(.real) + capped_ms,
},
);
}
@@ -576,7 +577,6 @@ fn fetchThenResume(self: *CorsGate, transfer: *Transfer) !void {
const owned_url = try arena.dupeZ(u8, transfer.req.url);
const owned_key = try arena.dupe(u8, key);
const owned_origin = try arena.dupe(u8, origin);
const owned_target = try URL.getOrigin(arena.allocator(), transfer.req.url) orelse "";
const owned_header_names = try arena.alloc([]const u8, header_names.items.len);
for (header_names.items, 0..) |name, i| {
@@ -591,7 +591,6 @@ fn fetchThenResume(self: *CorsGate, transfer: *Transfer) !void {
.key = owned_key,
.url = owned_url,
.origin = owned_origin,
.target = owned_target,
.method = transfer.req.method,
.request_headers = owned_header_names,
.wants_credentials = transfer.req.credentials_mode == .include,
+7 -7
View File
@@ -159,7 +159,7 @@ pub fn get(self: *CorsStore, key: Key) ?Entry {
const entry = self.map.get(key) orelse return null;
if (entry.expires_at <= lp.datetime.timestamp(.real)) {
if (entry.expires_at <= lp.datetime.milliTimestamp(.real)) {
const kv = self.map.fetchRemove(key).?;
kv.key.deinit(self.allocator);
kv.value.deinit(self.allocator);
@@ -250,7 +250,7 @@ test "CorsStore: put then get, miss on different origin/target" {
.methods = std.EnumSet(http.Method).initOne(.POST),
.headers_wildcard = false,
.headers = headers,
.expires_at = lp.datetime.timestamp(.real) + 60_000,
.expires_at = lp.datetime.milliTimestamp(.real) + 60_000,
});
// store.get returns the store's own copy — not caller-owned, don't free it.
@@ -273,7 +273,7 @@ test "CorsStore: expired entries are evicted on get" {
.methods = .initEmpty(),
.headers_wildcard = true,
.headers = &.{}, // empty slice, nothing to free
.expires_at = lp.datetime.timestamp(.real) - 1,
.expires_at = lp.datetime.milliTimestamp(.real) - 1,
});
try testing.expectEqual(null, store.get(.{ .origin = "https://a.example", .target = "https://api.example" }));
@@ -295,7 +295,7 @@ test "CorsStore: put merges into existing entry rather than clobbering" {
.methods = std.EnumSet(http.Method).initOne(.POST),
.headers_wildcard = false,
.headers = h1,
.expires_at = lp.datetime.timestamp(.real) + 60_000,
.expires_at = lp.datetime.milliTimestamp(.real) + 60_000,
});
freeHeaders(allocator, h1);
@@ -307,7 +307,7 @@ test "CorsStore: put merges into existing entry rather than clobbering" {
.methods = std.EnumSet(http.Method).initOne(.PUT),
.headers_wildcard = false,
.headers = h2,
.expires_at = lp.datetime.timestamp(.real) + 60_000,
.expires_at = lp.datetime.milliTimestamp(.real) + 60_000,
});
freeHeaders(allocator, h2);
@@ -328,7 +328,7 @@ test "CorsStore: covers rejects credentialed request against uncredentialed wild
.methods = .initEmpty(),
.headers_wildcard = true,
.headers = &.{},
.expires_at = std.math.maxInt(i64),
.expires_at = std.math.maxInt(u64),
};
try testing.expect(!CorsStore.covers(entry, .GET, true, &.{}));
try testing.expect(CorsStore.covers(entry, .GET, false, &.{}));
@@ -341,7 +341,7 @@ test "CorsStore: covers never lets a wildcard cover Authorization" {
.methods = .initEmpty(),
.headers_wildcard = true,
.headers = &.{},
.expires_at = std.math.maxInt(i64),
.expires_at = std.math.maxInt(u64),
};
try testing.expect(!CorsStore.covers(entry, .GET, false, &.{"authorization"}));
try testing.expect(CorsStore.covers(entry, .GET, false, &.{"x-anything"}));