diff --git a/lib/storage/file.js b/lib/storage/file.js index d64aa09c725..1019de5d2fc 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -372,6 +372,9 @@ File.prototype.move = function(destination, callback) { * image.createReadStream() * .pipe(fs.createWriteStream('/Users/stephen/Photos/image.png')) * .on('error', function(err) {}) + * .on('response', function(response) { + * // Server connected and responded with the specified status and headers. + * }) * .on('complete', function() { * // The file is fully downloaded. * }); @@ -464,6 +467,8 @@ File.prototype.createReadStream = function(options) { request(authorizedReqOpts) .on('error', done) + .on('response', throughStream.emit.bind(throughStream, 'response')) + .on('data', function(chunk) { if (crc32c) { localCrcHash = crc.calculate(chunk, localCrcHash); @@ -1025,7 +1030,7 @@ File.prototype.getSignedPolicy = function(options, callback) { * @param {string=} options.responseDisposition - The * response-content-disposition parameter (http://goo.gl/yMWxQV) of the * signed url. - * @param {string=} options.responseType - The response-content-type parameter + * @param {string=} options.responseType - The response-content-type parameter * of the signed url. * @param {function=} callback - The callback function. * @@ -1071,20 +1076,20 @@ File.prototype.getSignedUrl = function(options, callback) { var responseContentType = ''; if (util.is(options.responseType, 'string')) { - responseContentType = - '&response-content-type=' + + responseContentType = + '&response-content-type=' + encodeURIComponent(options.responseType); } var responseContentDisposition = ''; if (util.is(options.promptSaveAs, 'string')) { responseContentDisposition = - '&response-content-disposition=attachment; filename="' + + '&response-content-disposition=attachment; filename="' + encodeURIComponent(options.promptSaveAs) + '"'; } if (util.is(options.responseDisposition, 'string')) { - responseContentDisposition = - '&response-content-disposition=' + + responseContentDisposition = + '&response-content-disposition=' + encodeURIComponent(options.responseDisposition); } diff --git a/test/storage/file.js b/test/storage/file.js index 9913f3c20e7..c4e82371ed0 100644 --- a/test/storage/file.js +++ b/test/storage/file.js @@ -370,6 +370,30 @@ describe('File', function() { }); describe('createReadStream', function() { + + function getFakeRequest(data, fakeResponse) { + function FakeRequest(req) { + if (!(this instanceof FakeRequest)) { + return new FakeRequest(req); + } + + var that = this; + + stream.Readable.call(this); + this._read = function() { + this.push(data); + this.push(null); + }; + + setImmediate(function() { + that.emit('response', fakeResponse); + that.emit('complete', fakeResponse); + }); + } + nodeutil.inherits(FakeRequest, stream.Readable); + return FakeRequest; + } + it('should create an authorized request', function(done) { var expectedPath = util.format('https://{b}.storage.googleapis.com/{o}', { b: file.bucket.name, @@ -398,6 +422,19 @@ describe('File', function() { }); }); + it('should emit response event from request', function(done) { + var response = { + headers: { 'x-goog-hash': 'md5=fakefakefake' } + }; + request_Override = getFakeRequest('body', response); + + file.createReadStream({ validation: false }) + .on('response', function(res) { + assert.deepEqual(response, res); + done(); + }); + }); + it('should get readable stream from request', function(done) { var fakeRequest = { a: 'b', c: 'd' }; @@ -442,28 +479,6 @@ describe('File', function() { } }; - function getFakeRequest(data, fakeResponse) { - function FakeRequest(req) { - if (!(this instanceof FakeRequest)) { - return new FakeRequest(req); - } - - var that = this; - - stream.Readable.call(this); - this._read = function() { - this.push(data); - this.push(null); - }; - - setImmediate(function() { - that.emit('complete', fakeResponse); - }); - } - nodeutil.inherits(FakeRequest, stream.Readable); - return FakeRequest; - } - beforeEach(function() { file.metadata.mediaLink = 'http://uri';