topbit 3.1.0 → 3.1.2

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.
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const http2 = require('node:http2')
4
- const Http2Pool = require('./Http2Pool')
4
+ const Http2Pool = require('./Http2Pool.js')
5
5
 
6
6
  let error_502_text = `<!DOCTYPE html><html>
7
7
  <head>
@@ -52,6 +52,19 @@ function fmtpath(path) {
52
52
  return `${path}*`
53
53
  }
54
54
 
55
+ // 主机名提取 (IPv6 兼容优化版)
56
+ function extractHostname(host) {
57
+ if (!host) return ''
58
+ if (host.charCodeAt(0) === 91) { // '[' IPv6
59
+ const end = host.indexOf(']')
60
+ return end > -1 ? host.substring(0, end + 1) : host
61
+ }
62
+ const idx = host.indexOf(':')
63
+ if (idx === -1) return host
64
+ if (host.indexOf(':', idx + 1) !== -1) return host // 裸 IPv6
65
+ return host.substring(0, idx)
66
+ }
67
+
55
68
  let Http2Proxy = function (options = {}) {
56
69
 
57
70
  if (!(this instanceof Http2Proxy)) return Http2Proxy(options)
@@ -188,8 +201,8 @@ Http2Proxy.prototype.checkAndSetConfig = function (backend_obj, tmp) {
188
201
 
189
202
  }
190
203
 
191
- if (tmp.max && typeof tmp.max === 'number' && tmp.max > 1)
192
- backend_obj.max = tmp.max
204
+ if (tmp.maxConnect && typeof tmp.maxConnect === 'number' && tmp.maxConnect > 1)
205
+ backend_obj.maxConnect = tmp.maxConnect
193
206
 
194
207
  if (tmp.debug !== undefined) backend_obj.debug = tmp.debug
195
208
 
@@ -244,8 +257,7 @@ Http2Proxy.prototype.setHostProxy = function (cfg) {
244
257
  weight: 1,
245
258
  weightCount: 0,
246
259
  reconnDelay: 500,
247
- max: 50,
248
- maxConnect: tmp.maxConnect || 0,
260
+ maxConnect: tmp.maxConnect || 10,
249
261
  debug: this.debug,
250
262
  h2Pool: null,
251
263
  timeout: this.timeout,
@@ -268,7 +280,6 @@ Http2Proxy.prototype.setHostProxy = function (cfg) {
268
280
 
269
281
  backend_obj.h2Pool = new Http2Pool({
270
282
  debug: backend_obj.debug,
271
- max: backend_obj.max,
272
283
  url: backend_obj.url,
273
284
  connectOptions: backend_obj.connectOptions,
274
285
  parent: backend_obj,
@@ -338,23 +349,6 @@ Http2Proxy.prototype.getBackend = function (c, host) {
338
349
  }
339
350
  }
340
351
 
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
352
  return pr
359
353
  }
360
354
 
@@ -401,22 +395,7 @@ Http2Proxy.prototype.mid = function () {
401
395
 
402
396
  return async (c, next) => {
403
397
 
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
- }
398
+ let host = extractHostname(c.host)
420
399
 
421
400
  if (!self.hostProxy[host] || !self.hostProxy[host][c.routepath]) {
422
401
  if (self.full) {
@@ -427,25 +406,7 @@ Http2Proxy.prototype.mid = function () {
427
406
  }
428
407
 
429
408
  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
- }
409
+ if (!pr) return c.status(503).to(error_503_text)
449
410
 
450
411
  if (self.addIP && c.headers['x-real-ip']) {
451
412
  c.headers['x-real-ip'] += `,${c.ip}`
@@ -454,7 +415,6 @@ Http2Proxy.prototype.mid = function () {
454
415
  }
455
416
 
456
417
  let hii = pr.h2Pool
457
- let session_client
458
418
 
459
419
  try {
460
420
  if (pr.headers) {
@@ -462,73 +422,38 @@ Http2Proxy.prototype.mid = function () {
462
422
  }
463
423
 
464
424
  if (pr.rewrite) {
465
- let rpath = pr.rewrite(c, c.major >= 2 ? c.headers[':path'] : c.request.url)
425
+ let rpath = pr.rewrite(c, c.major > 1 ? c.headers[':path'] : c.req.url)
466
426
 
467
427
  if (rpath) {
468
428
  let path_typ = typeof rpath
469
429
  if (path_typ === 'object' && rpath.redirect) {
470
430
  return c.setHeader('location', rpath.redirect)
471
431
  } else if (path_typ === 'string') {
472
- c.headers[':path'] = rpath
432
+ if (c.major > 1)
433
+ c.headers[':path'] = rpath
434
+ else c.req.url = rpath
473
435
  }
474
436
  }
475
437
  }
476
438
 
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
439
  await new Promise(async (rv, rj) => {
491
440
  let resolved = false
492
441
  let rejected = false
493
442
  let request_stream = c.stream
494
443
  let stm = null
495
444
 
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
- })
445
+ stm = await hii.request(c.major > 1 ? c.headers : this.fmtHeaders(c.headers, c))
446
+ .catch(err => {
447
+ rejected = true
448
+ rj(err)
449
+ stm = null
450
+ })
504
451
 
505
452
  if (!stm) {
506
453
  rj(new Error('request failed'))
507
454
  return false
508
455
  }
509
456
 
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
457
  c.stream.on('timeout', () => {
533
458
  stm.close(http2.constants.NGHTTP2_CANCEL)
534
459
  //stm.destroy()
@@ -541,11 +466,6 @@ Http2Proxy.prototype.mid = function () {
541
466
  })
542
467
 
543
468
  c.stream.on('error', err => {
544
- if (timeout_timer) {
545
- clearTimeout(timeout_timer)
546
- timeout_timer = null
547
- }
548
-
549
469
  stm.close(http2.constants.NGHTTP2_INTERNAL_ERROR)
550
470
  stm.destroy()
551
471
  })
@@ -562,11 +482,6 @@ Http2Proxy.prototype.mid = function () {
562
482
  })
563
483
 
564
484
  stm.on('aborted', err => {
565
- if (timeout_timer) {
566
- clearTimeout(timeout_timer)
567
- timeout_timer = null
568
- }
569
-
570
485
  !stm.destroyed && stm.destroy()
571
486
 
572
487
  if (!resolved && !rejected) {
@@ -576,13 +491,6 @@ Http2Proxy.prototype.mid = function () {
576
491
  })
577
492
 
578
493
  stm.on('close', () => {
579
- if (timeout_timer) {
580
- clearTimeout(timeout_timer)
581
- timeout_timer = null
582
- }
583
-
584
- stm.removeAllListeners()
585
-
586
494
  if (stm.rstCode === http2.constants.NGHTTP2_NO_ERROR) {
587
495
  if (!resolved && !rejected) {
588
496
  resolved = true
@@ -594,13 +502,9 @@ Http2Proxy.prototype.mid = function () {
594
502
  rj(new Error(`stream close, exit code ${stm.rstCode}`))
595
503
  }
596
504
  }
597
-
598
- session_client.aliveStreams--
599
505
  })
600
506
 
601
507
  stm.on('response', (headers, flags) => {
602
- timeout_timer && clearTimeout(timeout_timer)
603
- timeout_timer = setTimeout(timeout_handler, pr.timeout + 5000)
604
508
  if (c.res && c.res.writable) {
605
509
  if (c.res.respond) {
606
510
  c.res.respond(headers)
@@ -636,25 +540,21 @@ Http2Proxy.prototype.mid = function () {
636
540
  stm.end()
637
541
  })
638
542
 
639
- let data_count = 0
640
- stm.on('data', chunk => {
641
- data_count++
642
- c.res && c.res.writable && c.res.write(chunk)
543
+ const onDrain = () => stm.resume()
544
+ if (c.res) c.res.on('drain', onDrain)
643
545
 
644
- if (data_count >= 111) {
645
- data_count = 0
646
- timeout_timer && clearTimeout(timeout_timer)
647
- timeout_timer = setTimeout(timeout_handler, pr.timeout + 5000)
546
+ stm.on('data', chunk => {
547
+ if (c.res && c.res.writable) {
548
+ if (c.res.write(chunk) === false) {
549
+ stm.pause()
550
+ }
648
551
  }
649
552
  })
650
553
 
651
554
  stm.on('end', () => {
652
- if (timeout_timer) {
653
- clearTimeout(timeout_timer)
654
- timeout_timer = null
655
- }
656
-
657
- stm.close()
555
+ if (c.res) c.res.removeListener('drain', onDrain)
556
+
557
+ !stm.closed && stm.close()
658
558
 
659
559
  if (!resolved && !rejected) {
660
560
  resolved = true
@@ -666,8 +566,6 @@ Http2Proxy.prototype.mid = function () {
666
566
  } catch (err) {
667
567
  self.debug && console.error(err||'request null error')
668
568
  c.status(503).to(error_503_text)
669
- } finally {
670
- session_client = null
671
569
  }
672
570
 
673
571
  }
@@ -4,6 +4,20 @@ const urlparse = require('node:url');
4
4
  const http = require('node:http');
5
5
  const https = require('node:https');
6
6
 
7
+ // 主机名提取 (IPv6 兼容优化版)
8
+ function extractHostname(host) {
9
+ if (!host) return ''
10
+ if (host.charCodeAt(0) === 91) { // '[' IPv6
11
+ const end = host.indexOf(']')
12
+ return end > -1 ? host.substring(0, end + 1) : host
13
+ }
14
+ const idx = host.indexOf(':')
15
+ if (idx === -1) return host
16
+ if (host.indexOf(':', idx + 1) !== -1) return host // 裸 IPv6
17
+ return host.substring(0, idx)
18
+ }
19
+
20
+
7
21
  /**
8
22
  * {
9
23
  * host : {}
@@ -406,22 +420,7 @@ class Proxy {
406
420
 
407
421
  return async (c, next) => {
408
422
 
409
- let host = c.host
410
-
411
- let hind = c.host.length - 1
412
-
413
- if (hind > 4) {
414
- let eind = hind - 5
415
-
416
- while (hind >= eind) {
417
- if (c.host[hind] === ':') {
418
- host = c.host.substring(0, hind)
419
- break
420
- }
421
-
422
- hind--
423
- }
424
- }
423
+ let host = extractHostname(c.host)
425
424
 
426
425
  if (self.hostProxy[host]===undefined || self.hostProxy[host][c.routepath]===undefined) {
427
426
  if (self.full) {
@@ -433,7 +432,7 @@ class Proxy {
433
432
  let pr = self.getBackend(c, host)
434
433
 
435
434
  if (pr === null) {
436
- for (let i = 0; i < 200; i++) {
435
+ for (let i = 0; i < 50; i++) {
437
436
  await new Promise((rv, rj) => {setTimeout(rv, 10)})
438
437
  pr = self.getBackend(c, host)
439
438
  if (pr) break