333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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);
}