| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 | 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";const isFetchSupported = typeof fetch === 'function' && typeof Request === 'function' && typeof Response === 'function';const isReadableStreamSupported = isFetchSupported && typeof ReadableStream === 'function';// used only inside the fetch adapterconst encodeText = isFetchSupported && (typeof TextEncoder === 'function' ?    ((encoder) => (str) => encoder.encode(str))(new TextEncoder()) :    async (str) => new Uint8Array(await new Response(str).arrayBuffer()));const test = (fn, ...args) => {  try {    return !!fn(...args);  } catch (e) {    return false  }}const supportsRequestStream = isReadableStreamSupported && test(() => {  let duplexAccessed = false;  const hasContentType = new Request(platform.origin, {    body: new ReadableStream(),    method: 'POST',    get duplex() {      duplexAccessed = true;      return 'half';    },  }).headers.has('Content-Type');  return duplexAccessed && !hasContentType;});const DEFAULT_CHUNK_SIZE = 64 * 1024;const supportsResponseStream = isReadableStreamSupported &&  test(() => utils.isReadableStream(new Response('').body));const resolvers = {  stream: supportsResponseStream && ((res) => res.body)};isFetchSupported && (((res) => {  ['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach(type => {    !resolvers[type] && (resolvers[type] = utils.isFunction(res[type]) ? (res) => res[type]() :      (_, config) => {        throw new AxiosError(`Response type '${type}' is not supported`, AxiosError.ERR_NOT_SUPPORT, config);      })  });})(new Response));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;}export default isFetchSupported && (async (config) => {  let {    url,    method,    data,    signal,    cancelToken,    timeout,    onDownloadProgress,    onUploadProgress,    responseType,    headers,    withCredentials = 'same-origin',    fetchOptions  } = resolveConfig(config);  responseType = responseType ? (responseType + '').toLowerCase() : 'text';  let composedSignal = composeSignals([signal, cancelToken && cancelToken.toAbortSignal()], timeout);  let request;  const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => {      composedSignal.unsubscribe();  });  let requestContentLength;  try {    if (      onUploadProgress && supportsRequestStream && method !== 'get' && method !== 'head' &&      (requestContentLength = await resolveBodyLength(headers, data)) !== 0    ) {      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] = progressEventDecorator(          requestContentLength,          progressEventReducer(asyncDecorator(onUploadProgress))        );        data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);      }    }    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 = "credentials" in Request.prototype;    request = new Request(url, {      ...fetchOptions,      signal: composedSignal,      method: method.toUpperCase(),      headers: headers.normalize().toJSON(),      body: data,      duplex: "half",      credentials: isCredentialsSupported ? withCredentials : undefined    });    let response = await fetch(request);    const isStreamResponse = supportsResponseStream && (responseType === 'stream' || responseType === 'response');    if (supportsResponseStream && (onDownloadProgress || (isStreamResponse && unsubscribe))) {      const options = {};      ['status', 'statusText', 'headers'].forEach(prop => {        options[prop] = response[prop];      });      const responseContentLength = utils.toFiniteNumber(response.headers.get('content-length'));      const [onProgress, flush] = onDownloadProgress && progressEventDecorator(        responseContentLength,        progressEventReducer(asyncDecorator(onDownloadProgress), true)      ) || [];      response = new Response(        trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {          flush && flush();          unsubscribe && unsubscribe();        }),        options      );    }    responseType = responseType || 'text';    let responseData = await resolvers[utils.findKey(resolvers, responseType) || 'text'](response, config);    !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();    if (err && err.name === 'TypeError' && /fetch/i.test(err.message)) {      throw Object.assign(        new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request),        {          cause: err.cause || err        }      )    }    throw AxiosError.from(err, err && err.code, config, request);  }});
 |