mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 22:53:28 +00:00
Make HTTP Response header values mutable
The HTTP response values _are_ mutable, but because we're using std.http.Header
the type is a `[]const u8`. This introduce a custom `Header` type where the
value is `[]u8`.
The goal is largely to allow more efficient value-comparison, by allowing
calling code to lower-case in-place. I specifically have the Mime parser in
mind:
25dcae7648/src/browser/mime.zig (L134)
This commit is contained in:
@@ -38,8 +38,6 @@ const BUFFER_LEN = 32 * 1024;
|
|||||||
// The longest individual header line that we support
|
// The longest individual header line that we support
|
||||||
const MAX_HEADER_LINE_LEN = 4096;
|
const MAX_HEADER_LINE_LEN = 4096;
|
||||||
|
|
||||||
const HeaderList = std.ArrayListUnmanaged(std.http.Header);
|
|
||||||
|
|
||||||
// Thread-safe. Holds our root certificate, connection pool and state pool
|
// Thread-safe. Holds our root certificate, connection pool and state pool
|
||||||
// Used to create Requests.
|
// Used to create Requests.
|
||||||
pub const Client = struct {
|
pub const Client = struct {
|
||||||
@@ -113,7 +111,7 @@ pub const Request = struct {
|
|||||||
arena: Allocator,
|
arena: Allocator,
|
||||||
|
|
||||||
// List of request headers
|
// List of request headers
|
||||||
headers: HeaderList,
|
headers: std.ArrayListUnmanaged(std.http.Header),
|
||||||
|
|
||||||
// Used to limit the # of redirects we'll follow
|
// Used to limit the # of redirects we'll follow
|
||||||
_redirect_count: u16,
|
_redirect_count: u16,
|
||||||
@@ -1437,9 +1435,10 @@ const Reader = struct {
|
|||||||
pub const ResponseHeader = struct {
|
pub const ResponseHeader = struct {
|
||||||
status: u16 = 0,
|
status: u16 = 0,
|
||||||
keepalive: bool = false,
|
keepalive: bool = false,
|
||||||
headers: HeaderList = .{},
|
headers: std.ArrayListUnmanaged(Header) = .{},
|
||||||
|
|
||||||
// Stored header has already been lower-cased, we expect name to be lowercased
|
// Stored header has already been lower-cased
|
||||||
|
// `name` parameter should be passed in lower-cased
|
||||||
pub fn get(self: *const ResponseHeader, name: []const u8) ?[]const u8 {
|
pub fn get(self: *const ResponseHeader, name: []const u8) ?[]const u8 {
|
||||||
for (self.headers.items) |h| {
|
for (self.headers.items) |h| {
|
||||||
if (std.mem.eql(u8, name, h.name)) {
|
if (std.mem.eql(u8, name, h.name)) {
|
||||||
@@ -1462,12 +1461,23 @@ pub const ResponseHeader = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// We don't want to use std.http.Header, because the value is `[]const u8`.
|
||||||
|
// We _could_ use it and @constCast, but this gives us more safety.
|
||||||
|
// The main reason we want to do this is that a caller could lower-case the
|
||||||
|
// value in-place.
|
||||||
|
// The value (and key) are both safe to mutate because they're cloned from
|
||||||
|
// the byte stream by our arena.
|
||||||
|
const Header = struct {
|
||||||
|
name: []const u8,
|
||||||
|
value: []u8,
|
||||||
|
};
|
||||||
|
|
||||||
const HeaderIterator = struct {
|
const HeaderIterator = struct {
|
||||||
index: usize,
|
index: usize,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
headers: HeaderList,
|
headers: std.ArrayListUnmanaged(Header),
|
||||||
|
|
||||||
pub fn next(self: *HeaderIterator) ?[]const u8 {
|
pub fn next(self: *HeaderIterator) ?[]u8 {
|
||||||
const name = self.name;
|
const name = self.name;
|
||||||
const index = self.index;
|
const index = self.index;
|
||||||
for (self.headers.items[index..], index..) |h, i| {
|
for (self.headers.items[index..], index..) |h, i| {
|
||||||
@@ -2107,11 +2117,13 @@ test "HttpClient: HeaderIterator" {
|
|||||||
try testing.expectEqual(null, it.next());
|
try testing.expectEqual(null, it.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
try header.headers.append(testing.allocator, .{ .name = "h1", .value = "value1" });
|
// @constCast is totally unsafe here, but it's just a test, and we know
|
||||||
try header.headers.append(testing.allocator, .{ .name = "h2", .value = "value2" });
|
// nothing is going to write to it, so it works.
|
||||||
try header.headers.append(testing.allocator, .{ .name = "h3", .value = "value3" });
|
try header.headers.append(testing.allocator, .{ .name = "h1", .value = @constCast("value1") });
|
||||||
try header.headers.append(testing.allocator, .{ .name = "h1", .value = "value4" });
|
try header.headers.append(testing.allocator, .{ .name = "h2", .value = @constCast("value2") });
|
||||||
try header.headers.append(testing.allocator, .{ .name = "h1", .value = "value5" });
|
try header.headers.append(testing.allocator, .{ .name = "h3", .value = @constCast("value3") });
|
||||||
|
try header.headers.append(testing.allocator, .{ .name = "h1", .value = @constCast("value4") });
|
||||||
|
try header.headers.append(testing.allocator, .{ .name = "h1", .value = @constCast("value5") });
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = header.iterate("nope");
|
var it = header.iterate("nope");
|
||||||
@@ -2148,7 +2160,7 @@ const TestResponse = struct {
|
|||||||
keepalive: ?bool,
|
keepalive: ?bool,
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
body: std.ArrayListUnmanaged(u8),
|
body: std.ArrayListUnmanaged(u8),
|
||||||
headers: std.ArrayListUnmanaged(std.http.Header),
|
headers: std.ArrayListUnmanaged(Header),
|
||||||
|
|
||||||
fn init() TestResponse {
|
fn init() TestResponse {
|
||||||
return .{
|
return .{
|
||||||
|
|||||||
Reference in New Issue
Block a user