@sentry/core
Version:
Base implementation for all Sentry JavaScript SDKs
154 lines (150 loc) • 6.04 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const currentScopes = require('../currentScopes.js');
const integration = require('../integration.js');
const semanticAttributes = require('../semanticAttributes.js');
const cookie = require('../utils/cookie.js');
const request = require('../utils/request.js');
const getIpAddress = require('../vendor/getIpAddress.js');
const captureSpan = require('../tracing/spans/captureSpan.js');
const INTEGRATION_NAME = "RequestData";
const _requestDataIntegration = ((options = {}) => {
function resolveIncludeAndDataCollection(client) {
const dc = client.getDataCollectionOptions();
const dataCollection = {
...dc,
...options.include?.cookies === true && dc.cookies === false && { cookies: true },
...options.include?.headers === true && dc.httpHeaders.request === false && {
httpHeaders: { ...dc.httpHeaders, request: true }
}
};
return {
dataCollection,
include: {
cookies: dataCollection.cookies !== false,
// Always attach body data that's already on the scope — dataCollection.httpBodies gates write-time, not read-time
data: true,
headers: dataCollection.httpHeaders.request !== false,
ip: dataCollection.userInfo,
query_string: dataCollection.queryParams !== false,
// No dataCollection equivalent — URL is always included
url: true,
...options.include
}
};
}
return {
name: INTEGRATION_NAME,
processEvent(event, _hint, client) {
const { sdkProcessingMetadata = {} } = event;
const { normalizedRequest, ipAddress } = sdkProcessingMetadata;
const { include } = resolveIncludeAndDataCollection(client);
if (normalizedRequest) {
addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, include);
}
return event;
},
processSegmentSpan(span, client) {
const { sdkProcessingMetadata = {} } = currentScopes.getIsolationScope().getScopeData();
const { normalizedRequest, ipAddress } = sdkProcessingMetadata;
if (!normalizedRequest) {
return;
}
const { include, dataCollection } = resolveIncludeAndDataCollection(client);
addNormalizedRequestDataToSpan(span, normalizedRequest, ipAddress, include, dataCollection);
}
};
});
const requestDataIntegration = integration.defineIntegration(_requestDataIntegration);
function addNormalizedRequestDataToEvent(event, req, additionalData, include) {
event.request = {
...event.request,
...extractNormalizedRequestData(req, include)
};
if (include.ip) {
const ip = req.headers && getIpAddress.getClientIPAddress(req.headers) || additionalData.ipAddress;
if (ip) {
event.user = {
...event.user,
ip_address: ip
};
}
}
}
function addNormalizedRequestDataToSpan(span, normalizedRequest, ipAddress, include, dataCollection) {
const requestData = extractNormalizedRequestData(normalizedRequest, include);
const attributes = {};
if (requestData.url) {
attributes["url.full"] = requestData.url;
}
if (requestData.method) {
attributes["http.request.method"] = requestData.method;
}
if (requestData.query_string) {
attributes["url.query"] = normalizeQueryString(requestData.query_string);
}
captureSpan.safeSetSpanJSONAttributes(span, attributes);
if (requestData.cookies && Object.keys(requestData.cookies).length > 0) {
const cookieString = Object.entries(requestData.cookies).map(([name, value]) => `${name}=${value}`).join("; ");
const cookieAttributes = request.httpHeadersToSpanAttributes({ cookie: cookieString }, dataCollection, "request");
captureSpan.safeSetSpanJSONAttributes(span, cookieAttributes);
}
if (requestData.headers) {
const headerAttributes = request.httpHeadersToSpanAttributes(requestData.headers, dataCollection, "request");
captureSpan.safeSetSpanJSONAttributes(span, headerAttributes);
}
if (requestData.data != null) {
const serialized = typeof requestData.data === "string" ? requestData.data : JSON.stringify(requestData.data);
if (serialized) {
captureSpan.safeSetSpanJSONAttributes(span, { "http.request.body.data": serialized });
}
}
if (include.ip) {
const ip = normalizedRequest.headers && getIpAddress.getClientIPAddress(normalizedRequest.headers) || ipAddress || void 0;
if (ip) {
captureSpan.safeSetSpanJSONAttributes(span, { [semanticAttributes.SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: ip });
}
}
}
function extractNormalizedRequestData(normalizedRequest, include) {
const requestData = {};
const headers = { ...normalizedRequest.headers };
if (include.headers) {
requestData.headers = headers;
if (!include.cookies) {
delete headers.cookie;
}
if (!include.ip) {
const ipHeaderNamesLower = new Set(getIpAddress.ipHeaderNames.map((name) => name.toLowerCase()));
for (const key of Object.keys(headers)) {
if (ipHeaderNamesLower.has(key.toLowerCase())) {
delete headers[key];
}
}
}
}
requestData.method = normalizedRequest.method;
if (include.url) {
requestData.url = normalizedRequest.url;
}
if (include.cookies) {
const cookies = normalizedRequest.cookies || (headers?.cookie ? cookie.parseCookie(headers.cookie) : void 0);
requestData.cookies = cookies || {};
}
if (include.query_string) {
requestData.query_string = normalizedRequest.query_string;
}
if (include.data) {
requestData.data = normalizedRequest.data;
}
return requestData;
}
function normalizeQueryString(queryString) {
if (typeof queryString === "string") {
return queryString || void 0;
}
const pairs = Array.isArray(queryString) ? queryString : Object.entries(queryString);
const result = pairs.map(([key, value]) => `${key}=${value}`).join("&");
return result || void 0;
}
exports.requestDataIntegration = requestDataIntegration;
//# sourceMappingURL=requestdata.js.map