Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 19x 19x 15x 15x 15x 15x 14x 14x 14x 14x 14x 14x 1x 14x 14x 14x 14x 10x 10x 7x 14x 14x | import { PatcherContext } from '../context'
import { XHRWithFingerprintContext, FingerprintContextSymbol } from './types'
import { AGENT_DATA_HEADER } from '../../../../shared/const'
import { logger } from '../../../shared/logger'
/**
* Creates a patched version of the `send` method for `XMLHttpRequest` instances.
* This allows for the injection and handling of signals in requests based on the provided context.
*
* @param {PatcherContext} ctx - The context object containing configurations and methods for signal processing.
* @return {function} A patched `send` method for `XMLHttpRequest` instances.
*/
export function createPatchedSend(ctx: PatcherContext): typeof XMLHttpRequest.prototype.send {
const originalSend = XMLHttpRequest.prototype.send
return function patchedSend(this: XHRWithFingerprintContext, body?: Document | XMLHttpRequestBodyInit | null) {
const sendRequest = () => originalSend.call(this, body)
const fingerprintContext = this[FingerprintContextSymbol]
const handleSignalsInjectionPromise = fingerprintContext?.handleSignalsInjectionPromise
if (handleSignalsInjectionPromise) {
let didInjectSignals = false
prepareResponseHandling(this, ctx, () => didInjectSignals)
// Signals' promise is present only in async requests. In that case, we can await the signal promise before sending the request
handleSignalsInjectionPromise
.then((didInject) => {
didInjectSignals = didInject
})
.finally(() => {
sendRequest()
})
return
}
// Sync requests are not supported for now
return sendRequest()
}
}
/**
* Prepares the handling of the response for the specified XMLHttpRequest by attaching
* logic to manage agent data and context processing after the request is completed.
*
* @param {XMLHttpRequest} request - The XMLHttpRequest object for which response handling is prepared.
* @param {PatcherContext} ctx - The context used for processing agent data after the request is completed.
* @param {function(): boolean} didInjectSignals - A function that determines if signals were injected
* and influences whether agent data is processed.
*/
function prepareResponseHandling(request: XMLHttpRequest, ctx: PatcherContext, didInjectSignals: () => boolean) {
// Helper to process agent data after response, only once
const processAgentData = () => {
try {
request.removeEventListener?.('loadend', processAgentData)
if (didInjectSignals()) {
const agentData = request.getResponseHeader(AGENT_DATA_HEADER)
if (agentData) {
ctx.processAgentData(agentData)
}
}
} catch (e) {
logger.error('Error processing XHR agent data:', e)
}
}
try {
request.addEventListener('loadend', processAgentData)
} catch {
logger.error('Failed to add event listener for XHR agent data processing')
}
}
|