microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
dev/v-peq/fix-certificateProvider_pathTraversal

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/cdp-proxy/reactNativeCDPProxy.ts

227lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import { IncomingMessage } from "http";
5import {
6 Connection,
7 Server,
8 WebSocketTransport,
9 IProtocolCommand,
10 IProtocolError,
11 IProtocolSuccess,
12} from "vscode-cdp-proxy";
13import { CancellationToken, EventEmitter } from "vscode";
14import { OutputChannelLogger } from "../extension/log/OutputChannelLogger";
15import { LogLevel } from "../extension/log/LogHelper";
16import { DebuggerEndpointHelper } from "./debuggerEndpointHelper";
17import { BaseCDPMessageHandler } from "./CDPMessageHandlers/baseCDPMessageHandler";
18
19export class ReactNativeCDPProxy {
20 private readonly PROXY_LOG_TAGS = {
21 DEBUGGER_COMMAND: "Command Debugger To Target",
22 APPLICATION_COMMAND: "Command Target To Debugger",
23 DEBUGGER_REPLY: "Reply From Debugger To Target",
24 APPLICATION_REPLY: "Reply From Target To Debugger",
25 };
26
27 private server: Server | null = null;
28 private hostAddress: string;
29 private port: number;
30 private debuggerTarget: Connection | null = null;
31 private applicationTarget: Connection | null = null;
32 private logger: OutputChannelLogger;
33 private logLevel: LogLevel;
34 private debuggerEndpointHelper: DebuggerEndpointHelper;
35 private CDPMessageHandler!: BaseCDPMessageHandler;
36 private applicationTargetPort: number = 0;
37 private browserInspectUri: string;
38 private cancellationToken: CancellationToken | undefined;
39 private applicationTargetEventEmitter: EventEmitter<unknown> = new EventEmitter();
40 private errorEventEmitter: EventEmitter<Error> = new EventEmitter();
41
42 public readonly onError = this.errorEventEmitter.event;
43 public readonly onApplicationTargetConnectionClosed = this.applicationTargetEventEmitter.event;
44
45 constructor(hostAddress: string, port: number, logLevel: LogLevel = LogLevel.None) {
46 this.port = port;
47 this.hostAddress = hostAddress;
48 this.logger = OutputChannelLogger.getChannel(
49 "React Native Chrome Proxy",
50 process.env.REACT_NATIVE_TOOLS_LAZY_LOGS !== "false",
51 false,
52 true,
53 );
54 this.logLevel = logLevel;
55 this.browserInspectUri = "";
56 this.debuggerEndpointHelper = new DebuggerEndpointHelper();
57 }
58
59 public async initializeServer(
60 CDPMessageHandler: BaseCDPMessageHandler,
61 logLevel: LogLevel,
62 cancellationToken?: CancellationToken,
63 ): Promise<void> {
64 this.logLevel = logLevel;
65 this.CDPMessageHandler = CDPMessageHandler;
66 this.cancellationToken = cancellationToken;
67
68 this.server = await Server.create({ port: this.port, host: this.hostAddress });
69 this.server.onConnection(this.onConnectionHandler.bind(this));
70 }
71
72 public async stopServer(): Promise<void> {
73 if (this.server) {
74 this.server.dispose();
75 this.server = null;
76 }
77
78 if (this.applicationTarget) {
79 await this.applicationTarget.close();
80 this.applicationTarget = null;
81 }
82
83 this.browserInspectUri = "";
84 this.cancellationToken = undefined;
85 }
86
87 public setBrowserInspectUri(browserInspectUri: string): void {
88 this.browserInspectUri = browserInspectUri;
89 }
90
91 public setApplicationTargetPort(applicationTargetPort: number): void {
92 this.applicationTargetPort = applicationTargetPort;
93 }
94
95 // eslint-disable-next-line @typescript-eslint/no-unused-vars
96 private async onConnectionHandler([debuggerTarget, request]: [
97 Connection,
98 IncomingMessage,
99 ]): Promise<void> {
100 // Only allow connections without an Origin header (i.e., from vscode-js-debug's
101 // raw WebSocket client). Browser-initiated WebSocket connections always include
102 // an Origin header and should be rejected.
103 if (request.headers.origin) {
104 await debuggerTarget.close();
105 return;
106 }
107
108 this.debuggerTarget = debuggerTarget;
109
110 this.debuggerTarget.pause(); // don't listen for events until the target is ready
111
112 if (!this.browserInspectUri) {
113 if (this.cancellationToken) {
114 this.browserInspectUri = await this.debuggerEndpointHelper.retryGetWSEndpoint(
115 `http://localhost:${this.applicationTargetPort}`,
116 90,
117 this.cancellationToken,
118 );
119 } else {
120 this.browserInspectUri = await this.debuggerEndpointHelper.getWSEndpoint(
121 `http://localhost:${this.applicationTargetPort}`,
122 );
123 }
124 }
125
126 this.applicationTarget = new Connection(
127 await WebSocketTransport.create(this.browserInspectUri),
128 );
129
130 this.applicationTarget.onError(this.onApplicationTargetError.bind(this));
131 this.debuggerTarget.onError(this.onDebuggerTargetError.bind(this));
132
133 this.applicationTarget.onCommand(this.handleApplicationTargetCommand.bind(this));
134 this.debuggerTarget.onCommand(this.handleDebuggerTargetCommand.bind(this));
135
136 this.applicationTarget.onReply(this.handleApplicationTargetReply.bind(this));
137 this.debuggerTarget.onReply(this.handleDebuggerTargetReply.bind(this));
138
139 this.applicationTarget.onEnd(this.onApplicationTargetClosed.bind(this));
140 this.debuggerTarget.onEnd(this.onDebuggerTargetClosed.bind(this));
141
142 this.CDPMessageHandler?.setApplicationTarget(this.applicationTarget);
143 this.CDPMessageHandler?.setDebuggerTarget(this.debuggerTarget);
144
145 // dequeue any messages we got in the meantime
146 this.debuggerTarget.unpause();
147 }
148
149 private handleDebuggerTargetCommand(event: IProtocolCommand) {
150 this.logger.logWithCustomTag(
151 this.PROXY_LOG_TAGS.DEBUGGER_COMMAND,
152 JSON.stringify(event, null, 2),
153 this.logLevel,
154 );
155 const processedMessage = this.CDPMessageHandler.processDebuggerCDPMessage(event);
156
157 if (processedMessage.sendBack) {
158 this.debuggerTarget?.send(processedMessage.event);
159 } else {
160 this.applicationTarget?.send(processedMessage.event);
161 }
162 }
163
164 private handleApplicationTargetCommand(event: IProtocolCommand) {
165 this.logger.logWithCustomTag(
166 this.PROXY_LOG_TAGS.APPLICATION_COMMAND,
167 JSON.stringify(event, null, 2),
168 this.logLevel,
169 );
170 const processedMessage = this.CDPMessageHandler.processApplicationCDPMessage(event);
171
172 if (processedMessage.sendBack) {
173 this.applicationTarget?.send(processedMessage.event);
174 } else {
175 this.debuggerTarget?.send(processedMessage.event);
176 }
177 }
178
179 private handleDebuggerTargetReply(event: IProtocolError | IProtocolSuccess) {
180 this.logger.logWithCustomTag(
181 this.PROXY_LOG_TAGS.DEBUGGER_REPLY,
182 JSON.stringify(event, null, 2),
183 this.logLevel,
184 );
185 const processedMessage = this.CDPMessageHandler.processDebuggerCDPMessage(event);
186
187 if (processedMessage.sendBack) {
188 this.debuggerTarget?.send(processedMessage.event);
189 } else {
190 this.applicationTarget?.send(processedMessage.event);
191 }
192 }
193
194 private handleApplicationTargetReply(event: IProtocolError | IProtocolSuccess) {
195 this.logger.logWithCustomTag(
196 this.PROXY_LOG_TAGS.APPLICATION_REPLY,
197 JSON.stringify(event, null, 2),
198 this.logLevel,
199 );
200 const processedMessage = this.CDPMessageHandler.processApplicationCDPMessage(event);
201
202 if (processedMessage.sendBack) {
203 this.applicationTarget?.send(processedMessage.event);
204 } else {
205 this.debuggerTarget?.send(processedMessage.event);
206 }
207 }
208
209 private onDebuggerTargetError(err: Error) {
210 this.logger.error("Error on debugger transport", err);
211 }
212
213 private onApplicationTargetError(err: Error) {
214 this.logger.error("Error on application transport", err);
215 }
216
217 private async onApplicationTargetClosed() {
218 this.applicationTarget = null;
219 this.applicationTargetEventEmitter.fire({});
220 }
221
222 private async onDebuggerTargetClosed() {
223 this.browserInspectUri = "";
224 this.CDPMessageHandler.processDebuggerCDPMessage({ method: "close" });
225 this.debuggerTarget = null;
226 }
227}
228