topbit 1.0.0 → 3.0.0

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.
Files changed (89) hide show
  1. package/LICENSE +128 -0
  2. package/README.cn.md +1519 -0
  3. package/README.md +1483 -0
  4. package/bin/app.js +17 -0
  5. package/bin/loadinfo.sh +18 -0
  6. package/bin/new-ctl.js +234 -0
  7. package/bin/newapp.js +22 -0
  8. package/demo/allow.js +98 -0
  9. package/demo/cert/localhost-cert.pem +19 -0
  10. package/demo/cert/localhost-privkey.pem +28 -0
  11. package/demo/controller/api.js +15 -0
  12. package/demo/extends.js +5 -0
  13. package/demo/group-api.js +161 -0
  14. package/demo/group-api2.js +109 -0
  15. package/demo/http2.js +34 -0
  16. package/demo/http2_proxy_backend.js +45 -0
  17. package/demo/http2proxy.js +48 -0
  18. package/demo/http_proxy_backend.js +44 -0
  19. package/demo/httpproxy.js +47 -0
  20. package/demo/loader.js +27 -0
  21. package/demo/log.js +118 -0
  22. package/demo/memlimit.js +31 -0
  23. package/demo/min.js +7 -0
  24. package/demo/serv.js +15 -0
  25. package/images/middleware.jpg +0 -0
  26. package/images/topbit-middleware.png +0 -0
  27. package/images/topbit.png +0 -0
  28. package/package.json +42 -11
  29. package/src/_loadExtends.js +21 -0
  30. package/src/bodyparser.js +420 -0
  31. package/src/connfilter.js +125 -0
  32. package/src/context1.js +166 -0
  33. package/src/context2.js +182 -0
  34. package/src/ctxpool.js +39 -0
  35. package/src/ext.js +318 -0
  36. package/src/extends/Http2Pool.js +365 -0
  37. package/src/extends/__randstring.js +24 -0
  38. package/src/extends/cookie.js +44 -0
  39. package/src/extends/cors.js +334 -0
  40. package/src/extends/errorlog.js +252 -0
  41. package/src/extends/http2limit.js +126 -0
  42. package/src/extends/http2proxy.js +691 -0
  43. package/src/extends/jwt.js +217 -0
  44. package/src/extends/mixlogger.js +63 -0
  45. package/src/extends/paramcheck.js +266 -0
  46. package/src/extends/proxy.js +662 -0
  47. package/src/extends/realip.js +34 -0
  48. package/src/extends/referer.js +68 -0
  49. package/src/extends/resource.js +398 -0
  50. package/src/extends/session.js +174 -0
  51. package/src/extends/setfinal.js +50 -0
  52. package/src/extends/sni.js +48 -0
  53. package/src/extends/sse.js +293 -0
  54. package/src/extends/timing.js +111 -0
  55. package/src/extends/tofile.js +123 -0
  56. package/src/fastParseUrl.js +426 -0
  57. package/src/headerLimit.js +18 -0
  58. package/src/http1.js +336 -0
  59. package/src/http2.js +337 -0
  60. package/src/httpc.js +251 -0
  61. package/src/lib/npargv.js +354 -0
  62. package/src/lib/zipdata.js +45 -0
  63. package/src/loader/loader.js +999 -0
  64. package/src/logger.js +32 -0
  65. package/src/loggermsg.js +349 -0
  66. package/src/makeId.js +200 -0
  67. package/src/midcore.js +213 -0
  68. package/src/middleware1.js +103 -0
  69. package/src/middleware2.js +116 -0
  70. package/src/monitor.js +380 -0
  71. package/src/movefile.js +30 -0
  72. package/src/optionsCheck.js +54 -0
  73. package/src/randstring.js +23 -0
  74. package/src/router.js +682 -0
  75. package/src/sendmsg.js +27 -0
  76. package/src/strong.js +72 -0
  77. package/src/token/token.js +461 -0
  78. package/src/topbit.js +1293 -0
  79. package/src/versionCheck.js +31 -0
  80. package/test/test-bigctx.js +29 -0
  81. package/test/test-daemon-args.js +7 -0
  82. package/test/test-ext.js +81 -0
  83. package/test/test-find.js +69 -0
  84. package/test/test-route-sort.js +71 -0
  85. package/test/test-route.js +49 -0
  86. package/test/test-route2.js +51 -0
  87. package/test/test-run-args.js +7 -0
  88. package/test/test-url.js +52 -0
  89. package/main.js +0 -0
