Commit 69bcdbefd0

Nameless <truemedian@gmail.com>
2024-02-26 16:38:27
std.http: clear confusing trailer check, add sanity check for invalid field name
1 parent 9410b11
Changed files (1)
lib
lib/std/http/HeaderIterator.zig
@@ -12,26 +12,39 @@ pub fn init(bytes: []const u8) HeaderIterator {
 
 pub fn next(it: *HeaderIterator) ?std.http.Header {
     const end = std.mem.indexOfPosLinear(u8, it.bytes, it.index, "\r\n").?;
-    var kv_it = std.mem.splitSequence(u8, it.bytes[it.index..end], ": ");
-    const name = kv_it.next().?;
-    const value = kv_it.rest();
-    if (name.len == 0 and value.len == 0) {
+    if (it.index == end) { // found the trailer boundary (\r\n\r\n)
         if (it.is_trailer) return null;
+
         const next_end = std.mem.indexOfPosLinear(u8, it.bytes, end + 2, "\r\n") orelse
             return null;
+
+        var kv_it = std.mem.splitScalar(u8, it.bytes[end + 2 .. next_end], ':');
+        const name = kv_it.first();
+        const value = kv_it.rest();
+
         it.is_trailer = true;
         it.index = next_end + 2;
-        kv_it = std.mem.splitSequence(u8, it.bytes[end + 2 .. next_end], ": ");
+        if (name.len == 0)
+            return null;
+
+        return .{
+            .name = name,
+            .value = std.mem.trim(u8, value, " \t"),
+        };
+    } else { // normal header
+        var kv_it = std.mem.splitScalar(u8, it.bytes[it.index..end], ':');
+        const name = kv_it.first();
+        const value = kv_it.rest();
+
+        it.index = end + 2;
+        if (name.len == 0)
+            return null;
+
         return .{
-            .name = kv_it.next().?,
-            .value = kv_it.rest(),
+            .name = name,
+            .value = std.mem.trim(u8, value, " \t"),
         };
     }
-    it.index = end + 2;
-    return .{
-        .name = name,
-        .value = value,
-    };
 }
 
 test next {
@@ -62,7 +75,23 @@ test next {
         try std.testing.expectEqualStrings("g", header.value);
     }
     try std.testing.expectEqual(null, it.next());
+
+    it = HeaderIterator.init("200 OK\r\n: ss\r\n\r\n");
+    try std.testing.expect(!it.is_trailer);
+    try std.testing.expectEqual(null, it.next());
+
+    it = HeaderIterator.init("200 OK\r\na: b\r\n\r\n: ss\r\n\r\n");
+    try std.testing.expect(!it.is_trailer);
+    {
+        const header = it.next().?;
+        try std.testing.expect(!it.is_trailer);
+        try std.testing.expectEqualStrings("a", header.name);
+        try std.testing.expectEqualStrings("b", header.value);
+    }
+    try std.testing.expectEqual(null, it.next());
+    try std.testing.expect(it.is_trailer);
 }
 
 const HeaderIterator = @This();
 const std = @import("../std.zig");
+const assert = std.debug.assert;