四好公路
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

105 lines
2.3 KiB

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