Skip to content

Commit

Permalink
Use content-type header if present to detect format
Browse files Browse the repository at this point in the history
Detect request format (HTML or JSON) from `content-type` header.

Previous:
- path extension (.json, .html)
- "Accept" header
- default (.UNKNOWN => .HTML)

Current:
- path extension (.json, .html)
- "Accept" header
- "Content-Type" header
- default (.UNKNOWN => .HTML)

Adjust `http.Headers` to do case-insensitive matching to conform to HTTP
spec: https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names
  • Loading branch information
bobf committed Mar 10, 2024
1 parent ea1962f commit dd54d55
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 3 deletions.
16 changes: 14 additions & 2 deletions src/jetzig/http/Headers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ pub fn deinit(self: *Self) void {
self.headers.deinit(self.allocator);
}

// Gets the first value for a given header identified by `name`.
// Gets the first value for a given header identified by `name`. Case-insensitive string comparison.
pub fn getFirstValue(self: *Self, name: []const u8) ?[]const u8 {
for (self.headers.items) |header| {
if (std.mem.eql(u8, header.name, name)) return header.value;
if (name.len != header.name.len) continue;
for (name, header.name) |expected, actual| {
if (std.ascii.toLower(expected) != std.ascii.toLower(actual)) continue;
}
return header.value;
}
return null;
}
Expand Down Expand Up @@ -78,6 +82,14 @@ test "append" {
try std.testing.expectEqualStrings(headers.getFirstValue("foo").?, "bar");
}

test "case-insensitive matching" {
const allocator = std.testing.allocator;
var headers = Self.init(allocator);
defer headers.deinit();
try headers.append("Content-Type", "bar");
try std.testing.expectEqualStrings(headers.getFirstValue("content-type").?, "bar");
}

test "iterator" {
const allocator = std.testing.allocator;
var headers = Self.init(allocator);
Expand Down
16 changes: 15 additions & 1 deletion src/jetzig/http/Request.zig
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ pub fn render(self: *Self, status_code: jetzig.http.status_codes.StatusCode) jet
}

pub fn requestFormat(self: *Self) jetzig.http.Request.Format {
return self.extensionFormat() orelse self.acceptHeaderFormat() orelse .UNKNOWN;
return self.extensionFormat() orelse
self.acceptHeaderFormat() orelse
self.contentTypeHeaderFormat() orelse
.UNKNOWN;
}

pub fn getHeader(self: *Self, key: []const u8) ?[]const u8 {
Expand Down Expand Up @@ -233,6 +236,17 @@ pub fn acceptHeaderFormat(self: *Self) ?jetzig.http.Request.Format {
return null;
}

pub fn contentTypeHeaderFormat(self: *Self) ?jetzig.http.Request.Format {
const acceptHeader = self.getHeader("content-type");

if (acceptHeader) |item| {
if (std.mem.eql(u8, item, "text/html")) return .HTML;
if (std.mem.eql(u8, item, "application/json")) return .JSON;
}

return null;
}

pub fn hash(self: *Self) ![]const u8 {
return try std.fmt.allocPrint(
self.allocator,
Expand Down

0 comments on commit dd54d55

Please sign in to comment.