Skip to content

Commit

Permalink
feat: scaffold network request interception (#1050)
Browse files Browse the repository at this point in the history
  • Loading branch information
Thiago Perrotta authored Aug 20, 2023
1 parent a94e1bd commit 667186a
Show file tree
Hide file tree
Showing 24 changed files with 1,522 additions and 513 deletions.
36 changes: 36 additions & 0 deletions src/bidiMapper/BidiNoOpParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
BrowsingContext,
Cdp,
Input,
Network,
Script,
Session,
} from '../protocol/protocol.js';
Expand Down Expand Up @@ -112,6 +113,41 @@ export class BidiNoOpParser implements IBidiParser {
}
// keep-sorted end

// Network domain
// keep-sorted start block=yes
parseAddInterceptParams(params: unknown): Network.AddInterceptParameters {
return params as Network.AddInterceptParameters;
}
parseContinueRequestParams(
params: unknown
): Network.ContinueRequestParameters {
return params as Network.ContinueRequestParameters;
}
parseContinueResponseParams(
params: unknown
): Network.ContinueResponseParameters {
return params as Network.ContinueResponseParameters;
}
parseContinueWithAuthParams(
params: unknown
): Network.ContinueWithAuthParameters {
return params as Network.ContinueWithAuthParameters;
}
parseFailRequestParams(params: unknown): Network.FailRequestParameters {
return params as Network.FailRequestParameters;
}
parseProvideResponseParams(
params: unknown
): Network.ProvideResponseParameters {
return params as Network.ProvideResponseParameters;
}
parseRemoveInterceptParams(
params: unknown
): Network.RemoveInterceptParameters {
return params as Network.RemoveInterceptParameters;
}
// keep-sorted end

// Session domain
// keep-sorted start block=yes
parseSubscribeParams(params: unknown): Session.SubscriptionRequest {
Expand Down
22 changes: 22 additions & 0 deletions src/bidiMapper/BidiParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
BrowsingContext,
Cdp,
Input,
Network,
Script,
Session,
} from '../protocol/protocol.js';
Expand Down Expand Up @@ -56,6 +57,27 @@ export interface IBidiParser {
parseReleaseActionsParams(params: unknown): Input.ReleaseActionsParameters;
// keep-sorted end

// Network domain
// keep-sorted start block=yes
parseAddInterceptParams(params: unknown): Network.AddInterceptParameters;
parseContinueRequestParams(
params: unknown
): Network.ContinueRequestParameters;
parseContinueResponseParams(
params: unknown
): Network.ContinueResponseParameters;
parseContinueWithAuthParams(
params: unknown
): Network.ContinueWithAuthParameters;
parseFailRequestParams(params: unknown): Network.FailRequestParameters;
parseProvideResponseParams(
params: unknown
): Network.ProvideResponseParameters;
parseRemoveInterceptParams(
params: unknown
): Network.RemoveInterceptParameters;
// keep-sorted end block=yes

// Script domain
// keep-sorted start block=yes
parseAddPreloadScriptParams(
Expand Down
42 changes: 42 additions & 0 deletions src/bidiMapper/CommandProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ import {InputProcessor} from './domains/input/InputProcessor.js';
import {PreloadScriptStorage} from './domains/script/PreloadScriptStorage.js';
import {ScriptProcessor} from './domains/script/ScriptProcessor.js';
import type {RealmStorage} from './domains/script/realmStorage.js';
import {NetworkProcessor} from './domains/network/NetworkProcessor.js';
import {SessionProcessor} from './domains/session/SessionProcessor.js';
import {NetworkStorage} from './domains/network/NetworkStorage.js';

export const enum CommandProcessorEvents {
Response = 'response',
Expand All @@ -57,6 +59,7 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
#browsingContextProcessor: BrowsingContextProcessor;
#cdpProcessor: CdpProcessor;
#inputProcessor: InputProcessor;
#networkProcessor: NetworkProcessor;
#scriptProcessor: ScriptProcessor;
#sessionProcessor: SessionProcessor;
// keep-sorted end
Expand All @@ -76,6 +79,8 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
super();
this.#parser = parser;
this.#logger = logger;

const networkStorage = new NetworkStorage(eventManager);
const preloadScriptStorage = new PreloadScriptStorage();

// keep-sorted start block=yes
Expand All @@ -86,6 +91,7 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
eventManager,
browsingContextStorage,
realmStorage,
networkStorage,
preloadScriptStorage,
logger
);
Expand All @@ -94,6 +100,10 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
cdpConnection
);
this.#inputProcessor = new InputProcessor(browsingContextStorage);
this.#networkProcessor = new NetworkProcessor(
browsingContextStorage,
networkStorage
);
this.#scriptProcessor = new ScriptProcessor(
browsingContextStorage,
realmStorage,
Expand Down Expand Up @@ -187,6 +197,38 @@ export class CommandProcessor extends EventEmitter<CommandProcessorEventsMap> {
);
// keep-sorted end

