Skip to content

Intercepting Fetch function – Request Headers

I am intercepting already intercepted fetch and I cannot read final request data (specifically request headers).

By intercepting I mean wrapping original window.fetch()

See comments below.

// this was already wrapped before me...
// so it's NOT pure window.fetch
const originalFetch = window.fetch;
 
window.fetch = function() {
    
    // this will be added to the request
    arguments[1].headers.append("X-Security-A", 1);
    
    // After apply() below, the arguments are changed using
    // other external functions, which also intercept the fetch
    // and they will add additional headers;
    // I don't have access to these functions.
    
    // I cannot change the resource URL, because the external
    // functions check it.
    
    // I need to read the new headers, but the [arguments]
    // remain unchanged. They are changed somewhere within this apply()
    var promise = originalFetch.apply(this, arguments);
    
    // this will be added, but will NOT be added to actual
    // request, which already happened
    arguments[1].headers.append("X-Security-B", 1);
    
    promise.then((response) => {
        
            // Here I will get the results, but the request headers
            // are still NOT here;
            // only the ones I added
            // If I look in Chrome Console the sent request
            // contains all the headers I need to see.
            
            // HOW CAN I GET THE REQUEST HEADERS HERE?

            console.log('XXX Promise', promise);
            console.log('XXX Headers ', Array.from(arguments[1].headers.entries()));
            console.log('XXX Response', response);
            return response;
        });

    return promise;
}

Answer

Okay, so once the window.Fetch is wrapped second time, then you cannot get the latest arguments before the actual request.

It would be perfect to be able to make the first wrap, but my script runs as last.

However it is possible to intercept the prototype.call() and prototype.apply() and that worked for me 🙂

const originalFetch = window.fetch;
const originalCall = window.Function.prototype.call;

window.fetch = function() {
    
    var lastCall;
    window.Function.prototype.call = function(){
        lastCall = arguments;
        return originalCall.apply(this, arguments);
    };
    
    var x = originalFetch.apply(this, arguments);

    window.Function.prototype.call = originalCall; // reset
    
    x.then((response) => {
        
        console.log("XXX intercepted:", lastCall, response);
        
        return response;
    });
    
    return x;
};