@sentry/core
Version:
Base implementation for all Sentry JavaScript SDKs
152 lines (148 loc) • 6.07 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const currentScopes = require('../currentScopes.js');
const attributes = require('@sentry/conventions/attributes');
const escapeStringForRegex = require('../vendor/escapeStringForRegex.js');
const dsn = require('./dsn.js');
const url = require('./url.js');
const servedTunnels = /* @__PURE__ */ new WeakMap();
const SERVE_TUNNEL_INTEGRATION_NAME = "ServeTunnel";
function setServedTunnel(client, tunnelOptions, forward) {
const allowedDsns = resolveAllowedDsns(tunnelOptions.allowedDsns, client.getDsn());
const servedTunnel = {
paths: resolveTunnelPaths(tunnelOptions, allowedDsns),
basePath: tunnelOptions.basePath,
allowedDsns,
forward
};
servedTunnels.set(client, servedTunnel);
return servedTunnel;
}
function getServeTunnelForwarder(client) {
return client.getIntegrationByName?.(SERVE_TUNNEL_INTEGRATION_NAME)?.forward;
}
function getServedTunnel() {
const client = currentScopes.getClient();
if (!client) {
return void 0;
}
const servedTunnel = servedTunnels.get(client);
if (servedTunnel) {
return servedTunnel;
}
const tunnelOptions = client.getOptions()._managedTunnel;
const forward = getServeTunnelForwarder(client);
return tunnelOptions && forward ? setServedTunnel(client, tunnelOptions, forward) : void 0;
}
function applyTunnelDefaults(tunnel, defaults) {
if (!tunnel || typeof tunnel === "string" || tunnel !== true && tunnel.path) {
return tunnel;
}
const { basePath, ...rest } = defaults ?? {};
const normalizedBasePath = normalizeTunnelBasePath(basePath);
const resolvedDefaults = normalizedBasePath ? { ...rest, basePath: normalizedBasePath } : rest;
if (!Object.keys(resolvedDefaults).length) {
return tunnel;
}
return { ...resolvedDefaults, ...tunnel === true ? {} : tunnel };
}
function getTunnelPath(dsn$1) {
const components = dsn$1 ? dsn.makeDsn(dsn$1) : currentScopes.getClient()?.getDsn();
return components ? `/${fnv1a32(dsn.dsnToString(components)).toString(36)}` : void 0;
}
function getTunnelPaths() {
return getServedTunnel()?.paths ?? [];
}
function resolveTunnelPaths(tunnelOptions, allowedDsns) {
const fixedPath = tunnelOptions.path?.replace(/\/$/, "");
if (fixedPath) {
return [fixedPath];
}
const paths = allowedDsns.map((dsn) => getTunnelPath(dsn));
return [...new Set(paths.filter((path) => !!path))];
}
function getTunnelIgnoreSpanFilters(tunnelOptions, paths) {
if (!paths.length) {
return [];
}
const basePath = escapeStringForRegex.escapeStringForRegex(normalizeTunnelBasePath(tunnelOptions.basePath));
const pathPattern = `${basePath}(?:${paths.map(escapeStringForRegex.escapeStringForRegex).join("|")})/?`;
return [
// oxlint-disable-next-line sdk/no-regexp-constructor -- built from escaped config values, not end user input
{ attributes: { [attributes.URL_PATH]: new RegExp(`^${pathPattern}$`) } },
// oxlint-disable-next-line sdk/no-regexp-constructor -- built from escaped config values, not end user input
{ attributes: { "http.url": new RegExp(`^[a-z][a-z\\d+.-]*://[^/]+${pathPattern}(?:[?#].*)?$`) } }
];
}
function normalizeTunnelBasePath(basePath) {
const path = (basePath?.startsWith("./") ? basePath.slice(1) : basePath ?? "").replace(/\/$/, "");
return !path || path.startsWith("/") ? path : `/${path}`;
}
function resolveTunnelMatch(options) {
const servedTunnel = !options && getServedTunnel();
if (servedTunnel) {
return servedTunnel;
}
const allowedDsns = resolveAllowedDsns(options?.allowedDsns, currentScopes.getClient()?.getDsn());
return { paths: resolveTunnelPaths(options ?? {}, allowedDsns), basePath: options?.basePath, allowedDsns };
}
function matchesTunnel(request, tunnel) {
if (request.method !== "POST" || !request.url) {
return false;
}
const path = stripBasePath(url.parseUrl(request.url).path || "/", tunnel.basePath);
return path !== void 0 && tunnel.paths.includes(path.replace(/\/$/, ""));
}
function isTunnelRequest(request, options) {
return matchesTunnel(request, resolveTunnelMatch(options));
}
function isServedTunnelRequest(request) {
const servedTunnel = getServedTunnel();
return !!servedTunnel && matchesTunnel(request, servedTunnel);
}
function handleServedTunnelRequest(request) {
const servedTunnel = getServedTunnel();
if (!servedTunnel?.allowedDsns.length || !matchesTunnel(request, servedTunnel)) {
return void 0;
}
return servedTunnel.forward(request, servedTunnel.allowedDsns);
}
function resolveAllowedDsns(allowedDsns, ownDsn) {
const dsns = /* @__PURE__ */ new Set();
for (const components of [...(allowedDsns ?? []).map((dsn$1) => dsn.makeDsn(dsn$1)), ownDsn]) {
if (components) {
dsns.add(dsn.dsnToString(components));
}
}
return [...dsns];
}
function stripBasePath(pathname, basePath) {
const base = normalizeTunnelBasePath(basePath);
if (!base) {
return pathname;
}
return pathname === base || pathname.startsWith(`${base}/`) ? pathname.slice(base.length) : void 0;
}
function fnv1a32(input) {
let hash = 2166136261;
for (let i = 0; i < input.length; i++) {
hash ^= input.charCodeAt(i);
hash = Math.imul(hash, 16777619);
}
return hash >>> 0;
}
exports.SERVE_TUNNEL_INTEGRATION_NAME = SERVE_TUNNEL_INTEGRATION_NAME;
exports.applyTunnelDefaults = applyTunnelDefaults;
exports.getServeTunnelForwarder = getServeTunnelForwarder;
exports.getTunnelIgnoreSpanFilters = getTunnelIgnoreSpanFilters;
exports.getTunnelPath = getTunnelPath;
exports.getTunnelPaths = getTunnelPaths;
exports.handleServedTunnelRequest = handleServedTunnelRequest;
exports.isServedTunnelRequest = isServedTunnelRequest;
exports.isTunnelRequest = isTunnelRequest;
exports.matchesTunnel = matchesTunnel;
exports.normalizeTunnelBasePath = normalizeTunnelBasePath;
exports.resolveAllowedDsns = resolveAllowedDsns;
exports.resolveTunnelMatch = resolveTunnelMatch;
exports.resolveTunnelPaths = resolveTunnelPaths;
exports.setServedTunnel = setServedTunnel;
//# sourceMappingURL=tunnel.js.map