aboutsummaryrefslogtreecommitdiff
path: root/node_modules/koa-range
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/koa-range')
-rw-r--r--node_modules/koa-range/.npmignore4
-rw-r--r--node_modules/koa-range/.travis.yml5
-rw-r--r--node_modules/koa-range/Makefile29
-rw-r--r--node_modules/koa-range/README.md68
-rw-r--r--node_modules/koa-range/index.js105
-rw-r--r--node_modules/koa-range/package.json39
-rw-r--r--node_modules/koa-range/test/simple.js228
7 files changed, 478 insertions, 0 deletions
diff --git a/node_modules/koa-range/.npmignore b/node_modules/koa-range/.npmignore
new file mode 100644
index 00000000..2c4a5a49
--- /dev/null
+++ b/node_modules/koa-range/.npmignore
@@ -0,0 +1,4 @@
+node_modules
+*.DS_Store
+coverage
+.vscode
diff --git a/node_modules/koa-range/.travis.yml b/node_modules/koa-range/.travis.yml
new file mode 100644
index 00000000..9d168317
--- /dev/null
+++ b/node_modules/koa-range/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+ - "7"
+script: "make test-travis"
+after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"
diff --git a/node_modules/koa-range/Makefile b/node_modules/koa-range/Makefile
new file mode 100644
index 00000000..7d806c63
--- /dev/null
+++ b/node_modules/koa-range/Makefile
@@ -0,0 +1,29 @@
+
+include node_modules/make-lint/index.mk
+
+test:
+ @NODE_ENV=test ./node_modules/.bin/mocha \
+ --require should \
+ --harmony \
+ --harmony-async-await \
+ test/*.js \
+ --bail
+
+test-cov:
+ @NODE_ENV=test node --harmony \
+ --harmony-async-await \
+ ./node_modules/.bin/istanbul cover \
+ ./node_modules/.bin/_mocha \
+ -- -u exports \
+ --require should \
+ test/*.js \
+ --bail
+
+test-travis:
+ node --harmony \
+ --harmony-async-await \
+ ./node_modules/.bin/istanbul cover \
+ ./node_modules/.bin/_mocha --report lcovonly \
+ -- -R dot test/*.js
+
+.PHONY: test test-cov test-travis
diff --git a/node_modules/koa-range/README.md b/node_modules/koa-range/README.md
new file mode 100644
index 00000000..ab838996
--- /dev/null
+++ b/node_modules/koa-range/README.md
@@ -0,0 +1,68 @@
+
+koa-range
+=================
+range request implementation for koa
+
+[![NPM version][npm-img]][npm-url]
+[![Build status][travis-img]][travis-url]
+[![Test coverage][coveralls-img]][coveralls-url]
+[![License][license-img]][license-url]
+[![Dependency status][david-img]][david-url]
+
+[![NPM](https://nodei.co/npm/koa-range.png?stars&downloads)](https://nodei.co/npm/koa-range/)
+[![NPM](https://nodei.co/npm-dl/koa-range.png)](https://nodei.co/npm/koa-range/)
+
+### Installation
+
+```sh
+$ npm install koa-range
+```
+
+### Usage (with koa@2)
+
+```js
+var fs = require('fs');
+var range = require('koa-range');
+var route = require('koa-route');
+var Koa = require('koa');
+var app = new Koa();
+
+app.use(range);
+
+// via buffer
+app.use(route.get('/', async function (ctx) {
+ ctx.body = new Buffer(100);
+}));
+
+// via object
+app.use(route.get('/json', async function (ctx) {
+ ctx.body = {
+ 'foo': 'bar'
+ };
+}));
+
+// via readable stream
+app.use(route.get('/stream', async function (ctx) {
+ ctx.body = fs.createReadStream('your path');
+}));
+
+```
+
+Until async/await is supported by default, you will need to do one of the following:
+- Transpile your code with somehting like Babel
+- Use node v7 with --harmony-async-await flag
+
+### License
+
+MIT
+
+[npm-img]: https://img.shields.io/npm/v/koa-range.svg?style=flat-square
+[npm-url]: https://npmjs.org/package/koa-range
+[travis-img]: https://img.shields.io/travis/koajs/koa-range.svg?style=flat-square
+[travis-url]: https://travis-ci.org/koajs/koa-range
+[coveralls-img]: https://img.shields.io/coveralls/koajs/koa-range.svg?style=flat-square
+[coveralls-url]: https://coveralls.io/r/koajs/koa-range?branch=master
+[license-img]: https://img.shields.io/badge/license-MIT-green.svg?style=flat-square
+[license-url]: https://opensource.org/licenses/MIT
+[david-img]: https://img.shields.io/david/koajs/koa-range.svg?style=flat-square
+[david-url]: https://david-dm.org/koajs/koa-range
diff --git a/node_modules/koa-range/index.js b/node_modules/koa-range/index.js
new file mode 100644
index 00000000..94451f4c
--- /dev/null
+++ b/node_modules/koa-range/index.js
@@ -0,0 +1,105 @@
+
+var util = require('util');
+var slice = require('stream-slice').slice;
+var Stream = require('stream');
+
+module.exports = async function (ctx, next) {
+ var range = ctx.header.range;
+ ctx.set('Accept-Ranges', 'bytes');
+
+ if (!range) {
+ return next();
+ }
+
+ var ranges = rangeParse(range);
+
+ if (!ranges || ranges.length == 0) {
+ ctx.status = 416;
+ return;
+ }
+
+ if (ctx.method == 'PUT') {
+ ctx.status = 400;
+ return;
+ }
+
+ await next();
+
+ if (ctx.method != 'GET' ||
+ ctx.body == null) {
+ return;
+ }
+
+ var first = ranges[0];
+ var rawBody = ctx.body;
+ var len = rawBody.length;
+
+ // avoid multi ranges
+ var firstRange = ranges[0];
+ var start = firstRange[0];
+ var end = firstRange[1];
+
+ if (!Buffer.isBuffer(rawBody)) {
+ if (rawBody instanceof Stream.Readable) {
+ len = ctx.length || '*';
+ rawBody = rawBody.pipe(slice(start, end + 1));
+ } else if (typeof rawBody !== 'string') {
+ rawBody = new Buffer(JSON.stringify(rawBody));
+ len = rawBody.length;
+ } else {
+ rawBody = new Buffer(rawBody);
+ len = rawBody.length;
+ }
+ }
+
+ //Adjust infinite end
+ if (end === Infinity) {
+ if (Number.isInteger(len)) {
+ end = len - 1;
+ } else {
+ // FIXME(Calle Svensson): If we don't know how much we can return, we do a normal HTTP 200 repsonse
+ ctx.status = 200;
+ return;
+ }
+ }
+
+ var args = [start, end+1].filter(function(item) {
+ return typeof item == 'number';
+ });
+
+ ctx.set('Content-Range', rangeContentGenerator(start, end, len));
+ ctx.status = 206;
+
+ if (rawBody instanceof Stream) {
+ ctx.body = rawBody;
+ } else {
+ ctx.body = rawBody.slice.apply(rawBody, args);
+ }
+
+ if (len !== '*') {
+ ctx.length = end - start + 1;
+ }
+};
+
+function rangeParse(str) {
+ var token = str.split('=');
+ if (!token || token.length != 2 || token[0] != 'bytes') {
+ return null;
+ }
+ return token[1].split(',')
+ .map(function(range) {
+ return range.split('-').map(function(value) {
+ if (value === '') {
+ return Infinity;
+ }
+ return Number(value);
+ });
+ })
+ .filter(function(range) {
+ return !isNaN(range[0]) && !isNaN(range[1]) && range[0] <= range[1];
+ });
+}
+
+function rangeContentGenerator(start, end, length) {
+ return util.format('bytes %d-%d/%s', start, end, length);
+}
diff --git a/node_modules/koa-range/package.json b/node_modules/koa-range/package.json
new file mode 100644
index 00000000..9e7733ae
--- /dev/null
+++ b/node_modules/koa-range/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "koa-range",
+ "version": "0.3.0",
+ "description": "range request implementation for koa",
+ "main": "index.js",
+ "scripts": {
+ "test": "make test"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:yorkie/koa-range.git"
+ },
+ "keywords": [
+ "range",
+ "koa",
+ "http"
+ ],
+ "author": "Yorkie Neil <yorkiefixer@gmail.com>",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/yorkie/koa-range/issues"
+ },
+ "homepage": "https://github.com/yorkie/koa-range",
+ "devDependencies": {
+ "istanbul": "^1.1.0-alpha.1",
+ "koa": "^2.0.0",
+ "koa-route": "^3.2.0",
+ "make-lint": "^1.0.1",
+ "mocha": "^2.4.5",
+ "should": "^8.2.2",
+ "supertest": "^0.13.0"
+ },
+ "dependencies": {
+ "stream-slice": "^0.1.2"
+ },
+ "engines" : {
+ "node" : ">=7"
+ }
+}
diff --git a/node_modules/koa-range/test/simple.js b/node_modules/koa-range/test/simple.js
new file mode 100644
index 00000000..de8feae7
--- /dev/null
+++ b/node_modules/koa-range/test/simple.js
@@ -0,0 +1,228 @@
+
+var fs = require('fs');
+var request = require('supertest');
+var should = require('should');
+var route = require('koa-route');
+var range = require('../');
+var Koa = require('koa');
+var app = new Koa();
+
+var rawbody = new Buffer(1024);
+var rawFileBuffer = fs.readFileSync('./README.md') + '';
+
+app.use(range);
+app.use(route.get('/', async function(ctx) {
+ ctx.body = rawbody;
+}));
+app.use(route.post('/', async function(ctx) {
+ ctx.status = 200;
+}));
+app.use(route.get('/json', async function(ctx) {
+ ctx.body = {foo:'bar'};
+}));
+app.use(route.get('/string', async function(ctx) {
+ ctx.body = 'koa-range';
+}));
+app.use(route.get('/stream', async function(ctx) {
+ ctx.body = fs.createReadStream('./README.md');
+}));
+app.use(route.get('/empty', async function(ctx) {
+ ctx.body = undefined;
+ ctx.status = 304;
+}));
+
+app.on('error', function(err) {
+ throw err;
+});
+
+describe('normal requests', function() {
+
+ it('should return 200 without range', function(done) {
+ request(app.listen())
+ .get('/')
+ .expect('Accept-Ranges', 'bytes')
+ .expect(200)
+ .end(done);
+ });
+
+ it('should return 200 when method not GET', function(done) {
+ request(app.listen())
+ .post('/')
+ .set('range', 'bytes=0-300')
+ .expect('Accept-Ranges', 'bytes')
+ .expect(200)
+ .end(done);
+ });
+
+});
+
+describe('range requests', function() {
+
+ it('should return 206 with partial content', function(done) {
+ request(app.listen())
+ .get('/')
+ .set('range', 'bytes=0-299')
+ .expect('Content-Length', '300')
+ .expect('Accept-Ranges', 'bytes')
+ .expect('Content-Range', 'bytes 0-299/1024')
+ .expect(206)
+ .end(done);
+ });
+
+ it('should return 400 with PUT', function(done) {
+ request(app.listen())
+ .put('/')
+ .set('range', 'bytes=0-299')
+ .expect('Accept-Ranges', 'bytes')
+ .expect(400)
+ .end(done);
+ });
+
+ it('should return 416 with invalid range', function(done) {
+ request(app.listen())
+ .get('/')
+ .set('range', 'bytes=400-300')
+ .expect('Accept-Ranges', 'bytes')
+ .expect(416)
+ .end(done);
+ });
+
+ it('should return 416 with invalid range', function(done) {
+ request(app.listen())
+ .get('/')
+ .set('range', 'bytes=x-300')
+ .expect('Accept-Ranges', 'bytes')
+ .expect(416)
+ .end(done);
+ });
+
+ it('should return 416 with invalid range', function(done) {
+ request(app.listen())
+ .get('/')
+ .set('range', 'bytes=400-x')
+ .expect('Accept-Ranges', 'bytes')
+ .expect(416)
+ .end(done);
+ });
+
+ it('should return 416 with invalid range', function(done) {
+ request(app.listen())
+ .get('/')
+ .set('range', 'bytes')
+ .expect('Accept-Ranges', 'bytes')
+ .expect(416)
+ .end(done);
+ });
+
+});
+
+describe('range requests with stream', function() {
+
+ it('should return 206 with partial content', function(done) {
+ request(app.listen())
+ .get('/stream')
+ .set('range', 'bytes=0-99')
+ .expect('Transfer-Encoding', 'chunked')
+ .expect('Accept-Ranges', 'bytes')
+ .expect('Content-Range', 'bytes 0-99/*')
+ .expect(206)
+ .end(function(err, res) {
+ should.not.exist(err);
+ res.text.should.equal(rawFileBuffer.slice(0, 100));
+ done();
+ });
+ });
+
+ it('should return 206 with open ended range', function(done) {
+ request(app.listen())
+ .get('/stream')
+ .set('range', 'bytes=0-')
+ .expect('Transfer-Encoding', 'chunked')
+ .expect(200)
+ .end(function(err, res) {
+ should.not.exist(err);
+ res.text.should.startWith(rawFileBuffer.slice(0, 300));
+ done();
+ });
+ });
+
+});
+
+describe('range requests with json', function() {
+
+ it('should return 206 with partial content', function(done) {
+ request(app.listen())
+ .get('/json')
+ .set('range', 'bytes=0-5')
+ .expect('Accept-Ranges', 'bytes')
+ .expect('Content-Range', 'bytes 0-5/13')
+ .expect('Content-Length', '6')
+ .expect(206)
+ .end(function(err, res) {
+ should.not.exist(err);
+ res.text.should.equal('{"foo"');
+ done();
+ });
+ });
+
+ it('should return 206 with single byte range', function(done) {
+ request(app.listen())
+ .get('/json')
+ .set('range', 'bytes=2-2')
+ .expect('Accept-Ranges', 'bytes')
+ .expect('Content-Range', 'bytes 2-2/13')
+ .expect('Content-Length', '1')
+ .expect(206)
+ .end(function(err, res) {
+ should.not.exist(err);
+ res.text.should.equal('f');
+ done();
+ });
+ });
+});
+
+describe('range requests with string', function() {
+
+ it('should return 206 with partial content', function(done) {
+ request(app.listen())
+ .get('/string')
+ .set('range', 'bytes=0-5')
+ .expect('Accept-Ranges', 'bytes')
+ .expect('Content-Range', 'bytes 0-5/9')
+ .expect('Content-Length', '6')
+ .expect(206)
+ .end(function(err, res) {
+ should.not.exist(err);
+ res.text.should.equal('koa-ra');
+ done();
+ });
+ });
+
+ it('should return 206 with open ended range', function(done) {
+ request(app.listen())
+ .get('/string')
+ .set('range', 'bytes=3-')
+ .expect('Accept-Ranges', 'bytes')
+ .expect('Content-Range', 'bytes 3-8/9')
+ .expect('Content-Length', '6')
+ .expect(206)
+ .end(function(err, res) {
+ should.not.exist(err);
+ res.text.should.equal('-range');
+ done();
+ });
+ });
+});
+
+describe('range requests with empty body', function() {
+ it('should return 304', function(done) {
+ request(app.listen())
+ .get('/empty')
+ .set('range', 'bytes=1-')
+ .expect(304)
+ .end(function(err, res) {
+ should.not.exist(err);
+ done();
+ });
+ });
+});