Skip to content

Commit 14e53f9

Browse files
authored
compress.gzip: change the endianness for validation to conform to the gzip file specification (fix #19839) (#19849)
1 parent c494b63 commit 14e53f9

14 files changed

Lines changed: 50 additions & 9 deletions

vlib/compress/gzip/gzip.v

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ pub fn compress(data []u8) ![]u8 {
2828
checksum := crc32.sum(data)
2929
length := data.len
3030
result << [
31-
u8(checksum >> 24),
32-
u8(checksum >> 16),
33-
u8(checksum >> 8),
3431
u8(checksum),
35-
u8(length >> 24),
36-
u8(length >> 16),
37-
u8(length >> 8),
32+
u8(checksum >> 8),
33+
u8(checksum >> 16),
34+
u8(checksum >> 24),
3835
u8(length),
36+
u8(length >> 8),
37+
u8(length >> 16),
38+
u8(length >> 24),
3939
] // 8 bytes
4040
return result
4141
}
@@ -140,12 +140,12 @@ pub fn decompress(data []u8, params DecompressParams) ![]u8 {
140140
header_length := gzip_header.length
141141

142142
decompressed := compr.decompress(data[header_length..data.len - 8], 0)!
143-
length_expected := (u32(data[data.len - 4]) << 24) | (u32(data[data.len - 3]) << 16) | (u32(data[data.len - 2]) << 8) | data[data.len - 1]
143+
length_expected := (u32(data[data.len - 1]) << 24) | (u32(data[data.len - 2]) << 16) | (u32(data[data.len - 3]) << 8) | data[data.len - 4]
144144
if params.verify_length && decompressed.len != length_expected {
145145
return error('length verification failed, got ${decompressed.len}, expected ${length_expected}')
146146
}
147147
checksum := crc32.sum(decompressed)
148-
checksum_expected := (u32(data[data.len - 8]) << 24) | (u32(data[data.len - 7]) << 16) | (u32(data[data.len - 6]) << 8) | data[data.len - 5]
148+
checksum_expected := (u32(data[data.len - 5]) << 24) | (u32(data[data.len - 6]) << 16) | (u32(data[data.len - 7]) << 8) | data[data.len - 8]
149149
if params.verify_checksum && checksum != checksum_expected {
150150
return error('checksum verification failed')
151151
}

vlib/compress/gzip/gzip_test.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ fn test_gzip_with_invalid_length() {
123123
uncompressed := 'Hello world!'
124124
mut compressed := compress(uncompressed.bytes())!
125125
compressed[compressed.len - 1] += 1
126-
assert_decompress_error(compressed, 'length verification failed, got 12, expected 13')!
126+
assert_decompress_error(compressed, 'length verification failed, got 12, expected 16777228')!
127127
}
128128

129129
fn test_gzip_with_invalid_flags() {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import os
2+
import compress.gzip
3+
4+
const samples_folder = os.join_path(os.dir(@FILE), 'samples')
5+
6+
fn s(fname string) string {
7+
return os.join_path(samples_folder, fname)
8+
}
9+
10+
fn read_and_decode_file(fpath string) !([]u8, string) {
11+
compressed := os.read_bytes(fpath)!
12+
decoded := gzip.decompress(compressed)!
13+
content := decoded.bytestr()
14+
return compressed, content
15+
}
16+
17+
fn test_reading_and_decoding_a_known_gziped_file() {
18+
compressed, content := read_and_decode_file(s('known.gz'))!
19+
assert compressed#[0..3] == [u8(31), 139, 8]
20+
assert compressed#[-5..] == [u8(127), 115, 1, 0, 0]
21+
assert content.contains('## Description:')
22+
assert content.contains('## Examples:')
23+
assert content.ends_with('```\n')
24+
}
25+
26+
fn test_decoding_all_samples_files() {
27+
for gz_file in os.walk_ext(samples_folder, '.gz') {
28+
_, content := read_and_decode_file(gz_file)!
29+
assert content.len > 0, 'decoded content should not be empty: `${content}`'
30+
}
31+
}
32+
33+
fn test_reading_gzip_files_compressed_with_different_options() {
34+
_, content1 := read_and_decode_file(s('readme_level_1.gz'))!
35+
_, content5 := read_and_decode_file(s('readme_level_5.gz'))!
36+
_, content9 := read_and_decode_file(s('readme_level_9.gz'))!
37+
_, content9_rsyncable := read_and_decode_file(s('readme_level_9_rsyncable.gz'))!
38+
assert content9_rsyncable == content9
39+
assert content9 == content5
40+
assert content5 == content1
41+
}
213 Bytes
Binary file not shown.
232 Bytes
Binary file not shown.
228 Bytes
Binary file not shown.
227 Bytes
Binary file not shown.
29 Bytes
Binary file not shown.
29 Bytes
Binary file not shown.
29 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)