| author | |
| committer | |
| log | 25ac70f973c84bb26ebb1b69eda30d2c6207c9b0 |
| tree | 1a91822da4b33bf25e14bddc65c3ef51b984e69b |
| parent | c7040171fb06bc4300547a9f4550346b847fc406 |
delete some bad readers/writers
add limited reader
update TLS
about to do something drastic to compress18 files changed, 390 insertions(+), 439 deletions(-)
lib/std/compress.zig+4-60| ... | ... | @@ -1,75 +1,19 @@ |
| 1 | 1 | //! Compression algorithms. |
| 2 | 2 | |
| 3 | const std = @import("std.zig"); | |
| 4 | ||
| 5 | 3 | pub const flate = @import("compress/flate.zig"); |
| 6 | 4 | pub const gzip = @import("compress/gzip.zig"); |
| 7 | pub const zlib = @import("compress/zlib.zig"); | |
| 8 | 5 | pub const lzma = @import("compress/lzma.zig"); |
| 9 | 6 | pub const lzma2 = @import("compress/lzma2.zig"); |
| 10 | 7 | pub const xz = @import("compress/xz.zig"); |
| 8 | pub const zlib = @import("compress/zlib.zig"); | |
| 11 | 9 | pub const zstd = @import("compress/zstandard.zig"); |
| 12 | 10 | |
| 13 | pub fn HashedReader(ReaderType: type, HasherType: type) type { | |
| 14 | return struct { | |
| 15 | child_reader: ReaderType, | |
| 16 | hasher: HasherType, | |
| 17 | ||
| 18 | pub const Error = ReaderType.Error; | |
| 19 | pub const Reader = std.io.Reader(*@This(), Error, read); | |
| 20 | ||
| 21 | pub fn read(self: *@This(), buf: []u8) Error!usize { | |
| 22 | const amt = try self.child_reader.read(buf); | |
| 23 | self.hasher.update(buf[0..amt]); | |
| 24 | return amt; | |
| 25 | } | |
| 26 | ||
| 27 | pub fn reader(self: *@This()) Reader { | |
| 28 | return .{ .context = self }; | |
| 29 | } | |
| 30 | }; | |
| 31 | } | |
| 32 | ||
| 33 | pub fn hashedReader( | |
| 34 | reader: anytype, | |
| 35 | hasher: anytype, | |
| 36 | ) HashedReader(@TypeOf(reader), @TypeOf(hasher)) { | |
| 37 | return .{ .child_reader = reader, .hasher = hasher }; | |
| 38 | } | |
| 39 | ||
| 40 | pub fn HashedWriter(WriterType: type, HasherType: type) type { | |
| 41 | return struct { | |
| 42 | child_writer: WriterType, | |
| 43 | hasher: HasherType, | |
| 44 | ||
| 45 | pub const Error = WriterType.Error; | |
| 46 | pub const Writer = std.io.Writer(*@This(), Error, write); | |
| 47 | ||
| 48 | pub fn write(self: *@This(), buf: []const u8) Error!usize { | |
| 49 | const amt = try self.child_writer.write(buf); | |
| 50 | self.hasher.update(buf[0..amt]); | |
| 51 | return amt; | |
| 52 | } | |
| 53 | ||
| 54 | pub fn writer(self: *@This()) Writer { | |
| 55 | return .{ .context = self }; | |
| 56 | } | |
| 57 | }; | |
| 58 | } | |
| 59 | ||
| 60 | pub fn hashedWriter( | |
| 61 | writer: anytype, | |
| 62 | hasher: anytype, | |
| 63 | ) HashedWriter(@TypeOf(writer), @TypeOf(hasher)) { | |
| 64 | return .{ .child_writer = writer, .hasher = hasher }; | |
| 65 | } | |
| 66 | ||
| 67 | 11 | test { |
| 12 | _ = flate; | |
| 13 | _ = gzip; | |
| 68 | 14 | _ = lzma; |
| 69 | 15 | _ = lzma2; |
| 70 | 16 | _ = xz; |
| 71 | _ = zstd; | |
| 72 | _ = flate; | |
| 73 | _ = gzip; | |
| 74 | 17 | _ = zlib; |
| 18 | _ = zstd; | |
| 75 | 19 | } |
lib/std/compress/flate/inflate.zig+1-1| ... | ... | @@ -821,7 +821,7 @@ pub fn BitReader(comptime T: type) type { |
| 821 | 821 | /// Skip zero terminated string. |
| 822 | 822 | pub fn skipStringZ(self: *Self) !void { |
| 823 | 823 | while (true) { |
| 824 | if (try self.readF(u8, 0) == 0) break; | |
| 824 | if (try self.readF(u8, .{}) == 0) break; | |
| 825 | 825 | } |
| 826 | 826 | } |
| 827 | 827 |
lib/std/compress/zstandard.zig+110-76| ... | ... | @@ -1,7 +1,12 @@ |
| 1 | const std = @import("std"); | |
| 1 | const std = @import("../std.zig"); | |
| 2 | 2 | const RingBuffer = std.RingBuffer; |
| 3 | 3 | |
| 4 | 4 | const types = @import("zstandard/types.zig"); |
| 5 | ||
| 6 | /// Recommended amount by the standard. Lower than this may result in inability | |
| 7 | /// to decompress common streams. | |
| 8 | pub const default_window_len = 8 * 1024 * 1024; | |
| 9 | ||
| 5 | 10 | pub const frame = types.frame; |
| 6 | 11 | pub const compressed_block = types.compressed_block; |
| 7 | 12 | |
| ... | ... | @@ -10,7 +15,8 @@ pub const decompress = @import("zstandard/decompress.zig"); |
| 10 | 15 | pub const Decompressor = struct { |
| 11 | 16 | const table_size_max = types.compressed_block.table_size_max; |
| 12 | 17 | |
| 13 | source: *std.io.BufferedReader, | |
| 18 | input: *std.io.BufferedReader, | |
| 19 | bytes_read: usize, | |
| 14 | 20 | state: enum { NewFrame, InFrame, LastBlock }, |
| 15 | 21 | decode_state: decompress.block.DecodeState, |
| 16 | 22 | frame_context: decompress.FrameContext, |
| ... | ... | @@ -23,14 +29,12 @@ pub const Decompressor = struct { |
| 23 | 29 | verify_checksum: bool, |
| 24 | 30 | checksum: ?u32, |
| 25 | 31 | current_frame_decompressed_size: usize, |
| 32 | err: ?Error = null, | |
| 26 | 33 | |
| 27 | 34 | pub const Options = struct { |
| 28 | 35 | verify_checksum: bool = true, |
| 36 | /// See `default_window_len`. | |
| 29 | 37 | window_buffer: []u8, |
| 30 | ||
| 31 | /// Recommended amount by the standard. Lower than this may result | |
| 32 | /// in inability to decompress common streams. | |
| 33 | pub const default_window_buffer_len = 8 * 1024 * 1024; | |
| 34 | 38 | }; |
| 35 | 39 | |
| 36 | 40 | const WindowBuffer = struct { |
| ... | ... | @@ -45,11 +49,13 @@ pub const Decompressor = struct { |
| 45 | 49 | MalformedBlock, |
| 46 | 50 | MalformedFrame, |
| 47 | 51 | OutOfMemory, |
| 52 | EndOfStream, | |
| 48 | 53 | }; |
| 49 | 54 | |
| 50 | pub fn init(source: *std.io.BufferedReader, options: Options) Decompressor { | |
| 55 | pub fn init(input: *std.io.BufferedReader, options: Options) Decompressor { | |
| 51 | 56 | return .{ |
| 52 | .source = source, | |
| 57 | .input = input, | |
| 58 | .bytes_read = 0, | |
| 53 | 59 | .state = .NewFrame, |
| 54 | 60 | .decode_state = undefined, |
| 55 | 61 | .frame_context = undefined, |
| ... | ... | @@ -65,100 +71,128 @@ pub const Decompressor = struct { |
| 65 | 71 | }; |
| 66 | 72 | } |
| 67 | 73 | |
| 68 | fn frameInit(self: *Decompressor) !void { | |
| 69 | const source_reader = self.source; | |
| 70 | switch (try decompress.decodeFrameHeader(source_reader)) { | |
| 74 | fn frameInit(d: *Decompressor) !void { | |
| 75 | const in = d.input; | |
| 76 | switch (try decompress.decodeFrameHeader(in, &d.bytes_read)) { | |
| 71 | 77 | .skippable => |header| { |
| 72 | try source_reader.skipBytes(header.frame_size, .{}); | |
| 73 | self.state = .NewFrame; | |
| 78 | try in.discardAll(header.frame_size); | |
| 79 | d.bytes_read += header.frame_size; | |
| 80 | d.state = .NewFrame; | |
| 74 | 81 | }, |
| 75 | 82 | .zstandard => |header| { |
| 76 | 83 | const frame_context = try decompress.FrameContext.init( |
| 77 | 84 | header, |
| 78 | self.buffer.data.len, | |
| 79 | self.verify_checksum, | |
| 85 | d.buffer.data.len, | |
| 86 | d.verify_checksum, | |
| 80 | 87 | ); |
| 81 | 88 | |
| 82 | 89 | const decode_state = decompress.block.DecodeState.init( |
| 83 | &self.literal_fse_buffer, | |
| 84 | &self.match_fse_buffer, | |
| 85 | &self.offset_fse_buffer, | |
| 90 | &d.literal_fse_buffer, | |
| 91 | &d.match_fse_buffer, | |
| 92 | &d.offset_fse_buffer, | |
| 86 | 93 | ); |
| 87 | 94 | |
| 88 | self.decode_state = decode_state; | |
| 89 | self.frame_context = frame_context; | |
| 95 | d.decode_state = decode_state; | |
| 96 | d.frame_context = frame_context; | |
| 90 | 97 | |
| 91 | self.checksum = null; | |
| 92 | self.current_frame_decompressed_size = 0; | |
| 98 | d.checksum = null; | |
| 99 | d.current_frame_decompressed_size = 0; | |
| 93 | 100 | |
| 94 | self.state = .InFrame; | |
| 101 | d.state = .InFrame; | |
| 95 | 102 | }, |
| 96 | 103 | } |
| 97 | 104 | } |
| 98 | 105 | |
| 99 | 106 | pub fn reader(self: *Decompressor) std.io.Reader { |
| 100 | return .{ .context = self }; | |
| 107 | return .{ | |
| 108 | .context = self, | |
| 109 | .vtable = &.{ | |
| 110 | .read = read, | |
| 111 | .readVec = readVec, | |
| 112 | .discard = discard, | |
| 113 | }, | |
| 114 | }; | |
| 101 | 115 | } |
| 102 | 116 | |
| 103 | pub fn read(self: *Decompressor, buffer: []u8) Error!usize { | |
| 104 | if (buffer.len == 0) return 0; | |
| 105 | ||
| 106 | var size: usize = 0; | |
| 107 | while (size == 0) { | |
| 108 | while (self.state == .NewFrame) { | |
| 109 | const initial_count = self.source.bytes_read; | |
| 110 | self.frameInit() catch |err| switch (err) { | |
| 111 | error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported, | |
| 112 | error.EndOfStream => return if (self.source.bytes_read == initial_count) | |
| 113 | 0 | |
| 114 | else | |
| 115 | error.MalformedFrame, | |
| 116 | else => return error.MalformedFrame, | |
| 117 | }; | |
| 118 | } | |
| 119 | size = try self.readInner(buffer); | |
| 117 | fn read(context: ?*anyopaque, bw: *std.io.BufferedWriter, limit: std.io.Reader.Limit) std.io.Reader.RwError!usize { | |
| 118 | const buf = limit.slice(try bw.writableSliceGreedy(1)); | |
| 119 | const n = try readVec(context, &.{buf}); | |
| 120 | bw.advance(n); | |
| 121 | return n; | |
| 122 | } | |
| 123 | ||
| 124 | fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize { | |
| 125 | var trash: [128]u8 = undefined; | |
| 126 | const buf = limit.slice(&trash); | |
| 127 | return readVec(context, &.{buf}); | |
| 128 | } | |
| 129 | ||
| 130 | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | |
| 131 | const d: *Decompressor = @ptrCast(@alignCast(context)); | |
| 132 | if (data.len == 0) return 0; | |
| 133 | const buffer = data[0]; | |
| 134 | while (d.state == .NewFrame) { | |
| 135 | const initial_count = d.bytes_read; | |
| 136 | d.frameInit() catch |err| switch (err) { | |
| 137 | error.DictionaryIdFlagUnsupported => { | |
| 138 | d.err = error.DictionaryIdFlagUnsupported; | |
| 139 | return error.ReadFailed; | |
| 140 | }, | |
| 141 | error.EndOfStream => { | |
| 142 | if (d.bytes_read == initial_count) return error.EndOfStream; | |
| 143 | d.err = error.MalformedFrame; | |
| 144 | return error.ReadFailed; | |
| 145 | }, | |
| 146 | else => { | |
| 147 | d.err = error.MalformedFrame; | |
| 148 | return error.ReadFailed; | |
| 149 | }, | |
| 150 | }; | |
| 120 | 151 | } |
| 121 | return size; | |
| 152 | return d.readInner(buffer) catch |err| { | |
| 153 | d.err = err; | |
| 154 | return error.ReadFailed; | |
| 155 | }; | |
| 122 | 156 | } |
| 123 | 157 | |
| 124 | fn readInner(self: *Decompressor, buffer: []u8) Error!usize { | |
| 125 | std.debug.assert(self.state != .NewFrame); | |
| 158 | fn readInner(d: *Decompressor, buffer: []u8) Error!usize { | |
| 159 | std.debug.assert(d.state != .NewFrame); | |
| 126 | 160 | |
| 127 | 161 | var ring_buffer = RingBuffer{ |
| 128 | .data = self.buffer.data, | |
| 129 | .read_index = self.buffer.read_index, | |
| 130 | .write_index = self.buffer.write_index, | |
| 162 | .data = d.buffer.data, | |
| 163 | .read_index = d.buffer.read_index, | |
| 164 | .write_index = d.buffer.write_index, | |
| 131 | 165 | }; |
| 132 | 166 | defer { |
| 133 | self.buffer.read_index = ring_buffer.read_index; | |
| 134 | self.buffer.write_index = ring_buffer.write_index; | |
| 167 | d.buffer.read_index = ring_buffer.read_index; | |
| 168 | d.buffer.write_index = ring_buffer.write_index; | |
| 135 | 169 | } |
| 136 | 170 | |
| 137 | const source_reader = self.source; | |
| 138 | while (ring_buffer.isEmpty() and self.state != .LastBlock) { | |
| 139 | const header_bytes = source_reader.readBytesNoEof(3) catch | |
| 140 | return error.MalformedFrame; | |
| 141 | const block_header = decompress.block.decodeBlockHeader(&header_bytes); | |
| 171 | const in = d.input; | |
| 172 | while (ring_buffer.isEmpty() and d.state != .LastBlock) { | |
| 173 | const header_bytes = try in.takeArray(3); | |
| 174 | d.bytes_read += header_bytes.len; | |
| 175 | const block_header = decompress.block.decodeBlockHeader(header_bytes); | |
| 142 | 176 | |
| 143 | 177 | decompress.block.decodeBlockReader( |
| 144 | 178 | &ring_buffer, |
| 145 | source_reader, | |
| 179 | in, | |
| 180 | &d.bytes_read, | |
| 146 | 181 | block_header, |
| 147 | &self.decode_state, | |
| 148 | self.frame_context.block_size_max, | |
| 149 | &self.literals_buffer, | |
| 150 | &self.sequence_buffer, | |
| 151 | ) catch | |
| 152 | return error.MalformedBlock; | |
| 153 | ||
| 154 | if (self.frame_context.content_size) |size| { | |
| 155 | if (self.current_frame_decompressed_size > size) return error.MalformedFrame; | |
| 182 | &d.decode_state, | |
| 183 | d.frame_context.block_size_max, | |
| 184 | &d.literals_buffer, | |
| 185 | &d.sequence_buffer, | |
| 186 | ) catch return error.MalformedBlock; | |
| 187 | ||
| 188 | if (d.frame_context.content_size) |size| { | |
| 189 | if (d.current_frame_decompressed_size > size) return error.MalformedFrame; | |
| 156 | 190 | } |
| 157 | 191 | |
| 158 | 192 | const size = ring_buffer.len(); |
| 159 | self.current_frame_decompressed_size += size; | |
| 193 | d.current_frame_decompressed_size += size; | |
| 160 | 194 | |
| 161 | if (self.frame_context.hasher_opt) |*hasher| { | |
| 195 | if (d.frame_context.hasher_opt) |*hasher| { | |
| 162 | 196 | if (size > 0) { |
| 163 | 197 | const written_slice = ring_buffer.sliceLast(size); |
| 164 | 198 | hasher.update(written_slice.first); |
| ... | ... | @@ -166,19 +200,19 @@ pub const Decompressor = struct { |
| 166 | 200 | } |
| 167 | 201 | } |
| 168 | 202 | if (block_header.last_block) { |
| 169 | self.state = .LastBlock; | |
| 170 | if (self.frame_context.has_checksum) { | |
| 171 | const checksum = source_reader.readInt(u32, .little) catch | |
| 172 | return error.MalformedFrame; | |
| 173 | if (self.verify_checksum) { | |
| 174 | if (self.frame_context.hasher_opt) |*hasher| { | |
| 203 | d.state = .LastBlock; | |
| 204 | if (d.frame_context.has_checksum) { | |
| 205 | const checksum = in.readInt(u32, .little) catch return error.MalformedFrame; | |
| 206 | d.bytes_read += 4; | |
| 207 | if (d.verify_checksum) { | |
| 208 | if (d.frame_context.hasher_opt) |*hasher| { | |
| 175 | 209 | if (checksum != decompress.computeChecksum(hasher)) |
| 176 | 210 | return error.ChecksumFailure; |
| 177 | 211 | } |
| 178 | 212 | } |
| 179 | 213 | } |
| 180 | if (self.frame_context.content_size) |content_size| { | |
| 181 | if (content_size != self.current_frame_decompressed_size) { | |
| 214 | if (d.frame_context.content_size) |content_size| { | |
| 215 | if (content_size != d.current_frame_decompressed_size) { | |
| 182 | 216 | return error.MalformedFrame; |
| 183 | 217 | } |
| 184 | 218 | } |
| ... | ... | @@ -189,8 +223,8 @@ pub const Decompressor = struct { |
| 189 | 223 | if (size > 0) { |
| 190 | 224 | ring_buffer.readFirstAssumeLength(buffer, size); |
| 191 | 225 | } |
| 192 | if (self.state == .LastBlock and ring_buffer.len() == 0) { | |
| 193 | self.state = .NewFrame; | |
| 226 | if (d.state == .LastBlock and ring_buffer.len() == 0) { | |
| 227 | d.state = .NewFrame; | |
| 194 | 228 | } |
| 195 | 229 | return size; |
| 196 | 230 | } |
lib/std/compress/zstandard/decode/block.zig+10-6| ... | ... | @@ -807,7 +807,8 @@ pub fn decodeBlockRingBuffer( |
| 807 | 807 | /// contain enough bytes. |
| 808 | 808 | pub fn decodeBlockReader( |
| 809 | 809 | dest: *RingBuffer, |
| 810 | source: anytype, | |
| 810 | in: *std.io.BufferedReader, | |
| 811 | bytes_read: *usize, | |
| 811 | 812 | block_header: frame.Zstandard.Block.Header, |
| 812 | 813 | decode_state: *DecodeState, |
| 813 | 814 | block_size_max: usize, |
| ... | ... | @@ -815,26 +816,29 @@ pub fn decodeBlockReader( |
| 815 | 816 | sequence_buffer: []u8, |
| 816 | 817 | ) !void { |
| 817 | 818 | const block_size = block_header.block_size; |
| 818 | var block_reader_limited = std.io.limitedReader(source, block_size); | |
| 819 | const block_reader = block_reader_limited.reader(); | |
| 820 | 819 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; |
| 821 | 820 | switch (block_header.block_type) { |
| 822 | 821 | .raw => { |
| 823 | 822 | if (block_size == 0) return; |
| 824 | 823 | const slice = dest.sliceAt(dest.write_index, block_size); |
| 825 | try source.readNoEof(slice.first); | |
| 826 | try source.readNoEof(slice.second); | |
| 824 | var vecs: [2][]u8 = &.{slice.first, slice.second }; | |
| 825 | try in.readVecAll(&vecs); | |
| 826 | assert(slice.first.len + slice.second.len == block_size); | |
| 827 | bytes_read.* += block_size; | |
| 827 | 828 | dest.write_index = dest.mask2(dest.write_index + block_size); |
| 828 | 829 | decode_state.written_count += block_size; |
| 829 | 830 | }, |
| 830 | 831 | .rle => { |
| 831 | const byte = try source.readByte(); | |
| 832 | const byte = try in.takeByte(); | |
| 833 | bytes_read.* += 1; | |
| 832 | 834 | for (0..block_size) |_| { |
| 833 | 835 | dest.writeAssumeCapacity(byte); |
| 834 | 836 | } |
| 835 | 837 | decode_state.written_count += block_size; |
| 836 | 838 | }, |
| 837 | 839 | .compressed => { |
| 840 | var block_reader_limited = std.io.limitedReader(source, block_size); | |
| 841 | const block_reader = block_reader_limited.reader(); | |
| 838 | 842 | const literals = try decodeLiteralsSection(block_reader, literals_buffer); |
| 839 | 843 | const sequences_header = try decodeSequencesHeader(block_reader); |
| 840 | 844 |
lib/std/compress/zstandard/decompress.zig+14-9| ... | ... | @@ -50,7 +50,7 @@ pub const FrameHeader = union(enum) { |
| 50 | 50 | skippable: SkippableHeader, |
| 51 | 51 | }; |
| 52 | 52 | |
| 53 | pub const HeaderError = error{ BadMagic, EndOfStream, ReservedBitSet }; | |
| 53 | pub const HeaderError = error{ ReadFailed, BadMagic, EndOfStream, ReservedBitSet }; | |
| 54 | 54 | |
| 55 | 55 | /// Returns the header of the frame at the beginning of `source`. |
| 56 | 56 | /// |
| ... | ... | @@ -61,16 +61,21 @@ pub const HeaderError = error{ BadMagic, EndOfStream, ReservedBitSet }; |
| 61 | 61 | /// - `error.EndOfStream` if `source` contains fewer than 4 bytes |
| 62 | 62 | /// - `error.ReservedBitSet` if the frame is a Zstandard frame and any of the |
| 63 | 63 | /// reserved bits are set |
| 64 | pub fn decodeFrameHeader(source: anytype) (@TypeOf(source).Error || HeaderError)!FrameHeader { | |
| 65 | const magic = try source.readInt(u32, .little); | |
| 64 | pub fn decodeFrameHeader(br: *std.io.BufferedReader, bytes_read: *usize) HeaderError!FrameHeader { | |
| 65 | const magic = try br.readInt(u32, .little); | |
| 66 | bytes_read.* += 4; | |
| 66 | 67 | const frame_type = try frameType(magic); |
| 67 | 68 | switch (frame_type) { |
| 68 | .zstandard => return FrameHeader{ .zstandard = try decodeZstandardHeader(source) }, | |
| 69 | .skippable => return FrameHeader{ | |
| 70 | .skippable = .{ | |
| 71 | .magic_number = magic, | |
| 72 | .frame_size = try source.readInt(u32, .little), | |
| 73 | }, | |
| 69 | .zstandard => return .{ .zstandard = try decodeZstandardHeader(br, bytes_read) }, | |
| 70 | .skippable => { | |
| 71 | const result: FrameHeader = .{ | |
| 72 | .skippable = .{ | |
| 73 | .magic_number = magic, | |
| 74 | .frame_size = try br.readInt(u32, .little), | |
| 75 | }, | |
| 76 | }; | |
| 77 | bytes_read.* += 4; | |
| 78 | return result; | |
| 74 | 79 | }, |
| 75 | 80 | } |
| 76 | 81 | } |
lib/std/crypto/tls.zig+99-94| ... | ... | @@ -49,8 +49,8 @@ pub const hello_retry_request_sequence = [32]u8{ |
| 49 | 49 | }; |
| 50 | 50 | |
| 51 | 51 | pub const close_notify_alert = [_]u8{ |
| 52 | @intFromEnum(AlertLevel.warning), | |
| 53 | @intFromEnum(AlertDescription.close_notify), | |
| 52 | @intFromEnum(Alert.Level.warning), | |
| 53 | @intFromEnum(Alert.Description.close_notify), | |
| 54 | 54 | }; |
| 55 | 55 | |
| 56 | 56 | pub const ProtocolVersion = enum(u16) { |
| ... | ... | @@ -138,103 +138,108 @@ pub const ExtensionType = enum(u16) { |
| 138 | 138 | _, |
| 139 | 139 | }; |
| 140 | 140 | |
| 141 | pub const AlertLevel = enum(u8) { | |
| 142 | warning = 1, | |
| 143 | fatal = 2, | |
| 144 | _, | |
| 145 | }; | |
| 141 | pub const Alert = struct { | |
| 142 | level: Level, | |
| 143 | description: Description, | |
| 146 | 144 | |
| 147 | pub const AlertDescription = enum(u8) { | |
| 148 | pub const Error = error{ | |
| 149 | TlsAlertUnexpectedMessage, | |
| 150 | TlsAlertBadRecordMac, | |
| 151 | TlsAlertRecordOverflow, | |
| 152 | TlsAlertHandshakeFailure, | |
| 153 | TlsAlertBadCertificate, | |
| 154 | TlsAlertUnsupportedCertificate, | |
| 155 | TlsAlertCertificateRevoked, | |
| 156 | TlsAlertCertificateExpired, | |
| 157 | TlsAlertCertificateUnknown, | |
| 158 | TlsAlertIllegalParameter, | |
| 159 | TlsAlertUnknownCa, | |
| 160 | TlsAlertAccessDenied, | |
| 161 | TlsAlertDecodeError, | |
| 162 | TlsAlertDecryptError, | |
| 163 | TlsAlertProtocolVersion, | |
| 164 | TlsAlertInsufficientSecurity, | |
| 165 | TlsAlertInternalError, | |
| 166 | TlsAlertInappropriateFallback, | |
| 167 | TlsAlertMissingExtension, | |
| 168 | TlsAlertUnsupportedExtension, | |
| 169 | TlsAlertUnrecognizedName, | |
| 170 | TlsAlertBadCertificateStatusResponse, | |
| 171 | TlsAlertUnknownPskIdentity, | |
| 172 | TlsAlertCertificateRequired, | |
| 173 | TlsAlertNoApplicationProtocol, | |
| 174 | TlsAlertUnknown, | |
| 145 | pub const Level = enum(u8) { | |
| 146 | warning = 1, | |
| 147 | fatal = 2, | |
| 148 | _, | |
| 175 | 149 | }; |
| 176 | 150 | |
| 177 | close_notify = 0, | |
| 178 | unexpected_message = 10, | |
| 179 | bad_record_mac = 20, | |
| 180 | record_overflow = 22, | |
| 181 | handshake_failure = 40, | |
| 182 | bad_certificate = 42, | |
| 183 | unsupported_certificate = 43, | |
| 184 | certificate_revoked = 44, | |
| 185 | certificate_expired = 45, | |
| 186 | certificate_unknown = 46, | |
| 187 | illegal_parameter = 47, | |
| 188 | unknown_ca = 48, | |
| 189 | access_denied = 49, | |
| 190 | decode_error = 50, | |
| 191 | decrypt_error = 51, | |
| 192 | protocol_version = 70, | |
| 193 | insufficient_security = 71, | |
| 194 | internal_error = 80, | |
| 195 | inappropriate_fallback = 86, | |
| 196 | user_canceled = 90, | |
| 197 | missing_extension = 109, | |
| 198 | unsupported_extension = 110, | |
| 199 | unrecognized_name = 112, | |
| 200 | bad_certificate_status_response = 113, | |
| 201 | unknown_psk_identity = 115, | |
| 202 | certificate_required = 116, | |
| 203 | no_application_protocol = 120, | |
| 204 | _, | |
| 151 | pub const Description = enum(u8) { | |
| 152 | pub const Error = error{ | |
| 153 | TlsAlertUnexpectedMessage, | |
| 154 | TlsAlertBadRecordMac, | |
| 155 | TlsAlertRecordOverflow, | |
| 156 | TlsAlertHandshakeFailure, | |
| 157 | TlsAlertBadCertificate, | |
| 158 | TlsAlertUnsupportedCertificate, | |
| 159 | TlsAlertCertificateRevoked, | |
| 160 | TlsAlertCertificateExpired, | |
| 161 | TlsAlertCertificateUnknown, | |
| 162 | TlsAlertIllegalParameter, | |
| 163 | TlsAlertUnknownCa, | |
| 164 | TlsAlertAccessDenied, | |
| 165 | TlsAlertDecodeError, | |
| 166 | TlsAlertDecryptError, | |
| 167 | TlsAlertProtocolVersion, | |
| 168 | TlsAlertInsufficientSecurity, | |
| 169 | TlsAlertInternalError, | |
| 170 | TlsAlertInappropriateFallback, | |
| 171 | TlsAlertMissingExtension, | |
| 172 | TlsAlertUnsupportedExtension, | |
| 173 | TlsAlertUnrecognizedName, | |
| 174 | TlsAlertBadCertificateStatusResponse, | |
| 175 | TlsAlertUnknownPskIdentity, | |
| 176 | TlsAlertCertificateRequired, | |
| 177 | TlsAlertNoApplicationProtocol, | |
| 178 | TlsAlertUnknown, | |
| 179 | }; | |
| 205 | 180 | |
| 206 | pub fn toError(alert: AlertDescription) Error!void { | |
| 207 | switch (alert) { | |
| 208 | .close_notify => {}, // not an error | |
| 209 | .unexpected_message => return error.TlsAlertUnexpectedMessage, | |
| 210 | .bad_record_mac => return error.TlsAlertBadRecordMac, | |
| 211 | .record_overflow => return error.TlsAlertRecordOverflow, | |
| 212 | .handshake_failure => return error.TlsAlertHandshakeFailure, | |
| 213 | .bad_certificate => return error.TlsAlertBadCertificate, | |
| 214 | .unsupported_certificate => return error.TlsAlertUnsupportedCertificate, | |
| 215 | .certificate_revoked => return error.TlsAlertCertificateRevoked, | |
| 216 | .certificate_expired => return error.TlsAlertCertificateExpired, | |
| 217 | .certificate_unknown => return error.TlsAlertCertificateUnknown, | |
| 218 | .illegal_parameter => return error.TlsAlertIllegalParameter, | |
| 219 | .unknown_ca => return error.TlsAlertUnknownCa, | |
| 220 | .access_denied => return error.TlsAlertAccessDenied, | |
| 221 | .decode_error => return error.TlsAlertDecodeError, | |
| 222 | .decrypt_error => return error.TlsAlertDecryptError, | |
| 223 | .protocol_version => return error.TlsAlertProtocolVersion, | |
| 224 | .insufficient_security => return error.TlsAlertInsufficientSecurity, | |
| 225 | .internal_error => return error.TlsAlertInternalError, | |
| 226 | .inappropriate_fallback => return error.TlsAlertInappropriateFallback, | |
| 227 | .user_canceled => {}, // not an error | |
| 228 | .missing_extension => return error.TlsAlertMissingExtension, | |
| 229 | .unsupported_extension => return error.TlsAlertUnsupportedExtension, | |
| 230 | .unrecognized_name => return error.TlsAlertUnrecognizedName, | |
| 231 | .bad_certificate_status_response => return error.TlsAlertBadCertificateStatusResponse, | |
| 232 | .unknown_psk_identity => return error.TlsAlertUnknownPskIdentity, | |
| 233 | .certificate_required => return error.TlsAlertCertificateRequired, | |
| 234 | .no_application_protocol => return error.TlsAlertNoApplicationProtocol, | |
| 235 | _ => return error.TlsAlertUnknown, | |
| 181 | close_notify = 0, | |
| 182 | unexpected_message = 10, | |
| 183 | bad_record_mac = 20, | |
| 184 | record_overflow = 22, | |
| 185 | handshake_failure = 40, | |
| 186 | bad_certificate = 42, | |
| 187 | unsupported_certificate = 43, | |
| 188 | certificate_revoked = 44, | |
| 189 | certificate_expired = 45, | |
| 190 | certificate_unknown = 46, | |
| 191 | illegal_parameter = 47, | |
| 192 | unknown_ca = 48, | |
| 193 | access_denied = 49, | |
| 194 | decode_error = 50, | |
| 195 | decrypt_error = 51, | |
| 196 | protocol_version = 70, | |
| 197 | insufficient_security = 71, | |
| 198 | internal_error = 80, | |
| 199 | inappropriate_fallback = 86, | |
| 200 | user_canceled = 90, | |
| 201 | missing_extension = 109, | |
| 202 | unsupported_extension = 110, | |
| 203 | unrecognized_name = 112, | |
| 204 | bad_certificate_status_response = 113, | |
| 205 | unknown_psk_identity = 115, | |
| 206 | certificate_required = 116, | |
| 207 | no_application_protocol = 120, | |
| 208 | _, | |
| 209 | ||
| 210 | pub fn toError(description: Description) Error!void { | |
| 211 | switch (description) { | |
| 212 | .close_notify => {}, // not an error | |
| 213 | .unexpected_message => return error.TlsAlertUnexpectedMessage, | |
| 214 | .bad_record_mac => return error.TlsAlertBadRecordMac, | |
| 215 | .record_overflow => return error.TlsAlertRecordOverflow, | |
| 216 | .handshake_failure => return error.TlsAlertHandshakeFailure, | |
| 217 | .bad_certificate => return error.TlsAlertBadCertificate, | |
| 218 | .unsupported_certificate => return error.TlsAlertUnsupportedCertificate, | |
| 219 | .certificate_revoked => return error.TlsAlertCertificateRevoked, | |
| 220 | .certificate_expired => return error.TlsAlertCertificateExpired, | |
| 221 | .certificate_unknown => return error.TlsAlertCertificateUnknown, | |
| 222 | .illegal_parameter => return error.TlsAlertIllegalParameter, | |
| 223 | .unknown_ca => return error.TlsAlertUnknownCa, | |
| 224 | .access_denied => return error.TlsAlertAccessDenied, | |
| 225 | .decode_error => return error.TlsAlertDecodeError, | |
| 226 | .decrypt_error => return error.TlsAlertDecryptError, | |
| 227 | .protocol_version => return error.TlsAlertProtocolVersion, | |
| 228 | .insufficient_security => return error.TlsAlertInsufficientSecurity, | |
| 229 | .internal_error => return error.TlsAlertInternalError, | |
| 230 | .inappropriate_fallback => return error.TlsAlertInappropriateFallback, | |
| 231 | .user_canceled => {}, // not an error | |
| 232 | .missing_extension => return error.TlsAlertMissingExtension, | |
| 233 | .unsupported_extension => return error.TlsAlertUnsupportedExtension, | |
| 234 | .unrecognized_name => return error.TlsAlertUnrecognizedName, | |
| 235 | .bad_certificate_status_response => return error.TlsAlertBadCertificateStatusResponse, | |
| 236 | .unknown_psk_identity => return error.TlsAlertUnknownPskIdentity, | |
| 237 | .certificate_required => return error.TlsAlertCertificateRequired, | |
| 238 | .no_application_protocol => return error.TlsAlertNoApplicationProtocol, | |
| 239 | _ => return error.TlsAlertUnknown, | |
| 240 | } | |
| 236 | 241 | } |
| 237 | } | |
| 242 | }; | |
| 238 | 243 | }; |
| 239 | 244 | |
| 240 | 245 | pub const SignatureScheme = enum(u16) { |
lib/std/crypto/tls/Client.zig+55-51| ... | ... | @@ -39,8 +39,9 @@ output: *std.io.BufferedWriter, |
| 39 | 39 | /// |
| 40 | 40 | /// Its buffer aliases the buffer of `input`. |
| 41 | 41 | reader: std.io.BufferedReader, |
| 42 | /// Populated under various error conditions. | |
| 43 | diagnostics: Diagnostics, | |
| 42 | /// Populated when `error.TlsAlert` is returned. | |
| 43 | alert: ?tls.Alert, | |
| 44 | read_err: ?ReadError, | |
| 44 | 45 | |
| 45 | 46 | tls_version: tls.ProtocolVersion, |
| 46 | 47 | read_seq: u64, |
| ... | ... | @@ -69,15 +70,16 @@ application_cipher: tls.ApplicationCipher, |
| 69 | 70 | /// this connection. |
| 70 | 71 | ssl_key_log: ?*SslKeyLog, |
| 71 | 72 | |
| 72 | pub const Diagnostics = union(enum) { | |
| 73 | /// Any `ReadFailure` and `WriteFailure` was due to `input` or `output` | |
| 74 | /// returning the error, respectively. | |
| 75 | transitive, | |
| 76 | /// Populated on `error.TlsAlert`. | |
| 77 | /// | |
| 78 | /// If this isn't a error alert, then it's a closure alert, which makes | |
| 79 | /// no sense in a handshake. | |
| 80 | alert: tls.AlertDescription, | |
| 73 | pub const ReadError = error{ | |
| 74 | /// The alert description will be stored in `alert`. | |
| 75 | TlsAlert, | |
| 76 | TlsBadLength, | |
| 77 | TlsBadRecordMac, | |
| 78 | TlsConnectionTruncated, | |
| 79 | TlsDecodeError, | |
| 80 | TlsRecordOverflow, | |
| 81 | TlsUnexpectedMessage, | |
| 82 | TlsIllegalParameter, | |
| 81 | 83 | }; |
| 82 | 84 | |
| 83 | 85 | pub const SslKeyLog = struct { |
| ... | ... | @@ -128,14 +130,13 @@ pub const Options = struct { |
| 128 | 130 | }; |
| 129 | 131 | |
| 130 | 132 | const InitError = error{ |
| 131 | //OutOfMemory, | |
| 132 | WriteFailure, | |
| 133 | ReadFailure, | |
| 133 | WriteFailed, | |
| 134 | ReadFailed, | |
| 134 | 135 | InsufficientEntropy, |
| 135 | 136 | DiskQuota, |
| 136 | 137 | LockViolation, |
| 137 | 138 | NotOpenForWriting, |
| 138 | /// The alert description will be stored in `Options.Diagnostics.alert`. | |
| 139 | /// The alert description will be stored in `alert`. | |
| 139 | 140 | TlsAlert, |
| 140 | 141 | TlsUnexpectedMessage, |
| 141 | 142 | TlsIllegalParameter, |
| ... | ... | @@ -192,7 +193,7 @@ pub fn init( |
| 192 | 193 | ) InitError!void { |
| 193 | 194 | assert(input.storage.buffer.len >= min_buffer_len); |
| 194 | 195 | assert(output.buffer.len >= min_buffer_len); |
| 195 | client.diagnostics = .transient; | |
| 196 | client.alert = null; | |
| 196 | 197 | const host = switch (options.host) { |
| 197 | 198 | .no_verification => "", |
| 198 | 199 | .explicit => |host| host, |
| ... | ... | @@ -417,10 +418,10 @@ pub fn init( |
| 417 | 418 | switch (ct) { |
| 418 | 419 | .alert => { |
| 419 | 420 | ctd.ensure(2) catch continue :fragment; |
| 420 | const level = ctd.decode(tls.AlertLevel); | |
| 421 | const desc = ctd.decode(tls.AlertDescription); | |
| 422 | _ = level; | |
| 423 | client.diagnostics = .{ .alert = desc }; | |
| 421 | client.alert = .{ | |
| 422 | .level = ctd.decode(tls.Alert.Level), | |
| 423 | .description = ctd.decode(tls.Alert.Description), | |
| 424 | }; | |
| 424 | 425 | return error.TlsAlert; |
| 425 | 426 | }, |
| 426 | 427 | .change_cipher_spec => { |
| ... | ... | @@ -924,7 +925,7 @@ pub fn writer(c: *Client) std.io.Writer { |
| 924 | 925 | fn writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 925 | 926 | const c: *Client = @alignCast(@ptrCast(context)); |
| 926 | 927 | const sliced_data = if (splat == 0) data[0..data.len -| 1] else data; |
| 927 | const output = &c.output; | |
| 928 | const output = c.output; | |
| 928 | 929 | const ciphertext_buf = try output.writableSliceGreedy(min_buffer_len); |
| 929 | 930 | var total_clear: usize = 0; |
| 930 | 931 | var ciphertext_end: usize = 0; |
| ... | ... | @@ -942,7 +943,7 @@ fn writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) std.i |
| 942 | 943 | /// distinguish between a properly finished TLS session, or a truncation |
| 943 | 944 | /// attack. |
| 944 | 945 | pub fn end(c: *Client) std.io.Writer.Error!void { |
| 945 | const output = &c.output; | |
| 946 | const output = c.output; | |
| 946 | 947 | const ciphertext_buf = try output.writableSliceGreedy(min_buffer_len); |
| 947 | 948 | const prepared = prepareCiphertextRecord(c, ciphertext_buf, &tls.close_notify_alert, .alert); |
| 948 | 949 | output.advance(prepared.cleartext_len); |
| ... | ... | @@ -1062,16 +1063,16 @@ fn read( |
| 1062 | 1063 | context: ?*anyopaque, |
| 1063 | 1064 | bw: *std.io.BufferedWriter, |
| 1064 | 1065 | limit: std.io.Reader.Limit, |
| 1065 | ) std.io.Reader.RwError!std.io.Reader.Status { | |
| 1066 | ) std.io.Reader.RwError!usize { | |
| 1066 | 1067 | const buf = limit.slice(try bw.writableSliceGreedy(1)); |
| 1067 | const status = try readVec(context, &.{buf}); | |
| 1068 | bw.advance(status.len); | |
| 1069 | return status; | |
| 1068 | const n = try readVec(context, &.{buf}); | |
| 1069 | bw.advance(n); | |
| 1070 | return n; | |
| 1070 | 1071 | } |
| 1071 | 1072 | |
| 1072 | 1073 | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1073 | 1074 | const c: *Client = @ptrCast(@alignCast(context)); |
| 1074 | if (c.eof()) return .{ .end = true }; | |
| 1075 | if (c.eof()) return error.EndOfStream; | |
| 1075 | 1076 | |
| 1076 | 1077 | var vp: VecPut = .{ .iovecs = data }; |
| 1077 | 1078 | |
| ... | ... | @@ -1093,11 +1094,11 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1093 | 1094 | if (c.received_close_notify) { |
| 1094 | 1095 | c.partial_ciphertext_end = 0; |
| 1095 | 1096 | assert(vp.total == amt); |
| 1096 | return .{ .len = amt, .end = c.eof() }; | |
| 1097 | return amt; | |
| 1097 | 1098 | } else if (amt > 0) { |
| 1098 | 1099 | // We don't need more data, so don't call read. |
| 1099 | 1100 | assert(vp.total == amt); |
| 1100 | return .{ .len = amt, .end = c.eof() }; | |
| 1101 | return amt; | |
| 1101 | 1102 | } |
| 1102 | 1103 | } |
| 1103 | 1104 | |
| ... | ... | @@ -1149,7 +1150,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1149 | 1150 | if (c.allow_truncation_attacks) { |
| 1150 | 1151 | c.received_close_notify = true; |
| 1151 | 1152 | } else { |
| 1152 | return error.TlsConnectionTruncated; | |
| 1153 | return failRead(c, error.TlsConnectionTruncated); | |
| 1153 | 1154 | } |
| 1154 | 1155 | } |
| 1155 | 1156 | |
| ... | ... | @@ -1168,7 +1169,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1168 | 1169 | // Perfect split. |
| 1169 | 1170 | if (frag.ptr == frag1.ptr) { |
| 1170 | 1171 | c.partial_ciphertext_end = c.partial_ciphertext_idx; |
| 1171 | return .{ .len = vp.total, .end = c.eof() }; | |
| 1172 | return vp.total; | |
| 1172 | 1173 | } |
| 1173 | 1174 | frag = frag1; |
| 1174 | 1175 | in = 0; |
| ... | ... | @@ -1188,7 +1189,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1188 | 1189 | const record_len_byte_0: u16 = straddleByte(frag, frag1, in + 3); |
| 1189 | 1190 | const record_len_byte_1: u16 = straddleByte(frag, frag1, in + 4); |
| 1190 | 1191 | const record_len = (record_len_byte_0 << 8) | record_len_byte_1; |
| 1191 | if (record_len > max_ciphertext_len) return error.TlsRecordOverflow; | |
| 1192 | if (record_len > max_ciphertext_len) return failRead(c, error.TlsRecordOverflow); | |
| 1192 | 1193 | |
| 1193 | 1194 | const full_record_len = record_len + tls.record_header_len; |
| 1194 | 1195 | const second_len = full_record_len - first.len; |
| ... | ... | @@ -1208,7 +1209,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1208 | 1209 | in += 2; |
| 1209 | 1210 | _ = legacy_version; |
| 1210 | 1211 | const record_len = mem.readInt(u16, frag[in..][0..2], .big); |
| 1211 | if (record_len > max_ciphertext_len) return error.TlsRecordOverflow; | |
| 1212 | if (record_len > max_ciphertext_len) return failRead(c, error.TlsRecordOverflow); | |
| 1212 | 1213 | in += 2; |
| 1213 | 1214 | const the_end = in + record_len; |
| 1214 | 1215 | if (the_end > frag.len) { |
| ... | ... | @@ -1255,7 +1256,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1255 | 1256 | &cleartext_stack_buffer; |
| 1256 | 1257 | const cleartext = cleartext_buf[0..ciphertext.len]; |
| 1257 | 1258 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_key) catch |
| 1258 | return error.TlsBadRecordMac; | |
| 1259 | return failRead(c, error.TlsBadRecordMac); | |
| 1259 | 1260 | const msg = mem.trimEnd(u8, cleartext, "\x00"); |
| 1260 | 1261 | break :cleartext .{ msg[0 .. msg.len - 1], @enumFromInt(msg[msg.len - 1]) }; |
| 1261 | 1262 | }, |
| ... | ... | @@ -1287,7 +1288,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1287 | 1288 | &cleartext_stack_buffer; |
| 1288 | 1289 | const cleartext = cleartext_buf[0..ciphertext.len]; |
| 1289 | 1290 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_write_key) catch |
| 1290 | return error.TlsBadRecordMac; | |
| 1291 | return failRead(c, error.TlsBadRecordMac); | |
| 1291 | 1292 | break :cleartext .{ cleartext, ct }; |
| 1292 | 1293 | }, |
| 1293 | 1294 | else => unreachable, |
| ... | ... | @@ -1296,23 +1297,24 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1296 | 1297 | c.read_seq = try std.math.add(u64, c.read_seq, 1); |
| 1297 | 1298 | switch (inner_ct) { |
| 1298 | 1299 | .alert => { |
| 1299 | if (cleartext.len != 2) return error.TlsDecodeError; | |
| 1300 | const level: tls.AlertLevel = @enumFromInt(cleartext[0]); | |
| 1301 | _ = level; | |
| 1302 | const desc: tls.AlertDescription = @enumFromInt(cleartext[1]); | |
| 1303 | switch (desc) { | |
| 1300 | if (cleartext.len != 2) return failRead(c, error.TlsDecodeError); | |
| 1301 | const alert: tls.Alert = .{ | |
| 1302 | .level = @enumFromInt(cleartext[0]), | |
| 1303 | .description = @enumFromInt(cleartext[1]), | |
| 1304 | }; | |
| 1305 | switch (alert.description) { | |
| 1304 | 1306 | .close_notify => { |
| 1305 | 1307 | c.received_close_notify = true; |
| 1306 | 1308 | c.partial_ciphertext_end = c.partial_ciphertext_idx; |
| 1307 | return .{ .len = vp.total, .end = c.eof() }; | |
| 1309 | return vp.total; | |
| 1308 | 1310 | }, |
| 1309 | 1311 | .user_canceled => { |
| 1310 | 1312 | // TODO: handle server-side closures |
| 1311 | return error.TlsUnexpectedMessage; | |
| 1313 | return failRead(c, error.TlsUnexpectedMessage); | |
| 1312 | 1314 | }, |
| 1313 | 1315 | else => { |
| 1314 | c.diagnostics = .{ .alert = desc }; | |
| 1315 | return error.TlsAlert; | |
| 1316 | c.alert = alert; | |
| 1317 | return failRead(c, error.TlsAlert); | |
| 1316 | 1318 | }, |
| 1317 | 1319 | } |
| 1318 | 1320 | }, |
| ... | ... | @@ -1324,8 +1326,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1324 | 1326 | const handshake_len = mem.readInt(u24, cleartext[ct_i..][0..3], .big); |
| 1325 | 1327 | ct_i += 3; |
| 1326 | 1328 | const next_handshake_i = ct_i + handshake_len; |
| 1327 | if (next_handshake_i > cleartext.len) | |
| 1328 | return error.TlsBadLength; | |
| 1329 | if (next_handshake_i > cleartext.len) return failRead(c, error.TlsBadLength); | |
| 1329 | 1330 | const handshake = cleartext[ct_i..next_handshake_i]; |
| 1330 | 1331 | switch (handshake_type) { |
| 1331 | 1332 | .new_session_ticket => { |
| ... | ... | @@ -1371,12 +1372,10 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1371 | 1372 | c.write_seq = 0; |
| 1372 | 1373 | }, |
| 1373 | 1374 | .update_not_requested => {}, |
| 1374 | _ => return error.TlsIllegalParameter, | |
| 1375 | _ => return failRead(c, error.TlsIllegalParameter), | |
| 1375 | 1376 | } |
| 1376 | 1377 | }, |
| 1377 | else => { | |
| 1378 | return error.TlsUnexpectedMessage; | |
| 1379 | }, | |
| 1378 | else => return failRead(c, error.TlsUnexpectedMessage), | |
| 1380 | 1379 | } |
| 1381 | 1380 | ct_i = next_handshake_i; |
| 1382 | 1381 | if (ct_i >= cleartext.len) break; |
| ... | ... | @@ -1411,7 +1410,7 @@ fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1411 | 1410 | vp.next(cleartext.len); |
| 1412 | 1411 | } |
| 1413 | 1412 | }, |
| 1414 | else => return error.TlsUnexpectedMessage, | |
| 1413 | else => return failRead(c, error.TlsUnexpectedMessage), | |
| 1415 | 1414 | } |
| 1416 | 1415 | in = end; |
| 1417 | 1416 | } |
| ... | ... | @@ -1423,6 +1422,11 @@ fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error |
| 1423 | 1422 | @panic("TODO"); |
| 1424 | 1423 | } |
| 1425 | 1424 | |
| 1425 | fn failRead(c: *Client, err: ReadError) error{ReadFailed} { | |
| 1426 | c.read_err = err; | |
| 1427 | return error.ReadFailed; | |
| 1428 | } | |
| 1429 | ||
| 1426 | 1430 | fn logSecrets(key_log_file: std.fs.File, context: anytype, secrets: anytype) void { |
| 1427 | 1431 | const locked = if (key_log_file.lock(.exclusive)) |_| true else |_| false; |
| 1428 | 1432 | defer if (locked) key_log_file.unlock(); |
lib/std/http/Client.zig+3-3| ... | ... | @@ -28,7 +28,7 @@ tls_buffer_size: if (disable_tls) u0 else usize = if (disable_tls) 0 else std.cr |
| 28 | 28 | /// If non-null, ssl secrets are logged to a stream. Creating such a stream |
| 29 | 29 | /// allows other processes with access to that stream to decrypt all |
| 30 | 30 | /// traffic over connections created with this `Client`. |
| 31 | ssl_key_logger: ?*std.io.BufferedWriter = null, | |
| 31 | ssl_key_log: ?*std.io.BufferedWriter = null, | |
| 32 | 32 | |
| 33 | 33 | /// When this is `true`, the next time this client performs an HTTPS request, |
| 34 | 34 | /// it will first rescan the system for root certificates. |
| ... | ... | @@ -342,7 +342,7 @@ pub const Connection = struct { |
| 342 | 342 | tls.client.init(&tls.reader, &tls.writer, .{ |
| 343 | 343 | .host = .{ .explicit = remote_host }, |
| 344 | 344 | .ca = .{ .bundle = client.ca_bundle }, |
| 345 | .ssl_key_logger = client.ssl_key_logger, | |
| 345 | .ssl_key_log = client.ssl_key_log, | |
| 346 | 346 | }) catch return error.TlsInitializationFailed; |
| 347 | 347 | // This is appropriate for HTTPS because the HTTP headers contain |
| 348 | 348 | // the content length which is used to detect truncation attacks. |
| ... | ... | @@ -1671,7 +1671,7 @@ pub fn fetch(client: *Client, options: FetchOptions) FetchError!FetchResult { |
| 1671 | 1671 | const decompress_buffer: []u8 = switch (response.head.content_encoding) { |
| 1672 | 1672 | .identity => &.{}, |
| 1673 | 1673 | .zstd => options.decompress_buffer orelse |
| 1674 | try client.allocator.alloc(u8, std.compress.zstd.Decompressor.Options.default_window_buffer_len * 2), | |
| 1674 | try client.allocator.alloc(u8, std.compress.zstd.default_window_len * 2), | |
| 1675 | 1675 | else => options.decompress_buffer orelse try client.allocator.alloc(u8, 8 * 1024), |
| 1676 | 1676 | }; |
| 1677 | 1677 | defer if (options.decompress_buffer == null) client.allocator.free(decompress_buffer); |
lib/std/io.zig+5-20| ... | ... | @@ -1,16 +1,11 @@ |
| 1 | const std = @import("std.zig"); | |
| 2 | 1 | const builtin = @import("builtin"); |
| 3 | const root = @import("root"); | |
| 4 | const c = std.c; | |
| 5 | 2 | const is_windows = builtin.os.tag == .windows; |
| 3 | ||
| 4 | const std = @import("std.zig"); | |
| 6 | 5 | const windows = std.os.windows; |
| 7 | 6 | const posix = std.posix; |
| 8 | 7 | const math = std.math; |
| 9 | 8 | const assert = std.debug.assert; |
| 10 | const fs = std.fs; | |
| 11 | const mem = std.mem; | |
| 12 | const meta = std.meta; | |
| 13 | const File = std.fs.File; | |
| 14 | 9 | const Allocator = std.mem.Allocator; |
| 15 | 10 | const Alignment = std.mem.Alignment; |
| 16 | 11 | |
| ... | ... | @@ -21,12 +16,6 @@ pub const BufferedReader = @import("io/BufferedReader.zig"); |
| 21 | 16 | pub const BufferedWriter = @import("io/BufferedWriter.zig"); |
| 22 | 17 | pub const AllocatingWriter = @import("io/AllocatingWriter.zig"); |
| 23 | 18 | |
| 24 | pub const CWriter = @import("io/c_writer.zig").CWriter; | |
| 25 | pub const cWriter = @import("io/c_writer.zig").cWriter; | |
| 26 | ||
| 27 | pub const LimitedReader = @import("io/limited_reader.zig").LimitedReader; | |
| 28 | pub const limitedReader = @import("io/limited_reader.zig").limitedReader; | |
| 29 | ||
| 30 | 19 | pub const MultiWriter = @import("io/multi_writer.zig").MultiWriter; |
| 31 | 20 | pub const multiWriter = @import("io/multi_writer.zig").multiWriter; |
| 32 | 21 | |
| ... | ... | @@ -38,9 +27,6 @@ pub const bitWriter = @import("io/bit_writer.zig").bitWriter; |
| 38 | 27 | pub const ChangeDetectionStream = @import("io/change_detection_stream.zig").ChangeDetectionStream; |
| 39 | 28 | pub const changeDetectionStream = @import("io/change_detection_stream.zig").changeDetectionStream; |
| 40 | 29 | |
| 41 | pub const FindByteWriter = @import("io/find_byte_writer.zig").FindByteWriter; | |
| 42 | pub const findByteWriter = @import("io/find_byte_writer.zig").findByteWriter; | |
| 43 | ||
| 44 | 30 | pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile; |
| 45 | 31 | |
| 46 | 32 | pub const tty = @import("io/tty.zig"); |
| ... | ... | @@ -63,7 +49,7 @@ pub fn poll( |
| 63 | 49 | .windows = if (is_windows) .{ |
| 64 | 50 | .first_read_done = false, |
| 65 | 51 | .overlapped = [1]windows.OVERLAPPED{ |
| 66 | mem.zeroes(windows.OVERLAPPED), | |
| 52 | std.mem.zeroes(windows.OVERLAPPED), | |
| 67 | 53 | } ** enum_fields.len, |
| 68 | 54 | .small_bufs = undefined, |
| 69 | 55 | .active = .{ |
| ... | ... | @@ -436,10 +422,10 @@ pub fn PollFiles(comptime StreamEnum: type) type { |
| 436 | 422 | for (&struct_fields, enum_fields) |*struct_field, enum_field| { |
| 437 | 423 | struct_field.* = .{ |
| 438 | 424 | .name = enum_field.name, |
| 439 | .type = fs.File, | |
| 425 | .type = std.fs.File, | |
| 440 | 426 | .default_value_ptr = null, |
| 441 | 427 | .is_comptime = false, |
| 442 | .alignment = @alignOf(fs.File), | |
| 428 | .alignment = @alignOf(std.fs.File), | |
| 443 | 429 | }; |
| 444 | 430 | } |
| 445 | 431 | return @Type(.{ .@"struct" = .{ |
| ... | ... | @@ -459,6 +445,5 @@ test { |
| 459 | 445 | _ = @import("io/bit_reader.zig"); |
| 460 | 446 | _ = @import("io/bit_writer.zig"); |
| 461 | 447 | _ = @import("io/buffered_atomic_file.zig"); |
| 462 | _ = @import("io/c_writer.zig"); | |
| 463 | 448 | _ = @import("io/test.zig"); |
| 464 | 449 | } |
lib/std/io/Reader.zig+9| ... | ... | @@ -6,6 +6,8 @@ const BufferedReader = std.io.BufferedReader; |
| 6 | 6 | const Allocator = std.mem.Allocator; |
| 7 | 7 | const ArrayList = std.ArrayListUnmanaged; |
| 8 | 8 | |
| 9 | pub const Limited = @import("Reader/Limited.zig"); | |
| 10 | ||
| 9 | 11 | context: ?*anyopaque, |
| 10 | 12 | vtable: *const VTable, |
| 11 | 13 | |
| ... | ... | @@ -252,6 +254,13 @@ pub fn buffered(r: Reader, buffer: []u8) BufferedReader { |
| 252 | 254 | }; |
| 253 | 255 | } |
| 254 | 256 | |
| 257 | pub fn limited(r: Reader, limit: Limit) Limited { | |
| 258 | return .{ | |
| 259 | .unlimited_reader = r, | |
| 260 | .remaining = limit, | |
| 261 | }; | |
| 262 | } | |
| 263 | ||
| 255 | 264 | fn endingRead(context: ?*anyopaque, bw: *BufferedWriter, limit: Limit) RwError!usize { |
| 256 | 265 | _ = context; |
| 257 | 266 | _ = bw; |
lib/std/io/Reader/Limited.zig created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | const Limited = @This(); | |
| 2 | ||
| 3 | const std = @import("../../std.zig"); | |
| 4 | const Reader = std.io.Reader; | |
| 5 | const BufferedWriter = std.io.BufferedWriter; | |
| 6 | ||
| 7 | unlimited_reader: Reader, | |
| 8 | remaining: Reader.Limit, | |
| 9 | ||
| 10 | pub fn reader(l: *Limited) Reader { | |
| 11 | return .{ | |
| 12 | .context = l, | |
| 13 | .vtable = &.{ | |
| 14 | .read = passthruRead, | |
| 15 | .readVec = passthruReadVec, | |
| 16 | .discard = passthruDiscard, | |
| 17 | }, | |
| 18 | }; | |
| 19 | } | |
| 20 | ||
| 21 | fn passthruRead(context: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!usize { | |
| 22 | const l: *Limited = @alignCast(@ptrCast(context)); | |
| 23 | const combined_limit = limit.min(l.remaining); | |
| 24 | const n = try l.unlimited_reader.read(bw, combined_limit); | |
| 25 | l.remaining.subtract(n); | |
| 26 | return n; | |
| 27 | } | |
| 28 | ||
| 29 | fn passthruDiscard(context: ?*anyopaque, limit: Reader.Limit) Reader.Error!usize { | |
| 30 | const l: *Limited = @alignCast(@ptrCast(context)); | |
| 31 | const combined_limit = limit.min(l.remaining); | |
| 32 | const n = try l.unlimited_reader.discard(combined_limit); | |
| 33 | l.remaining.subtract(n); | |
| 34 | return n; | |
| 35 | } | |
| 36 | ||
| 37 | fn passthruReadVec(context: ?*anyopaque, data: []const []u8) Reader.Error!usize { | |
| 38 | const l: *Limited = @alignCast(@ptrCast(context)); | |
| 39 | if (data.len == 0) return 0; | |
| 40 | if (data[0].len >= @intFromEnum(l.limit)) { | |
| 41 | const n = try l.unlimited_reader.readVec(&.{l.limit.slice(data[0])}); | |
| 42 | l.remaining.subtract(n); | |
| 43 | return n; | |
| 44 | } | |
| 45 | var total: usize = 0; | |
| 46 | for (data, 0..) |buf, i| { | |
| 47 | total += buf.len; | |
| 48 | if (total > @intFromEnum(l.limit)) { | |
| 49 | const n = try l.unlimited_reader.readVec(data[0..i]); | |
| 50 | l.remaining.subtract(n); | |
| 51 | return n; | |
| 52 | } | |
| 53 | } | |
| 54 | return 0; | |
| 55 | } |
lib/std/io/Writer.zig+2| ... | ... | @@ -95,10 +95,12 @@ pub const Offset = enum(u64) { |
| 95 | 95 | }; |
| 96 | 96 | |
| 97 | 97 | pub fn writeVec(w: Writer, data: []const []const u8) Error!usize { |
| 98 | assert(data.len > 0); | |
| 98 | 99 | return w.vtable.writeSplat(w.context, data, 1); |
| 99 | 100 | } |
| 100 | 101 | |
| 101 | 102 | pub fn writeSplat(w: Writer, data: []const []const u8, splat: usize) Error!usize { |
| 103 | assert(data.len > 0); | |
| 102 | 104 | return w.vtable.writeSplat(w.context, data, splat); |
| 103 | 105 | } |
| 104 | 106 |
lib/std/io/c_writer.zig deleted-44| ... | ... | @@ -1,44 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const io = std.io; | |
| 4 | const testing = std.testing; | |
| 5 | ||
| 6 | pub const CWriter = io.Writer(*std.c.FILE, std.fs.File.WriteError, cWriterWrite); | |
| 7 | ||
| 8 | pub fn cWriter(c_file: *std.c.FILE) CWriter { | |
| 9 | return .{ .context = c_file }; | |
| 10 | } | |
| 11 | ||
| 12 | fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize { | |
| 13 | const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file); | |
| 14 | if (amt_written >= 0) return amt_written; | |
| 15 | switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) { | |
| 16 | .SUCCESS => unreachable, | |
| 17 | .INVAL => unreachable, | |
| 18 | .FAULT => unreachable, | |
| 19 | .AGAIN => unreachable, // this is a blocking API | |
| 20 | .BADF => unreachable, // always a race condition | |
| 21 | .DESTADDRREQ => unreachable, // connect was never called | |
| 22 | .DQUOT => return error.DiskQuota, | |
| 23 | .FBIG => return error.FileTooBig, | |
| 24 | .IO => return error.InputOutput, | |
| 25 | .NOSPC => return error.NoSpaceLeft, | |
| 26 | .PERM => return error.PermissionDenied, | |
| 27 | .PIPE => return error.BrokenPipe, | |
| 28 | else => |err| return std.posix.unexpectedErrno(err), | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | test cWriter { | |
| 33 | if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest; | |
| 34 | ||
| 35 | const filename = "tmp_io_test_file.txt"; | |
| 36 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; | |
| 37 | defer { | |
| 38 | _ = std.c.fclose(out_file); | |
| 39 | std.fs.cwd().deleteFileZ(filename) catch {}; | |
| 40 | } | |
| 41 | ||
| 42 | const writer = cWriter(out_file); | |
| 43 | try writer.print("hi: {}\n", .{@as(i32, 123)}); | |
| 44 | } |
lib/std/io/limited_reader.zig deleted-45| ... | ... | @@ -1,45 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const assert = std.debug.assert; | |
| 4 | const testing = std.testing; | |
| 5 | ||
| 6 | pub fn LimitedReader(comptime ReaderType: type) type { | |
| 7 | return struct { | |
| 8 | inner_reader: ReaderType, | |
| 9 | bytes_left: u64, | |
| 10 | ||
| 11 | pub const Error = ReaderType.Error; | |
| 12 | pub const Reader = io.Reader(*Self, Error, read); | |
| 13 | ||
| 14 | const Self = @This(); | |
| 15 | ||
| 16 | pub fn read(self: *Self, dest: []u8) Error!usize { | |
| 17 | const max_read = @min(self.bytes_left, dest.len); | |
| 18 | const n = try self.inner_reader.read(dest[0..max_read]); | |
| 19 | self.bytes_left -= n; | |
| 20 | return n; | |
| 21 | } | |
| 22 | ||
| 23 | pub fn reader(self: *Self) Reader { | |
| 24 | return .{ .context = self }; | |
| 25 | } | |
| 26 | }; | |
| 27 | } | |
| 28 | ||
| 29 | /// Returns an initialised `LimitedReader`. | |
| 30 | /// `bytes_left` is a `u64` to be able to take 64 bit file offsets | |
| 31 | pub fn limitedReader(inner_reader: anytype, bytes_left: u64) LimitedReader(@TypeOf(inner_reader)) { | |
| 32 | return .{ .inner_reader = inner_reader, .bytes_left = bytes_left }; | |
| 33 | } | |
| 34 | ||
| 35 | test "basic usage" { | |
| 36 | const data = "hello world"; | |
| 37 | var fbs = std.io.fixedBufferStream(data); | |
| 38 | var early_stream = limitedReader(fbs.reader(), 3); | |
| 39 | ||
| 40 | var buf: [5]u8 = undefined; | |
| 41 | try testing.expectEqual(@as(usize, 3), try early_stream.reader().read(&buf)); | |
| 42 | try testing.expectEqualSlices(u8, data[0..3], buf[0..3]); | |
| 43 | try testing.expectEqual(@as(usize, 0), try early_stream.reader().read(&buf)); | |
| 44 | try testing.expectError(error.EndOfStream, early_stream.reader().skipBytes(10, .{})); | |
| 45 | } |
lib/std/net.zig+3-3| ... | ... | @@ -1919,9 +1919,9 @@ pub const Stream = struct { |
| 1919 | 1919 | limit: std.io.Reader.Limit, |
| 1920 | 1920 | ) std.io.Reader.Error!usize { |
| 1921 | 1921 | const buf = limit.slice(try bw.writableSliceGreedy(1)); |
| 1922 | const status = try readVec(context, &.{buf}); | |
| 1923 | bw.advance(status.len); | |
| 1924 | return status; | |
| 1922 | const n = try readVec(context, &.{buf}); | |
| 1923 | bw.advance(n); | |
| 1924 | return n; | |
| 1925 | 1925 | } |
| 1926 | 1926 | |
| 1927 | 1927 | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
lib/std/zip.zig+14-19| ... | ... | @@ -154,35 +154,30 @@ pub fn findEndRecord(seekable_stream: anytype, stream_len: u64) !EndRecord { |
| 154 | 154 | pub fn decompress( |
| 155 | 155 | method: CompressionMethod, |
| 156 | 156 | uncompressed_size: u64, |
| 157 | reader: anytype, | |
| 158 | writer: anytype, | |
| 157 | reader: *std.io.BufferedReader, | |
| 158 | writer: *std.io.BufferedWriter, | |
| 159 | compressed_remaining: *u64, | |
| 159 | 160 | ) !u32 { |
| 160 | 161 | var hash = std.hash.Crc32.init(); |
| 161 | ||
| 162 | 162 | var total_uncompressed: u64 = 0; |
| 163 | 163 | switch (method) { |
| 164 | 164 | .store => { |
| 165 | var buf: [4096]u8 = undefined; | |
| 166 | while (true) { | |
| 167 | const len = try reader.read(&buf); | |
| 168 | if (len == 0) break; | |
| 169 | try writer.writeAll(buf[0..len]); | |
| 170 | hash.update(buf[0..len]); | |
| 171 | total_uncompressed += @intCast(len); | |
| 172 | } | |
| 165 | reader.writeAll(writer, .limited(compressed_remaining.*)) catch |err| switch (err) { | |
| 166 | error.EndOfStream => return error.ZipDecompressTruncated, | |
| 167 | else => |e| return e, | |
| 168 | }; | |
| 169 | total_uncompressed += compressed_remaining.*; | |
| 173 | 170 | }, |
| 174 | 171 | .deflate => { |
| 175 | var br = std.io.bufferedReader(reader); | |
| 176 | var decompressor = std.compress.flate.decompressor(br.reader()); | |
| 172 | var decompressor: std.compress.flate.Decompressor = .init(reader); | |
| 177 | 173 | while (try decompressor.next()) |chunk| { |
| 178 | 174 | try writer.writeAll(chunk); |
| 179 | 175 | hash.update(chunk); |
| 180 | 176 | total_uncompressed += @intCast(chunk.len); |
| 181 | 177 | if (total_uncompressed > uncompressed_size) |
| 182 | 178 | return error.ZipUncompressSizeTooSmall; |
| 179 | compressed_remaining.* -= chunk.len; | |
| 183 | 180 | } |
| 184 | if (br.end != br.start) | |
| 185 | return error.ZipDeflateTruncated; | |
| 186 | 181 | }, |
| 187 | 182 | _ => return error.UnsupportedCompressionMethod, |
| 188 | 183 | } |
| ... | ... | @@ -552,15 +547,15 @@ pub fn Iterator(comptime SeekableStream: type) type { |
| 552 | 547 | @as(u64, @sizeOf(LocalFileHeader)) + |
| 553 | 548 | local_data_header_offset; |
| 554 | 549 | try stream.seekTo(local_data_file_offset); |
| 555 | var limited_reader = std.io.limitedReader(stream.context.reader(), self.compressed_size); | |
| 550 | var compressed_remaining: u64 = self.compressed_size; | |
| 556 | 551 | const crc = try decompress( |
| 557 | 552 | self.compression_method, |
| 558 | 553 | self.uncompressed_size, |
| 559 | limited_reader.reader(), | |
| 554 | stream.context.reader(), | |
| 560 | 555 | out_file.writer(), |
| 556 | &compressed_remaining, | |
| 561 | 557 | ); |
| 562 | if (limited_reader.bytes_left != 0) | |
| 563 | return error.ZipDecompressTruncated; | |
| 558 | if (compressed_remaining != 0) return error.ZipDecompressTruncated; | |
| 564 | 559 | return crc; |
| 565 | 560 | } |
| 566 | 561 | }; |
src/Package/Fetch.zig+1-1| ... | ... | @@ -1199,7 +1199,7 @@ fn unpackResource( |
| 1199 | 1199 | return try unpackTarball(f, tmp_directory.handle, dcp.reader()); |
| 1200 | 1200 | }, |
| 1201 | 1201 | .@"tar.zst" => { |
| 1202 | const window_size = std.compress.zstd.DecompressorOptions.default_window_buffer_len; | |
| 1202 | const window_size = std.compress.zstd.default_window_len; | |
| 1203 | 1203 | const window_buffer = try f.arena.allocator().create([window_size]u8); |
| 1204 | 1204 | const reader = resource.reader(); |
| 1205 | 1205 | var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader); |
src/Package/Fetch/git.zig+5-7| ... | ... | @@ -1490,7 +1490,7 @@ fn readObjectRaw(allocator: Allocator, reader: anytype, size: u64) ![]u8 { |
| 1490 | 1490 | /// |
| 1491 | 1491 | /// The format of the delta data is documented in |
| 1492 | 1492 | /// [pack-format](https://git-scm.com/docs/pack-format). |
| 1493 | fn expandDelta(base_object: anytype, delta_reader: anytype, writer: anytype) !void { | |
| 1493 | fn expandDelta(base_object: anytype, delta_reader: *std.io.BufferedReader, writer: *std.io.BufferedWriter) !void { | |
| 1494 | 1494 | while (true) { |
| 1495 | 1495 | const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.readByte() catch |e| switch (e) { |
| 1496 | 1496 | error.EndOfStream => return, |
| ... | ... | @@ -1521,13 +1521,11 @@ fn expandDelta(base_object: anytype, delta_reader: anytype, writer: anytype) !vo |
| 1521 | 1521 | var size: u24 = @bitCast(size_parts); |
| 1522 | 1522 | if (size == 0) size = 0x10000; |
| 1523 | 1523 | try base_object.seekTo(offset); |
| 1524 | var copy_reader = std.io.limitedReader(base_object.reader(), size); | |
| 1525 | var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); | |
| 1526 | try fifo.pump(copy_reader.reader(), writer); | |
| 1524 | ||
| 1525 | var base_object_br = base_object.reader(); | |
| 1526 | try base_object_br.readAll(writer, .limited(size)); | |
| 1527 | 1527 | } else if (inst.value != 0) { |
| 1528 | var data_reader = std.io.limitedReader(delta_reader, inst.value); | |
| 1529 | var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); | |
| 1530 | try fifo.pump(data_reader.reader(), writer); | |
| 1528 | try delta_reader.readAll(writer, .limited(inst.value)); | |
| 1531 | 1529 | } else { |
| 1532 | 1530 | return error.InvalidDeltaInstruction; |
| 1533 | 1531 | } |