@@ -184,10 +184,20 @@ function toContainerFailure(message: string, retryable: boolean) {
184184}
185185
186186/**
187- * DO → container: same shape as agentcast-exploration CDP proxy — browser URL with path rewritten to
188- * `/ws/terminal`, full handshake headers forwarded, ticket stripped from query. Session/tab identity
189- * from validated `X-*` overrides (main.go).
187+ * DO → container: worker URL path → `/ws/terminal`, ticket stripped (JWT length / auth). Identity from
188+ * validated `X-*` (main.go). Handshake headers are allowlisted only — forwarding full browser / CF
189+ * headers has caused failed upgrades (1006); Cloudflare’s container WS example forwards the client
190+ * request as-is, but we must strip hop-by-hop and edge noise for the inner hop.
190191 */
192+ const WS_FORWARD_HEADER_NAMES = [
193+ 'upgrade' ,
194+ 'connection' ,
195+ 'sec-websocket-key' ,
196+ 'sec-websocket-version' ,
197+ 'sec-websocket-protocol' ,
198+ 'sec-websocket-extensions' ,
199+ ] as const ;
200+
191201export function buildContainerWebSocketRequest (
192202 clientRequest : Request ,
193203 username : string ,
@@ -200,21 +210,22 @@ export function buildContainerWebSocketRequest(
200210 containerUrl . searchParams . delete ( 'sessionId' ) ;
201211 containerUrl . searchParams . delete ( 'tabId' ) ;
202212
203- const h = new Headers ( clientRequest . headers ) ;
213+ const h = new Headers ( ) ;
214+ for ( const name of WS_FORWARD_HEADER_NAMES ) {
215+ const v = clientRequest . headers . get ( name ) ;
216+ if ( v ) {
217+ h . set ( name , v ) ;
218+ }
219+ }
204220 h . set ( 'X-User' , username ) ;
205221 h . set ( 'X-Session-Id' , sessionId ) ;
206222 h . set ( 'X-Tab-Id' , tabId ) ;
207223
208- return new Request ( containerUrl . toString ( ) , { method : 'GET' , headers : h } ) ;
209- }
210-
211- /** Match exploration: return a fresh 101 Response with the DO `webSocket` so the client upgrade completes reliably. */
212- export function upgradeWebSocketResponse ( res : Response ) : Response {
213- const ws = ( res as { webSocket ?: WebSocket } ) . webSocket ;
214- if ( ws != null ) {
215- return new Response ( null , { status : 101 , webSocket : ws } ) ;
216- }
217- return res ;
224+ return new Request ( containerUrl . toString ( ) , {
225+ method : 'GET' ,
226+ headers : h ,
227+ signal : clientRequest . signal ,
228+ } ) ;
218229}
219230
220231function runtimeAnnotations ( context : RuntimeLogContext , containerId : string ) {
@@ -915,10 +926,9 @@ const ContainerRuntimeLive = Layer.effect(
915926 input . sessionId ,
916927 input . tabId
917928 ) ;
918- const switched = switchPort ( containerReq , 8080 ) ;
919929 let res : Response ;
920930 try {
921- res = await ready . container . fetch ( switched ) ;
931+ res = await ready . container . fetch ( containerReq ) ;
922932 } catch ( err ) {
923933 console . error ( '[ws/terminal] DO stub.fetch threw' , {
924934 containerId : ready . containerId ,
@@ -938,7 +948,7 @@ const ContainerRuntimeLive = Layer.effect(
938948 const peek = await res . clone ( ) . text ( ) . catch ( ( ) => '' ) ;
939949 console . log ( '[ws/terminal] non-upgrade response body' , peek . slice ( 0 , 400 ) ) ;
940950 }
941- return upgradeWebSocketResponse ( res ) ;
951+ return res ;
942952 } ,
943953 catch : toContainerFailure ( 'Container error, please retry in a moment.' , true ) ,
944954 } )
0 commit comments