"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;