Description
Symptoms
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