From ef9a138804e10e32d98eeec5fb80128629a2c94b Mon Sep 17 00:00:00 2001 From: Stephen Sawchuk Date: Tue, 28 Jul 2015 15:43:59 -0400 Subject: [PATCH] storage: add gzip option --- lib/storage/bucket.js | 16 +++++- lib/storage/file.js | 72 ++++++++++++++++++------ system-test/data/long-html-file.html | Bin 17371 -> 86425 bytes system-test/data/long-html-file.html.gz | Bin 0 -> 17371 bytes system-test/storage.js | 32 ++++++++++- test/storage/bucket.js | 15 +++++ test/storage/file.js | 11 ++++ 7 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 system-test/data/long-html-file.html.gz diff --git a/lib/storage/bucket.js b/lib/storage/bucket.js index c6c554f64e0..a09caa72afc 100644 --- a/lib/storage/bucket.js +++ b/lib/storage/bucket.js @@ -875,6 +875,8 @@ Bucket.prototype.setMetadata = function(metadata, callback) { * will be uploaded to the File object's bucket and under the File object's * name. Lastly, when this argument is omitted, the file is uploaded to your * bucket using the name of the local file. + * @param {boolean} options.gzip - Automatically gzip the file. This will set + * `options.metadata.contentEncoding` to `gzip`. * @param {object=} options.metadata - Metadata to set for your file. * @param {boolean=} options.resumable - Force a resumable upload. (default: * true for files larger than 5MB). Read more about resumable uploads @@ -927,6 +929,17 @@ Bucket.prototype.setMetadata = function(metadata, callback) { * }); * * //- + * // You can also have a file gzip'd on the fly. + * //- + * bucket.upload('index.html', { gzip: true }, function(err, file) { + * // Your bucket now contains: + * // - "index.html" (automatically compressed with gzip) + * + * // Downloading the file with `file.download` will automatically decode the + * // file. + * }); + * + * //- * // You may also re-use a File object, {module:storage/file}, that references * // the file you wish to create or overwrite. * //- @@ -990,7 +1003,8 @@ Bucket.prototype.upload = function(localPath, options, callback) { .pipe(newFile.createWriteStream({ validation: options.validation, resumable: resumable, - metadata: metadata + metadata: metadata, + gzip: options.gzip })) .on('error', function(err) { callback(err); diff --git a/lib/storage/file.js b/lib/storage/file.js index 5e6b940b236..833ff6dc0aa 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -34,6 +34,7 @@ var request = require('request').defaults({ }); var streamEvents = require('stream-events'); var through = require('through2'); +var zlib = require('zlib'); /** * @type {module:storage/acl} @@ -611,8 +612,10 @@ File.prototype.createReadStream = function(options) { * uploaded. * * @param {object=} options - Configuration object. - * @param {object=} options.metadata - Set the metadata for this file. - * @param {boolean=} options.resumable - Force a resumable upload. NOTE: When + * @param {boolean} options.gzip - Automatically gzip the file. This will set + * `options.metadata.contentEncoding` to `gzip`. + * @param {object} options.metadata - Set the metadata for this file. + * @param {boolean} options.resumable - Force a resumable upload. NOTE: When * working with streams, the file format and size is unknown until it's * completely consumed. Because of this, it's best for you to be explicit * for what makes sense given your input. Read more about resumable uploads @@ -642,6 +645,24 @@ File.prototype.createReadStream = function(options) { * }); * * //- + * //

Uploading a File with gzip compression

+ * //- + * var fs = require('fs'); + * var htmlFile = myBucket.file('index.html'); + * + * fs.createReadStream('/Users/stephen/site/index.html') + * .pipe(htmlFile.createWriteStream({ gzip: true })) + * .on('error', function(err) {}) + * .on('complete', function(metadata) { + * // The file upload is complete. + * }); + * + * //- + * // Downloading the file with `createReadStream` will automatically decode the + * // file. + * //- + * + * //- * //

Uploading a File with Metadata

