diff --git a/lib/storage/file.js b/lib/storage/file.js index ad0456589c0..18cdbf3b61f 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -313,8 +313,7 @@ File.prototype.createReadStream = function(options) { } else { this.getMetadata(function(err, metadata) { if (err) { - throughStream.emit('error', err); - throughStream.end(); + done(err); return; } @@ -342,25 +341,21 @@ File.prototype.createReadStream = function(options) { that.bucket.storage.makeAuthorizedRequest_(reqOpts, { onAuthorized: function(err, authorizedReqOpts) { if (err) { - throughStream.emit('error', err); - throughStream.end(); + done(err); return; } // For data integrity, hash the contents of the stream as we receive it // from the server. - var localCrc32cHash; + var localCrcHash; var localMd5Hash = crypto.createHash('md5'); request(authorizedReqOpts) - .on('error', function(err) { - throughStream.emit('error', err); - throughStream.end(); - }) + .on('error', done) .on('data', function(chunk) { if (crc32c) { - localCrc32cHash = crc.calculate(chunk, localCrc32cHash); + localCrcHash = crc.calculate(chunk, localCrcHash); } if (md5) { @@ -369,61 +364,76 @@ File.prototype.createReadStream = function(options) { }) .on('complete', function(res) { - if (rangeRequest) { - // Range requests can't receive data integrity checks. - throughStream.emit('complete', res); - throughStream.end(); - return; - } - - var failed = false; - var crcFail = true; - var md5Fail = true; - - var hashes = {}; - res.headers['x-goog-hash'].split(',').forEach(function(hash) { - var hashType = hash.split('=')[0]; - hashes[hashType] = hash.substr(hash.indexOf('=') + 1); + util.handleResp(null, res, res.body, function(err) { + if (err) { + done(err); + return; + } + + if (rangeRequest) { + // Range requests can't receive data integrity checks. + done(null, res); + return; + } + + var failed = false; + var crcFail = true; + var md5Fail = true; + + var hashes = {}; + res.headers['x-goog-hash'].split(',').forEach(function(hash) { + var hashType = hash.split('=')[0]; + hashes[hashType] = hash.substr(hash.indexOf('=') + 1); + }); + + var remoteMd5 = hashes.md5; + var remoteCrc = hashes.crc32c && hashes.crc32c.substr(4); + + if (crc32c) { + crcFail = + new Buffer([localCrcHash]).toString('base64') !== remoteCrc; + failed = crcFail; + } + + if (md5) { + md5Fail = localMd5Hash.digest('base64') !== remoteMd5; + failed = md5Fail; + } + + if (validation === 'all') { + failed = remoteMd5 ? md5Fail : crcFail; + } + + if (failed) { + var mismatchError = new Error([ + 'The downloaded data did not match the data from the server.', + 'To be sure the content is the same, you should download the', + 'file again.' + ].join(' ')); + mismatchError.code = 'CONTENT_DOWNLOAD_MISMATCH'; + + done(mismatchError); + } else { + done(null, res); + } }); - - var remoteMd5 = hashes.md5; - var remoteCrc = hashes.crc32c && hashes.crc32c.substr(4); - - if (crc32c) { - crcFail = - new Buffer([localCrc32cHash]).toString('base64') !== remoteCrc; - failed = crcFail; - } - - if (md5) { - md5Fail = localMd5Hash.digest('base64') !== remoteMd5; - failed = md5Fail; - } - - if (validation === 'all') { - failed = remoteMd5 ? md5Fail : crcFail; - } - - if (failed) { - var error = new Error([ - 'The downloaded data did not match the data from the server.', - 'To be sure the content is the same, you should download the', - 'file again.' - ].join(' ')); - error.code = 'CONTENT_DOWNLOAD_MISMATCH'; - - throughStream.emit('error', error); - } else { - throughStream.emit('complete', res); - } - - throughStream.end(); }) .pipe(throughStream); } }); } + + // End the stream, first emitting an error or complete event. + function done(err, response) { + if (err) { + throughStream.emit('error', err); + } else { + throughStream.emit('complete', response); + } + + throughStream.end(); + } }; /**