authorgravatar for 50341559+dbubel@users.noreply.github.comdbubel <50341559+dbubel@users.noreply.github.com> 2025-01-27 12:58:05-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-01-27 17:58:05+00:00
log21823d1b5d1ebfa27df954c2cef5d0f231fb8402
treee0c3d98f6b76610ce80daaabb882ea731a9c1cab
parent2043e8ae05449dc92ffaaf480fc22440cc9181ae
signaturebadge-check Signed by PGP key B5690EEEBB952194

std.http.Server: add Request.getHeader() function (#21625)


1 files changed, 71 insertions(+), 1 deletions(-)

lib/std/http/Server.zig+71-1
...@@ -299,7 +299,7 @@ pub const Request = struct {...@@ -299,7 +299,7 @@ pub const Request = struct {
299 }299 }
300 };300 };
301301
302 pub fn iterateHeaders(r: *Request) http.HeaderIterator {302 pub fn iterateHeaders(r: Request) http.HeaderIterator {
303 return http.HeaderIterator.init(r.server.read_buffer[0..r.head_end]);303 return http.HeaderIterator.init(r.server.read_buffer[0..r.head_end]);
304 }304 }
305305
...@@ -363,6 +363,76 @@ pub const Request = struct {...@@ -363,6 +363,76 @@ pub const Request = struct {
363 try testing.expectEqual(null, it.next());363 try testing.expectEqual(null, it.next());
364 }364 }
365365
366 /// Retrieves the value of a specified HTTP header from a Request struct.
367 ///
368 /// This function searches for a header with a name matching the provided string,
369 /// ignoring case. If found, it returns the header's value. If not found, it
370 /// returns null.
371 ///
372 /// Note: If multiple headers with the same name are present, this function
373 /// will return the value of the first matching header encountered.
374 ///
375 /// For accessing duplicate headers or iterating through all headers,
376 /// use the `iterateHeaders()` method directly.
377 pub fn getHeader(r: Request, s: []const u8) ?[]const u8 {
378 var iter = r.iterateHeaders();
379 while (iter.next()) |header| {
380 if (std.ascii.eqlIgnoreCase(s, header.name)) {
381 return header.value;
382 }
383 }
384 return null;
385 }
386
387 test getHeader {
388 const request_bytes = "GET /hi HTTP/1.0\r\n" ++
389 "content-tYpe: text/plain\r\n" ++
390 "content-Length:10\r\n" ++
391 "expeCt: 100-continue \r\n" ++
392 "TRansfer-encoding:\tdeflate, chunked \r\n" ++
393 "connectioN:\t keep-alive \r\n\r\n";
394 var read_buffer: [500]u8 = undefined;
395
396 @memcpy(read_buffer[0..request_bytes.len], request_bytes);
397 var server: Server = .{
398 .connection = undefined,
399 .state = .ready,
400 .read_buffer = &read_buffer,
401 .read_buffer_len = request_bytes.len,
402 .next_request_start = 0,
403 };
404 const request: Request = .{
405 .server = &server,
406 .head_end = request_bytes.len,
407 .head = undefined,
408 .reader_state = undefined,
409 };
410
411 // Test 1: Existing header with case-insensitive match
412 try testing.expectEqualStrings("text/plain", getHeader(request, "content-type").?);
413
414 // Test 2: Existing header with exact case match
415 try testing.expectEqualStrings("10", getHeader(request, "content-Length").?);
416
417 // Test 3: Existing header with leading/trailing whitespace
418 try testing.expectEqualStrings("100-continue", getHeader(request, "expect").?);
419
420 // Test 4: Existing header with tab separator
421 try testing.expectEqualStrings("deflate, chunked", getHeader(request, "Transfer-encoding").?);
422
423 // Test 5: Non-existent header
424 try testing.expectEqual(@as(?[]const u8, null), getHeader(request, "User-Agent"));
425
426 // Test 6: Case-insensitive match for header name
427 try testing.expectEqualStrings("keep-alive", getHeader(request, "CONNECTION").?);
428
429 // Test 7: Partial header name match (should fail)
430 try testing.expectEqual(@as(?[]const u8, null), getHeader(request, "content"));
431
432 // Test 8: Empty header name (should return null)
433 try testing.expectEqual(@as(?[]const u8, null), getHeader(request, ""));
434 }
435
366 pub const RespondOptions = struct {436 pub const RespondOptions = struct {
367 version: http.Version = .@"HTTP/1.1",437 version: http.Version = .@"HTTP/1.1",
368 status: http.Status = .ok,438 status: http.Status = .ok,