@@ -38,8 +38,6 @@ const BUFFER_LEN = 32 * 1024;
3838// The longest individual header line that we support
3939const MAX_HEADER_LINE_LEN = 4096 ;
4040
41- const HeaderList = std .ArrayListUnmanaged (std .http .Header );
42-
4341// Thread-safe. Holds our root certificate, connection pool and state pool
4442// Used to create Requests.
4543pub const Client = struct {
@@ -113,7 +111,7 @@ pub const Request = struct {
113111 arena : Allocator ,
114112
115113 // List of request headers
116- headers : HeaderList ,
114+ headers : std . ArrayListUnmanaged ( std . http . Header ) ,
117115
118116 // Used to limit the # of redirects we'll follow
119117 _redirect_count : u16 ,
@@ -1437,9 +1435,10 @@ const Reader = struct {
14371435pub const ResponseHeader = struct {
14381436 status : u16 = 0 ,
14391437 keepalive : bool = false ,
1440- headers : HeaderList = .{},
1438+ headers : std . ArrayListUnmanaged ( Header ) = .{},
14411439
1442- // Stored header has already been lower-cased, we expect name to be lowercased
1440+ // Stored header has already been lower-cased
1441+ // `name` parameter should be passed in lower-cased
14431442 pub fn get (self : * const ResponseHeader , name : []const u8 ) ? []const u8 {
14441443 for (self .headers .items ) | h | {
14451444 if (std .mem .eql (u8 , name , h .name )) {
@@ -1462,12 +1461,23 @@ pub const ResponseHeader = struct {
14621461 }
14631462};
14641463
1464+ // We don't want to use std.http.Header, because the value is `[]const u8`.
1465+ // We _could_ use it and @constCast, but this gives us more safety.
1466+ // The main reason we want to do this is that a caller could lower-case the
1467+ // value in-place.
1468+ // The value (and key) are both safe to mutate because they're cloned from
1469+ // the byte stream by our arena.
1470+ const Header = struct {
1471+ name : []const u8 ,
1472+ value : []u8 ,
1473+ };
1474+
14651475const HeaderIterator = struct {
14661476 index : usize ,
14671477 name : []const u8 ,
1468- headers : HeaderList ,
1478+ headers : std . ArrayListUnmanaged ( Header ) ,
14691479
1470- pub fn next (self : * HeaderIterator ) ? []const u8 {
1480+ pub fn next (self : * HeaderIterator ) ? []u8 {
14711481 const name = self .name ;
14721482 const index = self .index ;
14731483 for (self .headers .items [index .. ], index .. ) | h , i | {
@@ -2107,11 +2117,13 @@ test "HttpClient: HeaderIterator" {
21072117 try testing .expectEqual (null , it .next ());
21082118 }
21092119
2110- try header .headers .append (testing .allocator , .{ .name = "h1" , .value = "value1" });
2111- try header .headers .append (testing .allocator , .{ .name = "h2" , .value = "value2" });
2112- try header .headers .append (testing .allocator , .{ .name = "h3" , .value = "value3" });
2113- try header .headers .append (testing .allocator , .{ .name = "h1" , .value = "value4" });
2114- try header .headers .append (testing .allocator , .{ .name = "h1" , .value = "value5" });
2120+ // @constCast is totally unsafe here, but it's just a test, and we know
2121+ // nothing is going to write to it, so it works.
2122+ try header .headers .append (testing .allocator , .{ .name = "h1" , .value = @constCast ("value1" ) });
2123+ try header .headers .append (testing .allocator , .{ .name = "h2" , .value = @constCast ("value2" ) });
2124+ try header .headers .append (testing .allocator , .{ .name = "h3" , .value = @constCast ("value3" ) });
2125+ try header .headers .append (testing .allocator , .{ .name = "h1" , .value = @constCast ("value4" ) });
2126+ try header .headers .append (testing .allocator , .{ .name = "h1" , .value = @constCast ("value5" ) });
21152127
21162128 {
21172129 var it = header .iterate ("nope" );
@@ -2148,7 +2160,7 @@ const TestResponse = struct {
21482160 keepalive : ? bool ,
21492161 arena : std.heap.ArenaAllocator ,
21502162 body : std .ArrayListUnmanaged (u8 ),
2151- headers : std .ArrayListUnmanaged (std . http . Header ),
2163+ headers : std .ArrayListUnmanaged (Header ),
21522164
21532165 fn init () TestResponse {
21542166 return .{
0 commit comments