| author | |
| committer | |
| log | a0f9a5e78d1cf419e88c493f6f57e486df236e35 |
| tree | b91fc5370cf921491e50da075e0d3bc609da6a73 |
| parent | 07b753f22ba87357dca4aec3e93fbca912ac2197 |
* std.Io.Reader: fix confused semantics of rebase. Before it was
ambiguous whether it was supposed to be based on end or seek. Now it
is clearly based on seek, with an added assertion for clarity.
* std.crypto.tls.Client: fix panic due to not enough buffer size
available. Also, avoid unnecessary rebasing.
* std.http.Reader: introduce max_head_len to limit HTTP header length.
This prevents crash in underlying reader which may require a minimum
buffer length.
* std.http.Client: choose better buffer sizes for streams and TLS
client. Crucially, the buffer shared by HTTP reader and TLS client
needs to be big enough for all http headers *and* the max TLS record
size. Bump HTTP header size default from 4K to 8K.
fixes #24872
I have noticed however that there are still fetch problems6 files changed, 49 insertions(+), 46 deletions(-)
lib/std/Io.zig+6-1| ... | @@ -717,7 +717,12 @@ pub fn Poller(comptime StreamEnum: type) type { | ... | @@ -717,7 +717,12 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 717 | const unused = r.buffer[r.end..]; | 717 | const unused = r.buffer[r.end..]; |
| 718 | if (unused.len >= min_len) return unused; | 718 | if (unused.len >= min_len) return unused; |
| 719 | } | 719 | } |
| 720 | if (r.seek > 0) r.rebase(r.buffer.len) catch unreachable; | 720 | if (r.seek > 0) { |
| 721 | const data = r.buffer[r.seek..r.end]; | ||
| 722 | @memmove(r.buffer[0..data.len], data); | ||
| 723 | r.seek = 0; | ||
| 724 | r.end = data.len; | ||
| 725 | } | ||
| 721 | { | 726 | { |
| 722 | var list: std.ArrayListUnmanaged(u8) = .{ | 727 | var list: std.ArrayListUnmanaged(u8) = .{ |
| 723 | .items = r.buffer[0..r.end], | 728 | .items = r.buffer[0..r.end], |
lib/std/Io/Reader.zig+7-24| ... | @@ -86,12 +86,12 @@ pub const VTable = struct { | ... | @@ -86,12 +86,12 @@ pub const VTable = struct { |
| 86 | /// `Reader.buffer`, whichever is bigger. | 86 | /// `Reader.buffer`, whichever is bigger. |
| 87 | readVec: *const fn (r: *Reader, data: [][]u8) Error!usize = defaultReadVec, | 87 | readVec: *const fn (r: *Reader, data: [][]u8) Error!usize = defaultReadVec, |
| 88 | 88 | ||
| 89 | /// Ensures `capacity` more data can be buffered without rebasing. | 89 | /// Ensures `capacity` data can be buffered without rebasing. |
| 90 | /// | 90 | /// |
| 91 | /// Asserts `capacity` is within buffer capacity, or that the stream ends | 91 | /// Asserts `capacity` is within buffer capacity, or that the stream ends |
| 92 | /// within `capacity` bytes. | 92 | /// within `capacity` bytes. |
| 93 | /// | 93 | /// |
| 94 | /// Only called when `capacity` cannot fit into the unused capacity of | 94 | /// Only called when `capacity` cannot be satisfied by unused capacity of |
| 95 | /// `buffer`. | 95 | /// `buffer`. |
| 96 | /// | 96 | /// |
| 97 | /// The default implementation moves buffered data to the start of | 97 | /// The default implementation moves buffered data to the start of |
| ... | @@ -1037,7 +1037,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { | ... | @@ -1037,7 +1037,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1037 | /// | 1037 | /// |
| 1038 | /// Asserts buffer capacity is at least 1. | 1038 | /// Asserts buffer capacity is at least 1. |
| 1039 | pub fn fillMore(r: *Reader) Error!void { | 1039 | pub fn fillMore(r: *Reader) Error!void { |
| 1040 | try rebase(r, 1); | 1040 | try rebase(r, r.end - r.seek + 1); |
| 1041 | var bufs: [1][]u8 = .{""}; | 1041 | var bufs: [1][]u8 = .{""}; |
| 1042 | _ = try r.vtable.readVec(r, &bufs); | 1042 | _ = try r.vtable.readVec(r, &bufs); |
| 1043 | } | 1043 | } |
| ... | @@ -1205,24 +1205,6 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { | ... | @@ -1205,24 +1205,6 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { |
| 1205 | } }))) orelse error.Overflow; | 1205 | } }))) orelse error.Overflow; |
| 1206 | } | 1206 | } |
| 1207 | 1207 | ||
| 1208 | pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void { | ||
| 1209 | if (n <= r.buffer.len) return; | ||
| 1210 | if (r.seek > 0) rebase(r, r.buffer.len); | ||
| 1211 | var list: ArrayList(u8) = .{ | ||
| 1212 | .items = r.buffer[0..r.end], | ||
| 1213 | .capacity = r.buffer.len, | ||
| 1214 | }; | ||
| 1215 | defer r.buffer = list.allocatedSlice(); | ||
| 1216 | try list.ensureTotalCapacity(allocator, n); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | pub const FillAllocError = Error || Allocator.Error; | ||
| 1220 | |||
| 1221 | pub fn fillAlloc(r: *Reader, allocator: Allocator, n: usize) FillAllocError!void { | ||
| 1222 | try expandTotalCapacity(r, allocator, n); | ||
| 1223 | return fill(r, n); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { | 1208 | fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { |
| 1227 | const result_info = @typeInfo(Result).int; | 1209 | const result_info = @typeInfo(Result).int; |
| 1228 | comptime assert(result_info.bits % 7 == 0); | 1210 | comptime assert(result_info.bits % 7 == 0); |
| ... | @@ -1253,9 +1235,9 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu | ... | @@ -1253,9 +1235,9 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu |
| 1253 | } | 1235 | } |
| 1254 | } | 1236 | } |
| 1255 | 1237 | ||
| 1256 | /// Ensures `capacity` more data can be buffered without rebasing. | 1238 | /// Ensures `capacity` data can be buffered without rebasing. |
| 1257 | pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { | 1239 | pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1258 | if (r.end + capacity <= r.buffer.len) { | 1240 | if (r.buffer.len - r.seek >= capacity) { |
| 1259 | @branchHint(.likely); | 1241 | @branchHint(.likely); |
| 1260 | return; | 1242 | return; |
| 1261 | } | 1243 | } |
| ... | @@ -1263,11 +1245,12 @@ pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { | ... | @@ -1263,11 +1245,12 @@ pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1263 | } | 1245 | } |
| 1264 | 1246 | ||
| 1265 | pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void { | 1247 | pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1266 | if (r.end <= r.buffer.len - capacity) return; | 1248 | assert(r.buffer.len - r.seek < capacity); |
| 1267 | const data = r.buffer[r.seek..r.end]; | 1249 | const data = r.buffer[r.seek..r.end]; |
| 1268 | @memmove(r.buffer[0..data.len], data); | 1250 | @memmove(r.buffer[0..data.len], data); |
| 1269 | r.seek = 0; | 1251 | r.seek = 0; |
| 1270 | r.end = data.len; | 1252 | r.end = data.len; |
| 1253 | assert(r.buffer.len - r.seek >= capacity); | ||
| 1271 | } | 1254 | } |
| 1272 | 1255 | ||
| 1273 | test fixed { | 1256 | test fixed { |
lib/std/crypto/tls/Client.zig+14-10| ... | @@ -183,7 +183,6 @@ const InitError = error{ | ... | @@ -183,7 +183,6 @@ const InitError = error{ |
| 183 | /// `input` is asserted to have buffer capacity at least `min_buffer_len`. | 183 | /// `input` is asserted to have buffer capacity at least `min_buffer_len`. |
| 184 | pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client { | 184 | pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client { |
| 185 | assert(input.buffer.len >= min_buffer_len); | 185 | assert(input.buffer.len >= min_buffer_len); |
| 186 | assert(output.buffer.len >= min_buffer_len); | ||
| 187 | const host = switch (options.host) { | 186 | const host = switch (options.host) { |
| 188 | .no_verification => "", | 187 | .no_verification => "", |
| 189 | .explicit => |host| host, | 188 | .explicit => |host| host, |
| ... | @@ -1124,12 +1123,6 @@ fn readIndirect(c: *Client) Reader.Error!usize { | ... | @@ -1124,12 +1123,6 @@ fn readIndirect(c: *Client) Reader.Error!usize { |
| 1124 | if (record_end > input.buffered().len) return 0; | 1123 | if (record_end > input.buffered().len) return 0; |
| 1125 | } | 1124 | } |
| 1126 | 1125 | ||
| 1127 | if (r.seek == r.end) { | ||
| 1128 | r.seek = 0; | ||
| 1129 | r.end = 0; | ||
| 1130 | } | ||
| 1131 | const cleartext_buffer = r.buffer[r.end..]; | ||
| 1132 | |||
| 1133 | const cleartext_len, const inner_ct: tls.ContentType = cleartext: switch (c.application_cipher) { | 1126 | const cleartext_len, const inner_ct: tls.ContentType = cleartext: switch (c.application_cipher) { |
| 1134 | inline else => |*p| switch (c.tls_version) { | 1127 | inline else => |*p| switch (c.tls_version) { |
| 1135 | .tls_1_3 => { | 1128 | .tls_1_3 => { |
| ... | @@ -1145,7 +1138,8 @@ fn readIndirect(c: *Client) Reader.Error!usize { | ... | @@ -1145,7 +1138,8 @@ fn readIndirect(c: *Client) Reader.Error!usize { |
| 1145 | const operand: V = pad ++ mem.toBytes(big(c.read_seq)); | 1138 | const operand: V = pad ++ mem.toBytes(big(c.read_seq)); |
| 1146 | break :nonce @as(V, pv.server_iv) ^ operand; | 1139 | break :nonce @as(V, pv.server_iv) ^ operand; |
| 1147 | }; | 1140 | }; |
| 1148 | const cleartext = cleartext_buffer[0..ciphertext.len]; | 1141 | rebase(r, ciphertext.len); |
| 1142 | const cleartext = r.buffer[r.end..][0..ciphertext.len]; | ||
| 1149 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_key) catch | 1143 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_key) catch |
| 1150 | return failRead(c, error.TlsBadRecordMac); | 1144 | return failRead(c, error.TlsBadRecordMac); |
| 1151 | // TODO use scalar, non-slice version | 1145 | // TODO use scalar, non-slice version |
| ... | @@ -1171,7 +1165,8 @@ fn readIndirect(c: *Client) Reader.Error!usize { | ... | @@ -1171,7 +1165,8 @@ fn readIndirect(c: *Client) Reader.Error!usize { |
| 1171 | }; | 1165 | }; |
| 1172 | const ciphertext = input.take(message_len) catch unreachable; // already peeked | 1166 | const ciphertext = input.take(message_len) catch unreachable; // already peeked |
| 1173 | const auth_tag = (input.takeArray(P.mac_length) catch unreachable).*; // already peeked | 1167 | const auth_tag = (input.takeArray(P.mac_length) catch unreachable).*; // already peeked |
| 1174 | const cleartext = cleartext_buffer[0..ciphertext.len]; | 1168 | rebase(r, ciphertext.len); |
| 1169 | const cleartext = r.buffer[r.end..][0..ciphertext.len]; | ||
| 1175 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_write_key) catch | 1170 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_write_key) catch |
| 1176 | return failRead(c, error.TlsBadRecordMac); | 1171 | return failRead(c, error.TlsBadRecordMac); |
| 1177 | break :cleartext .{ cleartext.len, ct }; | 1172 | break :cleartext .{ cleartext.len, ct }; |
| ... | @@ -1179,7 +1174,7 @@ fn readIndirect(c: *Client) Reader.Error!usize { | ... | @@ -1179,7 +1174,7 @@ fn readIndirect(c: *Client) Reader.Error!usize { |
| 1179 | else => unreachable, | 1174 | else => unreachable, |
| 1180 | }, | 1175 | }, |
| 1181 | }; | 1176 | }; |
| 1182 | const cleartext = cleartext_buffer[0..cleartext_len]; | 1177 | const cleartext = r.buffer[r.end..][0..cleartext_len]; |
| 1183 | c.read_seq = std.math.add(u64, c.read_seq, 1) catch return failRead(c, error.TlsSequenceOverflow); | 1178 | c.read_seq = std.math.add(u64, c.read_seq, 1) catch return failRead(c, error.TlsSequenceOverflow); |
| 1184 | switch (inner_ct) { | 1179 | switch (inner_ct) { |
| 1185 | .alert => { | 1180 | .alert => { |
| ... | @@ -1275,6 +1270,15 @@ fn readIndirect(c: *Client) Reader.Error!usize { | ... | @@ -1275,6 +1270,15 @@ fn readIndirect(c: *Client) Reader.Error!usize { |
| 1275 | } | 1270 | } |
| 1276 | } | 1271 | } |
| 1277 | 1272 | ||
| 1273 | fn rebase(r: *Reader, capacity: usize) void { | ||
| 1274 | if (r.buffer.len - r.end >= capacity) return; | ||
| 1275 | const data = r.buffer[r.seek..r.end]; | ||
| 1276 | @memmove(r.buffer[0..data.len], data); | ||
| 1277 | r.seek = 0; | ||
| 1278 | r.end = data.len; | ||
| 1279 | assert(r.buffer.len - r.end >= capacity); | ||
| 1280 | } | ||
| 1281 | |||
| 1278 | fn failRead(c: *Client, err: ReadError) error{ReadFailed} { | 1282 | fn failRead(c: *Client, err: ReadError) error{ReadFailed} { |
| 1279 | c.read_err = err; | 1283 | c.read_err = err; |
| 1280 | return error.ReadFailed; | 1284 | return error.ReadFailed; |
lib/std/http.zig+3-1| ... | @@ -329,6 +329,7 @@ pub const Reader = struct { | ... | @@ -329,6 +329,7 @@ pub const Reader = struct { |
| 329 | /// read from `in`. | 329 | /// read from `in`. |
| 330 | trailers: []const u8 = &.{}, | 330 | trailers: []const u8 = &.{}, |
| 331 | body_err: ?BodyError = null, | 331 | body_err: ?BodyError = null, |
| 332 | max_head_len: usize, | ||
| 332 | 333 | ||
| 333 | pub const RemainingChunkLen = enum(u64) { | 334 | pub const RemainingChunkLen = enum(u64) { |
| 334 | head = 0, | 335 | head = 0, |
| ... | @@ -387,10 +388,11 @@ pub const Reader = struct { | ... | @@ -387,10 +388,11 @@ pub const Reader = struct { |
| 387 | pub fn receiveHead(reader: *Reader) HeadError![]const u8 { | 388 | pub fn receiveHead(reader: *Reader) HeadError![]const u8 { |
| 388 | reader.trailers = &.{}; | 389 | reader.trailers = &.{}; |
| 389 | const in = reader.in; | 390 | const in = reader.in; |
| 391 | const max_head_len = reader.max_head_len; | ||
| 390 | var hp: HeadParser = .{}; | 392 | var hp: HeadParser = .{}; |
| 391 | var head_len: usize = 0; | 393 | var head_len: usize = 0; |
| 392 | while (true) { | 394 | while (true) { |
| 393 | if (in.buffer.len - head_len == 0) return error.HttpHeadersOversize; | 395 | if (head_len >= max_head_len) return error.HttpHeadersOversize; |
| 394 | const remaining = in.buffered()[head_len..]; | 396 | const remaining = in.buffered()[head_len..]; |
| 395 | if (remaining.len == 0) { | 397 | if (remaining.len == 0) { |
| 396 | in.fillMore() catch |err| switch (err) { | 398 | in.fillMore() catch |err| switch (err) { |
lib/std/http/Client.zig+17-10| ... | @@ -42,7 +42,7 @@ connection_pool: ConnectionPool = .{}, | ... | @@ -42,7 +42,7 @@ connection_pool: ConnectionPool = .{}, |
| 42 | /// | 42 | /// |
| 43 | /// If the entire HTTP header cannot fit in this amount of bytes, | 43 | /// If the entire HTTP header cannot fit in this amount of bytes, |
| 44 | /// `error.HttpHeadersOversize` will be returned from `Request.wait`. | 44 | /// `error.HttpHeadersOversize` will be returned from `Request.wait`. |
| 45 | read_buffer_size: usize = 4096 + if (disable_tls) 0 else std.crypto.tls.Client.min_buffer_len, | 45 | read_buffer_size: usize = 8192, |
| 46 | /// Each `Connection` allocates this amount for the writer buffer. | 46 | /// Each `Connection` allocates this amount for the writer buffer. |
| 47 | write_buffer_size: usize = 1024, | 47 | write_buffer_size: usize = 1024, |
| 48 | 48 | ||
| ... | @@ -302,18 +302,22 @@ pub const Connection = struct { | ... | @@ -302,18 +302,22 @@ pub const Connection = struct { |
| 302 | const base = try gpa.alignedAlloc(u8, .of(Tls), alloc_len); | 302 | const base = try gpa.alignedAlloc(u8, .of(Tls), alloc_len); |
| 303 | errdefer gpa.free(base); | 303 | errdefer gpa.free(base); |
| 304 | const host_buffer = base[@sizeOf(Tls)..][0..remote_host.len]; | 304 | const host_buffer = base[@sizeOf(Tls)..][0..remote_host.len]; |
| 305 | const tls_read_buffer = host_buffer.ptr[host_buffer.len..][0..client.tls_buffer_size]; | 305 | // The TLS client wants enough buffer for the max encrypted frame |
| 306 | // size, and the HTTP body reader wants enough buffer for the | ||
| 307 | // entire HTTP header. This means we need a combined upper bound. | ||
| 308 | const tls_read_buffer_len = client.tls_buffer_size + client.read_buffer_size; | ||
| 309 | const tls_read_buffer = host_buffer.ptr[host_buffer.len..][0..tls_read_buffer_len]; | ||
| 306 | const tls_write_buffer = tls_read_buffer.ptr[tls_read_buffer.len..][0..client.tls_buffer_size]; | 310 | const tls_write_buffer = tls_read_buffer.ptr[tls_read_buffer.len..][0..client.tls_buffer_size]; |
| 307 | const write_buffer = tls_write_buffer.ptr[tls_write_buffer.len..][0..client.write_buffer_size]; | 311 | const socket_write_buffer = tls_write_buffer.ptr[tls_write_buffer.len..][0..client.write_buffer_size]; |
| 308 | const read_buffer = write_buffer.ptr[write_buffer.len..][0..client.read_buffer_size]; | 312 | const socket_read_buffer = socket_write_buffer.ptr[socket_write_buffer.len..][0..client.tls_buffer_size]; |
| 309 | assert(base.ptr + alloc_len == read_buffer.ptr + read_buffer.len); | 313 | assert(base.ptr + alloc_len == socket_read_buffer.ptr + socket_read_buffer.len); |
| 310 | @memcpy(host_buffer, remote_host); | 314 | @memcpy(host_buffer, remote_host); |
| 311 | const tls: *Tls = @ptrCast(base); | 315 | const tls: *Tls = @ptrCast(base); |
| 312 | tls.* = .{ | 316 | tls.* = .{ |
| 313 | .connection = .{ | 317 | .connection = .{ |
| 314 | .client = client, | 318 | .client = client, |
| 315 | .stream_writer = stream.writer(tls_write_buffer), | 319 | .stream_writer = stream.writer(tls_write_buffer), |
| 316 | .stream_reader = stream.reader(tls_read_buffer), | 320 | .stream_reader = stream.reader(socket_read_buffer), |
| 317 | .pool_node = .{}, | 321 | .pool_node = .{}, |
| 318 | .port = port, | 322 | .port = port, |
| 319 | .host_len = @intCast(remote_host.len), | 323 | .host_len = @intCast(remote_host.len), |
| ... | @@ -329,8 +333,8 @@ pub const Connection = struct { | ... | @@ -329,8 +333,8 @@ pub const Connection = struct { |
| 329 | .host = .{ .explicit = remote_host }, | 333 | .host = .{ .explicit = remote_host }, |
| 330 | .ca = .{ .bundle = client.ca_bundle }, | 334 | .ca = .{ .bundle = client.ca_bundle }, |
| 331 | .ssl_key_log = client.ssl_key_log, | 335 | .ssl_key_log = client.ssl_key_log, |
| 332 | .read_buffer = read_buffer, | 336 | .read_buffer = tls_read_buffer, |
| 333 | .write_buffer = write_buffer, | 337 | .write_buffer = socket_write_buffer, |
| 334 | // This is appropriate for HTTPS because the HTTP headers contain | 338 | // This is appropriate for HTTPS because the HTTP headers contain |
| 335 | // the content length which is used to detect truncation attacks. | 339 | // the content length which is used to detect truncation attacks. |
| 336 | .allow_truncation_attacks = true, | 340 | .allow_truncation_attacks = true, |
| ... | @@ -348,8 +352,9 @@ pub const Connection = struct { | ... | @@ -348,8 +352,9 @@ pub const Connection = struct { |
| 348 | } | 352 | } |
| 349 | 353 | ||
| 350 | fn allocLen(client: *Client, host_len: usize) usize { | 354 | fn allocLen(client: *Client, host_len: usize) usize { |
| 351 | return @sizeOf(Tls) + host_len + client.tls_buffer_size + client.tls_buffer_size + | 355 | const tls_read_buffer_len = client.tls_buffer_size + client.read_buffer_size; |
| 352 | client.write_buffer_size + client.read_buffer_size; | 356 | return @sizeOf(Tls) + host_len + tls_read_buffer_len + client.tls_buffer_size + |
| 357 | client.write_buffer_size + client.tls_buffer_size; | ||
| 353 | } | 358 | } |
| 354 | 359 | ||
| 355 | fn host(tls: *Tls) []u8 { | 360 | fn host(tls: *Tls) []u8 { |
| ... | @@ -1214,6 +1219,7 @@ pub const Request = struct { | ... | @@ -1214,6 +1219,7 @@ pub const Request = struct { |
| 1214 | .state = .ready, | 1219 | .state = .ready, |
| 1215 | // Populated when `http.Reader.bodyReader` is called. | 1220 | // Populated when `http.Reader.bodyReader` is called. |
| 1216 | .interface = undefined, | 1221 | .interface = undefined, |
| 1222 | .max_head_len = r.client.read_buffer_size, | ||
| 1217 | }; | 1223 | }; |
| 1218 | r.redirect_behavior.subtractOne(); | 1224 | r.redirect_behavior.subtractOne(); |
| 1219 | } | 1225 | } |
| ... | @@ -1679,6 +1685,7 @@ pub fn request( | ... | @@ -1679,6 +1685,7 @@ pub fn request( |
| 1679 | .state = .ready, | 1685 | .state = .ready, |
| 1680 | // Populated when `http.Reader.bodyReader` is called. | 1686 | // Populated when `http.Reader.bodyReader` is called. |
| 1681 | .interface = undefined, | 1687 | .interface = undefined, |
| 1688 | .max_head_len = client.read_buffer_size, | ||
| 1682 | }, | 1689 | }, |
| 1683 | .keep_alive = options.keep_alive, | 1690 | .keep_alive = options.keep_alive, |
| 1684 | .method = method, | 1691 | .method = method, |
lib/std/http/Server.zig+2| ... | @@ -29,6 +29,7 @@ pub fn init(in: *Reader, out: *Writer) Server { | ... | @@ -29,6 +29,7 @@ pub fn init(in: *Reader, out: *Writer) Server { |
| 29 | .state = .ready, | 29 | .state = .ready, |
| 30 | // Populated when `http.Reader.bodyReader` is called. | 30 | // Populated when `http.Reader.bodyReader` is called. |
| 31 | .interface = undefined, | 31 | .interface = undefined, |
| 32 | .max_head_len = in.buffer.len, | ||
| 32 | }, | 33 | }, |
| 33 | .out = out, | 34 | .out = out, |
| 34 | }; | 35 | }; |
| ... | @@ -251,6 +252,7 @@ pub const Request = struct { | ... | @@ -251,6 +252,7 @@ pub const Request = struct { |
| 251 | .in = undefined, | 252 | .in = undefined, |
| 252 | .state = .received_head, | 253 | .state = .received_head, |
| 253 | .interface = undefined, | 254 | .interface = undefined, |
| 255 | .max_head_len = 4096, | ||
| 254 | }, | 256 | }, |
| 255 | .out = undefined, | 257 | .out = undefined, |
| 256 | }; | 258 | }; |