Debugger breakpoints using incorrect URL for a remote debugging session and therefore failing to pause the process
See original GitHub issueSymptoms
This is related to the closed ticket #99, which describes the symptoms of this very problem.
You set a breakpoint, but the process isn’t paused when that breakpoint is encountered and carries merrily on.
Environment
This is a remote debugging session between a Windows client (running Chrome devtools) and a remote Linux server (running node with --inspect=0.0.0.0
).
What’s wrong
By watching the websocket communication with Wireshark it is apparent that the Chrome Dev tools are using an incorrect filepath/URL when calling Debugger.setBreakpointByUrl
.
What I am seeing
Request
{
"id": 17,
"method": "Debugger.setBreakpointByUrl",
"params": {
"lineNumber": 67,
"url": "EFS\\DEV-efsbastion\\username\\application\\projects\\service\\module\\index.js",
"columnNumber": 18,
"condition": ""
}
}
Response
{
"id": 17,
"result": {
"breakpointId": "EFS\\DEV-efsbastion\\username\\application\\projects\\service\\module\\index.js:67:18",
"locations": []
}
}
Note the empty locations array. I am no node debugger expert, but it feels like this locations array should be checked to ensure it is not empty after setting a new breakpoint marker before then showing the marker as active in the UI.
What I should be seeing
Request
{
"id": 17,
"method": "Debugger.setBreakpointByUrl",
"params": {
"lineNumber": 67,
"url": "/EFS/DEV-efsbastion/username/application/projects/service/module/index.js",
"columnNumber": 18,
"condition": ""
}
}
Response
{
"id": 17,
"result": {
"breakpointId": "/EFS/DEV-efsbastion/username/application/projects/service/module/index.js:67:18",
"locations": [{
"scriptId":"104",
"lineNumber":67,
"columnNumber":18
}]
}
}
Note the Linux path separators instead of Windows and the initial root slash on the path.
But isn’t this a node bug?
No, it is not from what I can tell because of the following two discoveries.
PHPStorm
PHPStorm/WebStorm debugger continues to work just fine using it’s URL regexes
Request
{
"id": 17,
"method": "Debugger.setBreakpointByUrl",
"params": {
"lineNumber": 67,
"urlRegex": "[/\\\\][iI][nN][dD][eE][xX]\\.[jJ][sS]([;?#!].*)?$"
}
}
Response
{
"id": 17,
"result": {
"breakpointId": "/[/\\\\][iI][nN][dD][eE][xX]\\.[jJ][sS]([;?#!].*)?$/:67:18",
"locations": [{
"scriptId":"104",
"lineNumber":67,
"columnNumber":18
}]
}
}
Manually recreating the request successfully
If I manually set the breakpoint myself I see a success response back over the websocket. For example consider the following code run from the Chrome console:
let id, key, socket
id = 1000
key = '<debugger-key-goes-here>'
const connect = userSuppliedKey => {
socket = new WebSocket(`ws://<ip-address-goes-here>:9229/${userSuppliedKey || key}`)
socket.addEventListener('message', e => {
const d = JSON.parse(e.data)
if (d) {
if (d.method === 'Debugger.scriptParsed') return console.log('scriptParsed', JSON.stringify({ scriptId: d.params.scriptId, url: d.params.url }))
if (d.method === 'Debugger.breakpointResolved') return console.log('breakpointResolved', JSON.stringify(Object.assign({ breakpointId: d.params.breakpointId }, d.params.location)))
}
console.info(`${e.data}`)
})
}
const send = (method, x) => socket.send(JSON.stringify({ id: ++id, method: `Debugger.${method}`, params: x }))
const _getPossibleBps = (start, end) => send('getPossibleBreakpoints', { start, end })
const getPossibleBps = (scriptId, start, end) => _getPossibleBps({ scriptId, lineNumber: start }, { scriptId, lineNumber: end })
const setBp = (lineNumber, url) => send('setBreakpointByUrl', { lineNumber, url, })
const removeBp = (lineNumber, url, columnNumber) => send('removeBreakpoint', { breakpointId: `${url}:${lineNumber}:${columnNumber || 0}` })
const enable = () => send('enable')
Which gives us this when run in the Chrome console
connect('<debugger-key-goes-here>')
// '<debugger-key-goes-here>'
enable()
// ...
// scriptParsed {"scriptId":"104","url":"/EFS/DEV-efsbastion/username/application/projects/service/module/index.js"}
// ...
getPossibleBps('104', 9, 15)
// {"id":1016,"result":{"locations":[{"scriptId":"104","lineNumber":9,"columnNumber":15},{"scriptId":"104","lineNumber":11,"columnNumber":15},{"scriptId":"104","lineNumber":12,"columnNumber":16},{"scriptId":"104","lineNumber":14,"columnNumber":4},{"scriptId":"104","lineNumber":15,"columnNumber":0},{"scriptId":"104","lineNumber":17,"columnNumber":4},{"scriptId":"104","lineNumber":18,"columnNumber":14}]}}
setBp(11, '/EFS/DEV-efsbastion/username/application/projects/service/module/index.js')
// {"id":1024,"result":{"breakpointId":"/EFS/DEV-efsbastion/username/application/projects/service/module/index.js:11:0","locations":[{"scriptId":"104","lineNumber":11,"columnNumber":15}]}}
removeBp(11, '/EFS/DEV-efsbastion/username/application/projects/service/module/index.js')
// {"id":1019,"result":{}}
Possible introduction of the issue
in combination with https://chromium.googlesource.com/chromium/src/+blame/master/third_party/blink/renderer/devtools/front_end/common/ParsedURL.js#103
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:42
Top GitHub Comments
Thanks for great report!
Inside V8 on inspector backend side we try to match breakpoint url and script url. In this case we send incorrect url from frontend side and when we receive new parsed script on backend side we do not set breakpoint properly.
I will do following two points next week:
I will update this issue as soon as I get some results.
(PhpStorm actually uses great regexp)
It seems to have gotten worse with the release of chrome 69. The workarounds I posted above no longer work with chrome 69.0.3497.81(stable) and with chrome 71.0.3548.0 (canary). Workstations still running 68.0.3440.106 do work with both workarounds.