import { configs } from './configs'; import { formDataToQuery } from '../utils/request-utils'; import { isFormData, isNullish, isObject, isString } from '../utils/type-utils'; function _tryReadXHRBody({ body, }: { body: any | null | undefined; url: string | URL | RequestInfo; }): string | null { if (isNullish(body)) { return null; } if (isString(body)) { return body; } if (isFormData(body)) { return formDataToQuery(body); } if (isObject(body)) { try { return JSON.stringify({ ...body }); } catch { return '[XHR] Failed to stringify response object'; } } return `[XHR] Cannot read body of type ${Object.prototype.toString.call(body)}`; } // Only patch XMLHttpRequest if not on web platform or if XMLHttpRequest is available if (typeof XMLHttpRequest !== 'undefined') { (function (xhr) { const originalOpen = XMLHttpRequest.prototype.open; xhr.open = function ( method: string, url: string | URL, async = true, username?: string | null, password?: string | null ) { const xhr = this as XMLHttpRequest; const networkRequest: { requestHeaders?: any; requestBody?: any; responseHeaders?: any; responseBody?: any; } = {}; // ts-expect-error const requestHeaders: Record = {}; const originalSetRequestHeader = xhr.setRequestHeader.bind(xhr); xhr.setRequestHeader = (header: string, value: string) => { requestHeaders[header] = value; return originalSetRequestHeader(header, value); }; if (configs.recordRequestHeaders) { networkRequest.requestHeaders = requestHeaders; } const originalSend = xhr.send.bind(xhr); xhr.send = (body) => { if (configs.shouldRecordBody) { const requestBody = _tryReadXHRBody({ body, url }); if ( requestBody?.length && requestBody.length <= configs.maxCapturingHttpPayloadSize ) { networkRequest.requestBody = requestBody; } } return originalSend(body); }; xhr.addEventListener('readystatechange', () => { if (xhr.readyState !== xhr.DONE) { return; } // ts-expect-error const responseHeaders: Record = {}; const rawHeaders = xhr.getAllResponseHeaders() || ''; const headers = rawHeaders .trim() .split(/[\r\n]+/) .filter(Boolean); headers.forEach((line) => { const parts = line.split(': '); const header = parts.shift(); const value = parts.join(': '); if (header) { responseHeaders[header] = value; } }); if (configs.recordResponseHeaders) { networkRequest.responseHeaders = responseHeaders; } if (configs.shouldRecordBody) { const responseBody = _tryReadXHRBody({ body: xhr.response, url }); if ( responseBody?.length && responseBody.length <= configs.maxCapturingHttpPayloadSize ) { networkRequest.responseBody = responseBody; } } }); // @ts-expect-error xhr.networkRequest = networkRequest; originalOpen.call(xhr, method, url as string, async, username, password); }; })(XMLHttpRequest.prototype); } else { console.info('XHR patch: XMLHttpRequest patching not available'); }