fix: zip may fail for 4GB+ files
Massimo Melina committed
May 25, 2022 at 23:18 UTC
1ed5d273c3002205b3a3ef18873d2c633e144fc6
2 files changed
+8
-15
server/src/QuickZipStream.ts
+6
-13
@@ -47,21 +47,20 @@ export class QuickZipStream extends Readable {
47
if (!value) break
48
this.prewalk.push(value) // we keep same shape of the generator, so
49
}
50
- let size = 0
50
+ let offset = 0
51
let centralDirSize = 0
52
for (const file of this.prewalk) {
53
const pathSize = Buffer.from(file.path, 'utf8').length
54
- const sizeSize = size > ZIP64_LIMIT ? 8 : 4
55
- const extraLength = (file.size > ZIP64_LIMIT ? 2 : 0) + (size > ZIP64_LIMIT ? 1 : 0)
54
+ const extraLength = (file.size > ZIP64_LIMIT ? 2 : 0) + (offset > ZIP64_LIMIT ? 1 : 0)
55
const extraDataSize = extraLength && (2+2 + extraLength*8)
57
- size += 4+2+2+2+ 4+4+4+4+ 2+2+ pathSize + file.size +4+4 +sizeSize*2
56
+ offset += 4+2+2+2+ 4+4+4+4+ 2+2+ pathSize + file.size
57
centralDirSize += 4+2+2+2+2+ 4+4+4+4+ 2+2+2+2+2+ 4+4 + pathSize + extraDataSize
58
}
60
- const centralOffset = size
59
+ const centralOffset = offset
60
if (centralOffset > ZIP64_LIMIT)
61
centralDirSize += 4+8+2+2+4+4+8+8+8+8+4+4+8+4
62
centralDirSize += 4+4+2+2+4+4+2
64
- return size + centralDirSize
63
+ return offset + centralDirSize
64
}
65
66
async _read(): Promise<void> {
@@ -105,13 +104,7 @@ export class QuickZipStream extends Readable {
104
this.workingFile = false
105
const extAttr = !mode ? 0 : (mode | 0x8000) * 0x10000 // it's like <<16 but doesn't overflow so easily
106
this.centralDir.push({ size, crc:crc!, pathAsBuffer, ts, offset, version, extAttr })
108
- const sizeSize = size > ZIP64_LIMIT ? 8 : 4
109
- this._push([
110
- 4, 0x08074b50,
111
- 4, crc,
112
- sizeSize, size,
113
- sizeSize, size,
114
- ])
107
+ this.push('') // continue piping
108
})
109
}
110
tests/test.ts
+2
-2
@@ -65,8 +65,8 @@ describe('basics', () => {
65
it('protectFromAbove', req('/protectFromAbove/child/alfa.txt', 403))
66
it('protectFromAbove.list', reqList('/protectFromAbove/child/', { outList:['alfa.txt'] }))
67
68
- it('zip.head', req('/f1/?get=zip', { empty:true, length:13074 }, { method:'HEAD' }) )
69
- it('zip.alfa is forbidden', req('/protectFromAbove/child/?get=zip&list=alfa.txt*renamed', { empty: true, length:138 }, { method:'HEAD' }))
68
+ it('zip.head', req('/f1/?get=zip', { empty:true, length:13010 }, { method:'HEAD' }) )
69
+ it('zip.alfa is forbidden', req('/protectFromAbove/child/?get=zip&list=alfa.txt*renamed', { empty: true, length:118 }, { method:'HEAD' }))
70
it('login', reqApi('login', { username, password }, 406)) // by default, we don't support clear-text login
71
72
it('referer', req('/f1/page/gpl.png', 403, {