| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- 'use strict';
- import AxiosError, { REDACTED } from './AxiosError.js';
- import isAbsoluteURL from '../helpers/isAbsoluteURL.js';
- import combineURLs from '../helpers/combineURLs.js';
- const malformedHttpProtocol = /^https?:(?!\/\/)/i;
- const httpProtocolControlCharacters = /[\t\n\r]/g;
- function stripLeadingC0ControlOrSpace(url) {
- let i = 0;
- while (i < url.length && url.charCodeAt(i) <= 0x20) {
- i++;
- }
- return url.slice(i);
- }
- function normalizeURLForProtocolCheck(url) {
- return stripLeadingC0ControlOrSpace(url).replace(httpProtocolControlCharacters, '');
- }
- // Redact the parts of a URL that can carry secrets before it is embedded in an
- // error message. AxiosError.toJSON() serializes `message` verbatim and errors
- // are commonly logged, while the opt-in `config.redact` model only cleans
- // config keys — it cannot reach the message. Redact only the genuinely
- // sensitive substrings — userinfo (credentials), query parameter values and
- // fragment contents — with the same REDACTED marker the config redaction uses,
- // while keeping the scheme, host, path and parameter names so the offending
- // request stays accurately identifiable.
- function redactFragment(fragment) {
- if (!fragment) {
- return fragment;
- }
- return fragment.replace(/(^|&)([^=&]*=)?[^&]+/g, (match, separator, parameterName = '') => {
- return `${separator}${parameterName}${REDACTED}`;
- });
- }
- function redactSensitiveURLParts(url) {
- const redactedURL = url.replace(/^(https?:\/{0,2})[^/?#]*@/i, `$1${REDACTED}@`);
- const fragmentIndex = redactedURL.indexOf('#');
- const urlWithoutFragment =
- fragmentIndex === -1 ? redactedURL : redactedURL.slice(0, fragmentIndex);
- const redactedURLWithoutFragment = urlWithoutFragment.replace(
- /([?&][^=&#]*=)[^&#]*/g,
- `$1${REDACTED}`
- );
- if (fragmentIndex === -1) {
- return redactedURLWithoutFragment;
- }
- return `${redactedURLWithoutFragment}#${redactFragment(redactedURL.slice(fragmentIndex + 1))}`;
- }
- function assertValidHttpProtocolURL(url, config) {
- if (typeof url === 'string') {
- const normalizedURL = normalizeURLForProtocolCheck(url);
- if (malformedHttpProtocol.test(normalizedURL)) {
- throw new AxiosError(
- `Invalid URL ${JSON.stringify(redactSensitiveURLParts(normalizedURL))}: missing "//" after protocol`,
- AxiosError.ERR_INVALID_URL,
- config
- );
- }
- }
- }
- /**
- * Creates a new URL by combining the baseURL with the requestedURL,
- * only when the requestedURL is not already an absolute URL.
- * If the requestURL is absolute, this function returns the requestedURL untouched.
- *
- * @param {string} baseURL The base URL
- * @param {string} requestedURL Absolute or relative URL to combine
- *
- * @returns {string} The combined full path
- */
- export default function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls, config) {
- assertValidHttpProtocolURL(requestedURL, config);
- let isRelativeUrl = !isAbsoluteURL(requestedURL);
- if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
- assertValidHttpProtocolURL(baseURL, config);
- return combineURLs(baseURL, requestedURL);
- }
- return requestedURL;
- }
|