Skip to content

Commit

Permalink
Support byte range requests (#71)
Browse files Browse the repository at this point in the history
* Support Byte Range Requests

See parse-community/parse-server#6028

* use promises

* Add Tests

* rename getFileStream to handleFileStream
  • Loading branch information
dplewis authored Sep 11, 2019
1 parent 90ba45c commit 2990242
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
28 changes: 28 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,33 @@ S3Adapter.prototype.getFileLocation = function(config, filename) {
return (config.mount + '/files/' + config.applicationId + '/' + filename);
}

S3Adapter.prototype.handleFileStream = function (filename, req, res) {
const params = {
Key: this._bucketPrefix + filename,
Range: req.get('Range'),
};
return this.createBucket().then(() => {
return new Promise((resolve, reject) => {
this._s3Client.getObject(params, (error, data) => {
if (error !== null) {
return reject(error);
}
if (data && !data.Body) {
return reject(data);
}
res.writeHead(206, {
'Accept-Ranges': data.AcceptRanges,
'Content-Length': data.ContentLength,
'Content-Range': data.ContentRange,
'Content-Type': data.ContentType,
});
res.write(data.Body);
res.end();
resolve(data.Body);
});
});
});
}

module.exports = S3Adapter;
module.exports.default = S3Adapter;
82 changes: 82 additions & 0 deletions spec/test.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,88 @@ describe('S3Adapter tests', () => {
});
});

describe('getFileStream', () => {
it('should handle range bytes', () => {
const s3 = new S3Adapter('accessKey', 'secretKey', 'myBucket');
s3._s3Client = {
createBucket: callback => callback(),
getObject: (params, callback) => {
const { Range } = params;

expect(Range).toBe('bytes=0-1');

const data = {
Body: Buffer.from('hello world', 'utf8'),
};
callback(null, data);
},
};
const req = {
get: () => 'bytes=0-1',
};
const resp = {
writeHead: jasmine.createSpy('writeHead'),
write: jasmine.createSpy('write'),
end: jasmine.createSpy('end'),
};
s3.handleFileStream('test.mov', req, resp).then((data) => {
expect(data.toString('utf8')).toBe('hello world');
expect(resp.writeHead).toHaveBeenCalled();
expect(resp.write).toHaveBeenCalled();
expect(resp.end).toHaveBeenCalled();
});
});

it('should handle range bytes error', () => {
const s3 = new S3Adapter('accessKey', 'secretKey', 'myBucket');
s3._s3Client = {
createBucket: callback => callback(),
getObject: (params, callback) => {
callback('FileNotFound', null);
},
};
const req = {
get: () => 'bytes=0-1',
};
const resp = {
writeHead: jasmine.createSpy('writeHead'),
write: jasmine.createSpy('write'),
end: jasmine.createSpy('end'),
};
s3.handleFileStream('test.mov', req, resp).catch((error) => {
expect(error).toBe('FileNotFound');
expect(resp.writeHead).not.toHaveBeenCalled();
expect(resp.write).not.toHaveBeenCalled();
expect(resp.end).not.toHaveBeenCalled();
});
});

it('should handle range bytes no data', () => {
const s3 = new S3Adapter('accessKey', 'secretKey', 'myBucket');
const data = { Error: 'NoBody' };
s3._s3Client = {
createBucket: callback => callback(),
getObject: (params, callback) => {
callback(null, data);
},
};
const req = {
get: () => 'bytes=0-1',
};
const resp = {
writeHead: jasmine.createSpy('writeHead'),
write: jasmine.createSpy('write'),
end: jasmine.createSpy('end'),
};
s3.handleFileStream('test.mov', req, resp).catch((error) => {
expect(error).toBe(data);
expect(resp.writeHead).not.toHaveBeenCalled();
expect(resp.write).not.toHaveBeenCalled();
expect(resp.end).not.toHaveBeenCalled();
});
});
});

describe('getFileLocation', () => {
var config = {
mount: 'http://my.server.com/parse',
Expand Down

0 comments on commit 2990242

Please sign in to comment.