Skip to content

Commit f5c9534

Browse files
zobotowhidabsar
andauthored
feat: DBGp Proxy support (#685)
* DBGP Proxy support. * Change protocol encoding to utf-8. * Fix package.json capabilities Untrusted Workspace. * Compatibility hack between pydbgpproxy and official dbgpProxy. * Changed setting title and keys to "php.debug". Populate ideKey in resolveDebugConfiguration. * More detailed errors for debugging socket close cases. Co-authored-by: Alvaro Pareja-Lecaros <[email protected]> Co-authored-by: towhidabsar <[email protected]>
1 parent 85a28a4 commit f5c9534

File tree

9 files changed

+428
-23
lines changed

9 files changed

+428
-23
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
66

7+
## [1.22.0]
8+
9+
### Added
10+
11+
- DBGp Proxy support.
12+
- `php.debug.ideKey` setting to set the Proxy IDE key globally.
13+
14+
### Changed
15+
16+
- Renamed `php.executablePath` setting to `php.debug.executablePath` and do not fallback to `php.validate.executablePath`.
17+
- Untrusted workspace settings.
18+
- Default protocol encoding changed to utf-8.
19+
720
## [1.21.1]
821

922
### Fixed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ There are also configurations for Xdebug v2 (Legacy) installations.
6565

6666
More general information on debugging with VS Code can be found on https://code.visualstudio.com/docs/editor/debugging.
6767

68-
> _Note:_ You can even debug a script without `launch.json`. If no folder is open, and the VS Code status bar is purple, pressing `F5` will start the open script with Xdebug3 specific parameters. If the php executable is not in path, you can provide it with the setting `php.executablePath` or a fallback `php.validate.executablePath`. For debugging to work, Xdebug must still be correctly installed.
68+
> _Note:_ You can even debug a script without `launch.json`. If no folder is open, and the VS Code status bar is purple, pressing `F5` will start the open script with Xdebug3 specific parameters. If the php executable is not in path, you can provide it with the setting `php.debug.executablePath`. For debugging to work, Xdebug must still be correctly installed.
6969
7070
#### Supported launch.json settings:
7171

@@ -77,6 +77,13 @@ More general information on debugging with VS Code can be found on https://code.
7777
- `log`: Whether to log all communication between VS Code and the adapter to the debug console. See _Troubleshooting_ further down.
7878
- `ignore`: An optional array of glob patterns that errors should be ignored from (for example `**/vendor/**/*.php`)
7979
- `maxConnections`: Accept only this number of parallel debugging sessions. Additional connections will be dropped and their execution will continue without debugging.
80+
- `proxy`: DBGp Proxy settings
81+
- `enable`: To enable proxy registration set to `true` (default is `false).
82+
- `host`: The address of the proxy. Supports host name, IP address, or Unix domain socket (default: 127.0.0.1).
83+
- `port`: The port where the adapter will register with the the proxy (default: `9001`).
84+
- `key`: A unique key that allows the proxy to match requests to your editor (default: `vsc`). The default is taken from VSCode settings `php.debug.idekey`.
85+
- `timeout`: The number of milliseconds to wait before giving up on the connection to proxy (default: `3000`).
86+
- `allowMultipleSessions`: If the proxy should forward multiple sessions/connections at the same time or not (default: `true`).
8087
- `xdebugSettings`: Allows you to override Xdebug's remote debugging settings to fine tuning Xdebug to your needs. For example, you can play with `max_children` and `max_depth` to change the max number of array and object children that are retrieved and the max depth in structures like arrays and objects. This can speed up the debugger on slow machines.
8188
For a full list of feature names that can be set please refer to the [Xdebug documentation](https://xdebug.org/docs-dbgp.php#feature-names).
8289
- `max_children`: max number of array or object children to initially retrieve
@@ -110,6 +117,7 @@ Options specific to CLI debugging:
110117
- Watches
111118
- Run as CLI
112119
- Run without debugging
120+
- DBGp Proxy registration and unregistration support
113121

114122
## Remote Host Debugging
115123

@@ -127,6 +135,14 @@ To make VS Code map the files on the server to the right files on your local mac
127135

128136
Please also note that setting any of the CLI debugging options will not work with remote host debugging, because the script is always launched locally. If you want to debug a CLI script on a remote host, you need to launch it manually from the command line.
129137

138+
## Proxy support
139+
140+
The debugger can register itself to a DBGp proxy with a IDE Key. The proxy will then forward to the IDE only those DBGp sessions that have this specified IDE key. This is helpful in a multiuser environment where developers cannot use the same DBGp port at the same time. Careful setup is needed that requests to the web server contain the matching IDE key.
141+
142+
The official implementation of the [dbgpProxy](https://xdebug.org/docs/dbgpProxy).
143+
144+
A _Xdebug helper_ browser extension is also recommended. There the request side IDE key can be easily configured.
145+
130146
## Troubleshooting
131147

132148
- Ask a question on [StackOverflow](https://stackoverflow.com/)

package.json

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@
146146
"onDebugResolve:php",
147147
"onCommand:php.debug.debugPhpFile"
148148
],
149+
"capabilities": {
150+
"untrustedWorkspaces": {
151+
"supported": "limited",
152+
"description": "%workspaceTrust%",
153+
"restrictedConfigurations": [
154+
"php.debug.executablePath"
155+
]
156+
}
157+
},
149158
"contributes": {
150159
"breakpoints": [
151160
{
@@ -250,6 +259,41 @@
250259
"type": "boolean",
251260
"description": "If true, will log all communication between VS Code and the adapter"
252261
},
262+
"proxy": {
263+
"type": "object",
264+
"properties": {
265+
"allowMultipleSessions": {
266+
"type": "boolean",
267+
"description": "If the proxy should expect multiple sessions/connections or not.",
268+
"default": true
269+
},
270+
"enable": {
271+
"type": "boolean",
272+
"description": "Whether to enable usage of a proxy",
273+
"default": false
274+
},
275+
"host": {
276+
"type": "string",
277+
"description": "Selects the host where the debug client is running, you can either use a host name, IP address, or 'unix:///path/to/sock' for a Unix domain socket. This setting is ignored if xdebug.remote_connect_back is enabled.",
278+
"default": "127.0.0.1"
279+
},
280+
"key": {
281+
"type": "string",
282+
"description": "A unique key that allows the proxy to match requests to your editor",
283+
"default": "${config:php.debug.ideKey}"
284+
},
285+
"port": {
286+
"type": "number",
287+
"description": "The port where the adapter will register with the the proxy.",
288+
"default": 9001
289+
},
290+
"timeout": {
291+
"type": "number",
292+
"description": "The port where the adapter will register with the the proxy.",
293+
"default": 3000
294+
}
295+
}
296+
},
253297
"xdebugSettings": {
254298
"type": "object",
255299
"properties": {
@@ -412,28 +456,25 @@
412456
}
413457
],
414458
"configuration": {
415-
"title": "PHP",
459+
"title": "PHP Debug",
416460
"properties": {
417-
"php.executablePath": {
461+
"php.debug.executablePath": {
418462
"type": [
419463
"string",
420464
"null"
421465
],
422466
"default": null,
423467
"description": "The path to a PHP executable.",
424468
"scope": "machine-overridable"
469+
},
470+
"php.debug.ideKey": {
471+
"type": "string",
472+
"default": "vsc",
473+
"description": "A unique key that allows the proxy to match requests to your editor. Only used when proxy configuration includes replacement.",
474+
"scope": "machine-overridable"
425475
}
426476
}
427477
},
428-
"capabilities": {
429-
"untrustedWorkspaces": {
430-
"supported": "limited",
431-
"description": "%workspaceTrust%",
432-
"restrictedConfigurations": [
433-
"php.executablePath"
434-
]
435-
}
436-
},
437478
"menus": {
438479
"editor/title/run": [
439480
{

src/dbgp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as iconv from 'iconv-lite'
44
import { DOMParser } from 'xmldom'
55

66
/** The encoding all Xdebug messages are encoded with */
7-
export const ENCODING = 'iso-8859-1'
7+
export const ENCODING = 'utf-8'
88

99
/** The two states the connection switches between */
1010
enum ParsingState {

src/extension.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ export function activate(context: vscode.ExtensionContext) {
3333
!debugConfiguration.runtimeExecutable
3434
) {
3535
// See if we have runtimeExecutable configured
36-
const conf = vscode.workspace.getConfiguration('php')
37-
const executablePath =
38-
conf.get<string>('executablePath') || conf.get<string>('validate.executablePath')
36+
const conf = vscode.workspace.getConfiguration('php.debug')
37+
const executablePath = conf.get<string>('executablePath')
3938
if (executablePath) {
4039
debugConfiguration.runtimeExecutable = executablePath
4140
}
@@ -45,18 +44,28 @@ export function activate(context: vscode.ExtensionContext) {
4544
await which.default('php')
4645
} catch (e) {
4746
const selected = await vscode.window.showErrorMessage(
48-
'PHP executable not found. Install PHP and add it to your PATH or set the php.executablePath setting',
47+
'PHP executable not found. Install PHP and add it to your PATH or set the php.debug.executablePath setting',
4948
'Open settings'
5049
)
5150
if (selected === 'Open settings') {
5251
await vscode.commands.executeCommand('workbench.action.openGlobalSettings', {
53-
query: 'php.executablePath',
52+
query: 'php.debug.executablePath',
5453
})
5554
return undefined
5655
}
5756
}
5857
}
5958
}
59+
if (debugConfiguration.proxy?.enable === true) {
60+
// Proxy configuration
61+
if (!debugConfiguration.proxy.key) {
62+
const conf = vscode.workspace.getConfiguration('php.debug')
63+
const ideKey = conf.get<string>('ideKey')
64+
if (ideKey) {
65+
debugConfiguration.proxy.key = ideKey
66+
}
67+
}
68+
}
6069
return debugConfiguration
6170
},
6271
})

src/phpDebug.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import minimatch = require('minimatch')
1414
import { BreakpointManager, BreakpointAdapter } from './breakpoints'
1515
import * as semver from 'semver'
1616
import { LogPointManager } from './logpoint'
17+
import { ProxyConnect } from './proxyConnect'
1718

1819
if (process.env['VSCODE_NLS_CONFIG']) {
1920
try {
@@ -71,6 +72,15 @@ export interface LaunchRequestArguments extends VSCodeDebugProtocol.LaunchReques
7172
ignore?: string[]
7273
/** Xdebug configuration */
7374
xdebugSettings?: { [featureName: string]: string | number }
75+
/** proxy connection configuration */
76+
proxy?: {
77+
allowMultipleSessions: boolean
78+
enable: boolean
79+
host: string
80+
key: string
81+
port: number
82+
timeout: number
83+
}
7484

7585
// CLI options
7686

@@ -158,6 +168,9 @@ class PhpDebugSession extends vscode.DebugSession {
158168
*/
159169
private _logPointManager = new LogPointManager()
160170

171+
/** The proxy initialization and termination connection. */
172+
private _proxyConnect: ProxyConnect
173+
161174
/** the promise that gets resolved once we receive the done request */
162175
private _donePromise: Promise<void>
163176

@@ -447,6 +460,9 @@ class PhpDebugSession extends vscode.DebugSession {
447460
let port = 0
448461
if (!args.noDebug) {
449462
port = await createServer()
463+
if (args.proxy?.enable === true) {
464+
await this.setupProxy(port)
465+
}
450466
}
451467
if (args.program || args.runtimeArgs) {
452468
await launchScript(port)
@@ -460,6 +476,26 @@ class PhpDebugSession extends vscode.DebugSession {
460476
this.sendEvent(new vscode.InitializedEvent())
461477
}
462478

479+
private async setupProxy(idePort: number): Promise<void> {
480+
this._proxyConnect = new ProxyConnect(
481+
this._args.proxy!.host,
482+
this._args.proxy!.port,
483+
idePort,
484+
this._args.proxy!.allowMultipleSessions,
485+
this._args.proxy!.key,
486+
this._args.proxy!.timeout
487+
)
488+
const proxyConsole = (str: string) => this.sendEvent(new vscode.OutputEvent(str + '\n'), true)
489+
490+
this._proxyConnect.on('log_request', proxyConsole)
491+
this._proxyConnect.on('log_response', proxyConsole)
492+
493+
this._proxyConnect.on('log_error', (error: Error) => {
494+
this.sendEvent(new vscode.OutputEvent('PROXY ERROR: ' + error.message + '\n', 'stderr'))
495+
})
496+
return this._proxyConnect.sendProxyInitCommand()
497+
}
498+
463499
/**
464500
* Checks the status of a StatusResponse and notifies VS Code accordingly
465501
* @param {xdebug.StatusResponse} response
@@ -1096,6 +1132,10 @@ class PhpDebugSession extends vscode.DebugSession {
10961132
if (this._phpProcess) {
10971133
this._phpProcess.kill()
10981134
}
1135+
// Unregister proxy
1136+
if (this._proxyConnect) {
1137+
await this._proxyConnect.sendProxyStopCommand()
1138+
}
10991139
} catch (error) {
11001140
this.sendErrorResponse(response, error)
11011141
return

0 commit comments

Comments
 (0)