Skip to content

Commit 033d6b4

Browse files
committed
ref(core): Keep the Node tunnel handler out of bundles without a tunnel
Core's HTTP server instrumentation imported the tunnel's Node handler, so every Node and Cloudflare bundle carried it. The tunnel now registers the handler in the tunnel store when its hooks install, and the instrumentation calls it from there.
1 parent 2918f88 commit 033d6b4

6 files changed

Lines changed: 48 additions & 16 deletions

File tree

‎packages/core/src/integrations/http/server-subscription.ts‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ import { DEBUG_BUILD } from '../../debug-build';
2525
import { debug } from '../../utils/debug-logger';
2626
import { safeCallback } from '../../utils/safeCallback';
2727
import { isServedTunnelRequest } from '../../utils/tunnel';
28-
import { handleServedNodeTunnelRequest } from '../../utils/tunnelForward';
29-
import { setHttpServerAnswersTunnel } from '../../utils/tunnelStore';
28+
import { getNodeTunnelHandler, setHttpServerHandlesTunnel } from '../../utils/tunnelStore';
3029
import { getClient, getCurrentScope, getIsolationScope, withIsolationScope } from '../../currentScopes';
3130
import { hasSpansEnabled } from '../../utils/hasSpansEnabled';
3231
import {
@@ -139,7 +138,7 @@ export function instrumentServer(options: HttpInstrumentationOptions, server: Ht
139138
// second wrapper for the tunnel. With `intercept: false` the app answers them, so they keep their own isolation
140139
// scope.
141140
if (isServedTunnelRequest(request)) {
142-
if (handleServedNodeTunnelRequest(request, response)) {
141+
if (getNodeTunnelHandler()?.(request, response)) {
143142
return true;
144143
}
145144

@@ -258,7 +257,7 @@ export function getHttpServerSubscriptions(options: HttpInstrumentationOptions):
258257
// this because it creates spans through a separate code path).
259258
const userWrap = options.wrapServerEmitRequest;
260259
const spanWrap = buildServerSpanWrap(options);
261-
setHttpServerAnswersTunnel();
260+
setHttpServerHandlesTunnel();
262261

263262
const effectiveOptions: HttpInstrumentationOptions = {
264263
...options,

‎packages/core/src/server.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export {
1414
isServedTunnelRequest as _INTERNAL_isServedTunnelRequest,
1515
isTunnelRequest,
1616
} from './utils/tunnel';
17-
export { httpServerAnswersTunnel as _INTERNAL_httpServerAnswersTunnel } from './utils/tunnelStore';
17+
export {
18+
httpServerHandlesTunnel as _INTERNAL_httpServerHandlesTunnel,
19+
setNodeTunnelHandler as _INTERNAL_setNodeTunnelHandler,
20+
} from './utils/tunnelStore';
1821
export {
1922
forwardTunnelRequest as _INTERNAL_forwardTunnelRequest,
2023
handleServedNodeTunnelRequest as _INTERNAL_handleServedNodeTunnelRequest,

‎packages/core/src/utils/tunnelForward.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ export function handleTunnelRequestIfMatched(
130130
);
131131
}
132132

133+
/**
134+
* Answers a tunnel request on a Node server ahead of the app, see {@link handleServedNodeTunnelRequest}.
135+
*/
136+
export type NodeTunnelHandler = (request: NodeTunnelRequest, response: NodeTunnelResponse) => boolean;
137+
133138
/**
134139
* Answers a request to the tunnel `serveTunnelIntegration` serves on a Node server, ahead of the app. Returns `true`
135140
* when it claimed the request and answers it, `false` to hand the request to the app.

‎packages/core/src/utils/tunnelStore.ts‎

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { getGlobalSingleton } from '../carrier';
33
import type { IgnoreSpanFilter } from '../types/options';
44
import type { TunnelDefaults } from './tunnelDefaults';
55
import type { ServedTunnel, TunnelForwarder } from './tunnel';
6+
import type { NodeTunnelHandler } from './tunnelForward';
67

78
/**
89
* What the tunnel keeps per server client.
@@ -23,8 +24,10 @@ export interface ClientTunnelState {
2324
export interface TunnelStore {
2425
clients: WeakMap<Client, ClientTunnelState>;
2526
defaults?: TunnelDefaults;
26-
/** Whether core's HTTP server instrumentation is set up, whose `emit` wrapper answers tunnel requests itself. */
27-
httpServerAnswersTunnel?: boolean;
27+
/** Whether core's HTTP server instrumentation is set up, whose `emit` wrapper handles tunnel requests itself. */
28+
httpServerHandlesTunnel?: boolean;
29+
/** Answers tunnel requests on Node servers. The tunnel sets it, so apps without one don't bundle it. */
30+
nodeHandler?: NodeTunnelHandler;
2831
}
2932

3033
/**
@@ -64,16 +67,30 @@ export function setStoredTunnelDefaults(defaults: TunnelDefaults | undefined): v
6467
}
6568

6669
/**
67-
* Records that core's HTTP server instrumentation is set up. Its `emit` wrapper answers tunnel requests, so `node:http`
70+
* Records that core's HTTP server instrumentation is set up. Its `emit` wrapper handles tunnel requests, so `node:http`
6871
* servers need no second one for the tunnel.
6972
*/
70-
export function setHttpServerAnswersTunnel(): void {
71-
getTunnelStore().httpServerAnswersTunnel = true;
73+
export function setHttpServerHandlesTunnel(): void {
74+
getTunnelStore().httpServerHandlesTunnel = true;
7275
}
7376

7477
/**
75-
* Whether core's HTTP server instrumentation answers tunnel requests, see {@link setHttpServerAnswersTunnel}.
78+
* Whether core's HTTP server instrumentation handles tunnel requests, see {@link setHttpServerHandlesTunnel}.
7679
*/
77-
export function httpServerAnswersTunnel(): boolean {
78-
return !!getTunnelStore().httpServerAnswersTunnel;
80+
export function httpServerHandlesTunnel(): boolean {
81+
return !!getTunnelStore().httpServerHandlesTunnel;
82+
}
83+
84+
/**
85+
* Sets what answers tunnel requests on Node servers, like the forwarder `serveTunnelIntegration` brings in.
86+
*/
87+
export function setNodeTunnelHandler(handler: NodeTunnelHandler): void {
88+
getTunnelStore().nodeHandler = handler;
89+
}
90+
91+
/**
92+
* What answers tunnel requests on Node servers, see {@link setNodeTunnelHandler}.
93+
*/
94+
export function getNodeTunnelHandler(): NodeTunnelHandler | undefined {
95+
return getTunnelStore().nodeHandler;
7996
}

‎packages/server-utils/src/integrations/serveTunnel.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import type { ServerTunnelOptions } from '@sentry/core';
22
import { defineIntegration } from '@sentry/core';
3-
import { HTTP_ON_SERVER_REQUEST, serveTunnelIntegration as coreServeTunnelIntegration } from '@sentry/core/server';
3+
import {
4+
_INTERNAL_handleServedNodeTunnelRequest as handleServedNodeTunnelRequest,
5+
_INTERNAL_setNodeTunnelHandler as setNodeTunnelHandler,
6+
HTTP_ON_SERVER_REQUEST,
7+
serveTunnelIntegration as coreServeTunnelIntegration,
8+
} from '@sentry/core/server';
49
import { subscribe } from '../utils/diagnosticsChannel';
510
import { instrumentTunnelServer } from '../utils/tunnelServer';
611

@@ -16,6 +21,9 @@ export function instrumentTunnelServers(): void {
1621
}
1722

1823
isSubscribed = true;
24+
// Core's HTTP server instrumentation answers tunnel requests through it, without bundling it for apps that have no
25+
// tunnel.
26+
setNodeTunnelHandler(handleServedNodeTunnelRequest);
1927
subscribe(HTTP_ON_SERVER_REQUEST, instrumentTunnelServer);
2028
}
2129

‎packages/server-utils/src/utils/tunnelServer.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { debug } from '@sentry/core';
22
import {
33
_INTERNAL_handleServedNodeTunnelRequest as handleServedNodeTunnelRequest,
4-
_INTERNAL_httpServerAnswersTunnel as httpServerAnswersTunnel,
4+
_INTERNAL_httpServerHandlesTunnel as httpServerHandlesTunnel,
55
} from '@sentry/core/server';
66
import { DEBUG_BUILD } from '../debug-build';
77

@@ -20,7 +20,7 @@ const tunnelServers = new WeakSet<TunnelServer>();
2020
export function instrumentTunnelServer(message: unknown): void {
2121
try {
2222
const server = (message as { server?: TunnelServer } | undefined)?.server;
23-
if (!server || tunnelServers.has(server) || httpServerAnswersTunnel()) {
23+
if (!server || tunnelServers.has(server) || httpServerHandlesTunnel()) {
2424
return;
2525
}
2626

0 commit comments

Comments
 (0)