* // * // One last case you may run into is when you want to upload a file to your @@ -661,13 +682,23 @@ File.prototype.createReadStream = function(options) { * } * } * })) - * .on('error', function(err) {}); + * .on('error', function(err) {}) + * .on('complete', function(metadata) { + * // The file upload is complete. + * }); */ File.prototype.createWriteStream = function(options) { options = options || {}; var that = this; + + var gzip = options.gzip; + var metadata = options.metadata || {}; + if (gzip) { + metadata.contentEncoding = 'gzip'; + } + var validations = ['crc32c', 'md5']; var validation; @@ -693,9 +724,11 @@ File.prototype.createWriteStream = function(options) { var localCrc32cHash; var localMd5Hash = crypto.createHash('md5'); - var dup = streamEvents(duplexify()); + var writableStream = streamEvents(duplexify()); - var throughStream = through(function(chunk, enc, next) { + var throughStream = through(); + + var validationStream = through(function(chunk, enc, next) { if (crc32c) { localCrc32cHash = crc.calculate(chunk, localCrc32cHash); } @@ -708,25 +741,30 @@ File.prototype.createWriteStream = function(options) { next(); }); + validationStream.on('end', function() { + if (crc32c) { + localCrc32cHash = new Buffer([localCrc32cHash]).toString('base64'); + } + + if (md5) { + localMd5Hash = localMd5Hash.digest('base64'); + } + }); + throughStream - .on('end', function() { - if (crc32c) { - localCrc32cHash = new Buffer([localCrc32cHash]).toString('base64'); - } - if (md5) { - localMd5Hash = localMd5Hash.digest('base64'); - } - }) + .pipe(gzip ? zlib.createGzip() : through()) + + .pipe(validationStream) - .pipe(dup) + .pipe(writableStream) // Wait until we've received data to determine what upload technique to use. .once('writing', function() { - if (util.is(options.resumable, 'boolean') && !options.resumable) { - that.startSimpleUpload_(dup, metadata); + if (options.resumable === false) { + that.startSimpleUpload_(writableStream, metadata); } else { - that.startResumableUpload_(dup, metadata); + that.startResumableUpload_(writableStream, metadata); } }) diff --git a/system-test/data/long-html-file.html b/system-test/data/long-html-file.html index 1eda297b8dc5f6ae2f9edc06eb9d6e8a7abd3f42..f8682dc7ae3bea2c261c1f28fd69fd01aee5d6cf 100644 GIT binary patch literal 86425 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 Bs(Jtb literal 17371 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 diff --git a/system-test/data/long-html-file.html.gz b/system-test/data/long-html-file.html.gz new file mode 100644 index 0000000000000000000000000000000000000000..1eda297b8dc5f6ae2f9edc06eb9d6e8a7abd3f42 GIT binary patch literal 17371 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 literal 0 HcmV?d00001 diff --git a/system-test/storage.js b/system-test/storage.js index 735977f5a60..66926e2b3b0 100644 --- a/system-test/storage.js +++ b/system-test/storage.js @@ -42,8 +42,11 @@ var files = { big: { path: 'system-test/data/three-mb-file.tif' }, - gzip: { + html: { path: 'system-test/data/long-html-file.html' + }, + gzip: { + path: 'system-test/data/long-html-file.html.gz' } }; @@ -535,6 +538,24 @@ describe('storage', function() { }); }); + it('should gzip a file on the fly and download it', function(done) { + var options = { + gzip: true + }; + + var expectedContents = fs.readFileSync(files.html.path, 'utf-8'); + + bucket.upload(files.html.path, options, function(err, file) { + assert.ifError(err); + + file.download(function(err, contents) { + assert.ifError(err); + assert.strictEqual(contents.toString(), expectedContents); + file.delete(done); + }); + }); + }); + it('should upload a gzipped file and download it', function(done) { var options = { metadata: { @@ -542,9 +563,16 @@ describe('storage', function() { } }; + var expectedContents = fs.readFileSync(files.html.path, 'utf-8'); + bucket.upload(files.gzip.path, options, function(err, file) { assert.ifError(err); - file.download(done); + + file.download(function(err, contents) { + assert.ifError(err); + assert.strictEqual(contents.toString(), expectedContents); + file.delete(done); + }); }); }); diff --git a/test/storage/bucket.js b/test/storage/bucket.js index 887b546b52a..e8fae1e0cae 100644 --- a/test/storage/bucket.js +++ b/test/storage/bucket.js @@ -960,6 +960,21 @@ describe('Bucket', function() { bucket.upload(filepath, options, assert.ifError); }); + it('should allow specifying options.gzip', function(done) { + var fakeFile = new FakeFile(bucket, 'file-name'); + var options = { destination: fakeFile, gzip: true }; + fakeFile.createWriteStream = function(options) { + var ws = new stream.Writable(); + ws.write = util.noop; + setImmediate(function() { + assert.strictEqual(options.gzip, true); + done(); + }); + return ws; + }; + bucket.upload(filepath, options, assert.ifError); + }); + it('should allow specifying options.resumable', function(done) { var fakeFile = new FakeFile(bucket, 'file-name'); var options = { destination: fakeFile, resumable: false }; diff --git a/test/storage/file.js b/test/storage/file.js index ac14eb5bdd7..7067f4feb30 100644 --- a/test/storage/file.js +++ b/test/storage/file.js @@ -920,6 +920,17 @@ describe('File', function() { writable.write('data'); }); + it('should set metadata.contentEncoding with gzip', function(done) { + var writable = file.createWriteStream({ gzip: true }); + + file.startResumableUpload_ = function(stream, metadata) { + assert.strictEqual(metadata.contentEncoding, 'gzip'); + done(); + }; + + writable.write('data'); + }); + describe('validation', function() { var data = 'test';