| author | |
| committer | |
| log | 399bace2f20e64e4c10c014dc3b8e202a891c6e4 |
| tree | a24ab1bbc42ca4d201bb43acd91f8e9815011fc4 |
| parent | ef14c732455dc089b56aab7392584c4fa8bc2c2d |
| parent | a0f9a5e78d1cf419e88c493f6f57e486df236e35 |
| signature |
std: more reliable HTTP and TLS networking7 files changed, 52 insertions(+), 48 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 |
| ... | @@ -1035,7 +1035,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { | ... | @@ -1035,7 +1035,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1035 | /// | 1035 | /// |
| 1036 | /// Asserts buffer capacity is at least 1. | 1036 | /// Asserts buffer capacity is at least 1. |
| 1037 | pub fn fillMore(r: *Reader) Error!void { | 1037 | pub fn fillMore(r: *Reader) Error!void { |
| 1038 | try rebase(r, 1); | 1038 | try rebase(r, r.end - r.seek + 1); |
| 1039 | var bufs: [1][]u8 = .{""}; | 1039 | var bufs: [1][]u8 = .{""}; |
| 1040 | _ = try r.vtable.readVec(r, &bufs); | 1040 | _ = try r.vtable.readVec(r, &bufs); |
| 1041 | } | 1041 | } |
| ... | @@ -1203,24 +1203,6 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { | ... | @@ -1203,24 +1203,6 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { |
| 1203 | } }))) orelse error.Overflow; | 1203 | } }))) orelse error.Overflow; |
| 1204 | } | 1204 | } |
| 1205 | 1205 | ||
| 1206 | pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void { | ||
| 1207 | if (n <= r.buffer.len) return; | ||
| 1208 | if (r.seek > 0) rebase(r, r.buffer.len); | ||
| 1209 | var list: ArrayList(u8) = .{ | ||
| 1210 | .items = r.buffer[0..r.end], | ||
| 1211 | .capacity = r.buffer.len, | ||
| 1212 | }; | ||
| 1213 | defer r.buffer = list.allocatedSlice(); | ||
| 1214 | try list.ensureTotalCapacity(allocator, n); | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | pub const FillAllocError = Error || Allocator.Error; | ||
| 1218 | |||
| 1219 | pub fn fillAlloc(r: *Reader, allocator: Allocator, n: usize) FillAllocError!void { | ||
| 1220 | try expandTotalCapacity(r, allocator, n); | ||
| 1221 | return fill(r, n); | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { | 1206 | fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { |
| 1225 | const result_info = @typeInfo(Result).int; | 1207 | const result_info = @typeInfo(Result).int; |
| 1226 | comptime assert(result_info.bits % 7 == 0); | 1208 | comptime assert(result_info.bits % 7 == 0); |
| ... | @@ -1251,9 +1233,9 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu | ... | @@ -1251,9 +1233,9 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu |
| 1251 | } | 1233 | } |
| 1252 | } | 1234 | } |
| 1253 | 1235 | ||
| 1254 | /// Ensures `capacity` more data can be buffered without rebasing. | 1236 | /// Ensures `capacity` data can be buffered without rebasing. |
| 1255 | pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { | 1237 | pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1256 | if (r.end + capacity <= r.buffer.len) { | 1238 | if (r.buffer.len - r.seek >= capacity) { |
| 1257 | @branchHint(.likely); | 1239 | @branchHint(.likely); |
| 1258 | return; | 1240 | return; |
| 1259 | } | 1241 | } |
| ... | @@ -1261,11 +1243,12 @@ pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { | ... | @@ -1261,11 +1243,12 @@ pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1261 | } | 1243 | } |
| 1262 | 1244 | ||
| 1263 | pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void { | 1245 | pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void { |
| 1264 | if (r.end <= r.buffer.len - capacity) return; | 1246 | assert(r.buffer.len - r.seek < capacity); |
| 1265 | const data = r.buffer[r.seek..r.end]; | 1247 | const data = r.buffer[r.seek..r.end]; |
| 1266 | @memmove(r.buffer[0..data.len], data); | 1248 | @memmove(r.buffer[0..data.len], data); |
| 1267 | r.seek = 0; | 1249 | r.seek = 0; |
| 1268 | r.end = data.len; | 1250 | r.end = data.len; |
| 1251 | assert(r.buffer.len - r.seek >= capacity); | ||
| 1269 | } | 1252 | } |
| 1270 | 1253 | ||
| 1271 | test fixed { | 1254 | 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 | }; |
src/Package/Fetch.zig+3-2| ... | @@ -1212,10 +1212,11 @@ fn unpackResource( | ... | @@ -1212,10 +1212,11 @@ fn unpackResource( |
| 1212 | return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | 1212 | return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); |
| 1213 | }, | 1213 | }, |
| 1214 | .@"tar.zst" => { | 1214 | .@"tar.zst" => { |
| 1215 | const window_size = std.compress.zstd.default_window_len; | 1215 | const window_len = std.compress.zstd.default_window_len; |
| 1216 | const window_buffer = try f.arena.allocator().create([window_size]u8); | 1216 | const window_buffer = try f.arena.allocator().alloc(u8, window_len + std.compress.zstd.block_size_max); |
| 1217 | var decompress: std.compress.zstd.Decompress = .init(resource.reader(), window_buffer, .{ | 1217 | var decompress: std.compress.zstd.Decompress = .init(resource.reader(), window_buffer, .{ |
| 1218 | .verify_checksum = false, | 1218 | .verify_checksum = false, |
| 1219 | .window_len = window_len, | ||
| 1219 | }); | 1220 | }); |
| 1220 | return try unpackTarball(f, tmp_directory.handle, &decompress.reader); | 1221 | return try unpackTarball(f, tmp_directory.handle, &decompress.reader); |
| 1221 | }, | 1222 | }, |