// Network domain
// keep-sorted start block=yes
case 'network.addIntercept':
return this.#networkProcessor.addIntercept(
this.#parser.parseAddInterceptParams(command.params)
);
case 'network.continueRequest':
return this.#networkProcessor.continueRequest(
this.#parser.parseContinueRequestParams(command.params)
);
case 'network.continueResponse':
return this.#networkProcessor.continueResponse(
this.#parser.parseContinueResponseParams(command.params)
);
case 'network.continueWithAuth':
return this.#networkProcessor.continueWithAuth(
this.#parser.parseContinueWithAuthParams(command.params)
);
case 'network.failRequest':
return this.#networkProcessor.failRequest(
this.#parser.parseFailRequestParams(command.params)
);
case 'network.provideResponse':
return this.#networkProcessor.provideResponse(
this.#parser.parseProvideResponseParams(command.params)
);
case 'network.removeIntercept':
return this.#networkProcessor.removeIntercept(
this.#parser.parseRemoveInterceptParams(command.params)
);
// keep-sorted end

// Script domain
// keep-sorted start block=yes
case 'script.addPreloadScript':
Expand Down
7 changes: 6 additions & 1 deletion src/bidiMapper/domains/context/browsingContextProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {LogType, type LoggerFn} from '../../../utils/log.js';
import type {EventManager} from '../events/EventManager.js';
import type {RealmStorage} from '../script/realmStorage.js';
import type {PreloadScriptStorage} from '../script/PreloadScriptStorage.js';
import type {NetworkStorage} from '../network/NetworkStorage.js';

