Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Addition of XHR/feat Breakpoints #1856

Merged
merged 11 commits into from
Nov 27, 2023
7 changes: 6 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"add.eventListener.breakpoint": "Toggle Event Listener Breakpoints",
"add.xhr.breakpoint": "Add XHR/fetch Breakpoint",
"breakpoint.xhr.contains":"Break when URL contains:",
"breakpoint.xhr.any":"Any XHR/fetch",
"edit.xhr.breakpoint": "Edit XHR/fetch Breakpoint",
"attach.node.process": "Attach to Node Process",
"base.cascadeTerminateToConfigurations.label": "A list of debug sessions which, when this debug session is terminated, will also be stopped.",
"base.enableDWARF.label": "Toggles whether the debugger will try to read DWARF debug symbols from WebAssembly, which can be resource intensive. Requires the `ms-vscode.wasm-dwarf-debugging` extension to function.",
Expand Down Expand Up @@ -186,7 +190,8 @@
"profile.start": "Take Performance Profile",
"profile.stop": "Stop Performance Profile",
"remove.eventListener.breakpoint.all": "Remove All Event Listener Breakpoints",
"remove.eventListener.breakpoint": "Remove Event Listener Breakpoint",
"remove.xhr.breakpoint.all": "Remove All XHR/fetch Breakpoints",
"remove.xhr.breakpoint": "Remove XHR/fetch Breakpoint",
"requestCDPProxy.label": "Request CDP Proxy for Debug Session",
"skipFiles.description": "An array of glob patterns for files to skip when debugging. The pattern `<node_internals>/**` matches all internal Node.js modules.",
"smartStep.description": "Automatically step through generated code that cannot be mapped back to the original source.",
Expand Down
4 changes: 3 additions & 1 deletion src/adapter/customBreakpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import * as l10n from '@vscode/l10n';
import Cdp from '../cdp/api';

export type CustomBreakpointId = string;
export interface IXHRBreakpoint {
match: string;
}

