157 lines
4.4 KiB
TypeScript
157 lines
4.4 KiB
TypeScript
import {
|
|
SpotNetworkRequest,
|
|
filterBody,
|
|
filterHeaders,
|
|
tryFilterUrl,
|
|
TrackedRequest,
|
|
} from "./networkTrackingUtils";
|
|
|
|
export const rawRequests: Array<
|
|
TrackedRequest & { startTs: number; duration: number }
|
|
> = [];
|
|
|
|
function getRequestStatus(request: TrackedRequest): number {
|
|
if (request.statusCode) return request.statusCode;
|
|
if (request.error) return 0;
|
|
return 200;
|
|
}
|
|
|
|
function modifyOnSpot(request: TrackedRequest) {
|
|
const id = request.requestId;
|
|
const index = rawRequests.findIndex((r) => r.requestId === id);
|
|
const ts = Date.now();
|
|
const start = rawRequests[index]?.startTs ?? ts;
|
|
rawRequests[index] = {
|
|
...rawRequests[index],
|
|
...request,
|
|
duration: ts - start,
|
|
};
|
|
}
|
|
|
|
function trackOnBefore(
|
|
details: browser.webRequest._OnBeforeRequestDetails & { reqBody?: string },
|
|
) {
|
|
if (details.method === "POST" && details.requestBody) {
|
|
if (details.requestBody.formData) {
|
|
details.reqBody = JSON.stringify(details.requestBody.formData);
|
|
} else if (details.requestBody.raw) {
|
|
const raw = details.requestBody.raw[0]?.bytes;
|
|
if (raw) details.reqBody = new TextDecoder("utf-8").decode(raw);
|
|
}
|
|
}
|
|
rawRequests.push({ ...details, startTs: Date.now(), duration: 0 });
|
|
}
|
|
|
|
function trackOnHeaders(
|
|
details: browser.webRequest._OnBeforeSendHeadersDetails,
|
|
) {
|
|
modifyOnSpot(details);
|
|
}
|
|
|
|
function trackOnCompleted(details: browser.webRequest._OnCompletedDetails) {
|
|
modifyOnSpot(details);
|
|
}
|
|
|
|
function trackOnError(details: browser.webRequest._OnErrorOccurredDetails) {
|
|
modifyOnSpot(details);
|
|
}
|
|
|
|
// Build final SpotNetworkRequest objects
|
|
function createSpotNetworkRequest(
|
|
trackedRequest: TrackedRequest,
|
|
trackedTab?: number,
|
|
): SpotNetworkRequest | undefined {
|
|
if (trackedRequest.tabId === -1) return;
|
|
if (trackedTab && trackedTab !== trackedRequest.tabId) return;
|
|
|
|
if (
|
|
["ping", "beacon", "image", "script", "font"].includes(trackedRequest.type)
|
|
) {
|
|
if (!trackedRequest.statusCode || trackedRequest.statusCode < 400) return;
|
|
}
|
|
|
|
const type = ["stylesheet", "script", "image", "media", "font"].includes(
|
|
trackedRequest.type,
|
|
)
|
|
? "resource"
|
|
: trackedRequest.type;
|
|
|
|
const requestHeaders = trackedRequest.requestHeaders
|
|
? filterHeaders(trackedRequest.requestHeaders)
|
|
: {};
|
|
const responseHeaders = trackedRequest.responseHeaders
|
|
? filterHeaders(trackedRequest.responseHeaders)
|
|
: {};
|
|
|
|
const reqSize = trackedRequest.reqBody
|
|
? trackedRequest.requestSize || trackedRequest.reqBody.length
|
|
: 0;
|
|
const status = getRequestStatus(trackedRequest);
|
|
|
|
let body = "";
|
|
if (trackedRequest.reqBody) {
|
|
try {
|
|
body = filterBody(trackedRequest.reqBody);
|
|
} catch (e) {
|
|
body = "Error parsing body";
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
const request: SpotNetworkRequest = {
|
|
method: trackedRequest.method,
|
|
type,
|
|
body,
|
|
responseBody: "",
|
|
requestHeaders,
|
|
responseHeaders,
|
|
time: trackedRequest.timeStamp,
|
|
timestamp: trackedRequest.timeStamp,
|
|
statusCode: status,
|
|
error: trackedRequest.error,
|
|
url: tryFilterUrl(trackedRequest.url),
|
|
fromCache: trackedRequest.fromCache || false,
|
|
encodedBodySize: reqSize,
|
|
responseBodySize: trackedRequest.responseSize,
|
|
duration: trackedRequest.duration,
|
|
};
|
|
|
|
return request;
|
|
}
|
|
|
|
export function startTrackingNetwork() {
|
|
rawRequests.length = 0;
|
|
browser.webRequest.onBeforeRequest.addListener(
|
|
trackOnBefore,
|
|
{ urls: ["<all_urls>"] },
|
|
["requestBody"], // allows capturing POST bodies
|
|
);
|
|
browser.webRequest.onBeforeSendHeaders.addListener(
|
|
trackOnHeaders,
|
|
{ urls: ["<all_urls>"] },
|
|
["requestHeaders"],
|
|
);
|
|
browser.webRequest.onCompleted.addListener(
|
|
trackOnCompleted,
|
|
{ urls: ["<all_urls>"] },
|
|
["responseHeaders"],
|
|
);
|
|
browser.webRequest.onErrorOccurred.addListener(trackOnError, {
|
|
urls: ["<all_urls>"],
|
|
});
|
|
}
|
|
|
|
export function stopTrackingNetwork() {
|
|
browser.webRequest.onBeforeRequest.removeListener(trackOnBefore);
|
|
browser.webRequest.onBeforeSendHeaders.removeListener(trackOnHeaders);
|
|
browser.webRequest.onCompleted.removeListener(trackOnCompleted);
|
|
browser.webRequest.onErrorOccurred.removeListener(trackOnError);
|
|
}
|
|
|
|
export function getFinalRequests(tabId?: number): SpotNetworkRequest[] {
|
|
const finalRequests = rawRequests
|
|
.map((r) => createSpotNetworkRequest(r, tabId))
|
|
.filter((r) => r !== undefined) as SpotNetworkRequest[];
|
|
rawRequests.length = 0;
|
|
return finalRequests;
|
|
}
|