123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- 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);
- }
|