Skip to content

Commit 3055ab7

Browse files
committed
std.http.Client: fail header parsing under more conditions
* when HTTP header continuations are used * when content-type or location header occurs more than once
1 parent 450f3bc commit 3055ab7

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

lib/std/http/Client.zig

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub const Request = struct {
9696
int64("HTTP/1.1") => .@"HTTP/1.1",
9797
else => return error.BadHttpVersion,
9898
};
99-
if (first_line[8] != ' ') return error.InvalidHttpHeaders;
99+
if (first_line[8] != ' ') return error.HttpHeadersInvalid;
100100
const status = @intToEnum(http.Status, parseInt3(first_line[9..12].*));
101101

102102
var headers: Response.Headers = .{
@@ -105,12 +105,19 @@ pub const Request = struct {
105105
};
106106

107107
while (it.next()) |line| {
108+
if (line.len == 0) return error.HttpHeadersInvalid;
109+
switch (line[0]) {
110+
' ', '\t' => return error.HttpHeaderContinuationsUnsupported,
111+
else => {},
112+
}
108113
var line_it = mem.split(u8, line, ": ");
109114
const header_name = line_it.first();
110115
const header_value = line_it.rest();
111116
if (std.ascii.eqlIgnoreCase(header_name, "location")) {
117+
if (headers.location != null) return error.HttpHeadersInvalid;
112118
headers.location = header_value;
113119
} else if (std.ascii.eqlIgnoreCase(header_name, "content-length")) {
120+
if (headers.content_length != null) return error.HttpHeadersInvalid;
114121
headers.content_length = try std.fmt.parseInt(u64, header_value, 10);
115122
}
116123
}
@@ -131,6 +138,29 @@ pub const Request = struct {
131138
return error.TestFailed);
132139
try testing.expectEqual(@as(?u64, 220), parsed.content_length);
133140
}
141+
142+
test "header continuation" {
143+
const example =
144+
"HTTP/1.0 200 OK\r\n" ++
145+
"Content-Type: text/html;\r\n charset=UTF-8\r\n" ++
146+
"Content-Length: 220\r\n\r\n";
147+
try testing.expectError(
148+
error.HttpHeaderContinuationsUnsupported,
149+
Response.Headers.parse(example),
150+
);
151+
}
152+
153+
test "extra content length" {
154+
const example =
155+
"HTTP/1.0 200 OK\r\n" ++
156+
"Content-Length: 220\r\n" ++
157+
"Content-Type: text/html; charset=UTF-8\r\n" ++
158+
"content-length: 220\r\n\r\n";
159+
try testing.expectError(
160+
error.HttpHeadersInvalid,
161+
Response.Headers.parse(example),
162+
);
163+
}
134164
};
135165

136166
pub const State = enum {
@@ -442,7 +472,7 @@ pub const Request = struct {
442472
const amt = try req.connection.read(buffer);
443473
const data = buffer[0..amt];
444474
const i = req.response.findHeadersEnd(data);
445-
if (req.response.state == .invalid) return error.InvalidHttpHeaders;
475+
if (req.response.state == .invalid) return error.HttpHeadersInvalid;
446476

447477
const headers_data = data[0..i];
448478
if (req.response.header_bytes.items.len + headers_data.len > req.response.max_header_bytes) {

0 commit comments

Comments
 (0)