From 3875ffbdfb81cc76fa0d2b3144145a0a5973763a Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Sat, 1 Jun 2024 17:09:49 +0100 Subject: [PATCH] Remove allocs in `Headers.getAll()` Provide `Headers.getAllIterator()` to iterate over matching headers, use this to iterate through `Accept-Encoding` headers in CompressionMiddleware. --- src/jetzig/http/Headers.zig | 44 +++++++++++++++++++ .../middleware/CompressionMiddleware.zig | 5 ++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/jetzig/http/Headers.zig b/src/jetzig/http/Headers.zig index 8db8c56..89d3671 100644 --- a/src/jetzig/http/Headers.zig +++ b/src/jetzig/http/Headers.zig @@ -59,6 +59,10 @@ pub fn getFirstValue(self: *const Headers, name: []const u8) ?[]const u8 { return self.get(name); } +pub fn count(self: Headers) usize { + return self.httpz_headers.len; +} + /// Add `name` and `value` to headers. pub fn append(self: *Headers, name: []const u8, value: []const u8) !void { if (self.httpz_headers.len >= self.httpz_headers.keys.len) return error.JetzigTooManyHeaders; @@ -75,6 +79,46 @@ pub fn append(self: *Headers, name: []const u8, value: []const u8) !void { self.httpz_headers.add(header.name, header.value); } +const Iterator = struct { + position: usize = 0, + headers: Headers, + filter_name: ?[]const u8 = null, + + pub fn next(self: *Iterator) ?Header { + const header_count = self.headers.count(); + if (self.position >= header_count) { + return null; + } + const start = self.position; + + var buf: [jetzig.config.get(u16, "max_bytes_header_name")]u8 = undefined; + const filter_name = if (self.filter_name) |name| std.ascii.lowerString(&buf, name) else null; + + for (start..header_count) |index| { + const key = self.headers.httpz_headers.keys[start + index]; + const value = self.headers.httpz_headers.values[start + index]; + self.position += 1; + if (filter_name) |name| { + if (std.mem.eql(u8, name, key)) { + return .{ .name = key, .value = value }; + } + } else { + return .{ .name = key, .value = value }; + } + } + + return null; + } +}; + +pub fn getAllIterator(self: Headers, name: []const u8) Iterator { + return .{ .headers = self, .filter_name = name }; +} + +pub fn iterator(self: Headers) Iterator { + return .{ .headers = self }; +} + test "append (deprecated)" { const allocator = std.testing.allocator; var httpz_headers = try httpz.key_value.KeyValue.init(allocator, 10); diff --git a/src/jetzig/middleware/CompressionMiddleware.zig b/src/jetzig/middleware/CompressionMiddleware.zig index 5417495..038f812 100644 --- a/src/jetzig/middleware/CompressionMiddleware.zig +++ b/src/jetzig/middleware/CompressionMiddleware.zig @@ -44,8 +44,9 @@ pub fn beforeResponse(request: *jetzig.http.Request, response: *jetzig.http.Resp } fn detectEncoding(request: *const jetzig.http.Request) ?Encoding { - for (request.headers.getAll("Accept-Encoding")) |encodings| { - var it = std.mem.tokenizeScalar(u8, encodings, ','); + var headers_it = request.headers.getAllIterator("Accept-Encoding"); + while (headers_it.next()) |header| { + var it = std.mem.tokenizeScalar(u8, header.value, ','); while (it.next()) |param| { inline for (@typeInfo(Encoding).Enum.fields) |field| { if (std.mem.eql(u8, field.name, jetzig.util.strip(param))) {