MCPcopy Index your code
hub / github.com/codeaashu/claude-code / openTunnel

Function openTunnel

src/upstreamproxy/relay.ts:344–428  ·  view source on GitHub ↗
(
  sock: ClientSocket,
  st: ConnState,
  connectLine: string,
  wsUrl: string,
  authHeader: string,
  wsAuthHeader: string,
)

Source from the content-addressed store, hash-verified

342}
343
344function openTunnel(
345 sock: ClientSocket,
346 st: ConnState,
347 connectLine: string,
348 wsUrl: string,
349 authHeader: string,
350 wsAuthHeader: string,
351): void {
352 // core/websocket/stream.go picks JSON vs binary-proto from the upgrade
353 // request's Content-Type header (defaults to JSON). Without application/proto
354 // the server protojson.Unmarshals our hand-encoded binary chunks and fails
355 // silently with EOF.
356 const headers = {
357 'Content-Type': 'application/proto',
358 Authorization: wsAuthHeader,
359 }
360 let ws: WebSocketLike
361 if (nodeWSCtor) {
362 ws = new nodeWSCtor(wsUrl, {
363 headers,
364 agent: getWebSocketProxyAgent(wsUrl),
365 ...getWebSocketTLSOptions(),
366 }) as unknown as WebSocketLike
367 } else {
368 ws = new globalThis.WebSocket(wsUrl, {
369 // @ts-expect-error — Bun extension; not in lib.dom WebSocket types
370 headers,
371 proxy: getWebSocketProxyUrl(wsUrl),
372 tls: getWebSocketTLSOptions() || undefined,
373 })
374 }
375 ws.binaryType = 'arraybuffer'
376 st.ws = ws
377
378 ws.onopen = () => {
379 // First chunk carries the CONNECT line plus Proxy-Authorization so the
380 // server can auth the tunnel and know the target host:port. Server
381 // responds with its own "HTTP/1.1 200" over the tunnel; we just pipe it.
382 const head =
383 `${connectLine}\r\n` + `Proxy-Authorization: ${authHeader}\r\n` + `\r\n`
384 ws.send(encodeChunk(Buffer.from(head, 'utf8')))
385 // Flush anything that arrived while the WS handshake was in flight —
386 // trailing bytes from the CONNECT packet and any data() callbacks that
387 // fired before onopen.
388 st.wsOpen = true
389 for (const buf of st.pending) {
390 forwardToWs(ws, buf)
391 }
392 st.pending = []
393 // Not all WS implementations expose ping(); empty chunk works as an
394 // application-level keepalive the server can ignore.
395 st.pinger = setInterval(sendKeepalive, PING_INTERVAL_MS, ws)
396 }
397
398 ws.onmessage = ev => {
399 const raw =
400 ev.data instanceof ArrayBuffer
401 ? new Uint8Array(ev.data)

Callers 1

handleDataFunction · 0.85

Calls 11

getWebSocketProxyAgentFunction · 0.85
getWebSocketTLSOptionsFunction · 0.85
getWebSocketProxyUrlFunction · 0.85
encodeChunkFunction · 0.85
forwardToWsFunction · 0.85
decodeChunkFunction · 0.85
logForDebuggingFunction · 0.85
cleanupConnFunction · 0.85
sendMethod · 0.65
writeMethod · 0.45
endMethod · 0.45

Tested by

no test coverage detected