@sentry/core
Version:
Base implementation for all Sentry JavaScript SDKs
155 lines (137 loc) • 4.84 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
// Curious about `thismessage:/`? See: https://www.rfc-editor.org/rfc/rfc2557.html
// > When the methods above do not yield an absolute URI, a base URL
// > of "thismessage:/" MUST be employed. This base URL has been
// > defined for the sole purpose of resolving relative references
// > within a multipart/related structure when no other base URI is
// > specified.
//
// We need to provide a base URL to `parseStringToURLObject` because the fetch API gives us a
// relative URL sometimes.
//
// This is the only case where we need to provide a base URL to `parseStringToURLObject`
// because the relative URL is not valid on its own.
const DEFAULT_BASE_URL = 'thismessage:/';
/**
* Checks if the URL object is relative
*
* @param url - The URL object to check
* @returns True if the URL object is relative, false otherwise
*/
function isURLObjectRelative(url) {
return 'isRelative' in url;
}
/**
* Parses string to a URL object
*
* @param url - The URL to parse
* @returns The parsed URL object or undefined if the URL is invalid
*/
function parseStringToURLObject(url, urlBase) {
const isRelative = url.startsWith('/');
const base = urlBase ?? (isRelative ? DEFAULT_BASE_URL : undefined);
try {
// Use `canParse` to short-circuit the URL constructor if it's not a valid URL
// This is faster than trying to construct the URL and catching the error
// Node 20+, Chrome 120+, Firefox 115+, Safari 17+
if ('canParse' in URL && !(URL ).canParse(url, base)) {
return undefined;
}
const fullUrlObject = new URL(url, base);
if (isRelative) {
// Because we used a fake base URL, we need to return a relative URL object.
// We cannot return anything about the origin, host, etc. because it will refer to the fake base URL.
return {
isRelative,
pathname: fullUrlObject.pathname,
search: fullUrlObject.search,
hash: fullUrlObject.hash,
};
}
return fullUrlObject;
} catch {
// empty body
}
return undefined;
}
/**
* Takes a URL object and returns a sanitized string which is safe to use as span name
* see: https://develop.sentry.dev/sdk/data-handling/#structuring-data
*/
function getSanitizedUrlStringFromUrlObject(url) {
if (isURLObjectRelative(url)) {
return url.pathname;
}
const newUrl = new URL(url);
newUrl.search = '';
newUrl.hash = '';
if (['80', '443'].includes(newUrl.port)) {
newUrl.port = '';
}
if (newUrl.password) {
newUrl.password = '%filtered%';
}
if (newUrl.username) {
newUrl.username = '%filtered%';
}
return newUrl.toString();
}
/**
* Parses string form of URL into an object
* // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B
* // intentionally using regex and not <a/> href parsing trick because React Native and other
* // environments where DOM might not be available
* @returns parsed URL object
*/
function parseUrl(url) {
if (!url) {
return {};
}
const match = url.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/);
if (!match) {
return {};
}
// coerce to undefined values to empty string so we don't get 'undefined'
const query = match[6] || '';
const fragment = match[8] || '';
return {
host: match[4],
path: match[5],
protocol: match[2],
search: query,
hash: fragment,
relative: match[5] + query + fragment, // everything minus origin
};
}
/**
* Strip the query string and fragment off of a given URL or path (if present)
*
* @param urlPath Full URL or path, including possible query string and/or fragment
* @returns URL or path without query string or fragment
*/
function stripUrlQueryAndFragment(urlPath) {
return (urlPath.split(/[?#]/, 1) )[0];
}
/**
* Takes a URL object and returns a sanitized string which is safe to use as span name
* see: https://develop.sentry.dev/sdk/data-handling/#structuring-data
*/
function getSanitizedUrlString(url) {
const { protocol, host, path } = url;
const filteredHost =
host
// Always filter out authority
?.replace(/^.*@/, '[filtered]:[filtered]@')
// Don't show standard :80 (http) and :443 (https) ports to reduce the noise
// TODO: Use new URL global if it exists
.replace(/(:80)$/, '')
.replace(/(:443)$/, '') || '';
return `${protocol ? `${protocol}://` : ''}${filteredHost}${path}`;
}
exports.getSanitizedUrlString = getSanitizedUrlString;
exports.getSanitizedUrlStringFromUrlObject = getSanitizedUrlStringFromUrlObject;
exports.isURLObjectRelative = isURLObjectRelative;
exports.parseStringToURLObject = parseStringToURLObject;
exports.parseUrl = parseUrl;
exports.stripUrlQueryAndFragment = stripUrlQueryAndFragment;
//# sourceMappingURL=url.js.map