2025-10-01 19:55:38 +02:00

250 lines
13 KiB
JavaScript

"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var WebDAVRequest_1 = require("../WebDAVRequest");
var stream_1 = require("stream");
var RangedStream = /** @class */ (function (_super) {
__extends(RangedStream, _super);
function RangedStream(min, max) {
var _this = _super.call(this) || this;
_this.min = min;
_this.max = max;
_this.nb = 0;
return _this;
}
RangedStream.prototype._transform = function (chunk, encoding, callback) {
if (this.nb < this.min) {
var lastNb = this.nb;
this.nb += chunk.length;
if (this.nb > this.min) {
var start = this.min - lastNb;
chunk = chunk.slice(start, this.nb > this.max ? this.max - this.min + 1 + start : undefined);
callback(null, chunk);
}
else
callback(null, Buffer.alloc(0));
}
else if (this.nb > this.max) {
this.nb += chunk.length;
callback(null, Buffer.alloc(0));
}
else {
this.nb += chunk.length;
if (this.nb > this.max)
chunk = chunk.slice(0, this.max - (this.nb - chunk.length) + 1);
callback(null, chunk);
}
};
return RangedStream;
}(stream_1.Transform));
var MultipleRangedStream = /** @class */ (function (_super) {
__extends(MultipleRangedStream, _super);
function MultipleRangedStream(ranges) {
var _this = _super.call(this) || this;
_this.ranges = ranges;
_this.streams = ranges.map(function (r) {
return {
stream: new RangedStream(r.min, r.max),
range: r
};
});
return _this;
}
MultipleRangedStream.prototype._transform = function (chunk, encoding, callback) {
this.streams.forEach(function (streamRange) {
streamRange.stream.write(chunk, encoding);
});
callback(null, Buffer.alloc(0));
};
MultipleRangedStream.prototype.end = function (chunk, encoding, cb) {
var _this = this;
if (this.onEnded)
process.nextTick(function () { return _this.onEnded(); });
_super.prototype.end.call(this, chunk, encoding, cb);
};
return MultipleRangedStream;
}(stream_1.Transform));
function parseRangeHeader(mimeType, size, range) {
var separator = Array.apply(null, { length: 20 })
.map(function () { return String.fromCharCode('a'.charCodeAt(0) + Math.floor(Math.random() * 26)); })
.join('');
var createMultipart = function (range) {
return "--" + separator + "\r\nContent-Type: " + mimeType + "\r\nContent-Range: bytes " + range.min + "-" + range.max + "/*\r\n\r\n";
};
var endMultipart = function () {
return "\r\n--" + separator + "--";
};
var ranges = range
.split(',')
.map(function (block) { return parseRangeBlock(size, block); });
var len = ranges.reduce(function (previous, mm) { return mm.max - mm.min + 1 + previous; }, 0)
+ (ranges.length <= 1 ?
0 : ranges.reduce(function (previous, mm) { return createMultipart(mm).length + previous; }, endMultipart().length + '\r\n'.length * (ranges.length - 1)));
return {
ranges: ranges,
separator: separator,
len: len,
createMultipart: createMultipart,
endMultipart: endMultipart
};
}
exports.parseRangeHeader = parseRangeHeader;
function parseRangeBlock(size, block) {
size -= 1;
var rRange = /([0-9]+)-([0-9]+)/;
var match = rRange.exec(block);
if (match)
return {
min: Math.min(size, parseInt(match[1], 10)),
max: Math.min(size, parseInt(match[2], 10))
};
var rStart = /([0-9]+)-/;
match = rStart.exec(block);
if (match)
return {
min: Math.min(size + 1, parseInt(match[1], 10)),
max: size
};
var rEnd = /-([0-9]+)/;
match = rEnd.exec(block);
if (match)
return {
min: Math.max(0, size - parseInt(match[1], 10) + 1),
max: size
};
throw new Error('Cannot parse the range block');
}
var default_1 = /** @class */ (function () {
function default_1() {
}
default_1.prototype.unchunked = function (ctx, data, callback) {
ctx.noBodyExpected(function () {
ctx.getResource(function (e, r) {
ctx.checkIfHeader(r, function () {
var targetSource = ctx.headers.isSource;
//ctx.requirePrivilegeEx(targetSource ? [ 'canRead', 'canSource', 'canGetMimeType' ] : [ 'canRead', 'canGetMimeType' ], () => {
r.type(function (e, type) {
if (e) {
if (!ctx.setCodeFromError(e))
ctx.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError);
return callback();
}
if (!type.isFile) {
ctx.setCode(WebDAVRequest_1.HTTPCodes.MethodNotAllowed);
return callback();
}
var range = ctx.headers.find('Range');
r.size(targetSource, function (e, size) { return process.nextTick(function () {
if (e && !range) {
if (!ctx.setCodeFromError(e))
ctx.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError);
return callback();
}
r.mimeType(targetSource, function (e, mimeType) { return process.nextTick(function () {
if (e) {
if (!ctx.setCodeFromError(e))
ctx.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError);
return callback();
}
r.openReadStream(targetSource, function (e, rstream) {
if (e) {
if (!ctx.setCodeFromError(e))
ctx.setCode(WebDAVRequest_1.HTTPCodes.MethodNotAllowed);
return callback();
}
//ctx.invokeEvent('read', r);
rstream.on('error', function (e) {
if (!ctx.setCodeFromError(e))
ctx.setCode(WebDAVRequest_1.HTTPCodes.InternalServerError);
return callback();
});
if (range) {
try {
var _a = parseRangeHeader(mimeType, size, range), ranges_1 = _a.ranges, separator = _a.separator, len = _a.len, createMultipart_1 = _a.createMultipart, endMultipart_1 = _a.endMultipart;
ctx.setCode(WebDAVRequest_1.HTTPCodes.PartialContent);
ctx.response.setHeader('Accept-Ranges', 'bytes');
ctx.response.setHeader('Content-Length', len.toString());
if (ranges_1.length <= 1) {
ctx.response.setHeader('Content-Type', mimeType);
ctx.response.setHeader('Content-Range', "bytes " + ranges_1[0].min + "-" + ranges_1[0].max + "/*");
rstream.on('end', callback);
return rstream.pipe(new RangedStream(ranges_1[0].min, ranges_1[0].max)).pipe(ctx.response);
}
ctx.response.setHeader('Content-Type', "multipart/byteranges; boundary=" + separator);
var multi_1 = new MultipleRangedStream(ranges_1);
rstream.pipe(multi_1);
var current_1 = 0;
var dones_1 = {};
var evalNext_1 = function () {
if (current_1 === ranges_1.length) {
return ctx.response.end(endMultipart_1(), function () {
callback();
});
}
var sr = dones_1[current_1];
if (sr) {
if (current_1 > 0)
ctx.response.write('\r\n');
ctx.response.write(createMultipart_1(sr.range));
sr.stream.on('end', function () {
++current_1;
evalNext_1();
});
sr.stream.on('data', function (chunk, encoding) {
ctx.response.write(chunk, encoding);
});
//sr.stream.pipe(ctx.response);
}
};
multi_1.streams.forEach(function (sr, index) {
dones_1[index] = sr;
});
multi_1.onEnded = function () {
multi_1.streams.forEach(function (sr, index) {
sr.stream.end();
});
evalNext_1();
};
}
catch (ex) {
ctx.setCode(WebDAVRequest_1.HTTPCodes.BadRequest);
callback();
}
}
else {
ctx.setCode(WebDAVRequest_1.HTTPCodes.OK);
ctx.response.setHeader('Accept-Ranges', 'bytes');
ctx.response.setHeader('Content-Type', mimeType);
if (size !== null && size !== undefined && size > -1)
ctx.response.setHeader('Content-Length', size.toString());
rstream.on('end', callback);
rstream.pipe(ctx.response);
}
});
}); });
}); });
});
//})
});
});
});
};
default_1.prototype.isValidFor = function (ctx, type) {
return type && type.isFile;
};
return default_1;
}());
exports.default = default_1;