@@ -53,49 +53,65 @@ export class WebSocketDapAdapter implements vscode.DebugAdapter {
5353 // Diagnostic: the tunnel server may reject the WS upgrade with an HTTP
5454 // response (e.g. 401/403). The plain `error` event only surfaces
5555 // "Unexpected server response: 403" — grab the full response here so
56- // we can log status text and diagnostic headers (which token auth the
57- // tunnel checked, rejection reason, etc.).
58- let unexpectedResponse : { status : number ; statusMessage : string ; headers : string } | undefined ;
56+ // we can log status, all headers, and the response body. This is what
57+ // we hand to the Dev Tunnels team when filing a report.
5958 const onUnexpectedResponse = ( _req : unknown , res : IncomingMessage ) => {
60- const interestingHeaders = [
61- "www-authenticate" ,
62- "x-tunnel-authorization" ,
63- "x-tunnel-service-version" ,
64- "x-powered-by" ,
65- "server" ,
66- "date" ,
67- "content-type" ,
68- "content-length" ,
69- "x-request-id" ,
70- "x-correlation-id" ,
71- "x-ms-request-id" ,
72- "x-ms-error-code"
73- ] ;
74- const headerLines = interestingHeaders
75- . map ( h => {
76- const v = res . headers [ h ] ;
77- return v ? `${ h } =${ Array . isArray ( v ) ? v . join ( "," ) : v } ` : undefined ;
78- } )
79- . filter ( Boolean )
80- . join ( " " ) ;
81- unexpectedResponse = {
82- status : res . statusCode ?? 0 ,
83- statusMessage : res . statusMessage ?? "" ,
84- headers : headerLines
85- } ;
59+ // Parse target URL for correlation without exposing credentials.
60+ let target = "" ;
61+ try {
62+ const u = new URL ( this . _tunnelUrl ) ;
63+ target = `${ u . host } ${ u . pathname } ` ;
64+ } catch {
65+ target = "<unparseable>" ;
66+ }
67+
8668 log (
87- `[debugger] Tunnel rejected WS upgrade: ${ unexpectedResponse . status } ` +
88- `${ unexpectedResponse . statusMessage } | ${ headerLines } `
69+ `[debugger] Tunnel rejected WS upgrade: ${ res . statusCode ?? 0 } ` +
70+ `${ res . statusMessage ?? "" } (target= ${ target } , httpVersion= ${ res . httpVersion } ) `
8971 ) ;
90- // Drain the body so the socket can close cleanly, and capture any
91- // error text the tunnel included (e.g. a JSON {message: "..."}).
72+
73+ // Log every response header. These are server-emitted on a rejection
74+ // response and don't contain our credentials. Dev Tunnels typically
75+ // includes correlation IDs (x-request-id / x-ms-request-id) and a
76+ // rejection reason (www-authenticate / x-tunnel-*) that pinpoint
77+ // why the upgrade was denied.
78+ const headerEntries = Object . entries ( res . headers ) ;
79+ if ( headerEntries . length === 0 ) {
80+ log ( `[debugger] Tunnel response headers: <none>` ) ;
81+ } else {
82+ log ( `[debugger] Tunnel response headers (${ headerEntries . length } ):` ) ;
83+ for ( const [ name , value ] of headerEntries ) {
84+ const rendered = Array . isArray ( value ) ? value . join ( ", " ) : String ( value ?? "" ) ;
85+ log ( `[debugger] ${ name } : ${ rendered } ` ) ;
86+ }
87+ }
88+
89+ // Drain the body so the socket can close cleanly, and capture the
90+ // full error text the tunnel included (e.g. a JSON {message: "..."}).
9291 const chunks : Buffer [ ] = [ ] ;
93- res . on ( "data" , ( c : Buffer ) => chunks . push ( c ) ) ;
92+ let totalLen = 0 ;
93+ const BODY_CAP = 8 * 1024 ; // 8KiB is plenty for a tunnel error payload
94+ res . on ( "data" , ( c : Buffer ) => {
95+ totalLen += c . length ;
96+ if ( Buffer . concat ( chunks ) . length < BODY_CAP ) {
97+ chunks . push ( c ) ;
98+ }
99+ } ) ;
94100 res . on ( "end" , ( ) => {
95- if ( chunks . length > 0 ) {
96- const body = Buffer . concat ( chunks ) . toString ( "utf8" ) . slice ( 0 , 500 ) ;
97- log ( `[debugger] Tunnel rejection body: ${ body } ` ) ;
101+ if ( totalLen === 0 ) {
102+ log ( `[debugger] Tunnel rejection body: <empty>` ) ;
103+ return ;
98104 }
105+ const buf = Buffer . concat ( chunks ) ;
106+ const truncated = totalLen > BODY_CAP ;
107+ const body = buf . slice ( 0 , BODY_CAP ) . toString ( "utf8" ) ;
108+ log (
109+ `[debugger] Tunnel rejection body (${ totalLen } bytes` +
110+ `${ truncated ? `, showing first ${ BODY_CAP } ` : "" } ):\n${ body } `
111+ ) ;
112+ } ) ;
113+ res . on ( "error" , ( err : Error ) => {
114+ log ( `[debugger] Error draining tunnel rejection body: ${ err . message } ` ) ;
99115 } ) ;
100116 } ;
101117 ws . on ( "unexpected-response" , onUnexpectedResponse ) ;
0 commit comments