diff options
author | Anna Henningsen <sqrt@entless.org> | 2016-03-24 02:13:09 +0100 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2016-04-05 20:01:48 +0200 |
commit | 2d7e31614dbc61b4fd5a594649c12d65398a815e (patch) | |
tree | dcd3d252029a716e59ccf391c6f2a0bcddf99291 /src | |
parent | 0d41463d1f9498ee89b3cc706752a689b787db70 (diff) | |
download | android-node-v8-2d7e31614dbc61b4fd5a594649c12d65398a815e.tar.gz android-node-v8-2d7e31614dbc61b4fd5a594649c12d65398a815e.tar.bz2 android-node-v8-2d7e31614dbc61b4fd5a594649c12d65398a815e.zip |
zlib: detect gzip files when using unzip*
Detect whether a gzip file is being passed to `unzip*` by
testing the first bytes for the gzip magic bytes, and setting
the decompression mode to `GUNZIP` or `INFLATE` according to
the result.
This enables gzip-only features like multi-member support
to be used together with the `unzip*` autodetection support
and thereby makes `gunzip*` and `unzip*` return identical
results for gzip input again.
Add a simple test for checking that features specific to
`zlib.gunzip`, notably support for multiple members, also work
when using `zlib.unzip`.
PR-URL: https://github.com/nodejs/node/pull/5884
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/node_zlib.cc | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 4bf5cc76ba..aee1cbae95 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -68,7 +68,8 @@ class ZCtx : public AsyncWrap { windowBits_(0), write_in_progress_(false), pending_close_(false), - refs_(0) { + refs_(0), + gzip_id_bytes_read_(0) { MakeWeak<ZCtx>(this); } @@ -225,6 +226,8 @@ class ZCtx : public AsyncWrap { static void Process(uv_work_t* work_req) { ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req); + const Bytef* next_expected_header_byte = nullptr; + // If the avail_out is left at 0, then it means that it ran out // of room. If there was avail_out left over, then it means // that all of the input was consumed. @@ -235,6 +238,50 @@ class ZCtx : public AsyncWrap { ctx->err_ = deflate(&ctx->strm_, ctx->flush_); break; case UNZIP: + if (ctx->strm_.avail_in > 0) { + next_expected_header_byte = ctx->strm_.next_in; + } + + switch (ctx->gzip_id_bytes_read_) { + case 0: + if (next_expected_header_byte == nullptr) { + break; + } + + if (*next_expected_header_byte == GZIP_HEADER_ID1) { + ctx->gzip_id_bytes_read_ = 1; + next_expected_header_byte++; + + if (ctx->strm_.avail_in == 1) { + // The only available byte was already read. + break; + } + } else { + ctx->mode_ = INFLATE; + break; + } + + // fallthrough + case 1: + if (next_expected_header_byte == nullptr) { + break; + } + + if (*next_expected_header_byte == GZIP_HEADER_ID2) { + ctx->gzip_id_bytes_read_ = 2; + ctx->mode_ = GUNZIP; + } else { + // There is no actual difference between INFLATE and INFLATERAW + // (after initialization). + ctx->mode_ = INFLATE; + } + + break; + default: + CHECK(0 && "invalid number of gzip magic number bytes read"); + } + + // fallthrough case INFLATE: case GUNZIP: case INFLATERAW: @@ -591,6 +638,7 @@ class ZCtx : public AsyncWrap { bool write_in_progress_; bool pending_close_; unsigned int refs_; + unsigned int gzip_id_bytes_read_; }; |