node-web-mvc
Version:
node spring mvc
155 lines (154 loc) • 5.82 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const crypto_1 = require("crypto");
const MediaType_1 = __importDefault(require("../MediaType"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const MultipartFile_1 = __importDefault(require("../MultipartFile"));
const EntityTooLargeError_1 = __importDefault(require("../../../errors/EntityTooLargeError"));
class MultipartSubpart {
get currentBuffer() {
return Buffer.from(this.raw);
}
constructor(boundary, config, raw) {
this.boundary = boundary;
this.headers = {};
this.raw = raw || [];
this.tempRaw = [];
this.size = 0;
this.status = 'boundary';
this.mediaRoot = config.mediaRoot;
this.maxFileSize = Number(config.maxFileSize);
this.chunkSize = Math.max(8192, boundary.length + 10);
}
read(code) {
const raw = this.raw;
const isCRLF = code == 10 && this.previousCode == 13;
this.previousCode = code;
switch (this.status) {
case 'body':
if (isCRLF && !this.needTryBoundary) {
// 在读取subaprt的body时,如果碰到\r\n 则需要进入边界检测
this.needTryBoundary = true;
// 移除最后已经读取的\r
this.tempRaw.pop();
// 将已经读取内容写出
this.tryWrite();
// 返回true 继续读取下个字节
return true;
}
this.tempRaw.push(code);
if (this.tempRaw.length > this.chunkSize) {
this.tryWrite();
}
// 根据读取进度检查边界
return this.checkBoundary();
default:
raw.push(code);
// 如果是读取header部分,碰到\r\n则进入下一个内容读取
if (isCRLF) {
// 这里需要把最后已经读取的\r\n移除
raw.pop();
raw.pop();
}
return !isCRLF;
}
}
finish(encoding) {
if (this.writter) {
const tempPath = this.writter.path.toString();
const promise = new Promise((resolve) => {
this.writter.end(resolve);
});
return {
content: new MultipartFile_1.default(this.filename, tempPath, this.mediaType, this.size, this.mediaRoot),
promise: promise,
};
}
else {
return {
content: this.currentBuffer.toString(encoding),
promise: null,
};
}
}
clearBuffer() {
this.raw.length = 0;
}
checkBoundary() {
const raw = this.tempRaw;
if (this.needTryBoundary && raw.length == this.boundary.length) {
this.needTryBoundary = false;
// 检测是否为结束或者开始boundary
const str = Buffer.from(raw).toString();
if (str == this.boundary) {
// 如果时边界,则返回停止读取,进入结束流程
return false;
}
// 如果不是边界,则需要把\r\n补充
raw.unshift(10);
raw.unshift(13);
}
// 返回继续读取
return true;
}
tryWrite() {
const tempRaw = this.tempRaw;
if (this.writter) {
const buffer = Buffer.from(tempRaw);
this.size = this.size + buffer.length;
if (this.size > this.maxFileSize) {
this.writter.end();
fs_1.default.unlinkSync(this.writter.path);
throw new EntityTooLargeError_1.default(this.filename, this.size, this.maxFileSize);
}
this.writter.write(buffer);
}
else {
this.raw.push(...tempRaw);
}
this.tempRaw.length = 0;
}
parseContentDisposition(content) {
const segments = content.split(';');
const info = {};
segments.forEach((segment) => {
const [k, v] = segment.trim().split('=');
info[k] = v ? v.slice(1, v.length - 1) : '';
});
return info;
}
parseSubpartHeader(content) {
var _a;
if (!content) {
const tempRoot = path_1.default.join(this.mediaRoot, 'tmp-files');
MultipartFile_1.default.ensureDirSync(tempRoot);
this.writter = this.isFile ? fs_1.default.createWriteStream(path_1.default.join(tempRoot, (0, crypto_1.randomUUID)())) : undefined;
return false;
}
const [keyName, value] = content.split(':');
const key = keyName.trim();
switch (key.toLowerCase()) {
case 'content-disposition':
{
const s = this.parseContentDisposition(value || '');
this.name = s.name;
this.isFile = 'filename' in s;
this.filename = s.filename;
this.headers[key] = value;
}
break;
case 'content-type':
this.mediaType = new MediaType_1.default((_a = value === null || value === void 0 ? void 0 : value.trim) === null || _a === void 0 ? void 0 : _a.call(value));
this.headers[key] = value;
break;
default:
this.headers[key] = value;
}
return true;
}
}
exports.default = MultipartSubpart;