Skip to content

Commit 7dc9761

Browse files
storage: createReadStream: accept start/end offsets
1 parent 23d399c commit 7dc9761

File tree

2 files changed

+80
-8
lines changed

2 files changed

+80
-8
lines changed

lib/storage/file.js

+22
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ File.prototype.copy = function(destination, callback) {
223223
* hash wasn't returned from the API. CRC32c will provide better performance
224224
* with less reliability. You may also choose to skip validation completely,
225225
* however this is **not recommended**.
226+
* @param {number} options.start - A byte offset to begin the file's download
227+
* from. NOTE: Byte ranges are inclusive; that is, `options.start = 0` and
228+
* `options.end = 999` represent the first 1000 bytes in a file or object.
229+
* @param {number} options.end - A byte offset to stop reading the file at.
230+
* NOTE: Byte ranges are inclusive; that is, `options.start = 0` and
231+
* `options.end = 999` represent the first 1000 bytes in a file or object.
226232
*
227233
* @example
228234
* //-
@@ -238,6 +244,16 @@ File.prototype.copy = function(destination, callback) {
238244
* image.createReadStream()
239245
* .pipe(fs.createWriteStream('/Users/stephen/Photos/image.png'))
240246
* .on('error', function(err) {});
247+
*
248+
* //-
249+
* // To limit the downloaded data to only a byte range, pass an options object.
250+
* //-
251+
* image.createReadStream({
252+
* start: 1050,
253+
* end: 1100
254+
* })
255+
* .pipe(fs.createWriteStream('/Users/stephen/Photos/image.png'))
256+
* .on('error', function(err) {});
241257
*/
242258
File.prototype.createReadStream = function(options) {
243259
options = options || {};
@@ -288,6 +304,12 @@ File.prototype.createReadStream = function(options) {
288304
uri: uri
289305
};
290306

307+
if (util.is(options.start, 'number') || util.is(options.end, 'number')) {
308+
reqOpts.headers = {
309+
Range: 'bytes=' + [options.start || '', options.end || ''].join('-')
310+
};
311+
}
312+
291313
that.bucket.storage.makeAuthorizedRequest_(reqOpts, {
292314
onAuthorized: function(err, authorizedReqOpts) {
293315
if (err) {

test/storage/file.js

+58-8
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ nodeutil.inherits(FakeDuplexify, duplexify);
5050
var makeWritableStream_Override;
5151
var fakeUtil = extend({}, util, {
5252
makeWritableStream: function() {
53-
var args = [].slice.call(arguments);
53+
var args = util.toArray(arguments);
5454
(makeWritableStream_Override || util.makeWritableStream).apply(null, args);
5555
makeWritableStream_Override = null;
5656
}
@@ -60,7 +60,7 @@ var request_Cached = request;
6060
var request_Override;
6161

6262
function fakeRequest() {
63-
var args = [].slice.apply(arguments);
63+
var args = util.toArray(arguments);
6464
var results = (request_Override || request_Cached).apply(null, args);
6565
request_Override = null;
6666
return results;
@@ -93,21 +93,24 @@ var File = require('sandboxed-module')
9393

9494
describe('File', function() {
9595
var FILE_NAME = 'file-name.png';
96-
var options = {
97-
makeAuthorizedRequest_: function(req, callback) {
98-
(callback.onAuthorized || callback)(null, req);
99-
}
100-
};
101-
var bucket = new Bucket(options, 'bucket-name');
10296
var file;
10397
var directoryFile;
98+
var bucket;
10499

105100
beforeEach(function() {
101+
var options = {
102+
makeAuthorizedRequest_: function(req, callback) {
103+
(callback.onAuthorized || callback)(null, req);
104+
}
105+
};
106+
bucket = new Bucket(options, 'bucket-name');
106107
file = new File(bucket, FILE_NAME);
107108
file.makeReq_ = util.noop;
108109

109110
directoryFile = new File(bucket, 'directory/file.jpg');
110111
directoryFile.makeReq_ = util.noop;
112+
113+
request_Override = null;
111114
});
112115

113116
describe('initialization', function() {
@@ -418,6 +421,53 @@ describe('File', function() {
418421
});
419422
});
420423
});
424+
425+
it('should accept a start range', function(done) {
426+
var startOffset = 100;
427+
428+
request_Override = function(opts) {
429+
setImmediate(function () {
430+
assert.equal(opts.headers.Range, 'bytes=' + startOffset + '-');
431+
done();
432+
});
433+
return duplexify();
434+
};
435+
436+
file.metadata = metadata;
437+
file.createReadStream({ start: startOffset });
438+
});
439+
440+
it('should accept an end range', function(done) {
441+
var endOffset = 100;
442+
443+
request_Override = function(opts) {
444+
setImmediate(function () {
445+
assert.equal(opts.headers.Range, 'bytes=-' + endOffset);
446+
done();
447+
});
448+
return duplexify();
449+
};
450+
451+
file.metadata = metadata;
452+
file.createReadStream({ end: endOffset });
453+
});
454+
455+
it('should accept both a start and end range', function(done) {
456+
var startOffset = 100;
457+
var endOffset = 101;
458+
459+
request_Override = function(opts) {
460+
setImmediate(function () {
461+
var expectedRange = 'bytes=' + startOffset + '-' + endOffset;
462+
assert.equal(opts.headers.Range, expectedRange);
463+
done();
464+
});
465+
return duplexify();
466+
};
467+
468+
file.metadata = metadata;
469+
file.createReadStream({ start: startOffset, end: endOffset });
470+
});
421471
});
422472

423473
describe('createWriteStream', function() {

0 commit comments

Comments
 (0)