mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-31 01:28:55 +00:00
only store stuff when we know we will cache
This commit is contained in:
@@ -915,23 +915,6 @@ fn processMessages(self: *Client) !bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const allocator = transfer.arena.allocator();
|
|
||||||
var header_list: std.ArrayList(Net.Header) = .empty;
|
|
||||||
|
|
||||||
var it = transfer.responseHeaderIterator();
|
|
||||||
while (it.next()) |hdr| {
|
|
||||||
header_list.append(
|
|
||||||
allocator,
|
|
||||||
.{
|
|
||||||
.name = try allocator.dupe(u8, hdr.name),
|
|
||||||
.value = try allocator.dupe(u8, hdr.value),
|
|
||||||
},
|
|
||||||
) catch |err| {
|
|
||||||
log.warn(.http, "cache header collect failed", .{ .err = err });
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// release it ASAP so that it's available; some done_callbacks
|
// release it ASAP so that it's available; some done_callbacks
|
||||||
// will load more resources.
|
// will load more resources.
|
||||||
self.endTransfer(transfer);
|
self.endTransfer(transfer);
|
||||||
@@ -966,30 +949,19 @@ fn processMessages(self: *Client) !bool {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
cache: {
|
if (transfer.pending_cache_metadata) |metadata| {
|
||||||
if (self.network.cache) |*cache| {
|
const cache = &self.network.cache.?;
|
||||||
const headers = &transfer.response_header.?;
|
|
||||||
|
|
||||||
const metadata = try CacheMetadata.fromHeaders(
|
|
||||||
transfer.req.url,
|
|
||||||
headers.status,
|
|
||||||
std.time.timestamp(),
|
|
||||||
header_list.items,
|
|
||||||
) orelse break :cache;
|
|
||||||
|
|
||||||
// TODO: Support Vary Keying
|
// TODO: Support Vary Keying
|
||||||
const cache_key = transfer.req.url;
|
const cache_key = transfer.req.url;
|
||||||
|
|
||||||
log.err(.browser, "http cache", .{ .key = cache_key, .metadata = metadata });
|
log.debug(.browser, "http cache", .{ .key = cache_key, .metadata = metadata });
|
||||||
|
cache.put(metadata, transfer.pending_cache_body.items) catch |err| {
|
||||||
cache.put(
|
log.warn(.http, "cache put failed", .{ .err = err });
|
||||||
metadata,
|
};
|
||||||
transfer.body.items,
|
|
||||||
) catch |err| log.warn(.http, "cache put failed", .{ .err = err });
|
|
||||||
log.debug(.browser, "http.cache.put", .{ .url = transfer.req.url });
|
log.debug(.browser, "http.cache.put", .{ .url = transfer.req.url });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
transfer.req.notification.dispatch(.http_request_done, &.{
|
transfer.req.notification.dispatch(.http_request_done, &.{
|
||||||
.transfer = transfer,
|
.transfer = transfer,
|
||||||
@@ -1184,7 +1156,8 @@ pub const Transfer = struct {
|
|||||||
// total bytes received in the response, including the response status line,
|
// total bytes received in the response, including the response status line,
|
||||||
// the headers, and the [encoded] body.
|
// the headers, and the [encoded] body.
|
||||||
bytes_received: usize = 0,
|
bytes_received: usize = 0,
|
||||||
body: std.ArrayListUnmanaged(u8) = .empty,
|
pending_cache_body: std.ArrayList(u8) = .empty,
|
||||||
|
pending_cache_metadata: ?CacheMetadata = null,
|
||||||
|
|
||||||
aborted: bool = false,
|
aborted: bool = false,
|
||||||
|
|
||||||
@@ -1236,6 +1209,8 @@ pub const Transfer = struct {
|
|||||||
self._notified_fail = false;
|
self._notified_fail = false;
|
||||||
self.response_header = null;
|
self.response_header = null;
|
||||||
self.bytes_received = 0;
|
self.bytes_received = 0;
|
||||||
|
self.pending_cache_metadata = null;
|
||||||
|
self.pending_cache_body = .empty;
|
||||||
|
|
||||||
self._tries += 1;
|
self._tries += 1;
|
||||||
}
|
}
|
||||||
@@ -1451,6 +1426,40 @@ pub const Transfer = struct {
|
|||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (transfer.client.network.cache != null and transfer.req.method == .GET) {
|
||||||
|
const rh = &transfer.response_header.?;
|
||||||
|
const allocator = transfer.arena.allocator();
|
||||||
|
|
||||||
|
const maybe_cm = try Cache.tryCache(
|
||||||
|
allocator,
|
||||||
|
std.time.timestamp(),
|
||||||
|
transfer.url,
|
||||||
|
rh.status,
|
||||||
|
rh.contentType(),
|
||||||
|
if (conn.getResponseHeader("cache-control", 0)) |h| h.value else null,
|
||||||
|
if (conn.getResponseHeader("vary", 0)) |h| h.value else null,
|
||||||
|
if (conn.getResponseHeader("etag", 0)) |h| h.value else null,
|
||||||
|
if (conn.getResponseHeader("last-modified", 0)) |h| h.value else null,
|
||||||
|
if (conn.getResponseHeader("age", 0)) |h| h.value else null,
|
||||||
|
conn.getResponseHeader("set-cookie", 0) != null,
|
||||||
|
conn.getResponseHeader("authorization", 0) != null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (maybe_cm) |cm| {
|
||||||
|
var header_list: std.ArrayList(Net.Header) = .empty;
|
||||||
|
var it = transfer.responseHeaderIterator();
|
||||||
|
while (it.next()) |hdr| {
|
||||||
|
try header_list.append(allocator, .{
|
||||||
|
.name = try allocator.dupe(u8, hdr.name),
|
||||||
|
.value = try allocator.dupe(u8, hdr.value),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer.pending_cache_metadata = cm;
|
||||||
|
transfer.pending_cache_metadata.?.headers = header_list.items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
transfer.req.notification.dispatch(.http_response_header_done, &.{
|
transfer.req.notification.dispatch(.http_response_header_done, &.{
|
||||||
.transfer = transfer,
|
.transfer = transfer,
|
||||||
});
|
});
|
||||||
@@ -1611,10 +1620,12 @@ pub const Transfer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const chunk = buffer[0..chunk_len];
|
const chunk = buffer[0..chunk_len];
|
||||||
transfer.body.appendSlice(transfer.arena.allocator(), chunk) catch |err| {
|
if (transfer.pending_cache_metadata != null) {
|
||||||
|
transfer.pending_cache_body.appendSlice(transfer.arena.allocator(), chunk) catch |err| {
|
||||||
log.err(.http, "cache body append", .{ .err = err, .req = transfer });
|
log.err(.http, "cache body append", .{ .err = err, .req = transfer });
|
||||||
return Net.writefunc_error;
|
return Net.writefunc_error;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
transfer.req.data_callback(Response.fromLive(transfer), chunk) catch |err| {
|
transfer.req.data_callback(Response.fromLive(transfer), chunk) catch |err| {
|
||||||
log.err(.http, "data_callback", .{ .err = err, .req = transfer });
|
log.err(.http, "data_callback", .{ .err = err, .req = transfer });
|
||||||
|
|||||||
90
src/network/cache/Cache.zig
vendored
90
src/network/cache/Cache.zig
vendored
@@ -122,63 +122,6 @@ pub const CachedMetadata = struct {
|
|||||||
cache_control: CacheControl,
|
cache_control: CacheControl,
|
||||||
vary: ?Vary,
|
vary: ?Vary,
|
||||||
headers: []const Http.Header,
|
headers: []const Http.Header,
|
||||||
|
|
||||||
pub fn fromHeaders(
|
|
||||||
url: [:0]const u8,
|
|
||||||
status: u16,
|
|
||||||
timestamp: i64,
|
|
||||||
headers: []const Http.Header,
|
|
||||||
) !?CachedMetadata {
|
|
||||||
var cc: ?CacheControl = null;
|
|
||||||
var vary: ?Vary = null;
|
|
||||||
var etag: ?[]const u8 = null;
|
|
||||||
var last_modified: ?[]const u8 = null;
|
|
||||||
var age_at_store: u64 = 0;
|
|
||||||
var content_type: []const u8 = "application/octet-stream";
|
|
||||||
|
|
||||||
// Only cache 200 for now. Technically, we can cache others.
|
|
||||||
switch (status) {
|
|
||||||
200 => {},
|
|
||||||
else => return null,
|
|
||||||
}
|
|
||||||
|
|
||||||
for (headers) |hdr| {
|
|
||||||
if (std.ascii.eqlIgnoreCase(hdr.name, "cache-control")) {
|
|
||||||
cc = CacheControl.parse(hdr.value) orelse return null;
|
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "etag")) {
|
|
||||||
etag = hdr.value;
|
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "last-modified")) {
|
|
||||||
last_modified = hdr.value;
|
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "vary")) {
|
|
||||||
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")) {
|
|
||||||
age_at_store = std.fmt.parseInt(u64, hdr.value, 10) catch 0;
|
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "content-type")) {
|
|
||||||
content_type = hdr.value;
|
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "set-cookie")) {
|
|
||||||
// Don't cache if has Set-Cookie.
|
|
||||||
return null;
|
|
||||||
} else if (std.ascii.eqlIgnoreCase(hdr.name, "authorization")) {
|
|
||||||
// Don't cache if has Authorization.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.url = url,
|
|
||||||
.content_type = content_type,
|
|
||||||
.status = status,
|
|
||||||
.stored_at = timestamp,
|
|
||||||
.age_at_store = age_at_store,
|
|
||||||
.etag = etag,
|
|
||||||
.last_modified = last_modified,
|
|
||||||
.cache_control = cc orelse return null,
|
|
||||||
.vary = vary,
|
|
||||||
.headers = headers,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CacheRequest = struct {
|
pub const CacheRequest = struct {
|
||||||
@@ -194,3 +137,36 @@ pub const CachedResponse = struct {
|
|||||||
metadata: CachedMetadata,
|
metadata: CachedMetadata,
|
||||||
data: CachedData,
|
data: CachedData,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn tryCache(
|
||||||
|
arena: std.mem.Allocator,
|
||||||
|
timestamp: i64,
|
||||||
|
url: [:0]const u8,
|
||||||
|
status: u16,
|
||||||
|
content_type: ?[]const u8,
|
||||||
|
cache_control: ?[]const u8,
|
||||||
|
vary: ?[]const u8,
|
||||||
|
etag: ?[]const u8,
|
||||||
|
last_modified: ?[]const u8,
|
||||||
|
age: ?[]const u8,
|
||||||
|
has_set_cookie: bool,
|
||||||
|
has_authorization: bool,
|
||||||
|
) !?CachedMetadata {
|
||||||
|
if (status != 200) return null;
|
||||||
|
if (has_set_cookie) return null;
|
||||||
|
if (has_authorization) return null;
|
||||||
|
const cc = CacheControl.parse(cache_control orelse return null) orelse return null;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.url = url,
|
||||||
|
.content_type = if (content_type) |ct| try arena.dupe(u8, ct) else "application/octet-stream",
|
||||||
|
.status = status,
|
||||||
|
.stored_at = timestamp,
|
||||||
|
.age_at_store = if (age) |a| std.fmt.parseInt(u64, a, 10) catch 0 else 0,
|
||||||
|
.cache_control = cc,
|
||||||
|
.vary = if (vary) |v| Vary.parse(v) else null,
|
||||||
|
.etag = if (etag) |e| try arena.dupe(u8, e) else null,
|
||||||
|
.last_modified = if (last_modified) |lm| try arena.dupe(u8, lm) else null,
|
||||||
|
.headers = &.{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user