fix: admin/monitoring: "input" bandwidth was not counting https traffic
Massimo Melina committed
Jun 5, 2025 at 21:38 UTC
6b2a7bc785ce7850b680e54b833f8dcd417dd22b
3 files changed
+18
-9
src/connections.ts
+4
-3
@@ -17,6 +17,7 @@ export class Connection {
17
private _cachedIp?: string
18
[rest:symbol]: any // let other modules add extra data, but using symbols to avoid name collision
19
20
+ // the sockets we collect are the plain ones, as soon as the tcp layer is connected
21
constructor(public readonly socket: Socket) {
22
all.push(this)
23
socket.on('close', () => {
@@ -45,9 +46,9 @@ export function newConnection(socket: Socket) {
46
const ip = normalizeIp(socket.remoteAddress || '')
47
const res = events.emit('newSocket', { socket, ip })
48
const msg = res?.isDefaultPrevented() ? 'plugin (newSocket)' : res?.find(_.isString)
48
- if (msg)
49
- return disconnect(socket, msg)
50
- new Connection(socket)
49
+ if (!msg)
50
+ return new Connection(socket)
51
+ disconnect(socket, msg)
52
}
53
54
export function getConnections(): Readonly<typeof all> {
src/listen.ts
+9
-3
@@ -6,7 +6,8 @@ import { app } from './index'
6
import * as https from 'https'
7
import { watchLoad } from './watchLoad'
8
import { networkInterfaces } from 'os';
9
-import { newConnection } from './connections'
9
+import { getConnections, newConnection } from './connections'
10
+import { TLSSocket } from 'node:tls'
11
import open from 'open'
12
import {
13
CFG, debounceAsync, ipForUrl, makeNetMatcher, MINUTE, objSameKeys, onlyTruthy, prefix, runAt, wait, xlate
@@ -145,14 +146,19 @@ const considerHttps = debounceAsync(async () => {
146
}
147
port = await startServer(httpsSrv, { port, host: listenInterface.get() })
148
if (!port) return
148
- httpsSrv.on('connection', newConnection)
149
+ httpsSrv.on('connection', newConnection) // this event is emitted as soon as the tcp layer is connected
150
+ httpsSrv.on('secureConnection', (socket: TLSSocket) => { // emitted when the TLS layer is connected
151
+ for (const c of getConnections()) // TLSSocket shares same ip:port, so we can find its matching Connection
152
+ if (socket.remoteAddress === c.socket.remoteAddress
153
+ && socket.remotePort === c.socket.remotePort)
154
+ return c.socket.emit('secure', socket) // let know Connection about the secure socket
155
+ })
156
printUrls(httpsSrv.name)
157
events.emit('httpsReady')
158
defaultBaseUrl.proto = 'https'
159
defaultBaseUrl.port = getCurrentPort(httpsSrv) ?? 0
160
}, { wait: 200 }) // give time to have key and cert ready
161
155
-
162
export const cert = defineConfig('cert', '')
163
export const privateKey = defineConfig('private_key', '')
164
const httpsNeeds = [cert, privateKey]
src/throttler.ts
+5
-3
@@ -121,6 +121,8 @@ setInterval(() => {
121
}
122
}, 1000)
123
124
-events.on('connection', (c: Connection) =>
125
- c.socket.on('data', data =>
126
- totalGot.set(x => x + data.length) ))
124
+events.on('connection', (c: Connection) => {
125
+ const count = (data: Buffer | string) => totalGot.set(x => x + data.length)
126
+ c.socket.on('data', count)
127
+ c.socket.on('secure', s => s.on('data', count)) // secure sockets won't forward 'data' events to the plain ones
128
+})