@swarmmachina/swm-core 1.1.2 → 1.1.4
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/package.json +1 -1
- package/src/http-context.js +185 -11
- package/src/index.js +5 -0
- package/src/res-streamer.js +1 -1
package/package.json
CHANGED
package/src/http-context.js
CHANGED
|
@@ -6,8 +6,15 @@ export default class HttpContext {
|
|
|
6
6
|
#ip = ''
|
|
7
7
|
#method = ''
|
|
8
8
|
#url = ''
|
|
9
|
+
#headersCached = false
|
|
10
|
+
#headers = {}
|
|
11
|
+
#fullQuery = null
|
|
12
|
+
#fullQueryParsed = false
|
|
13
|
+
#query = {}
|
|
14
|
+
#params = {}
|
|
9
15
|
#statusOverride = null
|
|
10
16
|
#contentLength = undefined
|
|
17
|
+
#pendingHeaders = new Map()
|
|
11
18
|
#bodyParser = new BodyParser()
|
|
12
19
|
#resStreamer = new ResStreamer()
|
|
13
20
|
|
|
@@ -108,10 +115,17 @@ export default class HttpContext {
|
|
|
108
115
|
|
|
109
116
|
this.#statusOverride = null
|
|
110
117
|
this.#contentLength = undefined
|
|
118
|
+
this.#pendingHeaders.clear()
|
|
111
119
|
|
|
112
120
|
this.#ip = ''
|
|
113
121
|
this.#url = ''
|
|
114
122
|
this.#method = ''
|
|
123
|
+
this.#headersCached = false
|
|
124
|
+
this.#headers = {}
|
|
125
|
+
this.#fullQuery = null
|
|
126
|
+
this.#fullQueryParsed = false
|
|
127
|
+
this.#query = {}
|
|
128
|
+
this.#params = {}
|
|
115
129
|
|
|
116
130
|
this.#bodyParser.reset(this, maxSize)
|
|
117
131
|
this.#resStreamer.reset(this, res)
|
|
@@ -135,9 +149,16 @@ export default class HttpContext {
|
|
|
135
149
|
|
|
136
150
|
this.#statusOverride = null
|
|
137
151
|
this.#contentLength = undefined
|
|
152
|
+
this.#pendingHeaders.clear()
|
|
138
153
|
this.#ip = ''
|
|
139
154
|
this.#url = ''
|
|
140
155
|
this.#method = ''
|
|
156
|
+
this.#headersCached = false
|
|
157
|
+
this.#headers = {}
|
|
158
|
+
this.#fullQuery = null
|
|
159
|
+
this.#fullQueryParsed = false
|
|
160
|
+
this.#query = {}
|
|
161
|
+
this.#params = {}
|
|
141
162
|
|
|
142
163
|
this.#bodyParser.clear()
|
|
143
164
|
this.#resStreamer.clear()
|
|
@@ -166,6 +187,68 @@ export default class HttpContext {
|
|
|
166
187
|
}
|
|
167
188
|
}
|
|
168
189
|
|
|
190
|
+
cacheHeaders() {
|
|
191
|
+
if (this.#headersCached || !this.req) {
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.req.forEach((key, value) => {
|
|
196
|
+
this.#headers[key] = value
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
this.#headersCached = true
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
cacheQuery() {
|
|
203
|
+
if (this.#fullQuery !== null || !this.req) {
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const fullQuery = this.req.getQuery()
|
|
208
|
+
|
|
209
|
+
this.#fullQuery = typeof fullQuery === 'string' ? fullQuery : ''
|
|
210
|
+
this.#fullQueryParsed = false
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
#parseFullQuery() {
|
|
214
|
+
if (this.#fullQueryParsed) {
|
|
215
|
+
return
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const fullQuery = this.#fullQuery
|
|
219
|
+
|
|
220
|
+
if (!fullQuery) {
|
|
221
|
+
this.#fullQueryParsed = true
|
|
222
|
+
return
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let start = 0
|
|
226
|
+
|
|
227
|
+
while (start <= fullQuery.length) {
|
|
228
|
+
let end = fullQuery.indexOf('&', start)
|
|
229
|
+
|
|
230
|
+
if (end === -1) {
|
|
231
|
+
end = fullQuery.length
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const eq = fullQuery.indexOf('=', start)
|
|
235
|
+
const hasEq = eq !== -1 && eq < end
|
|
236
|
+
const key = hasEq ? fullQuery.slice(start, eq) : fullQuery.slice(start, end)
|
|
237
|
+
|
|
238
|
+
if (!(key in this.#query)) {
|
|
239
|
+
this.#query[key] = hasEq ? fullQuery.slice(eq + 1, end) : ''
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (end === fullQuery.length) {
|
|
243
|
+
break
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
start = end + 1
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
this.#fullQueryParsed = true
|
|
250
|
+
}
|
|
251
|
+
|
|
169
252
|
ip() {
|
|
170
253
|
if (!this.res) {
|
|
171
254
|
return ''
|
|
@@ -213,7 +296,25 @@ export default class HttpContext {
|
|
|
213
296
|
* @returns {string|undefined}
|
|
214
297
|
*/
|
|
215
298
|
query(name) {
|
|
216
|
-
|
|
299
|
+
if (name in this.#query) {
|
|
300
|
+
return this.#query[name]
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (this.#fullQuery !== null) {
|
|
304
|
+
this.#parseFullQuery()
|
|
305
|
+
|
|
306
|
+
if (name in this.#query) {
|
|
307
|
+
return this.#query[name]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this.#query[name] = undefined
|
|
311
|
+
return undefined
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const value = this.req.getQuery(name)
|
|
315
|
+
|
|
316
|
+
this.#query[name] = value
|
|
317
|
+
return value
|
|
217
318
|
}
|
|
218
319
|
|
|
219
320
|
/**
|
|
@@ -221,7 +322,14 @@ export default class HttpContext {
|
|
|
221
322
|
* @returns {string|undefined}
|
|
222
323
|
*/
|
|
223
324
|
param(i) {
|
|
224
|
-
|
|
325
|
+
if (i in this.#params) {
|
|
326
|
+
return this.#params[i]
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const value = this.req.getParameter(i)
|
|
330
|
+
|
|
331
|
+
this.#params[i] = value
|
|
332
|
+
return value
|
|
225
333
|
}
|
|
226
334
|
|
|
227
335
|
/**
|
|
@@ -229,7 +337,18 @@ export default class HttpContext {
|
|
|
229
337
|
* @returns {string}
|
|
230
338
|
*/
|
|
231
339
|
header(name) {
|
|
232
|
-
|
|
340
|
+
if (name in this.#headers) {
|
|
341
|
+
return this.#headers[name]
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (this.#headersCached) {
|
|
345
|
+
return ''
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const value = this.req.getHeader(name)
|
|
349
|
+
|
|
350
|
+
this.#headers[name] = value
|
|
351
|
+
return value
|
|
233
352
|
}
|
|
234
353
|
|
|
235
354
|
contentLength() {
|
|
@@ -280,7 +399,11 @@ export default class HttpContext {
|
|
|
280
399
|
* @returns {HttpContext}
|
|
281
400
|
*/
|
|
282
401
|
setHeader(key, value) {
|
|
283
|
-
this.
|
|
402
|
+
if (this.replied || this.aborted) {
|
|
403
|
+
return this
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
this.#stageHeader(key, value)
|
|
284
407
|
return this
|
|
285
408
|
}
|
|
286
409
|
|
|
@@ -288,34 +411,85 @@ export default class HttpContext {
|
|
|
288
411
|
* @param {Record<string, string> | null | undefined} headers
|
|
289
412
|
*/
|
|
290
413
|
setHeaders(headers) {
|
|
414
|
+
if (this.replied || this.aborted) {
|
|
415
|
+
return
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
this.#stageHeaders(headers)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* @param {Record<string, string> | null | undefined} headers
|
|
423
|
+
*/
|
|
424
|
+
flushHeaders(headers = null) {
|
|
425
|
+
this.#flushPendingHeaders(headers)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* @param {string} key
|
|
430
|
+
* @param {string} value
|
|
431
|
+
*/
|
|
432
|
+
#stageHeader(key, value) {
|
|
433
|
+
if (value === undefined || value === null) {
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const headerName = String(key)
|
|
438
|
+
const headerValue = String(value)
|
|
439
|
+
|
|
440
|
+
this.#pendingHeaders.set(headerName.toLowerCase(), [headerName, headerValue])
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* @param {Record<string, string> | null | undefined} headers
|
|
445
|
+
*/
|
|
446
|
+
#stageHeaders(headers) {
|
|
291
447
|
if (!headers) {
|
|
292
448
|
return
|
|
293
449
|
}
|
|
294
450
|
|
|
295
451
|
if (headers === TEXT_PLAIN_HEADER) {
|
|
296
|
-
this
|
|
452
|
+
this.#stageHeader('content-type', 'text/plain; charset=utf-8')
|
|
297
453
|
return
|
|
298
454
|
}
|
|
299
455
|
|
|
300
456
|
if (headers === JSON_HEADER) {
|
|
301
|
-
this
|
|
457
|
+
this.#stageHeader('content-type', 'application/json; charset=utf-8')
|
|
302
458
|
return
|
|
303
459
|
}
|
|
304
460
|
|
|
305
461
|
if (headers === OCTET_STREAM_HEADER) {
|
|
306
|
-
this
|
|
462
|
+
this.#stageHeader('content-type', 'application/octet-stream')
|
|
307
463
|
return
|
|
308
464
|
}
|
|
309
465
|
|
|
310
466
|
for (const key in headers) {
|
|
311
467
|
const value = headers[key]
|
|
312
468
|
|
|
313
|
-
|
|
314
|
-
this.res.writeHeader(key, value)
|
|
315
|
-
}
|
|
469
|
+
this.#stageHeader(key, value)
|
|
316
470
|
}
|
|
317
471
|
}
|
|
318
472
|
|
|
473
|
+
/**
|
|
474
|
+
* @param {Record<string, string> | null | undefined} headers
|
|
475
|
+
*/
|
|
476
|
+
#flushPendingHeaders(headers = null) {
|
|
477
|
+
if (!this.res) {
|
|
478
|
+
this.#pendingHeaders.clear()
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (headers) {
|
|
483
|
+
this.#stageHeaders(headers)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
for (const [, [key, value]] of this.#pendingHeaders) {
|
|
487
|
+
this.res.writeHeader(key, value)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
this.#pendingHeaders.clear()
|
|
491
|
+
}
|
|
492
|
+
|
|
319
493
|
/**
|
|
320
494
|
* @param {any} result
|
|
321
495
|
* @returns {void}
|
|
@@ -399,7 +573,7 @@ export default class HttpContext {
|
|
|
399
573
|
}
|
|
400
574
|
|
|
401
575
|
this.res.writeStatus(this.getStatus(status))
|
|
402
|
-
this
|
|
576
|
+
this.#flushPendingHeaders(headers)
|
|
403
577
|
|
|
404
578
|
if (body != null) {
|
|
405
579
|
this.res.end(body)
|
package/src/index.js
CHANGED
|
@@ -325,6 +325,11 @@ export default class Server {
|
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
if (isPromise(result)) {
|
|
328
|
+
ctx.method()
|
|
329
|
+
ctx.url()
|
|
330
|
+
ctx.cacheQuery()
|
|
331
|
+
ctx.cacheHeaders()
|
|
332
|
+
|
|
328
333
|
// eslint-disable-next-line promise/catch-or-return
|
|
329
334
|
result.then(ctx.onResolve, ctx.onReject)
|
|
330
335
|
return
|
package/src/res-streamer.js
CHANGED
|
@@ -107,7 +107,7 @@ export default class ResStreamer {
|
|
|
107
107
|
|
|
108
108
|
res.cork(() => {
|
|
109
109
|
res.writeStatus(typeof status === 'string' ? status : this.#ctx.getStatus(status))
|
|
110
|
-
this.#ctx.
|
|
110
|
+
this.#ctx.flushHeaders(headers)
|
|
111
111
|
})
|
|
112
112
|
|
|
113
113
|
this.#started = true
|