File Explorer

/proc/2/root/var/runtime/node_modules/@aws-sdk/node_modules/axios/lib/adapters

This explorer reads the filesystem of the server it runs on, so /workspace/user isn't present here. Browsing and the terminal still work against this server's own disk from /.

fetch.js19.9 KB · 644 lines
import platform from '../platform/index.js';import utils from '../utils.js';import AxiosError from '../core/AxiosError.js';import composeSignals from '../helpers/composeSignals.js';import { trackStream } from '../helpers/trackStream.js';import AxiosHeaders from '../core/AxiosHeaders.js';import {  progressEventReducer,  progressEventDecorator,  asyncDecorator,} from '../helpers/progressEventReducer.js';import resolveConfig from '../helpers/resolveConfig.js';import settle from '../core/settle.js';import estimateDataURLDecodedBytes from '../helpers/estimateDataURLDecodedBytes.js';import { VERSION } from '../env/data.js';import { toByteStringHeaderObject } from '../helpers/sanitizeHeaderValue.js'; const DEFAULT_CHUNK_SIZE = 64 * 1024; const { isFunction } = utils; /** * Encode a UTF-8 string to a Latin-1 byte string for use with btoa(). * This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern. * * @param {string} str The string to encode * * @returns {string} UTF-8 bytes as a Latin-1 string */const encodeUTF8 = (str) =>  encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>    String.fromCharCode(parseInt(hex, 16))  ); // Node's WHATWG URL parser returns `username` and `password` percent-encoded.// Decode before composing the `auth` option so credentials such as// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the// original value for malformed input so a bad encoding never throws.const decodeURIComponentSafe = (value) => {  if (!utils.isString(value)) {    return value;  }   try {    return decodeURIComponent(value);  } catch (error) {    return value;  }}; const test = (fn, ...args) => {  try {    return !!fn(...args);  } catch (e) {    return false;  }}; const maybeWithAuthCredentials = (url) => {  const protocolIndex = url.indexOf('://');  let urlToCheck = url;  if (protocolIndex !== -1) {    urlToCheck = urlToCheck.slice(protocolIndex + 3);  }  return urlToCheck.includes('@') || urlToCheck.includes(':');}; const factory = (env) => {  const globalObject =    utils.global !== undefined && utils.global !== null      ? utils.global      : globalThis;  const { ReadableStream, TextEncoder } = globalObject;   env = utils.merge.call(    {      skipUndefined: true,    },    {      Request: globalObject.Request,      Response: globalObject.Response,    },    env  );   const { fetch: envFetch, Request, Response } = env;  const isFetchSupported = envFetch ? isFunction(envFetch) : typeof fetch === 'function';  const isRequestSupported = isFunction(Request);  const isResponseSupported = isFunction(Response);   if (!isFetchSupported) {    return false;  }   const isReadableStreamSupported = isFetchSupported && isFunction(ReadableStream);   const encodeText =    isFetchSupported &&    (typeof TextEncoder === 'function'      ? (          (encoder) => (str) =>            encoder.encode(str)        )(new TextEncoder())      : async (str) => new Uint8Array(await new Request(str).arrayBuffer()));   const supportsRequestStream =    isRequestSupported &&    isReadableStreamSupported &&    test(() => {      let duplexAccessed = false;       const request = new Request(platform.origin, {        body: new ReadableStream(),        method: 'POST',        get duplex() {          duplexAccessed = true;          return 'half';        },      });       const hasContentType = request.headers.has('Content-Type');       if (request.body != null) {        request.body.cancel();      }       return duplexAccessed && !hasContentType;    });   const supportsResponseStream =    isResponseSupported &&    isReadableStreamSupported &&    test(() => utils.isReadableStream(new Response('').body));   const resolvers = {    stream: supportsResponseStream && ((res) => res.body),  };   isFetchSupported &&    (() => {      ['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach((type) => {        !resolvers[type] &&          (resolvers[type] = (res, config) => {            let method = res && res[type];             if (method) {              return method.call(res);            }             throw new AxiosError(              `Response type '${type}' is not supported`,              AxiosError.ERR_NOT_SUPPORT,              config            );          });      });    })();   const getBodyLength = async (body) => {    if (body == null) {      return 0;    }     if (utils.isBlob(body)) {      return body.size;    }     if (utils.isSpecCompliantForm(body)) {      const _request = new Request(platform.origin, {        method: 'POST',        body,      });      return (await _request.arrayBuffer()).byteLength;    }     if (utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) {      return body.byteLength;    }     if (utils.isURLSearchParams(body)) {      body = body + '';    }     if (utils.isString(body)) {      return (await encodeText(body)).byteLength;    }  };   const resolveBodyLength = async (headers, body) => {    const length = utils.toFiniteNumber(headers.getContentLength());     return length == null ? getBodyLength(body) : length;  };   return async (config) => {    let {      url,      method,      data,      signal,      cancelToken,      timeout,      onDownloadProgress,      onUploadProgress,      responseType,      headers,      withCredentials = 'same-origin',      fetchOptions,      maxContentLength,      maxBodyLength,    } = resolveConfig(config);     const hasMaxContentLength = utils.isNumber(maxContentLength) && maxContentLength > -1;    const hasMaxBodyLength = utils.isNumber(maxBodyLength) && maxBodyLength > -1;    const own = (key) => (utils.hasOwnProp(config, key) ? config[key] : undefined);     let _fetch = envFetch || fetch;     responseType = responseType ? (responseType + '').toLowerCase() : 'text';     let composedSignal = composeSignals(      [signal, cancelToken && cancelToken.toAbortSignal()],      timeout    );     let request = null;     const unsubscribe =      composedSignal &&      composedSignal.unsubscribe &&      (() => {        composedSignal.unsubscribe();      });     let requestContentLength;     // AxiosError we raise while the request body is being streamed. Captured    // by identity so the catch block can surface it directly, regardless of    // how the runtime wraps the resulting fetch rejection (undici exposes it    // as `err.cause`; some browsers drop the original error entirely).    let pendingBodyError = null;     const maxBodyLengthError = () =>      new AxiosError(        'Request body larger than maxBodyLength limit',        AxiosError.ERR_BAD_REQUEST,        config,        request      );     try {      // HTTP basic authentication      let auth = undefined;      const configAuth = own('auth');       if (configAuth) {        const username = utils.getSafeProp(configAuth, 'username') || '';        const password = utils.getSafeProp(configAuth, 'password') || '';        auth = {          username,          password        };      }       if (maybeWithAuthCredentials(url)) {        const parsedURL = new URL(url, platform.origin);         if (!auth && (parsedURL.username || parsedURL.password)) {          const urlUsername = decodeURIComponentSafe(parsedURL.username);          const urlPassword = decodeURIComponentSafe(parsedURL.password);          auth = {            username: urlUsername,            password: urlPassword          };        }         if (parsedURL.username || parsedURL.password) {          parsedURL.username = '';          parsedURL.password = '';          url = parsedURL.href;        }      }       if (auth) {        headers.delete('authorization');        headers.set(          'Authorization',          'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || '')))        );      }       // Enforce maxContentLength for data: URLs up-front so we never materialize      // an oversized payload. The HTTP adapter applies the same check (see http.js      // "if (protocol === 'data:')" branch).      if (hasMaxContentLength && typeof url === 'string' && url.startsWith('data:')) {        const estimated = estimateDataURLDecodedBytes(url);        if (estimated > maxContentLength) {          throw new AxiosError(            'maxContentLength size of ' + maxContentLength + ' exceeded',            AxiosError.ERR_BAD_RESPONSE,            config,            request          );        }      }       // Enforce maxBodyLength against known-size bodies before dispatch using      // the body's *actual* size — never a caller-declared Content-Length,      // which could under-report to slip an oversized body past the check.      // Unknown-size streams return undefined here and are counted per-chunk      // below as fetch consumes them.      if (hasMaxBodyLength && method !== 'get' && method !== 'head') {        const outboundLength = await getBodyLength(data);        if (typeof outboundLength === 'number' && isFinite(outboundLength)) {          requestContentLength = outboundLength;          if (outboundLength > maxBodyLength) {            throw maxBodyLengthError();          }        }      }       // A streamed body under maxBodyLength must be counted as fetch consumes      // it; its size is never trusted from a caller-declared Content-Length.      const mustEnforceStreamBody =        hasMaxBodyLength && (utils.isReadableStream(data) || utils.isStream(data));       const trackRequestStream = (stream, onProgress, flush) =>        trackStream(          stream,          DEFAULT_CHUNK_SIZE,          (loadedBytes) => {            if (hasMaxBodyLength && loadedBytes > maxBodyLength) {              throw (pendingBodyError = maxBodyLengthError());            }            onProgress && onProgress(loadedBytes);          },          flush        );       if (        supportsRequestStream &&        method !== 'get' &&        method !== 'head' &&        (onUploadProgress || mustEnforceStreamBody)      ) {        requestContentLength =          requestContentLength == null ? await resolveBodyLength(headers, data) : requestContentLength;         // A declared length of 0 is only trusted to skip the wrap when we are        // not enforcing a stream limit (which must not rely on that header).        if (requestContentLength !== 0 || mustEnforceStreamBody) {          let _request = new Request(url, {            method: 'POST',            body: data,            duplex: 'half',          });           let contentTypeHeader;           if (utils.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {            headers.setContentType(contentTypeHeader);          }           if (_request.body) {            const [onProgress, flush] =              (onUploadProgress &&                progressEventDecorator(                  requestContentLength,                  progressEventReducer(asyncDecorator(onUploadProgress))                )) ||              [];             data = trackRequestStream(_request.body, onProgress, flush);          }        }      } else if (        mustEnforceStreamBody &&        !isRequestSupported &&        isReadableStreamSupported &&        method !== 'get' &&        method !== 'head'      ) {        data = trackRequestStream(data);      } else if (        mustEnforceStreamBody &&        isRequestSupported &&        !supportsRequestStream &&        method !== 'get' &&        method !== 'head'      ) {        throw new AxiosError(          'Stream request bodies are not supported by the current fetch implementation',          AxiosError.ERR_NOT_SUPPORT,          config,          request        );      }       if (!utils.isString(withCredentials)) {        withCredentials = withCredentials ? 'include' : 'omit';      }       // Cloudflare Workers throws when credentials are defined      // see https://github.com/cloudflare/workerd/issues/902      const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype;       // If data is FormData and Content-Type is multipart/form-data without boundary,      // delete it so fetch can set it correctly with the boundary      if (utils.isFormData(data)) {        const contentType = headers.getContentType();        if (          contentType &&          /^multipart\/form-data/i.test(contentType) &&          !/boundary=/i.test(contentType)        ) {          headers.delete('content-type');        }      }       // Set User-Agent header if not already set (fetch defaults to 'node' in Node.js)      headers.set('User-Agent', 'axios/' + VERSION, false);       const resolvedOptions = {        ...fetchOptions,        signal: composedSignal,        method: method.toUpperCase(),        headers: toByteStringHeaderObject(headers.normalize()),        body: data,        duplex: 'half',        credentials: isCredentialsSupported ? withCredentials : undefined,      };       request = isRequestSupported && new Request(url, resolvedOptions);       let response = await (isRequestSupported        ? _fetch(request, fetchOptions)        : _fetch(url, resolvedOptions));       const responseHeaders = AxiosHeaders.from(response.headers);       // Cheap pre-check: if the server honestly declares a content-length that      // already exceeds the cap, reject before we start streaming.      if (hasMaxContentLength) {        const declaredLength = utils.toFiniteNumber(responseHeaders.getContentLength());        if (declaredLength != null && declaredLength > maxContentLength) {          throw new AxiosError(            'maxContentLength size of ' + maxContentLength + ' exceeded',            AxiosError.ERR_BAD_RESPONSE,            config,            request          );        }      }       const isStreamResponse =        supportsResponseStream && (responseType === 'stream' || responseType === 'response');       if (        supportsResponseStream &&        response.body &&        (onDownloadProgress || hasMaxContentLength || (isStreamResponse && unsubscribe))      ) {        const options = {};         ['status', 'statusText', 'headers'].forEach((prop) => {          options[prop] = response[prop];        });         const responseContentLength = utils.toFiniteNumber(responseHeaders.getContentLength());         const [onProgress, flush] =          (onDownloadProgress &&            progressEventDecorator(              responseContentLength,              progressEventReducer(asyncDecorator(onDownloadProgress), true)            )) ||          [];         let bytesRead = 0;        const onChunkProgress = (loadedBytes) => {          if (hasMaxContentLength) {            bytesRead = loadedBytes;            if (bytesRead > maxContentLength) {              throw new AxiosError(                'maxContentLength size of ' + maxContentLength + ' exceeded',                AxiosError.ERR_BAD_RESPONSE,                config,                request              );            }          }          onProgress && onProgress(loadedBytes);        };         response = new Response(          trackStream(response.body, DEFAULT_CHUNK_SIZE, onChunkProgress, () => {            flush && flush();            unsubscribe && unsubscribe();          }),          options        );      }       responseType = responseType || 'text';       let responseData = await resolvers[utils.findKey(resolvers, responseType) || 'text'](        response,        config      );       // Fallback enforcement for environments without ReadableStream support      // (legacy runtimes). Detect materialized size from typed output; skip      // streams/Response passthrough since the user will read those themselves.      if (hasMaxContentLength && !supportsResponseStream && !isStreamResponse) {        let materializedSize;        if (responseData != null) {          if (typeof responseData.byteLength === 'number') {            materializedSize = responseData.byteLength;          } else if (typeof responseData.size === 'number') {            materializedSize = responseData.size;          } else if (typeof responseData === 'string') {            materializedSize =              typeof TextEncoder === 'function'                ? new TextEncoder().encode(responseData).byteLength                : responseData.length;          }        }        if (typeof materializedSize === 'number' && materializedSize > maxContentLength) {          throw new AxiosError(            'maxContentLength size of ' + maxContentLength + ' exceeded',            AxiosError.ERR_BAD_RESPONSE,            config,            request          );        }      }       !isStreamResponse && unsubscribe && unsubscribe();       return await new Promise((resolve, reject) => {        settle(resolve, reject, {          data: responseData,          headers: AxiosHeaders.from(response.headers),          status: response.status,          statusText: response.statusText,          config,          request,        });      });    } catch (err) {      unsubscribe && unsubscribe();       // Safari can surface fetch aborts as a DOMException-like object whose      // branded getters throw. Prefer our composed signal reason before reading      // the caught error, preserving timeout vs cancellation semantics.      if (composedSignal && composedSignal.aborted && composedSignal.reason instanceof AxiosError) {        const canceledError = composedSignal.reason;        canceledError.config = config;        request && (canceledError.request = request);        if (err !== canceledError) {          // Non-enumerable to match native Error `cause` semantics so loggers          // don't recurse into circular fetch internals (see #7205).          Object.defineProperty(canceledError, 'cause', {            __proto__: null,            value: err,            writable: true,            enumerable: false,            configurable: true,          });        }        throw canceledError;      }       // Surface a maxBodyLength violation we raised while the request body was      // being streamed. Matching by identity (rather than reading      // `err.cause.isAxiosError`) keeps the error deterministic across runtimes      // and avoids both prototype-pollution reads and mis-attributing a foreign      // AxiosError that merely happened to land in `err.cause`.      if (pendingBodyError) {        request && !pendingBodyError.request && (pendingBodyError.request = request);        throw pendingBodyError;      }       // Re-throw AxiosErrors we raised synchronously (data: URL / content-length      // pre-checks, response size enforcement) without re-wrapping them.      if (err instanceof AxiosError) {        request && !err.request && (err.request = request);        throw err;      }       if (err && err.name === 'TypeError' && /Load failed|fetch/i.test(err.message)) {        const networkError = new AxiosError(          'Network Error',          AxiosError.ERR_NETWORK,          config,          request,          err && err.response        );        // Non-enumerable to match native Error `cause` semantics so loggers        // don't recurse into circular fetch internals (see #7205).        Object.defineProperty(networkError, 'cause', {          __proto__: null,          value: err.cause || err,          writable: true,          enumerable: false,          configurable: true,        });        throw networkError;      }       throw AxiosError.from(err, err && err.code, config, request, err && err.response);    }  };}; const seedCache = new Map(); export const getFetch = (config) => {  let env = (config && config.env) || {};  const { fetch, Request, Response } = env;  const seeds = [Request, Response, fetch];   let len = seeds.length,    i = len,    seed,    target,    map = seedCache;   while (i--) {    seed = seeds[i];    target = map.get(seed);     target === undefined && map.set(seed, (target = i ? new Map() : factory(env)));     map = target;  }   return target;}; const adapter = getFetch(); export default adapter;