aboutsummaryrefslogtreecommitdiff
path: root/lib/std/http
diff options
context:
space:
mode:
authordbubel <50341559+dbubel@users.noreply.github.com>2025-01-27 12:58:05 -0500
committerGitHub <noreply@github.com>2025-01-27 17:58:05 +0000
commit21823d1b5d1ebfa27df954c2cef5d0f231fb8402 (patch)
treee0c3d98f6b76610ce80daaabb882ea731a9c1cab /lib/std/http
parent2043e8ae05449dc92ffaaf480fc22440cc9181ae (diff)
downloadzig-21823d1b5d1ebfa27df954c2cef5d0f231fb8402.tar.gz
zig-21823d1b5d1ebfa27df954c2cef5d0f231fb8402.zip
std.http.Server: add Request.getHeader() function (#21625)
Diffstat (limited to 'lib/std/http')
-rw-r--r--lib/std/http/Server.zig72
1 files changed, 71 insertions, 1 deletions
diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig
index 25d3e44253..b2716cc74c 100644
--- a/lib/std/http/Server.zig
+++ b/lib/std/http/Server.zig
@@ -299,7 +299,7 @@ pub const Request = struct {
}
};
- pub fn iterateHeaders(r: *Request) http.HeaderIterator {
+ pub fn iterateHeaders(r: Request) http.HeaderIterator {
return http.HeaderIterator.init(r.server.read_buffer[0..r.head_end]);
}
@@ -363,6 +363,76 @@ pub const Request = struct {
try testing.expectEqual(null, it.next());
}
+ /// Retrieves the value of a specified HTTP header from a Request struct.
+ ///
+ /// This function searches for a header with a name matching the provided string,
+ /// ignoring case. If found, it returns the header's value. If not found, it
+ /// returns null.
+ ///
+ /// Note: If multiple headers with the same name are present, this function
+ /// will return the value of the first matching header encountered.
+ ///
+ /// For accessing duplicate headers or iterating through all headers,
+ /// use the `iterateHeaders()` method directly.
+ pub fn getHeader(r: Request, s: []const u8) ?[]const u8 {
+ var iter = r.iterateHeaders();
+ while (iter.next()) |header| {
+ if (std.ascii.eqlIgnoreCase(s, header.name)) {
+ return header.value;
+ }
+ }
+ return null;
+ }
+
+ test getHeader {
+ const request_bytes = "GET /hi HTTP/1.0\r\n" ++
+ "content-tYpe: text/plain\r\n" ++
+ "content-Length:10\r\n" ++
+ "expeCt: 100-continue \r\n" ++
+ "TRansfer-encoding:\tdeflate, chunked \r\n" ++
+ "connectioN:\t keep-alive \r\n\r\n";
+ var read_buffer: [500]u8 = undefined;
+
+ @memcpy(read_buffer[0..request_bytes.len], request_bytes);
+ var server: Server = .{
+ .connection = undefined,
+ .state = .ready,
+ .read_buffer = &read_buffer,
+ .read_buffer_len = request_bytes.len,
+ .next_request_start = 0,
+ };
+ const request: Request = .{
+ .server = &server,
+ .head_end = request_bytes.len,
+ .head = undefined,
+ .reader_state = undefined,
+ };
+
+ // Test 1: Existing header with case-insensitive match
+ try testing.expectEqualStrings("text/plain", getHeader(request, "content-type").?);
+
+ // Test 2: Existing header with exact case match
+ try testing.expectEqualStrings("10", getHeader(request, "content-Length").?);
+
+ // Test 3: Existing header with leading/trailing whitespace
+ try testing.expectEqualStrings("100-continue", getHeader(request, "expect").?);
+
+ // Test 4: Existing header with tab separator
+ try testing.expectEqualStrings("deflate, chunked", getHeader(request, "Transfer-encoding").?);
+
+ // Test 5: Non-existent header
+ try testing.expectEqual(@as(?[]const u8, null), getHeader(request, "User-Agent"));
+
+ // Test 6: Case-insensitive match for header name
+ try testing.expectEqualStrings("keep-alive", getHeader(request, "CONNECTION").?);
+
+ // Test 7: Partial header name match (should fail)
+ try testing.expectEqual(@as(?[]const u8, null), getHeader(request, "content"));
+
+ // Test 8: Empty header name (should return null)
+ try testing.expectEqual(@as(?[]const u8, null), getHeader(request, ""));
+ }
+
pub const RespondOptions = struct {
version: http.Version = .@"HTTP/1.1",
status: http.Status = .ok,