export interface ICustomBreakpoint {
id: string;
Expand Down
11 changes: 6 additions & 5 deletions src/adapter/debugAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export class DebugAdapter implements IDisposable {
readonly breakpointManager: BreakpointManager;
private _disposables = new DisposableList();
private _customBreakpoints: string[] = [];
private _xhrBreakpoints: string[] = [];
private _thread: Thread | undefined;
private _threadDeferred = getDeferred<Thread>();
private _configurationDoneDeferred: IDeferred<void>;
Expand Down Expand Up @@ -103,6 +104,7 @@ export class DebugAdapter implements IDisposable {
this.dap.on('exceptionInfo', () => this._withThread(thread => thread.exceptionInfo()));
this.dap.on('setCustomBreakpoints', params => this.setCustomBreakpoints(params));
this.dap.on('toggleSkipFileStatus', params => this._toggleSkipFileStatus(params));
this.dap.on('toggleSkipFileStatus', params => this._toggleSkipFileStatus(params));
this.dap.on('prettyPrintSource', params => this._prettyPrintSource(params));
this.dap.on('revealPage', () => this._withThread(thread => thread.revealPage()));
this.dap.on('getPerformance', () =>
Expand Down Expand Up @@ -455,7 +457,7 @@ export class DebugAdapter implements IDisposable {
profile.start(this.dap, this._thread, { type: BasicCpuProfiler.type });
}

this._thread.updateCustomBreakpoints(this._customBreakpoints);
this._thread.updateCustomBreakpoints(this._xhrBreakpoints, this._customBreakpoints);

this.asyncStackPolicy
.connect(cdp)
Expand All @@ -475,12 +477,11 @@ export class DebugAdapter implements IDisposable {

async setCustomBreakpoints({
ids,
xhr,
}: Dap.SetCustomBreakpointsParams): Promise<Dap.SetCustomBreakpointsResult> {
await this._thread?.updateCustomBreakpoints(xhr, ids);
this._customBreakpoints = ids;
if (this._thread) {
await this._thread.updateCustomBreakpoints(ids);
}

this._xhrBreakpoints = xhr;
return {};
}

Expand Down
33 changes: 27 additions & 6 deletions src/adapter/threads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { BreakpointManager, EntryBreakpointMode } from './breakpoints';
import { UserDefinedBreakpoint } from './breakpoints/userDefinedBreakpoint';
import { ICompletions } from './completions';
import { ExceptionMessage, IConsole, QueryObjectsMessage } from './console';
import { CustomBreakpointId, customBreakpoints } from './customBreakpoints';
import { customBreakpoints } from './customBreakpoints';
import { IEvaluator } from './evaluator';
import { IExceptionPauseService } from './exceptionPauseService';
import * as objectPreview from './objectPreview';
Expand Down Expand Up @@ -156,6 +156,11 @@ class StateQueue {
}
}

const enum CustomBreakpointPrefix {
XHR = 'x',
Event = 'e',
}

export class Thread implements IVariableStoreLocationProvider {
private static _lastThreadId = 0;
public readonly id: number;
Expand All @@ -173,7 +178,7 @@ export class Thread implements IVariableStoreLocationProvider {
private _sourceMapDisabler?: SourceMapDisabler;
private _expectedPauseReason?: ExpectedPauseReason;
private _excludedCallers: readonly Dap.ExcludedCaller[] = [];
private _enabledCustomBreakpoints?: ReadonlySet<CustomBreakpointId>;
private _enabledCustomBreakpoints?: ReadonlySet<string>;
private readonly stateQueue = new StateQueue();
private readonly _onPausedEmitter = new EventEmitter<IPausedDetails>();
private readonly _dap: DeferredContainer<Dap.Api>;
Expand Down Expand Up @@ -1250,23 +1255,39 @@ export class Thread implements IVariableStoreLocationProvider {
return `@ VM${raw.scriptId || 'XX'}:${raw.lineNumber}`;
}

async updateCustomBreakpoints(ids: CustomBreakpointId[]): Promise<void> {
async updateCustomBreakpoints(xhr: string[], events: string[]): Promise<void> {
if (!this.target.supportsCustomBreakpoints()) return;
this._enabledCustomBreakpoints ??= new Set();

// Do not fail for custom breakpoints, to account for
// future changes in cdp vs stale breakpoints saved in the workspace.
const newIds = new Set(ids);
const newIds = new Set<string>();
for (const x of xhr) {
newIds.add(CustomBreakpointPrefix.XHR + x);
}
for (const e of events) {
newIds.add(CustomBreakpointPrefix.Event + e);
}
const todo: (Promise<unknown> | undefined)[] = [];

for (const newId of newIds) {
if (!this._enabledCustomBreakpoints.has(newId)) {
todo.push(customBreakpoints().get(newId)?.apply(this._cdp, true));
const id = newId.slice(CustomBreakpointPrefix.XHR.length);
todo.push(
newId.startsWith(CustomBreakpointPrefix.XHR)
? this._cdp.DOMDebugger.setXHRBreakpoint({ url: id })
: customBreakpoints().get(id)?.apply(this._cdp, true),
);
}
}
for (const oldId of this._enabledCustomBreakpoints) {
if (!newIds.has(oldId)) {
todo.push(customBreakpoints().get(oldId)?.apply(this._cdp, false));
const id = oldId.slice(CustomBreakpointPrefix.XHR.length);
todo.push(
oldId.startsWith(CustomBreakpointPrefix.XHR)
? this._cdp.DOMDebugger.removeXHRBreakpoint({ url: id })
: customBreakpoints().get(id)?.apply(this._cdp, false),
);
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/build/dapCustom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,15 @@ const dapCustom: JSONSchema4 = {
},
description: 'Id of breakpoints that should be enabled.',
},
xhr: {
type: 'array',
items: {
type: 'string',
},
description: 'strings of XHR breakpoints that should be enabled.',
},
},
required: ['ids'],
required: ['ids', 'xhr'],
}),

...makeRequest('prettyPrintSource', 'Pretty prints source for debugging.', {
Expand Down
64 changes: 53 additions & 11 deletions src/build/generate-contributions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,21 @@
import { JSONSchema6, JSONSchema6Definition } from 'json-schema';
import type strings from '../../package.nls.json';
import {
allCommands,
allDebugTypes,
AutoAttachMode,
Commands,
Configuration,
ContextKey,
CustomViews,
DebugType,
IConfigurationTypes,
allCommands,
allDebugTypes,
preferredDebugTypes,
} from '../common/contributionUtils';
import { knownToolToken } from '../common/knownTools';
import { mapValues, sortKeys, walkObject } from '../common/objUtils';
import {
AnyLaunchConfiguration,
baseDefaults,
breakpointLanguages,
chromeAttachConfigDefaults,
chromeLaunchConfigDefaults,
edgeAttachConfigDefaults,
edgeLaunchConfigDefaults,
extensionHostConfigDefaults,
IBaseConfiguration,
IChromeAttachConfiguration,
IChromeLaunchConfiguration,
Expand All @@ -39,10 +32,17 @@ import {
INodeLaunchConfiguration,
ITerminalLaunchConfiguration,
KillBehavior,
nodeAttachConfigDefaults,
nodeLaunchConfigDefaults,
OutputSource,
ResolvingConfiguration,
baseDefaults,
breakpointLanguages,
chromeAttachConfigDefaults,
chromeLaunchConfigDefaults,
edgeAttachConfigDefaults,
edgeLaunchConfigDefaults,
extensionHostConfigDefaults,
nodeAttachConfigDefaults,
nodeLaunchConfigDefaults,
terminalBaseDefaults,
} from '../configuration';

Expand Down Expand Up @@ -1232,6 +1232,21 @@ const commands: ReadonlyArray<{
title: refString('remove.eventListener.breakpoint.all'),
icon: '$(close-all)',
},
{
command: Commands.AddXHRBreakpoints,
title: refString('add.xhr.breakpoint'),
icon: '$(add)',
},
{
command: Commands.RemoveXHRBreakpoints,
title: refString('remove.xhr.breakpoint'),
icon: '$(remove)',
},
{
command: Commands.EditXHRBreakpoint,
title: refString('edit.xhr.breakpoint'),
icon: '$(edit)',
},
{
command: Commands.AttachProcess,
title: refString('attach.node.process'),
Expand Down Expand Up @@ -1474,6 +1489,33 @@ const menus: Menus = {
},
],
'view/item/context': [
{
command: Commands.AddXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
},
{
command: Commands.EditXHRBreakpoint,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
group: 'inline',
},
{
command: Commands.EditXHRBreakpoint,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
},
{
command: Commands.RemoveXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
group: 'inline',
},
{
command: Commands.RemoveXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
},
{
command: Commands.AddXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrCategory`,
group: 'inline',
},
{
command: Commands.CallersGoToCaller,
group: 'inline',
Expand Down
32 changes: 30 additions & 2 deletions src/cdp/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,8 @@ export namespace Cdp {
| 'IdTokenHttpNotFound'
| 'IdTokenNoResponse'
| 'IdTokenInvalidResponse'
| 'IdTokenIdpErrorResponse'
| 'IdTokenCrossSiteIdpErrorResponse'
| 'IdTokenInvalidRequest'
| 'IdTokenInvalidContentType'
| 'ErrorIdToken'
Expand Down Expand Up @@ -2938,7 +2940,7 @@ export namespace Cdp {

/**
* Definition of PermissionDescriptor defined in the Permissions API:
* https://w3c.github.io/permissions/#dictdef-permissiondescriptor.
* https://w3c.github.io/permissions/#dom-permissiondescriptor.
*/
export interface PermissionDescriptor {
/**
Expand Down Expand Up @@ -23093,6 +23095,7 @@ export namespace Cdp {
| 'unload'
| 'usb'
| 'vertical-scroll'
| 'web-printing'
| 'web-share'
| 'window-management'
| 'window-placement'
Expand Down Expand Up @@ -24323,6 +24326,8 @@ export namespace Cdp {
* that is incompatible with prerender and has caused the cancellation of the attempt.
*/
disallowedMojoInterface?: string;

mismatchedHeaders?: PrerenderMismatchedHeaders[];
}

/**
Expand Down Expand Up @@ -24557,6 +24562,17 @@ export namespace Cdp {
| 'PrefetchResponseUsed'
| 'PrefetchSuccessfulButNotUsed'
| 'PrefetchNotUsedProbeFailed';

/**
* Information of headers to be displayed when the header mismatch occurred.
*/
export interface PrerenderMismatchedHeaders {
headerName: string;

initialValue?: string;

activationValue?: string;
}
}

/**
Expand Down Expand Up @@ -27424,6 +27440,8 @@ export namespace Cdp {
controlledClients?: Target.TargetID[];

targetId?: Target.TargetID;

routerRules?: string;
}

/**
Expand Down Expand Up @@ -28700,6 +28718,16 @@ export namespace Cdp {
ends: integer[];
}

export interface AttributionReportingTriggerSpec {
/**
* number instead of integer because not all uint32 can be represented by
* int
*/
triggerData: number[];

eventReportWindows: AttributionReportingEventReportWindows;
}

export type AttributionReportingTriggerDataMatching = 'exact' | 'modulus';

export interface AttributionReportingSourceRegistration {
Expand All @@ -28710,7 +28738,7 @@ export namespace Cdp {
*/
expiry: integer;

eventReportWindows: AttributionReportingEventReportWindows;
triggerSpecs: AttributionReportingTriggerSpec[];

/**
* duration in seconds
Expand Down
Loading