mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-30 17:18:57 +00:00
shortcircuit a lot of caching checks
This commit is contained in:
@@ -983,7 +983,6 @@ fn processMessages(self: *Client) !bool {
|
|||||||
log.err(.browser, "http cache", .{ .key = cache_key, .metadata = metadata });
|
log.err(.browser, "http cache", .{ .key = cache_key, .metadata = metadata });
|
||||||
|
|
||||||
cache.put(
|
cache.put(
|
||||||
.{ .url = cache_key },
|
|
||||||
metadata,
|
metadata,
|
||||||
transfer.body.items,
|
transfer.body.items,
|
||||||
) catch |err| log.warn(.http, "cache put failed", .{ .err = err });
|
) catch |err| log.warn(.http, "cache put failed", .{ .err = err });
|
||||||
|
|||||||
94
src/network/cache/Cache.zig
vendored
94
src/network/cache/Cache.zig
vendored
@@ -34,45 +34,57 @@ pub fn get(self: *Cache, arena: std.mem.Allocator, req: CacheRequest) ?CachedRes
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(self: *Cache, req: CacheRequest, metadata: CachedMetadata, body: []const u8) !void {
|
pub fn put(self: *Cache, metadata: CachedMetadata, body: []const u8) !void {
|
||||||
return switch (self.kind) {
|
return switch (self.kind) {
|
||||||
inline else => |*c| c.put(req, metadata, body),
|
inline else => |*c| c.put(metadata, body),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CacheControl = struct {
|
pub const CacheControl = struct {
|
||||||
max_age: ?u64 = null,
|
max_age: u64,
|
||||||
s_maxage: ?u64 = null,
|
|
||||||
is_public: bool = false,
|
|
||||||
must_revalidate: bool = false,
|
must_revalidate: bool = false,
|
||||||
no_cache: bool = false,
|
|
||||||
no_store: bool = false,
|
|
||||||
immutable: bool = false,
|
immutable: bool = false,
|
||||||
|
|
||||||
pub fn parse(value: []const u8) CacheControl {
|
pub fn parse(value: []const u8) ?CacheControl {
|
||||||
var cc: CacheControl = .{};
|
var cc: CacheControl = .{ .max_age = undefined };
|
||||||
|
|
||||||
|
var max_age_set = false;
|
||||||
|
var max_s_age_set = false;
|
||||||
|
var is_public = false;
|
||||||
|
|
||||||
var iter = std.mem.splitScalar(u8, value, ',');
|
var iter = std.mem.splitScalar(u8, value, ',');
|
||||||
while (iter.next()) |part| {
|
while (iter.next()) |part| {
|
||||||
const directive = std.mem.trim(u8, part, &std.ascii.whitespace);
|
const directive = std.mem.trim(u8, part, &std.ascii.whitespace);
|
||||||
if (std.ascii.eqlIgnoreCase(directive, "no-store")) {
|
if (std.ascii.eqlIgnoreCase(directive, "no-store")) {
|
||||||
cc.no_store = true;
|
return null;
|
||||||
} else if (std.ascii.eqlIgnoreCase(directive, "no-cache")) {
|
} else if (std.ascii.eqlIgnoreCase(directive, "no-cache")) {
|
||||||
cc.no_cache = true;
|
return null;
|
||||||
} else if (std.ascii.eqlIgnoreCase(directive, "must-revalidate")) {
|
} else if (std.ascii.eqlIgnoreCase(directive, "must-revalidate")) {
|
||||||
cc.must_revalidate = true;
|
cc.must_revalidate = true;
|
||||||
} else if (std.ascii.eqlIgnoreCase(directive, "immutable")) {
|
} else if (std.ascii.eqlIgnoreCase(directive, "immutable")) {
|
||||||
cc.immutable = true;
|
cc.immutable = true;
|
||||||
} else if (std.ascii.eqlIgnoreCase(directive, "public")) {
|
} else if (std.ascii.eqlIgnoreCase(directive, "public")) {
|
||||||
cc.is_public = true;
|
is_public = true;
|
||||||
} else if (std.ascii.startsWithIgnoreCase(directive, "max-age=")) {
|
} else if (std.ascii.startsWithIgnoreCase(directive, "max-age=")) {
|
||||||
cc.max_age = std.fmt.parseInt(u64, directive[8..], 10) catch null;
|
if (!max_s_age_set) {
|
||||||
|
if (std.fmt.parseInt(u64, directive[8..], 10) catch null) |max_age| {
|
||||||
|
cc.max_age = max_age;
|
||||||
|
max_age_set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (std.ascii.startsWithIgnoreCase(directive, "s-maxage=")) {
|
} else if (std.ascii.startsWithIgnoreCase(directive, "s-maxage=")) {
|
||||||
cc.s_maxage = std.fmt.parseInt(u64, directive[9..], 10) catch null;
|
if (std.fmt.parseInt(u64, directive[9..], 10) catch null) |max_age| {
|
||||||
// s-maxage takes precedence over max-age
|
cc.max_age = max_age;
|
||||||
cc.max_age = cc.s_maxage orelse cc.max_age;
|
max_age_set = true;
|
||||||
|
max_s_age_set = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!max_age_set) return null;
|
||||||
|
if (!is_public) return null;
|
||||||
|
if (cc.max_age == 0) return null;
|
||||||
|
|
||||||
return cc;
|
return cc;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -86,13 +98,6 @@ pub const Vary = union(enum) {
|
|||||||
return .{ .value = value };
|
return .{ .value = value };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: Vary, allocator: std.mem.Allocator) void {
|
|
||||||
switch (self) {
|
|
||||||
.wildcard => {},
|
|
||||||
.value => |v| allocator.free(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toString(self: Vary) []const u8 {
|
pub fn toString(self: Vary) []const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.wildcard => "*",
|
.wildcard => "*",
|
||||||
@@ -124,56 +129,43 @@ pub const CachedMetadata = struct {
|
|||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
headers: []const Http.Header,
|
headers: []const Http.Header,
|
||||||
) !?CachedMetadata {
|
) !?CachedMetadata {
|
||||||
var cc: CacheControl = .{};
|
var cc: ?CacheControl = null;
|
||||||
var vary: ?Vary = null;
|
var vary: ?Vary = null;
|
||||||
var etag: ?[]const u8 = null;
|
var etag: ?[]const u8 = null;
|
||||||
var last_modified: ?[]const u8 = null;
|
var last_modified: ?[]const u8 = null;
|
||||||
var age_at_store: u64 = 0;
|
var age_at_store: u64 = 0;
|
||||||
var content_type: []const u8 = "application/octet-stream";
|
var content_type: []const u8 = "application/octet-stream";
|
||||||
var has_set_cookie = false;
|
|
||||||
var has_authorization = false;
|
// Only cache 200 for now. Technically, we can cache others.
|
||||||
|
switch (status) {
|
||||||
|
200 => {},
|
||||||
|
else => return null,
|
||||||
|
}
|
||||||
|
|
||||||
for (headers) |hdr| {
|
for (headers) |hdr| {
|
||||||
if (std.ascii.eqlIgnoreCase(hdr.name, "cache-control")) {
|
if (std.ascii.eqlIgnoreCase(hdr.name, "cache-control")) {
|
||||||
cc = CacheControl.parse(hdr.value);
|
cc = CacheControl.parse(hdr.value) orelse return null;
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "etag")) {
|
} else if (std.ascii.eqlIgnoreCase(hdr.name, "etag")) {
|
||||||
etag = hdr.value;
|
etag = hdr.value;
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "last-modified")) {
|
} else if (std.ascii.eqlIgnoreCase(hdr.name, "last-modified")) {
|
||||||
last_modified = hdr.value;
|
last_modified = hdr.value;
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "vary")) {
|
} else if (std.ascii.eqlIgnoreCase(hdr.name, "vary")) {
|
||||||
vary = Vary.parse(hdr.value);
|
vary = Vary.parse(hdr.value);
|
||||||
|
// Vary: * means the response cannot be cached
|
||||||
|
if (vary) |v| if (v == .wildcard) return null;
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "age")) {
|
} else if (std.ascii.eqlIgnoreCase(hdr.name, "age")) {
|
||||||
age_at_store = std.fmt.parseInt(u64, hdr.value, 10) catch 0;
|
age_at_store = std.fmt.parseInt(u64, hdr.value, 10) catch 0;
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "content-type")) {
|
} else if (std.ascii.eqlIgnoreCase(hdr.name, "content-type")) {
|
||||||
content_type = hdr.value;
|
content_type = hdr.value;
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "set-cookie")) {
|
} else if (std.ascii.eqlIgnoreCase(hdr.name, "set-cookie")) {
|
||||||
has_set_cookie = true;
|
// Don't cache if has Set-Cookie.
|
||||||
|
return null;
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "authorization")) {
|
} else if (std.ascii.eqlIgnoreCase(hdr.name, "authorization")) {
|
||||||
has_authorization = true;
|
// Don't cache if has Authorization.
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no-store: must not be stored
|
|
||||||
if (cc.no_store) return null;
|
|
||||||
|
|
||||||
// Vary: * means the response cannot be cached
|
|
||||||
if (vary) |v| if (v == .wildcard) return null;
|
|
||||||
|
|
||||||
// must have an explicit max-age to be cacheable
|
|
||||||
if (cc.max_age == null) return null;
|
|
||||||
|
|
||||||
// Set-Cookie without explicit public
|
|
||||||
if (has_set_cookie and !cc.is_public) return null;
|
|
||||||
|
|
||||||
// Authorization header without explicit public or s-maxage
|
|
||||||
if (has_authorization and !cc.is_public and cc.s_maxage == null) return null;
|
|
||||||
|
|
||||||
// Only cache 200 for now. Technically, we can cache others.
|
|
||||||
switch (status) {
|
|
||||||
200 => {},
|
|
||||||
else => return null,
|
|
||||||
}
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.url = url,
|
.url = url,
|
||||||
.content_type = content_type,
|
.content_type = content_type,
|
||||||
@@ -182,7 +174,7 @@ pub const CachedMetadata = struct {
|
|||||||
.age_at_store = age_at_store,
|
.age_at_store = age_at_store,
|
||||||
.etag = etag,
|
.etag = etag,
|
||||||
.last_modified = last_modified,
|
.last_modified = last_modified,
|
||||||
.cache_control = cc,
|
.cache_control = cc orelse return null,
|
||||||
.vary = vary,
|
.vary = vary,
|
||||||
.headers = headers,
|
.headers = headers,
|
||||||
};
|
};
|
||||||
|
|||||||
4
src/network/cache/FsCache.zig
vendored
4
src/network/cache/FsCache.zig
vendored
@@ -142,8 +142,8 @@ pub fn get(self: *FsCache, arena: std.mem.Allocator, req: CacheRequest) ?Cache.C
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(self: *FsCache, req: CacheRequest, meta: CachedMetadata, body: []const u8) !void {
|
pub fn put(self: *FsCache, meta: CachedMetadata, body: []const u8) !void {
|
||||||
const hashed_key = hashKey(req.url);
|
const hashed_key = hashKey(meta.url);
|
||||||
const meta_p = metaPath(&hashed_key);
|
const meta_p = metaPath(&hashed_key);
|
||||||
const meta_tmp_p = metaTmpPath(&hashed_key);
|
const meta_tmp_p = metaTmpPath(&hashed_key);
|
||||||
const body_p = bodyPath(&hashed_key);
|
const body_p = bodyPath(&hashed_key);
|
||||||
|
|||||||
Reference in New Issue
Block a user