@@ -0,0 +1,691 @@
1
+ 'use strict'
2
+
3
+ const http2 = require('node:http2')
4
+ const Http2Pool = require('./Http2Pool')
5
+
6
+ let error_502_text = `<!DOCTYPE html><html>
7
+ <head>
8
+ <meta charset="UTF-8">
9
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
10
+ <title>Error 502</title>
11
+ </head>
12
+ <body>
13
+ <div style="width:100%;font-size:105%;color:#737373;padding:0.8rem;">
14
+ <h2>502 Bad Gateway</h2><br>
15
+ <p>代理请求不可达。</p>
16
+ </div>
17
+ </body>
18
+ </html>`
19
+
20
+ let error_503_text = `<!DOCTYPE html><html>
21
+ <head>
22
+ <meta charset="UTF-8">
23
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
24
+ <title>Error 503</title>
25
+ </head>
26
+ <body>
27
+ <div style="width:100%;font-size:105%;color:#737373;padding:0.8rem;">
28
+ <h2>503 Service Unavailable</h2><br>
29
+ <p>此服务暂时不可用。</p>
30
+ </div>
31
+ </body>
32
+ </html>`
33
+
34
+ function fmtpath(path) {
35
+ path = path.trim()
36
+ if (path.length == 0) {
37
+ return '/*'
38
+ }
39
+
40
+ if (path[0] !== '/') {
41
+ path = `/${path}`
42
+ }
43
+
44
+ if (path.length > 1 && path[path.length - 1] !== '/') {
45
+ path = `${path}/`
46
+ }
47
+
48
+ if (path.indexOf('/:') >= 0) {
49
+ return path.substring(0, path.length-1)
50
+ }
51
+
52
+ return `${path}*`
53
+ }
54
+
55
+ let Http2Proxy = function (options = {}) {
56
+
57
+ if (!(this instanceof Http2Proxy)) return Http2Proxy(options)
58
+
59
+ if (typeof options !== 'object') options = {}
60
+
61
+ this.urlpreg = /(unix|http|https):\/\/[a-zA-Z0-9\-\_]+/
62
+
63
+ this.hostProxy = {}
64
+ this.proxyBalance = {}
65
+ this.pathTable = {}
66
+
67
+ this.methods = [
68
+ 'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE'
69
+ ]
70
+
71
+ this.maxBody = 50000000
72
+
73
+ //是否启用全代理模式。
74
+ this.full = false
75
+
76
+ this.timeout = 30000
77
+ this.connectTimeout = 15000
78
+
79
+ this.maxAliveStreams = 100
80
+
81
+ this.starPath = false
82
+
83
+ this.addIP = false
84
+
85
+ this.debug = false
86
+
87
+ this.config = {}
88
+
89
+ this.connectOptions = {
90
+ family: 4
91
+ }
92
+
93
+ for (let k in options) {
94
+ switch (k) {
95
+ case 'config':
96
+ this.config = options[k]
97
+ break
98
+
99
+ case 'starPath':
100
+ this.starPath = !!options[k]
101
+ break
102
+
103
+ case 'maxBody':
104
+ case 'timeout':
105
+ case 'connectTimeout':
106
+ case 'maxAliveStreams':
107
+ if (typeof options[k] === 'number' && !isNaN(options[k])) {
108
+ this[k] = options[k]
109
+ }
110
+ break
111
+
112
+ case 'addIP':
113
+ case 'full':
114
+ case 'debug':
115
+ this[k] = !!options[k]
116
+ break
117
+
118
+ case 'connectOptions':
119
+ if (options[k] && typeof options[k] === 'object') {
120
+ for (let a in options[k]) this.connectOptions[a] = options[k][a]
121
+ }
122
+ break
123
+ }
124
+ }
125
+
126
+ this.setHostProxy(this.config)
127
+
128
+ }
129
+
130
+ Http2Proxy.prototype.fmtConfig = function (cfg, k) {
131
+ if (typeof cfg[k] === 'string') {
132
+ cfg[k] = [
133
+ { path : '/', url : cfg[k] }
134
+ ]
135
+ } else if (! (cfg[k] instanceof Array) ) {
136
+ cfg[k] = [ cfg[k] ]
137
+ }
138
+ }
139
+
140
+ Http2Proxy.prototype.checkConfig = function (tmp, k) {
141
+
142
+ if (typeof tmp !== 'object' || (tmp instanceof Array) ) {
143
+ console.error(`${k} ${JSON.stringify(tmp)} 错误的配置格式`)
144
+ return false
145
+ }
146
+
147
+ if (tmp.path === undefined) {
148
+ tmp.path = '/'
149
+ }
150
+
151
+ tmp.path = tmp.path.trim().replace(/(\/){2,}/g, '/')
152
+
153
+ if (tmp.path.length > 2 && tmp.path[tmp.path.length - 1] === '/') {
154
+ tmp.path = tmp.substring(0, tmp.path.length-1)
155
+ }
156
+
157
+ if (tmp.url === undefined) {
158
+ console.error(`${k} ${tmp.path}:没有指定要代理转发的url。`)
159
+ return false
160
+ }
161
+
162
+ if (this.urlpreg.test(tmp.url) === false) {
163
+ console.error(`${tmp.url} : 错误的url,请检查。`)
164
+ return false
165
+ }
166
+
167
+ if (tmp.url[ tmp.url.length - 1 ] == '/') {
168
+ tmp.url = tmp.url.substring(0, tmp.url.length - 1)
169
+ }
170
+
171
+ if (tmp.headers !== undefined) {
172
+ if (typeof tmp.headers !== 'object') {
173
+ console.error(`${k} ${tmp.url} ${tmp.path}:headers属性要求是object类型,使用key-value形式提供。`)
174
+ return false
175
+ }
176
+ }
177
+
178
+ return true
179
+ }
180
+
181
+ Http2Proxy.prototype.checkAndSetConfig = function (backend_obj, tmp) {
182
+ if (tmp.headers && tmp.headers.toString() === '[object Object]') {
183
+ backend_obj.headers = {}
184
+
185
+ for (let h in tmp.headers) {
186
+ backend_obj.headers[h] = tmp.headers[h]
187
+ }
188
+
189
+ }
190
+
191
+ if (tmp.max && typeof tmp.max === 'number' && tmp.max > 1)
192
+ backend_obj.max = tmp.max
193
+
194
+ if (tmp.debug !== undefined) backend_obj.debug = tmp.debug
195
+
196
+ if (tmp.weight && typeof tmp.weight === 'number' && tmp.weight > 1)
197
+ backend_obj.weight = parseInt(tmp.weight)
198
+
199
+ if (tmp.reconnDelay !== undefined && typeof tmp.reconnDelay === 'number')
200
+ backend_obj.reconnDelay = tmp.reconnDelay
201
+
202
+ if (tmp.timeout !== undefined && typeof tmp.timeout === 'number')
203
+ backend_obj.timeout = tmp.timeout
204
+
205
+ if (tmp.rewrite && typeof tmp.rewrite === 'function')
206
+ backend_obj.rewrite = tmp.rewrite
207
+
208
+ if (tmp.connectTimeout && typeof tmp.connectTimeout === 'number' && !isNaN(tmp.connectTimeout))
209
+ {
210
+ backend_obj.connectTimeout = tmp.connectTimeout
211
+ }
212
+
213
+ }
214
+
215
+ Http2Proxy.prototype.setHostProxy = function (cfg) {
216
+ if (typeof cfg !== 'object') return false
217
+
218
+ let pt = ''
219
+ let tmp = ''
220
+ let backend_obj = null
221
+ let tmp_cfg
222
+
223
+ for (let k in cfg) {
224
+ tmp_cfg = Array.isArray(cfg[k]) ? cfg[k] : [ cfg[k] ]
225
+
226
+ for (let i = 0; i < tmp_cfg.length; i++) {
227
+ tmp = tmp_cfg[i]
228
+
229
+ if (!this.checkConfig(tmp, k)) continue
230
+
231
+ if (this.hostProxy[k] === undefined) {
232
+ this.hostProxy[k] = {}
233
+ this.proxyBalance[k] = {}
234
+ }
235
+
236
+ pt = fmtpath(tmp.path)
237
+
238
+ backend_obj = {
239
+ url: tmp.url,
240
+ headers: null,
241
+ path: tmp.path,
242
+ pathLength: tmp.path.length,
243
+ rewrite: false,
244
+ weight: 1,
245
+ weightCount: 0,
246
+ reconnDelay: 500,
247
+ max: 50,
248
+ maxConnect: tmp.maxConnect || 0,
249
+ debug: this.debug,
250
+ h2Pool: null,
251
+ timeout: this.timeout,
252
+ connectTimeout: this.connectTimeout,
253
+ maxAliveStreams: this.maxAliveStreams,
254
+ alive: false,
255
+ connectOptions: {
256
+ timeout: this.timeout,
257
+ ...this.connectOptions
258
+ }
259
+ }
260
+
261
+ if (tmp.connectOptions && typeof tmp.connectOptions === 'object') {
262
+ for (let o in tmp.connectOptions) {
263
+ backend_obj.connectOptions[o] = tmp.connectOptions[o]
264
+ }
265
+ }
266
+
267
+ this.checkAndSetConfig(backend_obj, tmp)
268
+
269
+ backend_obj.h2Pool = new Http2Pool({
270
+ debug: backend_obj.debug,
271
+ max: backend_obj.max,
272
+ url: backend_obj.url,
273
+ connectOptions: backend_obj.connectOptions,
274
+ parent: backend_obj,
275
+ reconnDelay: backend_obj.reconnDelay,
276
+ quiet: true,
277
+ timeout: backend_obj.timeout,
278
+ connectTimeout: backend_obj.connectTimeout,
279
+ maxAliveStreams: backend_obj.maxAliveStreams,
280
+ maxConnect: backend_obj.maxConnect
281
+ })
282
+
283
+ backend_obj.h2Pool.createPool()
284
+
285
+ if (this.hostProxy[k][pt] === undefined) {
286
+
287
+ this.hostProxy[k][pt] = [ backend_obj ]
288
+
289
+ this.proxyBalance[k][pt] = {
290
+ stepIndex : 0,
291
+ useWeight : false
292
+ }
293
+
294
+ } else if (this.hostProxy[k][pt] instanceof Array) {
295
+ this.hostProxy[k][pt].push(backend_obj)
296
+ }
297
+
298
+ if (backend_obj.weight > 1) this.proxyBalance[k][pt].useWeight = true
299
+
300
+ this.pathTable[pt] = 1
301
+
302
+ } //end sub for
303
+
304
+ } //end for
305
+
306
+ }
307
+
308
+ Http2Proxy.prototype.checkAlive = function (pr) {
309
+ if (!pr.h2Pool) return false
310
+ return pr.h2Pool.ok()
311
+ }
312
+
313
+ Http2Proxy.prototype.getBackend = function (c, host) {
314
+ let prlist = this.hostProxy[host][c.routepath]
315
+
316
+ let pxybalance = this.proxyBalance[host][c.routepath]
317
+
318
+ let pr
319
+
320
+ if (prlist.length === 1) {
321
+ pr = prlist[0]
322
+ } else {
323
+ if (pxybalance.stepIndex >= prlist.length) {
324
+ pxybalance.stepIndex = 0
325
+ }
326
+
327
+ pr = prlist[pxybalance.stepIndex]
328
+
329
+ if (pxybalance.useWeight) {
330
+ if (pr.weightCount >= pr.weight) {
331
+ pr.weightCount = 0
332
+ pxybalance.stepIndex += 1
333
+ } else {
334
+ pr.weightCount += 1
335
+ }
336
+ } else {
337
+ pxybalance.stepIndex += 1
338
+ }
339
+ }
340
+
341
+ if (!pr.alive) {
342
+ pr.h2Pool && pr.h2Pool.delayConnect()
343
+
344
+ for (let i = prlist.length - 1; i >= 0 ; i--) {
345
+
346
+ pr = prlist[i]
347
+
348
+ if (pr.alive) {
349
+ return pr
350
+ } else {
351
+ pr.h2Pool && pr.h2Pool.delayConnect()
352
+ }
353
+ }
354
+
355
+ return null
356
+ }
357
+
358
+ return pr
359
+ }
360
+
361
+ //把http1的消息头转换为http2支持的
362
+
363
+ Http2Proxy.prototype.fmtHeaders = function (headers, ctx) {
364
+ let http2_headers = {
365
+ ':method': ctx.method,
366
+ ':path': headers[':path'] || ctx.request.url || ctx.path,
367
+ }
368
+
369
+ for (let k in headers) {
370
+ //if (typeof k !== 'string') continue
371
+
372
+ switch (k) {
373
+ case 'connection':
374
+ case 'keep-alive':
375
+ case 'upgrade':
376
+ case 'transfer-encoding':
377
+ case 'proxy-connection':
378
+ case ':path':
379
+ case ':method':
380
+ case 'method':
381
+ break
382
+
383
+ case 'host':
384
+ http2_headers[':authority'] = headers[k]
385
+ break
386
+
387
+ default:
388
+ http2_headers[k] = headers[k]
389
+ }
390
+ }
391
+
392
+ return http2_headers
393
+ }
394
+
395
+ Http2Proxy.prototype.mid = function () {
396
+ let self = this
397
+
398
+ let timeoutError = new Error('request timeout')
399
+
400
+ timeoutError.code = 'ETIMEOUT'
401
+
402
+ return async (c, next) => {
403
+
404
+ let host = c.host
405
+
406
+ let hind = c.host.length - 1
407
+
408
+ if (hind > 4) {
409
+ let eind = hind - 5
410
+
411
+ while (hind >= eind) {
412
+ if (c.host[hind] === ':') {
413
+ host = c.host.substring(0, hind)
414
+ break
415
+ }
416
+
417
+ hind--
418
+ }
419
+ }
420
+
421
+ if (!self.hostProxy[host] || !self.hostProxy[host][c.routepath]) {
422
+ if (self.full) {
423
+ return c.status(502).to(error_502_text)
424
+ }
425
+
426
+ return await next(c)
427
+ }
428
+
429
+ let pr = self.getBackend(c, host)
430
+
431
+ if (!pr) {
432
+ pr = self.getBackend(c, host)
433
+
434
+ if (!pr) {
435
+ await c.ext.delay(9)
436
+ pr = self.getBackend(c, host)
437
+
438
+ if (!pr) {
439
+ for (let i = 0; i < 200; i++) {
440
+ await c.ext.delay(6 + i)
441
+ pr = self.getBackend(c, host)
442
+ if (pr) break
443
+ }
444
+ }
445
+
446
+ if (!pr) return c.status(503).to(error_503_text)
447
+ }
448
+ }
449
+
450
+ if (self.addIP && c.headers['x-real-ip']) {
451
+ c.headers['x-real-ip'] += `,${c.ip}`
452
+ } else {
453
+ c.headers['x-real-ip'] = c.ip
454
+ }
455
+
456
+ let hii = pr.h2Pool
457
+ let session_client
458
+
459
+ try {
460
+ if (pr.headers) {
461
+ for (let k in pr.headers) c.headers[k] = pr.headers[k]
462
+ }
463
+
464
+ if (pr.rewrite) {
465
+ let rpath = pr.rewrite(c, c.major >= 2 ? c.headers[':path'] : c.request.url)
466
+
467
+ if (rpath) {
468
+ let path_typ = typeof rpath
469
+ if (path_typ === 'object' && rpath.redirect) {
470
+ return c.setHeader('location', rpath.redirect)
471
+ } else if (path_typ === 'string') {
472
+ c.headers[':path'] = rpath
473
+ }
474
+ }
475
+ }
476
+
477
+ session_client = await hii.getSession()
478
+
479
+ if (session_client.deny) {
480
+ for (let i = 0; i < 50; i++) {
481
+ await c.ext.delay(5 + i)
482
+ session_client = await hii.getSession()
483
+ if (!session_client.deny) break
484
+ }
485
+
486
+ if (session_client.deny)
487
+ return c.status(429).to('服务繁忙,请稍后再试')
488
+ }
489
+
490
+ await new Promise(async (rv, rj) => {
491
+ let resolved = false
492
+ let rejected = false
493
+ let request_stream = c.stream
494
+ let stm = null
495
+
496
+ stm = await hii.request(
497
+ c.major === 2 ? c.headers : this.fmtHeaders(c.headers, c),
498
+ session_client
499
+ ).catch(err => {
500
+ rejected = true
501
+ rj(err)
502
+ stm = null
503
+ })
504
+
505
+ if (!stm) {
506
+ rj(new Error('request failed'))
507
+ return false
508
+ }
509
+
510
+ let timeout_handler = () => {
511
+ timeout_timer = null
512
+
513
+ //强制的异常结束,这意味着session的其他stream也会出现问题。
514
+ try {
515
+ !stm.closed && stm.close(http2.constants.NGHTTP2_CANCEL)
516
+ stm.destroy()
517
+ if (session_client.session && !session_client.session.destroyed) {
518
+ session_client.session.destroy()
519
+ }
520
+ } catch(e) {}
521
+
522
+ if (!resolved && !rejected) {
523
+ rejected = true
524
+ rj(new Error('force destroy stream, request timeout'))
525
+ }
526
+ }
527
+
528
+ session_client.aliveStreams++
529
+
530
+ let timeout_timer = setTimeout(timeout_handler, pr.timeout + 5000)
531
+
532
+ c.stream.on('timeout', () => {
533
+ stm.close(http2.constants.NGHTTP2_CANCEL)
534
+ //stm.destroy()
535
+ })
536
+
537
+ c.stream.on('close', () => {
538
+ if (request_stream && request_stream.rstCode !== http2.constants.NGHTTP2_NO_ERROR) {
539
+ stm.close(request_stream.rstCode)
540
+ }
541
+ })
542
+
543
+ c.stream.on('error', err => {
544
+ if (timeout_timer) {
545
+ clearTimeout(timeout_timer)
546
+ timeout_timer = null
547
+ }
548
+
549
+ stm.close(http2.constants.NGHTTP2_INTERNAL_ERROR)
550
+ stm.destroy()
551
+ })
552
+
553
+ c.stream.on('aborted', err => {
554
+ !request_stream.destroyed && request_stream.destroy()
555
+ //stm.close(http2.constants.NGHTTP2_CANCEL)
556
+ stm.destroy()
557
+ })
558
+
559
+ stm.setTimeout(pr.timeout, () => {
560
+ //stm.close(http2.constants.NGHTTP2_CANCEL)
561
+ stm.destroy()
562
+ })
563
+
564
+ stm.on('aborted', err => {
565
+ if (timeout_timer) {
566
+ clearTimeout(timeout_timer)
567
+ timeout_timer = null
568
+ }
569
+
570
+ !stm.destroyed && stm.destroy()
571
+
572
+ if (!resolved && !rejected) {
573
+ rejected = true
574
+ rj(err)
575
+ }
576
+ })
577
+
578
+ stm.on('close', () => {
579
+ if (timeout_timer) {
580
+ clearTimeout(timeout_timer)
581
+ timeout_timer = null
582
+ }
583
+
584
+ stm.removeAllListeners()
585
+
586
+ if (stm.rstCode === http2.constants.NGHTTP2_NO_ERROR) {
587
+ if (!resolved && !rejected) {
588
+ resolved = true
589
+ rv()
590
+ }
591
+ } else {
592
+ if (!resolved && !rejected) {
593
+ rejected = true
594
+ rj(new Error(`stream close, exit code ${stm.rstCode}`))
595
+ }
596
+ }
597
+
598
+ session_client.aliveStreams--
599
+ })
600
+
601
+ stm.on('response', (headers, flags) => {
602
+ timeout_timer && clearTimeout(timeout_timer)
603
+ timeout_timer = setTimeout(timeout_handler, pr.timeout + 5000)
604
+ if (c.res && c.res.writable) {
605
+ if (c.res.respond) {
606
+ c.res.respond(headers)
607
+ } else if (c.res.setHeader) {
608
+ c.status(headers[':status'])
609
+
610
+ for (let k in headers) {
611
+ if (typeof k !== 'string' || k[0] === ':') continue
612
+
613
+ c.res.setHeader(k, headers[k])
614
+ }
615
+ }
616
+ }
617
+
618
+ })
619
+
620
+ stm.on('frameError', err => {
621
+ stm.close(http2.constants.NGHTTP2_INTERNAL_ERROR)
622
+ stm.destroy()
623
+ })
624
+
625
+ stm.on('error', err => {
626
+ self.debug && console.error('------ error ------',err)
627
+ //stm.close(http2.constants.NGHTTP2_INTERNAL_ERROR)
628
+ stm.destroy(err)
629
+ })
630
+
631
+ c.req.on('data', chunk => {
632
+ stm.write(chunk)
633
+ })
634
+
635
+ c.req.on('end', () => {
636
+ stm.end()
637
+ })
638
+
639
+ let data_count = 0
640
+ stm.on('data', chunk => {
641
+ data_count++
642
+ c.res && c.res.writable && c.res.write(chunk)
643
+
644
+ if (data_count >= 111) {
645
+ data_count = 0
646
+ timeout_timer && clearTimeout(timeout_timer)
647
+ timeout_timer = setTimeout(timeout_handler, pr.timeout + 5000)
648
+ }
649
+ })
650
+
651
+ stm.on('end', () => {
652
+ if (timeout_timer) {
653
+ clearTimeout(timeout_timer)
654
+ timeout_timer = null
655
+ }
656
+
657
+ stm.close()
658
+
659
+ if (!resolved && !rejected) {
660
+ resolved = true
661
+ rv()
662
+ }
663
+ })
664
+
665
+ })
666
+ } catch (err) {
667
+ self.debug && console.error(err||'request null error')
668
+ c.status(503).to(error_503_text)
669
+ } finally {
670
+ session_client = null
671
+ }
672
+
673
+ }
674
+
675
+ }
676
+
677
+ Http2Proxy.prototype.init = function (app) {
678
+ app.config.timeout = this.timeout
679
+
680
+ for (let p in this.pathTable) {
681
+ app.router.map(this.methods, p, async c => {}, '@topbit_h2_proxy');
682
+ }
683
+
684
+ app.use(this.mid(), {
685
+ pre: true,
686
+ group: `topbit_h2_proxy`
687
+ })
688
+
689
+ }
690
+
691
+ module.exports = Http2Proxy