import {BrowsingContextImpl} from './browsingContextImpl.js';
import type {BrowsingContextStorage} from './browsingContextStorage.js';
Expand All @@ -38,6 +39,7 @@ export class BrowsingContextProcessor {
readonly #eventManager: EventManager;

readonly #browsingContextStorage: BrowsingContextStorage;
readonly #networkStorage: NetworkStorage;
readonly #preloadScriptStorage: PreloadScriptStorage;
readonly #realmStorage: RealmStorage;

Expand All @@ -49,6 +51,7 @@ export class BrowsingContextProcessor {
eventManager: EventManager,
browsingContextStorage: BrowsingContextStorage,
realmStorage: RealmStorage,
networkStorage: NetworkStorage,
preloadScriptStorage: PreloadScriptStorage,
logger?: LoggerFn
) {
Expand All @@ -57,6 +60,7 @@ export class BrowsingContextProcessor {
this.#eventManager = eventManager;
this.#browsingContextStorage = browsingContextStorage;
this.#preloadScriptStorage = preloadScriptStorage;
this.#networkStorage = networkStorage;
this.#realmStorage = realmStorage;
this.#logger = logger;

Expand Down Expand Up @@ -336,7 +340,8 @@ export class BrowsingContextProcessor {
sessionId,
this.#realmStorage,
this.#eventManager,
this.#preloadScriptStorage
this.#preloadScriptStorage,
this.#networkStorage
);

if (maybeContext) {
Expand Down
45 changes: 38 additions & 7 deletions src/bidiMapper/domains/context/cdpTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {NetworkManager} from '../network/NetworkManager.js';
import type {ChannelProxy} from '../script/channelProxy.js';
import type {RealmStorage} from '../script/realmStorage.js';
import type {PreloadScriptStorage} from '../script/PreloadScriptStorage.js';
import type {NetworkStorage} from '../network/NetworkStorage.js';
import type {Result} from '../../../utils/result.js';

export class CdpTarget {
Expand All @@ -34,6 +35,7 @@ export class CdpTarget {
readonly #cdpSessionId: Protocol.Target.SessionID;
readonly #eventManager: EventManager;
readonly #preloadScriptStorage: PreloadScriptStorage;
readonly #networkStorage: NetworkStorage;

readonly #targetUnblocked = new Deferred<Result<void>>();

Expand All @@ -43,18 +45,20 @@ export class CdpTarget {
cdpSessionId: Protocol.Target.SessionID,
realmStorage: RealmStorage,
eventManager: EventManager,
preloadScriptStorage: PreloadScriptStorage
preloadScriptStorage: PreloadScriptStorage,
networkStorage: NetworkStorage
): CdpTarget {
const cdpTarget = new CdpTarget(
targetId,
cdpClient,
cdpSessionId,
eventManager,
preloadScriptStorage
preloadScriptStorage,
networkStorage
);

LogManager.create(cdpTarget, realmStorage, eventManager);
NetworkManager.create(cdpClient, eventManager);
NetworkManager.create(cdpTarget, networkStorage);

cdpTarget.#setEventListeners();

Expand All @@ -70,13 +74,15 @@ export class CdpTarget {
cdpClient: ICdpClient,
cdpSessionId: Protocol.Target.SessionID,
eventManager: EventManager,
preloadScriptStorage: PreloadScriptStorage
preloadScriptStorage: PreloadScriptStorage,
networkStorage: NetworkStorage
) {
this.#targetId = targetId;
this.#cdpClient = cdpClient;
this.#cdpSessionId = cdpSessionId;
this.#eventManager = eventManager;
this.#preloadScriptStorage = preloadScriptStorage;
this.#networkStorage = networkStorage;
}

/** Returns a promise that resolves when the target is unblocked. */
Expand All @@ -92,13 +98,37 @@ export class CdpTarget {
return this.#cdpClient;
}

/**
* Needed for CDP escape path.
*/
/** Needed for CDP escape path. */
get cdpSessionId(): Protocol.Target.SessionID {
return this.#cdpSessionId;
}

/** Calls `Fetch.enable` with the added network intercepts. */
async fetchEnable() {
await this.#cdpClient.sendCommand(
'Fetch.enable',
this.#networkStorage.getFetchEnableParams()
);
}

/** Calls `Fetch.disable`. */
async fetchDisable() {
await this.#cdpClient.sendCommand('Fetch.disable');
}

/**
* Calls `Fetch.disable` followed by `Fetch.enable`.
* The order is important. Do not use `Promise.all`.
*
* This is necessary because `Fetch.disable` removes all intercepts.
* In a situation where there are two or more intercepts and one of them is
* removed, the `Fetch.enable` call will restore the remaining intercepts.
*/
async fetchApply() {
await this.fetchDisable();
await this.fetchEnable();
}

/**
* Enables all the required CDP domains and unblocks the target.
*/
Expand All @@ -117,6 +147,7 @@ export class CdpTarget {
// XXX: #1080: Do not always enable the network domain globally.
// TODO: enable Network domain for OOPiF targets.
this.#cdpClient.sendCommand('Network.enable'),
this.fetchApply(),
this.#cdpClient.sendCommand('Target.setAutoAttach', {
autoAttach: true,
waitForDebuggerOnStart: true,
Expand Down
Loading

0 comments on commit 667186a

Please sign in to comment.