Search code examples
javascriptgoogle-chrome-extensiongoogle-chrome-devtools

Chrome debugger Network.getResponseBody gives "no resource with given identifier found" even after waiting for Network.loadingFinished event


I am writing an extension that gets data from a browser game. It uses the chrome debugger library to attach a debugger and receives an event for every message the tab gets for the server. I look for the Network.responseReceived event that comes from the URL I need. I then wait for the Network.loadingFinished event that shares the same requestId. I send a Network.getResponseBody command using the requestId as an argument which gives me the body of the request which I process and store.

The issue is that lately, I will get the error: {"code":-32000,"message":"No resource with given identifier found"} randomly when requesting the response body and I don't know why. Sometimes it works, and sometimes it doesn't.

Things I have tried:

  • Sending the Network.getResponseBody before the Network.finishedLoading event
  • Sending the command as soon as I get the finishedLoading event
  • Sending the command repeatedly on an exponentially increasing delay if it fails
  • Sending the command on a varying static delay

No matter what I do, it fails around 50% of the time with a -32000 code and succeeds 50%. I can always get the correct requestId. Here is the code I used.

const maxRetryAttempts = 5;

// Gets the response body of the requestId in params.requestId
async function GetRewardResponseBody(debuggeeId, params, responseReceivedEpoch) {
  var errorArray = [];
  var initialDelayMS = 5;
  var fetchSucceeded = false;
  for(let retryAttempts = 1; retryAttempts <= maxRetryAttempts; retryAttempts++){
    await sendCommandPromise(debuggeeId.tabId, params)
    .then((response) => {
      ProcessRewardJSON(debuggeeId.tabId, response); // Processes data if I didn't get error -32000
      console.log("Successfully exiting with debugeeId: ", debuggeeId);
      fetchSucceeded = true;
      }).catch((error) => { // Error occured
      errorArray.push(error);
    });
    if (fetchSucceeded){break;} // Breaks from for loop so it doesn't re-request
    await delay(initialDelayMS); // waits until next attempt
    initialDelayMS *= 2;
  }
  if (!fetchSucceeded){
    console.log(errorArray); // Prints all errors to the console
  }
  console.log("Clearing timeout and returning");
  clearTimeout(debuggerTimeout); // Removes timeout that would auto remove the debugger
  RemoveDebugger(debuggeeId, false);
}

function sendCommandPromise(tabId, params) {
  return new Promise((resolve, reject) => {
    try{
      chrome.debugger.sendCommand(
        {"tabId" : tabId
      }, "Network.getResponseBody", {
        "requestId": params.requestId
      }, function(response) {
        if (chrome.runtime.lastError){ // Error -32000 was thrown
          reject(chrome.runtime.lastError);
        }
        else if (!response || !response.body) { // response body was empty for some reason
          console.error("Response was empty");
          reject(new Error("Response was empty"));
        }
        else {resolve(response);}
      });
    }
    catch(ex){ // Any other errors
      console.log("Error fetching resource");
      reject(ex)
    }
  });
}

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

---EDIT--- I looked through the messages that I received from the game and noticed that every time I fail to get the response body and end up with error -32000, I am missing the first 3 messages of the exchange. Here is a screenshot of an exchange where I succeeded and an exchange I got the error:

screenshot of messages for a successful request and failed request

Each row has the message type, the timestamp it was received, and the responseID for the chain of messages.

ALSO NOTE: For the successful requests, the Network.responseReceived message has the field "hasExtraInfo" set to true while the unsuccessful request's Network.responseReceived message has it set to false

Will Network.getResponseBody always fail if the Network.enable command is received after the Network.requestWillBeSent event is fired? I thought that it would work as long as you had the valid responseID for that request.


Solution

  • I forgot that I asked this but I found the answer shortly after posting so I thought I would put it here if anyone ran into the same issue.

    As it turns out, chrome will not allow you to access a response if either the debugger was not attached or network is not enabled when the Network.requestWillBeSent event is fired.

    That means that the only way to access a request body is to have both the debugger and network enabled BEFORE the Network.requestWillBeSent event is fired. It doesn't matter if you get the request ID from an event later in the chain, chrome will still block access to the response body if your extension missed that first event.

    I was able to solve the issue by having the debugger dynamically attach and detach when a tab navigates to the domain I am tracking, not just the page path. Waiting for the page path won't give me enough time to catch the first Network.requestWillBeSent event before the debugger is attached and the network is enabled.