velocious 1.0.677 → 1.0.679
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 +8 -1
- package/build/configuration-types.js +22 -0
- package/build/configuration.js +42 -0
- package/build/http-server/client/request-buffer/index.js +59 -7
- package/build/http-server/client/request.js +5 -0
- package/build/src/configuration-types.d.ts +57 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +19 -1
- package/build/src/configuration.d.ts +8 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +36 -1
- package/build/src/http-server/client/request-buffer/index.d.ts +12 -2
- package/build/src/http-server/client/request-buffer/index.d.ts.map +1 -1
- package/build/src/http-server/client/request-buffer/index.js +59 -8
- package/build/src/http-server/client/request.d.ts +5 -0
- package/build/src/http-server/client/request.d.ts.map +1 -1
- package/build/src/http-server/client/request.js +6 -1
- package/package.json +3 -3
- package/src/configuration-types.js +22 -0
- package/src/configuration.js +42 -0
- package/src/http-server/client/request-buffer/index.js +59 -7
- package/src/http-server/client/request.js +5 -0
|
@@ -31,6 +31,14 @@ function truncatePreview(input, limit = 300) {
|
|
|
31
31
|
export default class RequestBuffer {
|
|
32
32
|
bodyLength = 0
|
|
33
33
|
|
|
34
|
+
/** @type {import("../../../configuration-types.js").ResolvedHttpRequestBodyPolicy | undefined} */
|
|
35
|
+
requestBodyPolicy = undefined
|
|
36
|
+
|
|
37
|
+
/** @type {Buffer | undefined} */
|
|
38
|
+
rawBodyBuffer = undefined
|
|
39
|
+
|
|
40
|
+
destroyed = false
|
|
41
|
+
|
|
34
42
|
/** @type {Buffer[] | undefined} */
|
|
35
43
|
postBodyBuffers = undefined
|
|
36
44
|
|
|
@@ -73,7 +81,7 @@ export default class RequestBuffer {
|
|
|
73
81
|
* @returns {void}
|
|
74
82
|
*/
|
|
75
83
|
assertRequestBodySize(actualBytes) {
|
|
76
|
-
const maxBytes = this.configuration.getHttpServerMaxRequestBodyBytes()
|
|
84
|
+
const maxBytes = this.requestBodyPolicy?.maxRequestBodyBytes ?? this.configuration.getHttpServerMaxRequestBodyBytes()
|
|
77
85
|
|
|
78
86
|
if (maxBytes !== undefined && actualBytes > maxBytes) {
|
|
79
87
|
throw new HttpRequestBodyTooLargeError({actualBytes, maxBytes})
|
|
@@ -93,7 +101,25 @@ export default class RequestBuffer {
|
|
|
93
101
|
}
|
|
94
102
|
|
|
95
103
|
destroy() {
|
|
96
|
-
|
|
104
|
+
this.destroyed = true
|
|
105
|
+
this.rawBodyBuffer = undefined
|
|
106
|
+
this.postBody = undefined
|
|
107
|
+
this.postBodyBuffers = undefined
|
|
108
|
+
this.chunkedBodyChars = undefined
|
|
109
|
+
this.data = []
|
|
110
|
+
this.formDataPart = undefined
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Returns exact request body bytes for a completed request whose policy selected raw mode.
|
|
115
|
+
* @returns {Buffer} - A copy of the exact request body bytes.
|
|
116
|
+
*/
|
|
117
|
+
getRawBody() {
|
|
118
|
+
if (this.destroyed) throw new Error("Raw request body is unavailable after request cleanup")
|
|
119
|
+
if (this.requestBodyPolicy?.mode !== "raw") throw new Error("Raw request body is available only when the request body policy selects raw mode")
|
|
120
|
+
if (!this.completed || !this.rawBodyBuffer) throw new Error("Raw request body is unavailable before request parsing completes")
|
|
121
|
+
|
|
122
|
+
return Buffer.from(this.rawBodyBuffer)
|
|
97
123
|
}
|
|
98
124
|
|
|
99
125
|
/**
|
|
@@ -210,6 +236,7 @@ export default class RequestBuffer {
|
|
|
210
236
|
if (this.currentChunkSize === undefined) throw new Error("Chunk size not initialized")
|
|
211
237
|
if (!chunkedBodyChars) throw new Error("Chunked body not initialized")
|
|
212
238
|
|
|
239
|
+
this.assertRequestBodySize(chunkedBodyChars.length + 1)
|
|
213
240
|
chunkedBodyChars.push(char)
|
|
214
241
|
/**
|
|
215
242
|
* Current chunk bytes read.
|
|
@@ -429,6 +456,13 @@ export default class RequestBuffer {
|
|
|
429
456
|
const httpMethod = this.httpMethod?.toUpperCase()
|
|
430
457
|
|
|
431
458
|
if (!httpMethod) throw new Error("HTTP method not set")
|
|
459
|
+
if (!this.path) throw new Error("HTTP path not set")
|
|
460
|
+
|
|
461
|
+
this.requestBodyPolicy = this.configuration.resolveHttpRequestBodyPolicy({
|
|
462
|
+
headers: this.getHeadersHash(),
|
|
463
|
+
httpMethod,
|
|
464
|
+
path: this.path
|
|
465
|
+
})
|
|
432
466
|
|
|
433
467
|
if (!this.expectsRequestBody(httpMethod)) {
|
|
434
468
|
this.completeRequest()
|
|
@@ -446,7 +480,9 @@ export default class RequestBuffer {
|
|
|
446
480
|
this.assertRequestBodySize(this.contentLength)
|
|
447
481
|
}
|
|
448
482
|
|
|
449
|
-
const match = this.
|
|
483
|
+
const match = this.requestBodyPolicy.mode === "parsed"
|
|
484
|
+
? this.getHeader("content-type")?.value?.match(/^multipart\/form-data;\s*boundary=(.+)$/i)
|
|
485
|
+
: null
|
|
450
486
|
|
|
451
487
|
if (match) {
|
|
452
488
|
this.boundary = match[1]
|
|
@@ -490,7 +526,13 @@ export default class RequestBuffer {
|
|
|
490
526
|
|
|
491
527
|
postRequestDone() {
|
|
492
528
|
if (this.postBodyBuffers) {
|
|
493
|
-
|
|
529
|
+
const bodyBuffer = Buffer.concat(this.postBodyBuffers)
|
|
530
|
+
|
|
531
|
+
if (this.requestBodyPolicy?.mode === "raw") {
|
|
532
|
+
this.rawBodyBuffer = bodyBuffer
|
|
533
|
+
} else {
|
|
534
|
+
this.postBody = bodyBuffer.toString("utf8")
|
|
535
|
+
}
|
|
494
536
|
}
|
|
495
537
|
|
|
496
538
|
this.postBodyBuffers = undefined
|
|
@@ -542,9 +584,11 @@ export default class RequestBuffer {
|
|
|
542
584
|
|
|
543
585
|
if (!sizeToken) throw new Error(`Invalid chunk size line: ${line}`)
|
|
544
586
|
|
|
587
|
+
if (!/^[0-9a-f]+$/iu.test(sizeToken)) throw new Error(`Invalid chunk size: ${sizeToken}`)
|
|
588
|
+
|
|
545
589
|
const size = Number.parseInt(sizeToken, 16)
|
|
546
590
|
|
|
547
|
-
if (!Number.
|
|
591
|
+
if (!Number.isSafeInteger(size)) throw new Error(`Invalid chunk size: ${sizeToken}`)
|
|
548
592
|
|
|
549
593
|
if (size === 0) {
|
|
550
594
|
this.setState("chunked-trailer")
|
|
@@ -564,7 +608,13 @@ export default class RequestBuffer {
|
|
|
564
608
|
*/
|
|
565
609
|
finishChunkedBody() {
|
|
566
610
|
if (this.chunkedBodyChars) {
|
|
567
|
-
|
|
611
|
+
const bodyBuffer = Buffer.from(this.chunkedBodyChars)
|
|
612
|
+
|
|
613
|
+
if (this.requestBodyPolicy?.mode === "raw") {
|
|
614
|
+
this.rawBodyBuffer = bodyBuffer
|
|
615
|
+
} else {
|
|
616
|
+
this.postBody = bodyBuffer.toString("utf8")
|
|
617
|
+
}
|
|
568
618
|
}
|
|
569
619
|
|
|
570
620
|
delete this.chunkedBodyChars
|
|
@@ -584,7 +634,9 @@ export default class RequestBuffer {
|
|
|
584
634
|
this.state = "status" // Reset state to new request
|
|
585
635
|
this.completed = true
|
|
586
636
|
|
|
587
|
-
if (this.
|
|
637
|
+
if (this.requestBodyPolicy?.mode === "raw") {
|
|
638
|
+
this.rawBodyBuffer ||= Buffer.alloc(0)
|
|
639
|
+
} else if (this.getHeader("content-type")?.value?.startsWith("application/json")) {
|
|
588
640
|
this.parseApplicationJsonParams()
|
|
589
641
|
} else if (this.multiPartyFormData) {
|
|
590
642
|
// Done after each new form data part
|
|
@@ -107,6 +107,11 @@ export default class VelociousHttpServerClientRequest {
|
|
|
107
107
|
socketRemoteAddress: this.socketRemoteAddress()
|
|
108
108
|
})
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns exact body bytes for requests whose header-stage body policy selected raw mode.
|
|
112
|
+
* @returns {Buffer} - A copy of the exact request body bytes.
|
|
113
|
+
*/
|
|
114
|
+
rawBody() { return this.getRequestBuffer().getRawBody() }
|
|
110
115
|
socketRemoteAddress() { return this.client?.remoteAddress }
|
|
111
116
|
|
|
112
117
|
getRequestBuffer() { return this.getRequestParser().getRequestBuffer() }
|