| ... | ... | @@ -96,7 +96,7 @@ pub const Request = struct { |
| 96 | 96 | int64("HTTP/1.1") => .@"HTTP/1.1", |
| 97 | 97 | else => return error.BadHttpVersion, |
| 98 | 98 | }; |
| 99 | | if (first_line[8] != ' ') return error.InvalidHttpHeaders; |
| 99 | if (first_line[8] != ' ') return error.HttpHeadersInvalid; |
| 100 | 100 | const status = @intToEnum(http.Status, parseInt3(first_line[9..12].*)); |
| 101 | 101 | |
| 102 | 102 | var headers: Response.Headers = .{ |
| ... | ... | @@ -105,12 +105,19 @@ pub const Request = struct { |
| 105 | 105 | }; |
| 106 | 106 | |
| 107 | 107 | while (it.next()) |line| { |
| 108 | if (line.len == 0) return error.HttpHeadersInvalid; |
| 109 | switch (line[0]) { |
| 110 | ' ', '\t' => return error.HttpHeaderContinuationsUnsupported, |
| 111 | else => {}, |
| 112 | } |
| 108 | 113 | var line_it = mem.split(u8, line, ": "); |
| 109 | 114 | const header_name = line_it.first(); |
| 110 | 115 | const header_value = line_it.rest(); |
| 111 | 116 | if (std.ascii.eqlIgnoreCase(header_name, "location")) { |
| 117 | if (headers.location != null) return error.HttpHeadersInvalid; |
| 112 | 118 | headers.location = header_value; |
| 113 | 119 | } else if (std.ascii.eqlIgnoreCase(header_name, "content-length")) { |
| 120 | if (headers.content_length != null) return error.HttpHeadersInvalid; |
| 114 | 121 | headers.content_length = try std.fmt.parseInt(u64, header_value, 10); |
| 115 | 122 | } |
| 116 | 123 | } |
| ... | ... | @@ -131,6 +138,29 @@ pub const Request = struct { |
| 131 | 138 | return error.TestFailed); |
| 132 | 139 | try testing.expectEqual(@as(?u64, 220), parsed.content_length); |
| 133 | 140 | } |
| 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 | } |
| 134 | 164 | }; |
| 135 | 165 | |
| 136 | 166 | pub const State = enum { |
| ... | ... | @@ -442,7 +472,7 @@ pub const Request = struct { |
| 442 | 472 | const amt = try req.connection.read(buffer); |
| 443 | 473 | const data = buffer[0..amt]; |
| 444 | 474 | const i = req.response.findHeadersEnd(data); |
| 445 | | if (req.response.state == .invalid) return error.InvalidHttpHeaders; |
| 475 | if (req.response.state == .invalid) return error.HttpHeadersInvalid; |
| 446 | 476 | |
| 447 | 477 | const headers_data = data[0..i]; |
| 448 | 478 | if (req.response.header_bytes.items.len + headers_data.len > req.response.max_header_bytes) { |