Search code examples
javascriptgoogle-chromegoogle-chrome-extension

Chrome Extension: "No resource with given identifier found" when trying to Network.getResponseBody


I'm writing a Chrome Extension that can get HTTP response for a site. I try to use debugger for getting response body:

var gCurrentTab;

chrome.debugger.onEvent.addListener(function (source, method, params) {
        if (gCurrentTab.id != source.tabId) {
            return;
        }
        if (method == "Network.loadingFinished") {
            var tabId = source.tabId;
            var requestId = params.requestId;
            chrome.debugger.sendCommand(
                source,
                "Network.getResponseBody",
                {"requestId": requestId},
                function (body) {
                    console.log(body);
                    chrome.debugger.detach(source);
                });
        }
    }
);

chrome.webRequest.onBeforeRequest.addListener(function (details) {
        var url = details.url;
        if (url.indexOf('/mypage') >= 0) {
            chrome.tabs.query({
                currentWindow: true,
                active: true
            }, function (tabs) {
                gCurrentTab = tabs[0];
                chrome.debugger.attach({
                    tabId: gCurrentTab.id
                }, "1.0", function () {
                    chrome.debugger.sendCommand({
                        tabId: gCurrentTab.id
                    }, "Network.enable");
                });
            });
        }
    },
    {urls: []}, ["requestBody", "blocking"]);

But I always get

Unchecked runtime.lastError while running debugger.sendCommand: {"code":-32000,"message":"No resource with given identifier found"} at chrome-extension://ikphgobkghdkjkfplgokmapjlbdfeegl/background.js:11:29

error, and the body is undefined.

Does anyone have idea about why this happen? Thanks!


Solution

  • It was because the website sends many responses, and this code will see another request other than I want, then detach the debugger so I can't get the result.

    To solve this, just use a single debugger and do not detach it, or only detach when it's safe to.

    var gAttached = false;
    var gRequests = [];
    var gObjects = [];
    
    chrome.debugger.onEvent.addListener(function (source, method, params) {
            if (method == "Network.requestWillBeSent") {
                // If we see a url need to be handled, push it into index queue
                var rUrl = params.request.url;
                if (getTarget(rUrl) >= 0) {
                    gRequests.push(rUrl);
                }
            }
            if (method == "Network.responseReceived") {
                // We get its request id here, write it down to object queue
                var eUrl = params.response.url;
                var target = getTarget(eUrl);
                if (target >= 0) {
                    gObjects.push({
                        requestId: params.requestId,
                        target: target,
                        url: eUrl
                    });
                }
            }
            if (method == "Network.loadingFinished" && gObjects.length > 0) {
                // Pop out the request object from both object queue and request queue
                var requestId = params.requestId;
                var object = null;
                for (var o in gObjects) {
                    if (requestId == gObjects[o].requestId) {
                        object = gObjects.splice(o, 1)[0];
                        break;
                    }
                }
                // Usually loadingFinished will be immediately after responseReceived
                if (object == null) {
                    console.log('Failed!!');
                    return;
                }
                gRequests.splice(gRequests.indexOf(object.url), 1);
                chrome.debugger.sendCommand(
                    source,
                    "Network.getResponseBody",
                    {"requestId": requestId},
                    function (response) {
                        if (response) {
                            dispatch(source.tabId, object.target, JSON.parse(response.body));
                        } else {
                            console.log("Empty response for " + object.url);
                        }
                        // If we don't have any request waiting for response, re-attach debugger
                        // since without this step it will lead to memory leak.
                        if (gRequests.length == 0) {
                            chrome.debugger.detach({
                                tabId: source.tabId
                            }, function () {
                                chrome.debugger.attach({
                                    tabId: source.tabId
                                }, "1.0", function () {
                                    chrome.debugger.sendCommand({
                                        tabId: source.tabId
                                    }, "Network.enable");
                                });
                            });
                        }
                    });
            }
        }
    );
    
    var initialListener = function (details) {
        if (gAttached) return;  // Only need once at the very first request, so block all following requests
        var tabId = details.tabId;
        if (tabId > 0) {
            gAttached = true;
            chrome.debugger.attach({
                tabId: tabId
            }, "1.0", function () {
                chrome.debugger.sendCommand({
                    tabId: tabId
                }, "Network.enable");
            });
            // Remove self since the debugger is attached already
            chrome.webRequest.onBeforeRequest.removeListener(initialListener);
        }
    };
    
    // Attach debugger on startup
    chrome.webRequest.onBeforeRequest.addListener(initialListener, {urls: ["<all_urls>"]}, ["blocking"]);
    
    // Filter if the url is what we want
    function getTarget(url) {
        for (var i in TARGETS) {
            var target = TARGETS[i];
            if (url.match(target.url)) {
                return i;
            }
        }
        return -1;
    }
    
    const TARGETS = [
        {url: '/path1', desc: 'target1'},
        {url: '/path2', desc: 'target2'}
    ]