openreplay/spot/utils/networkDebuggerTracking.ts

110 lines
3.4 KiB
TypeScript

let requestMap = {}
export function resetMap() {
requestMap = {}
}
export async function attachDebuggerToTab(tabId: string | number) {
await new Promise((resolve, reject) => {
chrome.debugger.attach({ tabId }, "1.3", () => {
if (chrome.runtime.lastError)
return reject(chrome.runtime.lastError.message);
chrome.debugger.sendCommand({ tabId }, "Network.enable", {}, resolve);
});
chrome.debugger.onEvent.addListener(handleRequestIntercept);
});
}
export async function detachDebuggerFromTab(tabId: string) {
return new Promise((resolve, reject) => {
chrome.debugger.detach({ tabId }, resolve);
chrome.debugger.onEvent.removeListener(handleRequestIntercept);
});
}
const getType = (requestType: string) => {
switch (requestType) {
case "Fetch":
case "XHR":
case "xmlhttprequest":
return 'xmlhttprequest'
default:
return requestType
}
}
function handleRequestIntercept(source, method, params) {
if (!source.tabId) return; // Not our target tab
if (!params.request) return; // No request object
if (params.request.method === "OPTIONS") return; // Ignore preflight requests
switch (method) {
case "Network.requestWillBeSent":
const reqType = params.type ? getType(params.type) : "resource";
if (reqType !== "xmlhttprequest") {
console.log(params);
}
requestMap[params.requestId] = {
encodedBodySize: 0,
responseBodySize: 0,
duration: 0,
method: params.request.method,
type: reqType,
statusCode: 0,
url: params.request.url,
body: params.request.postData || "",
responseBody: "",
fromCache: false,
requestHeaders: params.request.headers || {},
responseHeaders: {},
timestamp: Date.now(),
};
break;
case "Network.responseReceived":
if (!requestMap[params.requestId]) return;
requestMap[params.requestId].statusCode = params.response.status;
requestMap[params.requestId].responseHeaders =
params.response.headers || {};
// fromDiskCache or fromServiceWorker if available
if (params.response.fromDiskCache)
requestMap[params.requestId].fromCache = true;
break;
case "Network.dataReceived":
if (!requestMap[params.requestId]) return;
requestMap[params.requestId].encodedBodySize += params.dataLength;
// There's no direct content-encoding size from debugger
break;
case "Network.loadingFinished":
if (!requestMap[params.requestId]) return;
requestMap[params.requestId].duration =
Date.now() - requestMap[params.requestId].time;
requestMap[params.requestId].responseBodySize =
requestMap[params.requestId].encodedBodySize;
chrome.debugger.sendCommand(
{ tabId: source.tabId },
"Network.getResponseBody",
{ requestId: params.requestId },
(res) => {
if (!res || res.error) {
requestMap[params.requestId].error = res?.error || "Unknown";
} else {
requestMap[params.requestId].responseBody = res.base64Encoded
? atob(res.body)
: res.body;
}
},
);
break;
case "Network.loadingFailed":
if (!requestMap[params.requestId]) return;
requestMap[params.requestId].error = params.errorText || "Unknown";
break;
}
}
export const getRequests = () => {
return Object.values(requestMap);
};