@bepalo/spine 1.0.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -120
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/parsers.d.ts +74 -21
- package/dist/cjs/parsers.d.ts.map +1 -1
- package/dist/cjs/parsers.js +711 -436
- package/dist/cjs/parsers.js.map +1 -1
- package/dist/cjs/router copy.d.ts +124 -0
- package/dist/cjs/router copy.d.ts.map +1 -0
- package/dist/cjs/router copy.js +1394 -0
- package/dist/cjs/router copy.js.map +1 -0
- package/dist/cjs/router.d.ts.map +1 -1
- package/dist/cjs/router.js +65 -49
- package/dist/cjs/router.js.map +1 -1
- package/dist/cjs/types.d.ts +5 -1
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/parsers.d.ts +74 -21
- package/dist/parsers.d.ts.map +1 -1
- package/dist/parsers.js +711 -436
- package/dist/parsers.js.map +1 -1
- package/dist/router copy.d.ts +124 -0
- package/dist/router copy.d.ts.map +1 -0
- package/dist/router copy.js +1394 -0
- package/dist/router copy.js.map +1 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +65 -49
- package/dist/router.js.map +1 -1
- package/dist/types.d.ts +5 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/parsers.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.parseMultipart = exports.parseHeaders = exports.parseBody = exports.SUPPORTED_MEDIA_TYPES_LIST = exports.SUPPORTED_MEDIA_TYPES = exports.parseCookie = exports.parseCookieFromRequest = exports.parseQuery = void 0;
|
|
12
|
+
exports.parseUpload = exports.parseMultipart = exports.defaultFieldParser = exports.parseHeaders = exports.parseBody = exports.SUPPORTED_MEDIA_TYPES_LIST = exports.SUPPORTED_MEDIA_TYPES = exports.parseCookie = exports.parseCookieFromRequest = exports.parseQuery = void 0;
|
|
13
13
|
const rjson_1 = require("@bepalo/rjson");
|
|
14
14
|
const types_ts_1 = require("./types.js");
|
|
15
15
|
const helpers_ts_1 = require("./helpers.js");
|
|
@@ -438,6 +438,24 @@ const parseHeaders = (rawHeaders, contentDisposition) => {
|
|
|
438
438
|
return headers;
|
|
439
439
|
};
|
|
440
440
|
exports.parseHeaders = parseHeaders;
|
|
441
|
+
const defaultFieldParser = (field, contentType) => {
|
|
442
|
+
switch (contentType) {
|
|
443
|
+
case "application/x-www-form-urlencoded": {
|
|
444
|
+
const searchParams = new URLSearchParams(field);
|
|
445
|
+
const parsed = {};
|
|
446
|
+
for (const key of searchParams.keys()) {
|
|
447
|
+
parsed[key] = searchParams.get(key);
|
|
448
|
+
}
|
|
449
|
+
return parsed;
|
|
450
|
+
}
|
|
451
|
+
case "application/json":
|
|
452
|
+
return JSON.parse(field);
|
|
453
|
+
case "application/rjson":
|
|
454
|
+
return rjson_1.RJSON.parse(field);
|
|
455
|
+
}
|
|
456
|
+
return field;
|
|
457
|
+
};
|
|
458
|
+
exports.defaultFieldParser = defaultFieldParser;
|
|
441
459
|
var ParseMultipartState;
|
|
442
460
|
(function (ParseMultipartState) {
|
|
443
461
|
ParseMultipartState[ParseMultipartState["Initializing"] = 0] = "Initializing";
|
|
@@ -448,7 +466,7 @@ var ParseMultipartState;
|
|
|
448
466
|
ParseMultipartState[ParseMultipartState["ParsingChunk"] = 5] = "ParsingChunk";
|
|
449
467
|
ParseMultipartState[ParseMultipartState["Done"] = 6] = "Done";
|
|
450
468
|
})(ParseMultipartState || (ParseMultipartState = {}));
|
|
451
|
-
const parseMultipart = ({ idGenerator, onStart, onEnd, onHeader, onData,
|
|
469
|
+
const parseMultipart = ({ dontCatch, maxFields, maxFiles, maxFieldSize, maxFileSize, maxTotalSize, idGenerator, onStart, onEnd, onHeader, onData, onDataComplete, onFileLimit, onFieldLimit, onFileSizeLimit, onFieldSizeLimit, onTotalSizeLimit, }) => {
|
|
452
470
|
const prefix = new TextEncoder().encode("--");
|
|
453
471
|
const crlfPrefix = new TextEncoder().encode("\r\n--");
|
|
454
472
|
const endSuffix = new TextEncoder().encode("--");
|
|
@@ -459,81 +477,140 @@ const parseMultipart = ({ idGenerator, onStart, onEnd, onHeader, onData, onDataC
|
|
|
459
477
|
const { request } = ctx;
|
|
460
478
|
const headers = request.headers;
|
|
461
479
|
const contentTypeHedaer = (_a = headers.get("content-type")) === null || _a === void 0 ? void 0 : _a.trim();
|
|
462
|
-
let error;
|
|
463
480
|
let boundary = new Uint8Array();
|
|
464
481
|
let boundaryPre = new Uint8Array();
|
|
465
482
|
let boundaryPost = new Uint8Array();
|
|
483
|
+
// let error: HttpError | undefined;
|
|
466
484
|
let response = undefined;
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
(
|
|
485
|
+
try {
|
|
486
|
+
if (request.body == null) {
|
|
487
|
+
throw new types_ts_1.HttpError(400, "Empty body");
|
|
488
|
+
}
|
|
489
|
+
if (
|
|
490
|
+
// error == null &&
|
|
491
|
+
contentTypeHedaer == null ||
|
|
472
492
|
!(contentTypeHedaer.length === 19
|
|
473
493
|
? contentTypeHedaer.startsWith("multipart/form-data")
|
|
474
|
-
: contentTypeHedaer.startsWith("multipart/form-data;")))
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
if (error == null && contentTypeHedaer != null) {
|
|
478
|
-
const separatorIndex = contentTypeHedaer.indexOf(";");
|
|
479
|
-
const boundaryHeader = separatorIndex != -1 &&
|
|
480
|
-
contentTypeHedaer.substring(separatorIndex).trim();
|
|
481
|
-
const equalsIndex = boundaryHeader && boundaryHeader.indexOf("=");
|
|
482
|
-
const boundaryStr = equalsIndex &&
|
|
483
|
-
equalsIndex > -1 &&
|
|
484
|
-
boundaryHeader.substring(equalsIndex + 1).trim();
|
|
485
|
-
if (!boundaryStr) {
|
|
486
|
-
error = new types_ts_1.HttpError(415, "Invalid boundary");
|
|
494
|
+
: contentTypeHedaer.startsWith("multipart/form-data;"))) {
|
|
495
|
+
throw new types_ts_1.HttpError(415, "Invalid header");
|
|
487
496
|
}
|
|
488
|
-
|
|
489
|
-
const
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
497
|
+
if (contentTypeHedaer != null) {
|
|
498
|
+
const separatorIndex = contentTypeHedaer.indexOf(";");
|
|
499
|
+
const boundaryHeader = separatorIndex != -1 &&
|
|
500
|
+
contentTypeHedaer.substring(separatorIndex).trim();
|
|
501
|
+
const equalsIndex = boundaryHeader && boundaryHeader.indexOf("=");
|
|
502
|
+
const boundaryStr = equalsIndex &&
|
|
503
|
+
equalsIndex > -1 &&
|
|
504
|
+
boundaryHeader.substring(equalsIndex + 1).trim();
|
|
505
|
+
if (!boundaryStr) {
|
|
506
|
+
throw new types_ts_1.HttpError(415, "Invalid boundary");
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
const boundaryBytes = new TextEncoder().encode(boundaryStr);
|
|
510
|
+
const boundaryLen = boundaryBytes.length;
|
|
511
|
+
const crlfPrefixLen = crlfPrefix.length;
|
|
512
|
+
//
|
|
513
|
+
boundary = new Uint8Array(prefix.length + boundaryLen);
|
|
514
|
+
boundary.set(prefix, 0);
|
|
515
|
+
boundary.set(boundaryBytes, prefix.length);
|
|
516
|
+
//
|
|
517
|
+
boundaryPre = new Uint8Array(crlfPrefixLen + boundaryLen);
|
|
518
|
+
boundaryPre.set(crlfPrefix, 0);
|
|
519
|
+
boundaryPre.set(boundaryBytes, crlfPrefixLen);
|
|
520
|
+
//
|
|
521
|
+
boundaryPost = new Uint8Array(prefix.length + boundaryLen + crlf1.length);
|
|
522
|
+
boundaryPost.set(prefix, 0);
|
|
523
|
+
boundaryPost.set(boundaryBytes, prefix.length);
|
|
524
|
+
boundaryPost.set(crlf1, prefix.length + boundaryLen);
|
|
525
|
+
}
|
|
505
526
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
let
|
|
518
|
-
let
|
|
519
|
-
let
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
527
|
+
// initialize context
|
|
528
|
+
ctx.fields = new Map();
|
|
529
|
+
ctx.files = new Map();
|
|
530
|
+
////////////////////////
|
|
531
|
+
// intialize states
|
|
532
|
+
////////////////////////////
|
|
533
|
+
let initializationStepDone = false;
|
|
534
|
+
let activeHeaders = undefined;
|
|
535
|
+
let activeId = "";
|
|
536
|
+
let activeName = "";
|
|
537
|
+
let activeFilename = undefined;
|
|
538
|
+
let activeChunk = undefined;
|
|
539
|
+
let activeHeaderStart = -1;
|
|
540
|
+
let activeHeaderEnd = -1;
|
|
541
|
+
let activeBodyStart = -1;
|
|
542
|
+
let activeBodyEnd = -1;
|
|
543
|
+
let leftOverBoundary = undefined;
|
|
544
|
+
let leftOverHeader = undefined;
|
|
545
|
+
let expectBoundaryCRLF = 0;
|
|
546
|
+
let headersChunks = [];
|
|
547
|
+
let fileInfo = undefined;
|
|
548
|
+
let totalFields = 0;
|
|
549
|
+
let totalFiles = 0;
|
|
550
|
+
let activeFieldSize = 0;
|
|
551
|
+
let activeFileSize = 0;
|
|
552
|
+
let streamIsDone = false;
|
|
553
|
+
// start processing body as a stream of chunks
|
|
554
|
+
if (response == null && onStart != null) {
|
|
555
|
+
response = yield onStart(ctx);
|
|
556
|
+
}
|
|
557
|
+
if (response == null) {
|
|
558
|
+
const reader = request.body.getReader();
|
|
559
|
+
const crlf_len_1 = crlf2.length - 1;
|
|
560
|
+
let parserState = ParseMultipartState.Initializing;
|
|
561
|
+
let boundaryIdx = 0;
|
|
562
|
+
let crlfIdx = 0;
|
|
563
|
+
const getNextChunk = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
564
|
+
const { done, value } = yield reader.read();
|
|
565
|
+
if (done) {
|
|
566
|
+
streamIsDone = done;
|
|
567
|
+
}
|
|
568
|
+
return value;
|
|
569
|
+
});
|
|
570
|
+
// find boundary starting from offset and based on boundaryIdx previously set
|
|
571
|
+
const findBoundary = (chunk, boundary, offset = 0) => {
|
|
572
|
+
const boundary_len_1 = boundary.length - 1;
|
|
573
|
+
let i = 0;
|
|
574
|
+
let startIdx = -1;
|
|
575
|
+
let matching = false;
|
|
576
|
+
// check unfinished boundary
|
|
577
|
+
if (boundaryIdx > 0) {
|
|
578
|
+
for (i = offset; i < chunk.length; i++) {
|
|
579
|
+
if (chunk[i] === boundary[boundaryIdx]) {
|
|
580
|
+
if (!matching && boundaryIdx < boundary_len_1) {
|
|
581
|
+
matching = true;
|
|
582
|
+
startIdx = i;
|
|
583
|
+
}
|
|
584
|
+
else if (boundaryIdx === boundary_len_1) {
|
|
585
|
+
boundaryIdx = 0;
|
|
586
|
+
return [!matching ? 0 : startIdx, i + 1, true, false];
|
|
587
|
+
}
|
|
588
|
+
boundaryIdx++;
|
|
589
|
+
}
|
|
590
|
+
else if (matching) {
|
|
591
|
+
boundaryIdx = 0;
|
|
592
|
+
startIdx = -1;
|
|
593
|
+
matching = false;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
// boundary spans whole chunk
|
|
597
|
+
if (matching && i >= chunk.length) {
|
|
598
|
+
return [startIdx < 0 ? 0 : startIdx, -1, false, true];
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
boundaryIdx = 0;
|
|
602
|
+
matching = false;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
528
605
|
for (i = offset; i < chunk.length; i++) {
|
|
529
606
|
if (chunk[i] === boundary[boundaryIdx]) {
|
|
530
|
-
if (!matching
|
|
607
|
+
if (!matching) {
|
|
531
608
|
matching = true;
|
|
532
609
|
startIdx = i;
|
|
533
610
|
}
|
|
534
611
|
else if (boundaryIdx === boundary_len_1) {
|
|
535
612
|
boundaryIdx = 0;
|
|
536
|
-
return [
|
|
613
|
+
return [startIdx, i + 1, false, false];
|
|
537
614
|
}
|
|
538
615
|
boundaryIdx++;
|
|
539
616
|
}
|
|
@@ -543,50 +620,44 @@ const parseMultipart = ({ idGenerator, onStart, onEnd, onHeader, onData, onDataC
|
|
|
543
620
|
matching = false;
|
|
544
621
|
}
|
|
545
622
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
623
|
+
return [startIdx, -1, false, false];
|
|
624
|
+
};
|
|
625
|
+
// find \r\n\r\n starting from offset and based on crlfIdx previously set
|
|
626
|
+
const findCRLF = (chunk, offset = 0) => {
|
|
627
|
+
let i = 0;
|
|
628
|
+
let startIdx = -1;
|
|
629
|
+
let matching = false;
|
|
630
|
+
if (crlfIdx > 0) {
|
|
631
|
+
for (i = offset; i < chunk.length; i++) {
|
|
632
|
+
if (chunk[i] === crlf2[crlfIdx]) {
|
|
633
|
+
if (!matching && crlfIdx < crlf_len_1) {
|
|
634
|
+
matching = true;
|
|
635
|
+
startIdx = i;
|
|
636
|
+
}
|
|
637
|
+
else if (crlfIdx === crlf_len_1) {
|
|
638
|
+
crlfIdx = 0;
|
|
639
|
+
return [!matching ? 0 : startIdx, i + 1, true];
|
|
640
|
+
}
|
|
641
|
+
crlfIdx++;
|
|
642
|
+
}
|
|
643
|
+
else if (matching) {
|
|
644
|
+
crlfIdx = 0;
|
|
645
|
+
startIdx = -1;
|
|
646
|
+
matching = false;
|
|
647
|
+
}
|
|
564
648
|
}
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
else if (matching) {
|
|
568
|
-
boundaryIdx = 0;
|
|
569
|
-
startIdx = -1;
|
|
649
|
+
crlfIdx = 0;
|
|
570
650
|
matching = false;
|
|
571
651
|
}
|
|
572
|
-
}
|
|
573
|
-
return [startIdx, -1, false, false];
|
|
574
|
-
};
|
|
575
|
-
// find \r\n\r\n starting from offset and based on crlfIdx previously set
|
|
576
|
-
const findCRLF = (chunk, offset = 0) => {
|
|
577
|
-
let i = 0;
|
|
578
|
-
let startIdx = -1;
|
|
579
|
-
let matching = false;
|
|
580
|
-
if (crlfIdx > 0) {
|
|
581
652
|
for (i = offset; i < chunk.length; i++) {
|
|
582
653
|
if (chunk[i] === crlf2[crlfIdx]) {
|
|
583
|
-
if (!matching
|
|
654
|
+
if (!matching) {
|
|
584
655
|
matching = true;
|
|
585
656
|
startIdx = i;
|
|
586
657
|
}
|
|
587
658
|
else if (crlfIdx === crlf_len_1) {
|
|
588
659
|
crlfIdx = 0;
|
|
589
|
-
return [
|
|
660
|
+
return [startIdx, i + 1, false];
|
|
590
661
|
}
|
|
591
662
|
crlfIdx++;
|
|
592
663
|
}
|
|
@@ -596,143 +667,92 @@ const parseMultipart = ({ idGenerator, onStart, onEnd, onHeader, onData, onDataC
|
|
|
596
667
|
matching = false;
|
|
597
668
|
}
|
|
598
669
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
670
|
+
return [startIdx, -1, false];
|
|
671
|
+
};
|
|
672
|
+
// onData wrapper
|
|
673
|
+
const _onData = (ctx, chunk, info) => __awaiter(void 0, void 0, void 0, function* () {
|
|
674
|
+
let response = undefined;
|
|
675
|
+
const { file } = info;
|
|
676
|
+
if (file != null) {
|
|
677
|
+
file.size += chunk.length;
|
|
678
|
+
activeFileSize += chunk.length;
|
|
679
|
+
if (maxFileSize != null &&
|
|
680
|
+
((file.totalSize && file.totalSize > maxFileSize) ||
|
|
681
|
+
activeFileSize > maxFileSize)) {
|
|
682
|
+
if (onFileSizeLimit != null) {
|
|
683
|
+
response = yield onFileSizeLimit(ctx, info);
|
|
684
|
+
}
|
|
685
|
+
if (response == null) {
|
|
686
|
+
throw new types_ts_1.HttpError(413, "File too large");
|
|
687
|
+
// return undefined;
|
|
688
|
+
}
|
|
611
689
|
}
|
|
612
|
-
crlfIdx++;
|
|
613
690
|
}
|
|
614
|
-
else
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
let streamIsDone = false;
|
|
624
|
-
const getNextChunk = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
625
|
-
const { done, value } = yield reader.read();
|
|
626
|
-
if (done) {
|
|
627
|
-
streamIsDone = done;
|
|
628
|
-
}
|
|
629
|
-
return value;
|
|
630
|
-
});
|
|
631
|
-
////////////////////////////
|
|
632
|
-
let initializationStepDone = false;
|
|
633
|
-
let activeHeaders = undefined;
|
|
634
|
-
let activeId = "";
|
|
635
|
-
let activeName = "";
|
|
636
|
-
let activeFilename = undefined;
|
|
637
|
-
let activeChunk = undefined;
|
|
638
|
-
let activeHeaderStart = -1;
|
|
639
|
-
let activeHeaderEnd = -1;
|
|
640
|
-
let activeBodyStart = -1;
|
|
641
|
-
let activeBodyEnd = -1;
|
|
642
|
-
let leftOverBoundary = undefined;
|
|
643
|
-
let leftOverHeader = undefined;
|
|
644
|
-
let expectBoundaryCRLF = 0;
|
|
645
|
-
let headersChunks = [];
|
|
646
|
-
let fileInfo = undefined;
|
|
647
|
-
///////////////////////////////////////
|
|
648
|
-
away: while (parserState !== ParseMultipartState.Done) {
|
|
649
|
-
switch (parserState) {
|
|
650
|
-
case ParseMultipartState.Initializing: {
|
|
651
|
-
activeChunk = yield getNextChunk();
|
|
652
|
-
parserState = ParseMultipartState.FindingBoundary;
|
|
653
|
-
activeHeaderStart = -1;
|
|
654
|
-
activeHeaderEnd = -1;
|
|
655
|
-
activeBodyStart = -1;
|
|
656
|
-
activeBodyEnd = -1;
|
|
657
|
-
break;
|
|
658
|
-
}
|
|
659
|
-
case ParseMultipartState.FindingBoundary: {
|
|
660
|
-
if (activeChunk == null) {
|
|
661
|
-
if (!streamIsDone) {
|
|
662
|
-
error = new types_ts_1.HttpError(400, "Invalid body");
|
|
691
|
+
else {
|
|
692
|
+
activeFieldSize += chunk.length;
|
|
693
|
+
if (maxFieldSize != null && activeFieldSize > maxFieldSize) {
|
|
694
|
+
if (onFieldSizeLimit != null) {
|
|
695
|
+
response = yield onFieldSizeLimit(ctx, info);
|
|
696
|
+
}
|
|
697
|
+
if (response == null) {
|
|
698
|
+
throw new types_ts_1.HttpError(413, "Field too large");
|
|
699
|
+
// return undefined;
|
|
663
700
|
}
|
|
664
|
-
break away;
|
|
665
701
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
activeChunk[boundaryEnd + 1] === endSuffix[1]) ||
|
|
672
|
-
boundaryStart + 2 >= boundaryEnd)) {
|
|
673
|
-
break away;
|
|
702
|
+
}
|
|
703
|
+
if (maxTotalSize != null &&
|
|
704
|
+
activeFileSize + activeFieldSize > maxTotalSize) {
|
|
705
|
+
if (onTotalSizeLimit != null) {
|
|
706
|
+
response = yield onTotalSizeLimit(ctx, info);
|
|
674
707
|
}
|
|
675
|
-
if (
|
|
676
|
-
|
|
677
|
-
|
|
708
|
+
if (response == null) {
|
|
709
|
+
throw new types_ts_1.HttpError(413, "Payload too large");
|
|
710
|
+
// return undefined;
|
|
678
711
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
break away;
|
|
697
|
-
}
|
|
698
|
-
leftOverBoundary = undefined;
|
|
712
|
+
}
|
|
713
|
+
if (response == null) {
|
|
714
|
+
response = yield onData(ctx, chunk, info);
|
|
715
|
+
}
|
|
716
|
+
return response;
|
|
717
|
+
});
|
|
718
|
+
///////////////////////////////////////
|
|
719
|
+
away: while (parserState !== ParseMultipartState.Done) {
|
|
720
|
+
switch (parserState) {
|
|
721
|
+
case ParseMultipartState.Initializing: {
|
|
722
|
+
activeChunk = yield getNextChunk();
|
|
723
|
+
parserState = ParseMultipartState.FindingBoundary;
|
|
724
|
+
activeHeaderStart = -1;
|
|
725
|
+
activeHeaderEnd = -1;
|
|
726
|
+
activeBodyStart = -1;
|
|
727
|
+
activeBodyEnd = -1;
|
|
728
|
+
break;
|
|
699
729
|
}
|
|
700
|
-
|
|
701
|
-
if (
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
id: activeId,
|
|
705
|
-
name: activeName,
|
|
706
|
-
filename: activeFilename,
|
|
707
|
-
file: fileInfo,
|
|
708
|
-
});
|
|
709
|
-
if (response != null) {
|
|
710
|
-
break away;
|
|
730
|
+
case ParseMultipartState.FindingBoundary: {
|
|
731
|
+
if (activeChunk == null) {
|
|
732
|
+
if (!streamIsDone) {
|
|
733
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
711
734
|
}
|
|
735
|
+
break away;
|
|
712
736
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
activeBodyEnd = boundaryStart;
|
|
721
|
-
activeHeaderStart = boundaryEnd + 2;
|
|
722
|
-
}
|
|
723
|
-
// keep looking if not found
|
|
724
|
-
if (boundaryStart < 0) {
|
|
725
|
-
if (streamIsDone) {
|
|
726
|
-
error = new types_ts_1.HttpError(400, "Invalid body");
|
|
737
|
+
// find start boundary
|
|
738
|
+
const [boundaryStart, boundaryEnd, leftOverMatch, leftOverCompleteMatch,] = findBoundary(activeChunk, initializationStepDone ? boundaryPre : boundary, activeHeaderEnd < 0 ? 0 : activeHeaderEnd + 2);
|
|
739
|
+
if (streamIsDone &&
|
|
740
|
+
((boundaryEnd != -1 &&
|
|
741
|
+
activeChunk[boundaryEnd] === endSuffix[0] &&
|
|
742
|
+
activeChunk[boundaryEnd + 1] === endSuffix[1]) ||
|
|
743
|
+
boundaryStart + 2 >= boundaryEnd)) {
|
|
727
744
|
break away;
|
|
728
745
|
}
|
|
729
|
-
if (initializationStepDone &&
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
746
|
+
if (!initializationStepDone && boundaryStart < 0) {
|
|
747
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
748
|
+
// break away;
|
|
749
|
+
}
|
|
750
|
+
// check for leftOverBoundary
|
|
751
|
+
if (leftOverBoundary != null &&
|
|
752
|
+
!leftOverMatch &&
|
|
753
|
+
!leftOverCompleteMatch &&
|
|
754
|
+
boundaryIdx === 0) {
|
|
755
|
+
response = yield _onData(ctx, leftOverBoundary, {
|
|
736
756
|
headers: activeHeaders,
|
|
737
757
|
id: activeId,
|
|
738
758
|
name: activeName,
|
|
@@ -742,245 +762,317 @@ const parseMultipart = ({ idGenerator, onStart, onEnd, onHeader, onData, onDataC
|
|
|
742
762
|
if (response != null) {
|
|
743
763
|
break away;
|
|
744
764
|
}
|
|
765
|
+
leftOverBoundary = undefined;
|
|
745
766
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
767
|
+
else if (leftOverMatch) {
|
|
768
|
+
if (initializationStepDone && onDataComplete != null) {
|
|
769
|
+
response = yield onDataComplete(ctx, {
|
|
770
|
+
headers: activeHeaders,
|
|
771
|
+
id: activeId,
|
|
772
|
+
name: activeName,
|
|
773
|
+
filename: activeFilename,
|
|
774
|
+
file: fileInfo,
|
|
775
|
+
});
|
|
776
|
+
activeFilename = undefined;
|
|
777
|
+
if (response != null) {
|
|
778
|
+
break away;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
else if (initializationStepDone) {
|
|
782
|
+
activeFilename = undefined;
|
|
783
|
+
}
|
|
784
|
+
leftOverBoundary = undefined;
|
|
758
785
|
}
|
|
759
|
-
if (
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
newLeftOver.set(leftOverBoundary, 0);
|
|
763
|
-
newLeftOver.set(currentLeftOver, leftOverBoundary.length);
|
|
764
|
-
leftOverBoundary = newLeftOver;
|
|
786
|
+
if (leftOverCompleteMatch) {
|
|
787
|
+
activeBodyEnd = -1;
|
|
788
|
+
activeHeaderStart = -1;
|
|
765
789
|
}
|
|
766
790
|
else {
|
|
767
|
-
|
|
791
|
+
activeBodyEnd = boundaryStart;
|
|
792
|
+
activeHeaderStart = boundaryEnd + 2;
|
|
768
793
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
if (
|
|
772
|
-
|
|
794
|
+
// keep looking if not found
|
|
795
|
+
if (boundaryStart < 0) {
|
|
796
|
+
if (streamIsDone) {
|
|
797
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
798
|
+
// break away;
|
|
773
799
|
}
|
|
774
|
-
|
|
775
|
-
chunk,
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
800
|
+
if (initializationStepDone && activeBodyStart != -1) {
|
|
801
|
+
const chunk = activeChunk.subarray(activeBodyStart, activeChunk.length - boundaryIdx);
|
|
802
|
+
response = yield _onData(ctx, chunk, {
|
|
803
|
+
headers: activeHeaders,
|
|
804
|
+
id: activeId,
|
|
805
|
+
name: activeName,
|
|
806
|
+
filename: activeFilename,
|
|
807
|
+
file: fileInfo,
|
|
808
|
+
});
|
|
809
|
+
if (response != null) {
|
|
810
|
+
break away;
|
|
811
|
+
}
|
|
784
812
|
}
|
|
813
|
+
activeChunk = yield getNextChunk();
|
|
814
|
+
activeHeaderStart = -1;
|
|
815
|
+
activeHeaderEnd = -1;
|
|
816
|
+
activeBodyStart = 0;
|
|
817
|
+
activeBodyEnd = -1;
|
|
818
|
+
continue;
|
|
785
819
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
820
|
+
// keep looking for the boundaryEnd in the next chunk
|
|
821
|
+
if (boundaryEnd < 0) {
|
|
822
|
+
if (streamIsDone) {
|
|
823
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
824
|
+
// break away;
|
|
825
|
+
}
|
|
826
|
+
if (leftOverBoundary != null && boundaryStart !== -1) {
|
|
827
|
+
const currentLeftOver = activeChunk.subarray(boundaryStart, activeChunk.length - boundaryStart);
|
|
828
|
+
const newLeftOver = new Uint8Array(leftOverBoundary.length + currentLeftOver.length);
|
|
829
|
+
newLeftOver.set(leftOverBoundary, 0);
|
|
830
|
+
newLeftOver.set(currentLeftOver, leftOverBoundary.length);
|
|
831
|
+
leftOverBoundary = newLeftOver;
|
|
832
|
+
}
|
|
833
|
+
else {
|
|
834
|
+
leftOverBoundary = activeChunk.subarray(activeChunk.length - boundaryIdx);
|
|
835
|
+
}
|
|
836
|
+
if (!leftOverCompleteMatch && activeBodyEnd > 0) {
|
|
837
|
+
const chunk = activeChunk.subarray(activeBodyStart, activeBodyEnd);
|
|
838
|
+
response = yield _onData(ctx, chunk, {
|
|
839
|
+
headers: activeHeaders,
|
|
840
|
+
id: activeId,
|
|
841
|
+
name: activeName,
|
|
842
|
+
filename: activeFilename,
|
|
843
|
+
file: fileInfo,
|
|
844
|
+
});
|
|
845
|
+
if (response != null) {
|
|
846
|
+
break away;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
activeChunk = yield getNextChunk();
|
|
850
|
+
activeHeaderStart = -1;
|
|
851
|
+
activeHeaderEnd = -1;
|
|
852
|
+
activeBodyStart = 0;
|
|
853
|
+
activeBodyEnd = -1;
|
|
854
|
+
continue;
|
|
813
855
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
activeHeaderStart = expectBoundaryCRLF;
|
|
819
|
-
expectBoundaryCRLF = 0;
|
|
856
|
+
if (!leftOverCompleteMatch &&
|
|
857
|
+
boundaryEnd > activeChunk.length - crlf1.length) {
|
|
858
|
+
expectBoundaryCRLF =
|
|
859
|
+
crlf1.length - (activeChunk.length - boundaryEnd);
|
|
820
860
|
}
|
|
821
861
|
else {
|
|
822
|
-
|
|
862
|
+
expectBoundaryCRLF = 0;
|
|
823
863
|
}
|
|
864
|
+
parserState = initializationStepDone
|
|
865
|
+
? ParseMultipartState.ParsingChunk
|
|
866
|
+
: ParseMultipartState.FindingCRLF;
|
|
867
|
+
if (!initializationStepDone) {
|
|
868
|
+
initializationStepDone = true;
|
|
869
|
+
}
|
|
870
|
+
break;
|
|
824
871
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
leftOverHeader = undefined;
|
|
831
|
-
}
|
|
832
|
-
// keep looking if not found
|
|
833
|
-
if (crlfStart < 0) {
|
|
834
|
-
if (streamIsDone) {
|
|
835
|
-
error = new types_ts_1.HttpError(400, "Invalid body");
|
|
872
|
+
case ParseMultipartState.FindingCRLF: {
|
|
873
|
+
if (activeChunk == null) {
|
|
874
|
+
if (!streamIsDone) {
|
|
875
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
876
|
+
}
|
|
836
877
|
break away;
|
|
837
878
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
879
|
+
if (activeHeaderStart < 0) {
|
|
880
|
+
if (expectBoundaryCRLF > 0) {
|
|
881
|
+
activeHeaderStart = expectBoundaryCRLF;
|
|
882
|
+
expectBoundaryCRLF = 0;
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
activeHeaderStart = 0;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
// find crlf2
|
|
889
|
+
const [crlfStart, crlfEnd, leftOverHeaderMatch] = findCRLF(activeChunk, activeHeaderStart);
|
|
890
|
+
// check for leftOverHeader
|
|
891
|
+
if (leftOverHeader != null && !leftOverHeaderMatch) {
|
|
892
|
+
headersChunks.push(leftOverHeader);
|
|
893
|
+
leftOverHeader = undefined;
|
|
894
|
+
}
|
|
895
|
+
// keep looking if not found
|
|
896
|
+
if (crlfStart < 0) {
|
|
897
|
+
if (streamIsDone) {
|
|
898
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
899
|
+
break away;
|
|
900
|
+
}
|
|
901
|
+
const headerChunk = activeChunk.subarray(activeHeaderStart, activeChunk.length);
|
|
902
|
+
headersChunks.push(headerChunk);
|
|
903
|
+
activeChunk = yield getNextChunk();
|
|
904
|
+
activeHeaderStart = -1;
|
|
905
|
+
activeHeaderEnd = -1;
|
|
906
|
+
activeBodyStart = -1;
|
|
907
|
+
activeBodyEnd = -1;
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
activeHeaderEnd = crlfStart;
|
|
911
|
+
// keep looking for the crlfEnd in the next chunk
|
|
912
|
+
if (crlfEnd < 0) {
|
|
913
|
+
if (streamIsDone) {
|
|
914
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
915
|
+
// break away;
|
|
916
|
+
}
|
|
917
|
+
if (leftOverHeader != null) {
|
|
918
|
+
const currentLeftOver = activeChunk.subarray(activeHeaderEnd);
|
|
919
|
+
const newLeftOver = new Uint8Array(leftOverHeader.length + currentLeftOver.length);
|
|
920
|
+
newLeftOver.set(leftOverHeader, 0);
|
|
921
|
+
newLeftOver.set(currentLeftOver, leftOverHeader.length);
|
|
922
|
+
leftOverBoundary = newLeftOver;
|
|
923
|
+
}
|
|
924
|
+
else {
|
|
925
|
+
leftOverHeader = activeChunk.subarray(activeHeaderEnd);
|
|
926
|
+
}
|
|
927
|
+
const headerChunk = activeChunk.subarray(activeHeaderStart, activeHeaderEnd);
|
|
928
|
+
headersChunks.push(headerChunk);
|
|
929
|
+
activeChunk = yield getNextChunk();
|
|
930
|
+
activeHeaderStart = 0;
|
|
931
|
+
activeHeaderEnd = -1;
|
|
932
|
+
activeBodyStart = -1;
|
|
933
|
+
activeBodyEnd = -1;
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
activeBodyStart = crlfEnd;
|
|
937
|
+
if (activeHeaderStart != -1) {
|
|
938
|
+
const headerChunk = activeChunk.subarray(activeHeaderStart, activeHeaderEnd);
|
|
939
|
+
headersChunks.push(headerChunk);
|
|
940
|
+
}
|
|
941
|
+
parserState = ParseMultipartState.ParsingHeaders;
|
|
942
|
+
break;
|
|
846
943
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
944
|
+
case ParseMultipartState.ParsingHeaders: {
|
|
945
|
+
if (activeChunk == null) {
|
|
946
|
+
if (!streamIsDone) {
|
|
947
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
948
|
+
}
|
|
852
949
|
break away;
|
|
853
950
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
951
|
+
let buffer = headersChunks.length === 1 ? headersChunks[0] : undefined;
|
|
952
|
+
if (headersChunks.length > 1) {
|
|
953
|
+
let requiredSize = 0;
|
|
954
|
+
let bufferOffset = 0;
|
|
955
|
+
for (const headerChunk of headersChunks) {
|
|
956
|
+
requiredSize += headerChunk.length;
|
|
957
|
+
}
|
|
958
|
+
buffer = new Uint8Array(requiredSize);
|
|
959
|
+
for (const headerChunk of headersChunks) {
|
|
960
|
+
if (headerChunk.length === 0) {
|
|
961
|
+
continue;
|
|
962
|
+
}
|
|
963
|
+
buffer.set(headerChunk, bufferOffset);
|
|
964
|
+
bufferOffset += headerChunk.length;
|
|
965
|
+
}
|
|
860
966
|
}
|
|
861
|
-
|
|
862
|
-
|
|
967
|
+
headersChunks = [];
|
|
968
|
+
leftOverHeader = undefined;
|
|
969
|
+
const contentDisposition = {};
|
|
970
|
+
activeHeaders = (0, exports.parseHeaders)(new Uint8Array(buffer), contentDisposition);
|
|
971
|
+
if (contentDisposition["name"] == null) {
|
|
972
|
+
throw new types_ts_1.HttpError(400, "Invalid Content-Disposition header");
|
|
863
973
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
974
|
+
// intialize for formdata part
|
|
975
|
+
activeName = contentDisposition.name;
|
|
976
|
+
activeFilename = contentDisposition.filename;
|
|
977
|
+
activeId =
|
|
978
|
+
idGenerator != null
|
|
979
|
+
? idGenerator({
|
|
980
|
+
headers: activeHeaders,
|
|
981
|
+
name: activeName,
|
|
982
|
+
filename: activeFilename,
|
|
983
|
+
})
|
|
984
|
+
: (0, utils_ts_1.toBase64UUID)(crypto.randomUUID());
|
|
985
|
+
if (activeFilename != null) {
|
|
986
|
+
const contentTypeHeader = activeHeaders.get("content-type");
|
|
987
|
+
const contentLengthHeader = activeHeaders.get("content-length");
|
|
988
|
+
const size = 0;
|
|
989
|
+
const totalSize = contentLengthHeader
|
|
990
|
+
? parseInt(contentLengthHeader)
|
|
991
|
+
: null;
|
|
992
|
+
const type = (contentTypeHeader
|
|
993
|
+
? contentTypeHeader
|
|
994
|
+
: "application/octet-stream");
|
|
995
|
+
fileInfo = {
|
|
996
|
+
name: activeFilename,
|
|
997
|
+
size,
|
|
998
|
+
totalSize,
|
|
999
|
+
type,
|
|
1000
|
+
};
|
|
1001
|
+
ctx.files.set(activeId, fileInfo);
|
|
885
1002
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
let buffer = headersChunks.length === 1 ? headersChunks[0] : undefined;
|
|
889
|
-
if (headersChunks.length > 1) {
|
|
890
|
-
let requiredSize = 0;
|
|
891
|
-
let bufferOffset = 0;
|
|
892
|
-
for (const headerChunk of headersChunks) {
|
|
893
|
-
requiredSize += headerChunk.length;
|
|
1003
|
+
else {
|
|
1004
|
+
ctx.fields.set(activeName, null);
|
|
894
1005
|
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1006
|
+
// reset states
|
|
1007
|
+
activeFieldSize = 0;
|
|
1008
|
+
activeFileSize = 0;
|
|
1009
|
+
// update states
|
|
1010
|
+
if (activeFilename != null) {
|
|
1011
|
+
totalFiles++;
|
|
1012
|
+
if (maxFiles != null && totalFiles > maxFiles) {
|
|
1013
|
+
if (onFileLimit != null) {
|
|
1014
|
+
response = yield onFileLimit(ctx, {
|
|
1015
|
+
headers: activeHeaders,
|
|
1016
|
+
id: activeId,
|
|
1017
|
+
name: activeName,
|
|
1018
|
+
filename: activeFilename,
|
|
1019
|
+
file: fileInfo,
|
|
1020
|
+
});
|
|
1021
|
+
if (response != null) {
|
|
1022
|
+
break away;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
else {
|
|
1026
|
+
throw new types_ts_1.HttpError(413, "Too many files");
|
|
1027
|
+
break away;
|
|
1028
|
+
}
|
|
899
1029
|
}
|
|
900
|
-
buffer.set(headerChunk, bufferOffset);
|
|
901
|
-
bufferOffset += headerChunk.length;
|
|
902
1030
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1031
|
+
else {
|
|
1032
|
+
totalFields++;
|
|
1033
|
+
if (maxFields != null && totalFields > maxFields) {
|
|
1034
|
+
if (onFieldLimit != null) {
|
|
1035
|
+
response = yield onFieldLimit(ctx, {
|
|
1036
|
+
headers: activeHeaders,
|
|
1037
|
+
id: activeId,
|
|
1038
|
+
name: activeName,
|
|
1039
|
+
});
|
|
1040
|
+
if (response != null) {
|
|
1041
|
+
break away;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
throw new types_ts_1.HttpError(413, "Too many fields");
|
|
1046
|
+
break away;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
// invoke callback
|
|
1051
|
+
if (onHeader != null) {
|
|
1052
|
+
response = yield onHeader(ctx, {
|
|
917
1053
|
headers: activeHeaders,
|
|
1054
|
+
id: activeId,
|
|
918
1055
|
name: activeName,
|
|
919
1056
|
filename: activeFilename,
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const size = 0;
|
|
926
|
-
const totalSize = contentLengthHeader
|
|
927
|
-
? parseInt(contentLengthHeader)
|
|
928
|
-
: null;
|
|
929
|
-
const type = (contentTypeHeader
|
|
930
|
-
? contentTypeHeader
|
|
931
|
-
: "application/octet-stream");
|
|
932
|
-
fileInfo = {
|
|
933
|
-
name: activeFilename,
|
|
934
|
-
size,
|
|
935
|
-
totalSize,
|
|
936
|
-
type,
|
|
937
|
-
};
|
|
938
|
-
ctx.files.set(activeId, fileInfo);
|
|
939
|
-
}
|
|
940
|
-
else {
|
|
941
|
-
ctx.fields.set(activeName, null);
|
|
942
|
-
}
|
|
943
|
-
// invoke callback
|
|
944
|
-
if (onHeader != null) {
|
|
945
|
-
response = yield onHeader(ctx, {
|
|
946
|
-
headers: activeHeaders,
|
|
947
|
-
id: activeId,
|
|
948
|
-
name: activeName,
|
|
949
|
-
filename: activeFilename,
|
|
950
|
-
file: fileInfo,
|
|
951
|
-
});
|
|
952
|
-
if (response != null) {
|
|
953
|
-
break away;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
parserState = ParseMultipartState.FindingBoundary;
|
|
957
|
-
break;
|
|
958
|
-
}
|
|
959
|
-
case ParseMultipartState.ParsingChunk: {
|
|
960
|
-
if (activeChunk == null) {
|
|
961
|
-
if (!streamIsDone) {
|
|
962
|
-
error = new types_ts_1.HttpError(400, "Invalid body");
|
|
1057
|
+
file: fileInfo,
|
|
1058
|
+
});
|
|
1059
|
+
if (response != null) {
|
|
1060
|
+
break away;
|
|
1061
|
+
}
|
|
963
1062
|
}
|
|
964
|
-
|
|
1063
|
+
parserState = ParseMultipartState.FindingBoundary;
|
|
1064
|
+
break;
|
|
965
1065
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
response = yield onData(ctx, {
|
|
972
|
-
chunk,
|
|
973
|
-
headers: activeHeaders,
|
|
974
|
-
id: activeId,
|
|
975
|
-
name: activeName,
|
|
976
|
-
filename: activeFilename,
|
|
977
|
-
file: fileInfo,
|
|
978
|
-
});
|
|
979
|
-
if (response != null) {
|
|
1066
|
+
case ParseMultipartState.ParsingChunk: {
|
|
1067
|
+
if (activeChunk == null) {
|
|
1068
|
+
if (!streamIsDone) {
|
|
1069
|
+
throw new types_ts_1.HttpError(400, "Invalid body");
|
|
1070
|
+
}
|
|
980
1071
|
break away;
|
|
981
1072
|
}
|
|
982
|
-
if (
|
|
983
|
-
|
|
1073
|
+
if (activeBodyStart != -1 && activeBodyStart < activeBodyEnd) {
|
|
1074
|
+
const chunk = activeChunk.subarray(activeBodyStart, activeBodyEnd);
|
|
1075
|
+
response = yield _onData(ctx, chunk, {
|
|
984
1076
|
headers: activeHeaders,
|
|
985
1077
|
id: activeId,
|
|
986
1078
|
name: activeName,
|
|
@@ -990,19 +1082,53 @@ const parseMultipart = ({ idGenerator, onStart, onEnd, onHeader, onData, onDataC
|
|
|
990
1082
|
if (response != null) {
|
|
991
1083
|
break away;
|
|
992
1084
|
}
|
|
1085
|
+
if (onDataComplete != null) {
|
|
1086
|
+
response = yield onDataComplete(ctx, {
|
|
1087
|
+
headers: activeHeaders,
|
|
1088
|
+
id: activeId,
|
|
1089
|
+
name: activeName,
|
|
1090
|
+
filename: activeFilename,
|
|
1091
|
+
file: fileInfo,
|
|
1092
|
+
});
|
|
1093
|
+
activeFilename = undefined;
|
|
1094
|
+
if (response != null) {
|
|
1095
|
+
break away;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1099
|
+
activeFilename = undefined;
|
|
1100
|
+
}
|
|
993
1101
|
}
|
|
1102
|
+
parserState = ParseMultipartState.FindingCRLF;
|
|
1103
|
+
break;
|
|
994
1104
|
}
|
|
995
|
-
parserState = ParseMultipartState.FindingCRLF;
|
|
996
|
-
break;
|
|
997
1105
|
}
|
|
998
1106
|
}
|
|
999
1107
|
}
|
|
1000
1108
|
}
|
|
1001
|
-
|
|
1109
|
+
catch (_error) {
|
|
1110
|
+
if (dontCatch) {
|
|
1111
|
+
throw _error;
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
const error = _error instanceof Error ? _error : new Error(String(_error));
|
|
1115
|
+
// handle error and return a response
|
|
1116
|
+
if (onEnd != null) {
|
|
1117
|
+
response = yield onEnd(ctx, {
|
|
1118
|
+
success: false,
|
|
1119
|
+
error,
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
return response instanceof Response
|
|
1123
|
+
? response
|
|
1124
|
+
: (0, helpers_ts_1.status)(error.status || 500, error.message);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
// handle complete and return a response
|
|
1002
1128
|
if (onEnd != null) {
|
|
1129
|
+
const status = response instanceof Response ? response.status : 200;
|
|
1003
1130
|
response = yield onEnd(ctx, {
|
|
1004
|
-
success:
|
|
1005
|
-
error,
|
|
1131
|
+
success: status >= 200 && status < 400,
|
|
1006
1132
|
});
|
|
1007
1133
|
}
|
|
1008
1134
|
if (response instanceof Response) {
|
|
@@ -1014,8 +1140,157 @@ const parseMultipart = ({ idGenerator, onStart, onEnd, onHeader, onData, onDataC
|
|
|
1014
1140
|
else if (response === types_ts_1.Break_Pipeline) {
|
|
1015
1141
|
return types_ts_1.Break_Pipeline;
|
|
1016
1142
|
}
|
|
1017
|
-
return
|
|
1143
|
+
return (0, helpers_ts_1.status)(200);
|
|
1018
1144
|
});
|
|
1019
1145
|
};
|
|
1020
1146
|
exports.parseMultipart = parseMultipart;
|
|
1147
|
+
const parseUpload = ({ path, fileHandle, write, end, parseField = exports.defaultFieldParser, dontCatch, maxFields, maxFiles, maxFieldSize, maxFileSize, maxTotalSize, progressIncrement = 10, idGenerator, onStart, onEnd, onHeader, onFieldHeader, onFileHeader, onFileData, onFileDataSpy, onFieldData, onFieldDataSpy, onFileProgress, onFieldComplete, onFileComplete, onComplete, onFileLimit, onFieldLimit, onFileSizeLimit, onFieldSizeLimit, onTotalSizeLimit, }) => {
|
|
1148
|
+
const getUploadPath = (id, file) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1149
|
+
return typeof path === "function"
|
|
1150
|
+
? yield path(id, file)
|
|
1151
|
+
: path + "/" + id + file.name.substring(file.name.lastIndexOf("."));
|
|
1152
|
+
});
|
|
1153
|
+
return (0, exports.parseMultipart)({
|
|
1154
|
+
maxFields,
|
|
1155
|
+
maxFiles,
|
|
1156
|
+
maxFieldSize,
|
|
1157
|
+
maxFileSize,
|
|
1158
|
+
maxTotalSize,
|
|
1159
|
+
idGenerator,
|
|
1160
|
+
onHeader: (ctx, info) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1161
|
+
let response = undefined;
|
|
1162
|
+
if (info.file) {
|
|
1163
|
+
const { id, file } = info;
|
|
1164
|
+
const uploadPath = yield getUploadPath(id, file);
|
|
1165
|
+
file.fullpath = uploadPath;
|
|
1166
|
+
file.handle = yield fileHandle(uploadPath);
|
|
1167
|
+
file.totalChunks = 0;
|
|
1168
|
+
file._prevProgress = 0;
|
|
1169
|
+
file.progress = 0;
|
|
1170
|
+
if (onFileHeader != null) {
|
|
1171
|
+
response = yield onFileHeader(ctx, info);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
const { name } = info;
|
|
1176
|
+
ctx.fields.set(name, "");
|
|
1177
|
+
if (onFieldHeader != null) {
|
|
1178
|
+
response = yield onFieldHeader(ctx, info);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
if (onHeader != null) {
|
|
1182
|
+
response = yield onHeader(ctx, info);
|
|
1183
|
+
}
|
|
1184
|
+
return response;
|
|
1185
|
+
}),
|
|
1186
|
+
onData: (ctx, chunk, info) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1187
|
+
if (info.file != null) {
|
|
1188
|
+
const { file } = info;
|
|
1189
|
+
file.totalChunks++;
|
|
1190
|
+
if (onFileProgress != null &&
|
|
1191
|
+
progressIncrement != null &&
|
|
1192
|
+
progressIncrement > 0) {
|
|
1193
|
+
if (file.totalSize) {
|
|
1194
|
+
const progress = (file.size / file.totalSize) * 100;
|
|
1195
|
+
const truncProgress = Math.trunc(progress / progressIncrement);
|
|
1196
|
+
if (truncProgress > file._prevProgress) {
|
|
1197
|
+
file.progress = progress;
|
|
1198
|
+
yield onFileProgress(ctx, info);
|
|
1199
|
+
file._prevProgress = truncProgress;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
if (onFileDataSpy != null) {
|
|
1204
|
+
const response = yield onFileDataSpy(ctx, chunk, info);
|
|
1205
|
+
if (response != null) {
|
|
1206
|
+
return response;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
if (onFileData != null) {
|
|
1210
|
+
return yield onFileData(ctx, chunk, info);
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
yield write(info.file, chunk, info);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
const { name } = info;
|
|
1218
|
+
if (onFieldDataSpy != null) {
|
|
1219
|
+
const response = yield onFieldDataSpy(ctx, chunk, info);
|
|
1220
|
+
if (response != null) {
|
|
1221
|
+
return response;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (onFieldData != null) {
|
|
1225
|
+
return yield onFieldData(ctx, chunk, info);
|
|
1226
|
+
}
|
|
1227
|
+
else {
|
|
1228
|
+
ctx.fields.set(name, ctx.fields.get(name) + new TextDecoder().decode(chunk));
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
}),
|
|
1232
|
+
onDataComplete: (ctx, info) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1233
|
+
let response = undefined;
|
|
1234
|
+
if (info.file) {
|
|
1235
|
+
if (end != null) {
|
|
1236
|
+
yield end(info.file, true, info);
|
|
1237
|
+
}
|
|
1238
|
+
if (onFileComplete != null) {
|
|
1239
|
+
response = yield onFileComplete(ctx, info);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
else {
|
|
1243
|
+
const { name, headers } = info;
|
|
1244
|
+
// parse field
|
|
1245
|
+
if (parseField != null) {
|
|
1246
|
+
const contentTypeHeader = headers.get("content-type");
|
|
1247
|
+
const field = ctx.fields.get(name);
|
|
1248
|
+
const contentType = contentTypeHeader
|
|
1249
|
+
? contentTypeHeader.split(";", 2)[0]
|
|
1250
|
+
: undefined;
|
|
1251
|
+
const parsed = yield parseField(field, contentType);
|
|
1252
|
+
ctx.fields.set(name, parsed);
|
|
1253
|
+
}
|
|
1254
|
+
if (onFieldComplete != null) {
|
|
1255
|
+
const field = ctx.fields.get(name);
|
|
1256
|
+
response = yield onFieldComplete(ctx, Object.assign(Object.assign({}, info), { field }));
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
if (onComplete != null) {
|
|
1260
|
+
response = yield onComplete(ctx, info);
|
|
1261
|
+
}
|
|
1262
|
+
return response;
|
|
1263
|
+
}),
|
|
1264
|
+
onStart: (ctx) => {
|
|
1265
|
+
if (onStart != null) {
|
|
1266
|
+
return onStart(ctx);
|
|
1267
|
+
}
|
|
1268
|
+
},
|
|
1269
|
+
onEnd: (ctx, info) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1270
|
+
var _a;
|
|
1271
|
+
if (onEnd != null) {
|
|
1272
|
+
return yield onEnd(ctx, info);
|
|
1273
|
+
}
|
|
1274
|
+
if (!info.success) {
|
|
1275
|
+
// console.error("[Upload](onEnd)", info.error);
|
|
1276
|
+
return (0, helpers_ts_1.status)(500, ((_a = info.error) === null || _a === void 0 ? void 0 : _a.message) || "Error while parsing upload");
|
|
1277
|
+
}
|
|
1278
|
+
return (0, helpers_ts_1.status)(200);
|
|
1279
|
+
}),
|
|
1280
|
+
onFileSizeLimit: (ctx, info) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1281
|
+
if (end != null) {
|
|
1282
|
+
yield end(info.file, false, info);
|
|
1283
|
+
}
|
|
1284
|
+
if (onFileSizeLimit != null) {
|
|
1285
|
+
return yield onFileSizeLimit(ctx, info);
|
|
1286
|
+
}
|
|
1287
|
+
}),
|
|
1288
|
+
dontCatch,
|
|
1289
|
+
onFileLimit,
|
|
1290
|
+
onFieldLimit,
|
|
1291
|
+
onFieldSizeLimit,
|
|
1292
|
+
onTotalSizeLimit,
|
|
1293
|
+
});
|
|
1294
|
+
};
|
|
1295
|
+
exports.parseUpload = parseUpload;
|
|
1021
1296
|
//# sourceMappingURL=parsers.js.map
|