authorgravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2024-02-27 14:22:34-06:00
committergravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2024-02-28 15:12:44-06:00
loge62b0773cca027e720db1b18ce3905b7fe24ca96
tree18e55b90c5c45a5191080dd7407d733c48b6e383
parent81713f20a6635c6905e81daa0a061e43c85db277
signaturelock-open Commit is signed but in an unrecognized format.

std.http: add tests against regressions for conforming fields


3 files changed, 184 insertions(+), 2 deletions(-)

lib/std/http/Client.zig+98
...@@ -551,6 +551,43 @@ pub const Response = struct {...@@ -551,6 +551,43 @@ pub const Response = struct {
551 return error.HttpHeadersInvalid; // missing empty line551 return error.HttpHeadersInvalid; // missing empty line
552 }552 }
553553
554 test parse {
555 const response_bytes = "HTTP/1.1 200 OK\r\n" ++
556 "LOcation:url\r\n" ++
557 "content-tYpe: text/plain\r\n" ++
558 "content-disposition:attachment; filename=example.txt \r\n" ++
559 "content-Length:10\r\n" ++
560 "TRansfer-encoding:\tdeflate, chunked \r\n" ++
561 "connectioN:\t keep-alive \r\n\r\n";
562
563 var header_buffer: [1024]u8 = undefined;
564 var res = Response{
565 .status = undefined,
566 .reason = undefined,
567 .version = undefined,
568 .keep_alive = false,
569 .parser = proto.HeadersParser.init(&header_buffer),
570 };
571
572 @memcpy(header_buffer[0..response_bytes.len], response_bytes);
573 res.parser.header_bytes_len = response_bytes.len;
574
575 try res.parse(response_bytes);
576
577 try testing.expectEqual(.@"HTTP/1.1", res.version);
578 try testing.expectEqualStrings("OK", res.reason);
579 try testing.expectEqual(.ok, res.status);
580
581 try testing.expectEqualStrings("url", res.location.?);
582 try testing.expectEqualStrings("text/plain", res.content_type.?);
583 try testing.expectEqualStrings("attachment; filename=example.txt", res.content_disposition.?);
584
585 try testing.expectEqual(true, res.keep_alive);
586 try testing.expectEqual(10, res.content_length.?);
587 try testing.expectEqual(.chunked, res.transfer_encoding);
588 try testing.expectEqual(.deflate, res.transfer_compression);
589 }
590
554 inline fn int64(array: *const [8]u8) u64 {591 inline fn int64(array: *const [8]u8) u64 {
555 return @bitCast(array.*);592 return @bitCast(array.*);
556 }593 }
...@@ -575,6 +612,67 @@ pub const Response = struct {...@@ -575,6 +612,67 @@ pub const Response = struct {
575 pub fn iterateHeaders(r: Response) http.HeaderIterator {612 pub fn iterateHeaders(r: Response) http.HeaderIterator {
576 return http.HeaderIterator.init(r.parser.get());613 return http.HeaderIterator.init(r.parser.get());
577 }614 }
615
616 test iterateHeaders {
617 const response_bytes = "HTTP/1.1 200 OK\r\n" ++
618 "LOcation:url\r\n" ++
619 "content-tYpe: text/plain\r\n" ++
620 "content-disposition:attachment; filename=example.txt \r\n" ++
621 "content-Length:10\r\n" ++
622 "TRansfer-encoding:\tdeflate, chunked \r\n" ++
623 "connectioN:\t keep-alive \r\n\r\n";
624
625 var header_buffer: [1024]u8 = undefined;
626 var res = Response{
627 .status = undefined,
628 .reason = undefined,
629 .version = undefined,
630 .keep_alive = false,
631 .parser = proto.HeadersParser.init(&header_buffer),
632 };
633
634 @memcpy(header_buffer[0..response_bytes.len], response_bytes);
635 res.parser.header_bytes_len = response_bytes.len;
636
637 var it = res.iterateHeaders();
638 {
639 const header = it.next().?;
640 try testing.expectEqualStrings("LOcation", header.name);
641 try testing.expectEqualStrings("url", header.value);
642 try testing.expect(!it.is_trailer);
643 }
644 {
645 const header = it.next().?;
646 try testing.expectEqualStrings("content-tYpe", header.name);
647 try testing.expectEqualStrings("text/plain", header.value);
648 try testing.expect(!it.is_trailer);
649 }
650 {
651 const header = it.next().?;
652 try testing.expectEqualStrings("content-disposition", header.name);
653 try testing.expectEqualStrings("attachment; filename=example.txt", header.value);
654 try testing.expect(!it.is_trailer);
655 }
656 {
657 const header = it.next().?;
658 try testing.expectEqualStrings("content-Length", header.name);
659 try testing.expectEqualStrings("10", header.value);
660 try testing.expect(!it.is_trailer);
661 }
662 {
663 const header = it.next().?;
664 try testing.expectEqualStrings("TRansfer-encoding", header.name);
665 try testing.expectEqualStrings("deflate, chunked", header.value);
666 try testing.expect(!it.is_trailer);
667 }
668 {
669 const header = it.next().?;
670 try testing.expectEqualStrings("connectioN", header.name);
671 try testing.expectEqualStrings("keep-alive", header.value);
672 try testing.expect(!it.is_trailer);
673 }
674 try testing.expectEqual(null, it.next());
675 }
578};676};
579677
580/// A HTTP request that has been sent.678/// A HTTP request that has been sent.
lib/std/http/Server.zig+84
...@@ -271,6 +271,29 @@ pub const Request = struct {...@@ -271,6 +271,29 @@ pub const Request = struct {
271 return error.MissingFinalNewline;271 return error.MissingFinalNewline;
272 }272 }
273273
274 test parse {
275 const request_bytes = "GET /hi HTTP/1.0\r\n" ++
276 "content-tYpe: text/plain\r\n" ++
277 "content-Length:10\r\n" ++
278 "expeCt: 100-continue \r\n" ++
279 "TRansfer-encoding:\tdeflate, chunked \r\n" ++
280 "connectioN:\t keep-alive \r\n\r\n";
281
282 const req = try parse(request_bytes);
283
284 try testing.expectEqual(.GET, req.method);
285 try testing.expectEqual(.@"HTTP/1.0", req.version);
286 try testing.expectEqualStrings("/hi", req.target);
287
288 try testing.expectEqualStrings("text/plain", req.content_type.?);
289 try testing.expectEqualStrings("100-continue", req.expect.?);
290
291 try testing.expectEqual(true, req.keep_alive);
292 try testing.expectEqual(10, req.content_length.?);
293 try testing.expectEqual(.chunked, req.transfer_encoding);
294 try testing.expectEqual(.deflate, req.transfer_compression);
295 }
296
274 inline fn int64(array: *const [8]u8) u64 {297 inline fn int64(array: *const [8]u8) u64 {
275 return @bitCast(array.*);298 return @bitCast(array.*);
276 }299 }
...@@ -280,6 +303,66 @@ pub const Request = struct {...@@ -280,6 +303,66 @@ pub const Request = struct {
280 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]);
281 }304 }
282305
306 test iterateHeaders {
307 const request_bytes = "GET /hi HTTP/1.0\r\n" ++
308 "content-tYpe: text/plain\r\n" ++
309 "content-Length:10\r\n" ++
310 "expeCt: 100-continue \r\n" ++
311 "TRansfer-encoding:\tdeflate, chunked \r\n" ++
312 "connectioN:\t keep-alive \r\n\r\n";
313
314 var read_buffer: [500]u8 = undefined;
315 @memcpy(read_buffer[0..request_bytes.len], request_bytes);
316
317 var server: Server = .{
318 .connection = undefined,
319 .state = .ready,
320 .read_buffer = &read_buffer,
321 .read_buffer_len = request_bytes.len,
322 .next_request_start = 0,
323 };
324
325 var request: Request = .{
326 .server = &server,
327 .head_end = request_bytes.len,
328 .head = undefined,
329 .reader_state = undefined,
330 };
331
332 var it = request.iterateHeaders();
333 {
334 const header = it.next().?;
335 try testing.expectEqualStrings("content-tYpe", header.name);
336 try testing.expectEqualStrings("text/plain", header.value);
337 try testing.expect(!it.is_trailer);
338 }
339 {
340 const header = it.next().?;
341 try testing.expectEqualStrings("content-Length", header.name);
342 try testing.expectEqualStrings("10", header.value);
343 try testing.expect(!it.is_trailer);
344 }
345 {
346 const header = it.next().?;
347 try testing.expectEqualStrings("expeCt", header.name);
348 try testing.expectEqualStrings("100-continue", header.value);
349 try testing.expect(!it.is_trailer);
350 }
351 {
352 const header = it.next().?;
353 try testing.expectEqualStrings("TRansfer-encoding", header.name);
354 try testing.expectEqualStrings("deflate, chunked", header.value);
355 try testing.expect(!it.is_trailer);
356 }
357 {
358 const header = it.next().?;
359 try testing.expectEqualStrings("connectioN", header.name);
360 try testing.expectEqualStrings("keep-alive", header.value);
361 try testing.expect(!it.is_trailer);
362 }
363 try testing.expectEqual(null, it.next());
364 }
365
283 pub const RespondOptions = struct {366 pub const RespondOptions = struct {
284 version: http.Version = .@"HTTP/1.1",367 version: http.Version = .@"HTTP/1.1",
285 status: http.Status = .ok,368 status: http.Status = .ok,
...@@ -1060,5 +1143,6 @@ const mem = std.mem;...@@ -1060,5 +1143,6 @@ const mem = std.mem;
1060const net = std.net;1143const net = std.net;
1061const Uri = std.Uri;1144const Uri = std.Uri;
1062const assert = std.debug.assert;1145const assert = std.debug.assert;
1146const testing = std.testing;
10631147
1064const Server = @This();1148const Server = @This();
lib/std/http/test.zig+2-2
...@@ -328,8 +328,8 @@ test "receiving arbitrary http headers from the client" {...@@ -328,8 +328,8 @@ test "receiving arbitrary http headers from the client" {
328 defer test_server.destroy();328 defer test_server.destroy();
329329
330 const request_bytes = "GET /bar HTTP/1.1\r\n" ++330 const request_bytes = "GET /bar HTTP/1.1\r\n" ++
331 "CoNneCtIoN: close\r\n" ++331 "CoNneCtIoN:close\r\n" ++
332 "aoeu: asdf\r\n" ++332 "aoeu: asdf \r\n" ++
333 "\r\n";333 "\r\n";
334 const gpa = std.testing.allocator;334 const gpa = std.testing.allocator;
335 const stream = try std.net.tcpConnectToHost(gpa, "127.0.0.1", test_server.port());335 const stream = try std.net.tcpConnectToHost(gpa, "127.0.0.1", test_server.port());