Documentation for Jetty

Streaming Response Support

Status: Implemented

Overview

Add support for streaming HTTP responses (chunked transfer-encoding and SSE) through the tunnel, so that long-lived or chunked responses are delivered incrementally to the client instead of being buffered entirely in memory.

Protocol

Three new WebSocket frame types (agent -> edge):

  • http_response_start -- begins a streaming response with status code and headers (no body).
  • http_response_chunk -- a base64-encoded chunk of the response body.
  • http_response_end -- signals the response is complete.

The existing http_response frame (full buffered body) remains supported for backward compatibility.

Components

wsproto (cli/internal/wsproto/proto.go)

New constants and structs:

  • TypeHTTPResponseStart, TypeHTTPResponseChunk, TypeHTTPResponseEnd
  • HTTPResponseStart struct (Type, RequestID, Status, Headers)
  • HTTPResponseChunk struct (Type, RequestID, DataB64)
  • HTTPResponseEnd struct (Type, RequestID)

Edge server (cli/internal/edge/edge.go)

  • streamWriter type holds a reference to the client http.ResponseWriter and a done channel.
  • Session gets a streaming map (map[string]*streamWriter) alongside the existing pending map.
  • readAgentLoop handles the three new frame types: writes headers on http_response_start, writes decoded chunks on http_response_chunk, and closes the done channel on http_response_end.
  • handlePublicHTTP registers both a pending channel and a stream writer for each request. If the agent uses streaming (closes the channel instead of sending a full response), it waits on the stream writer done channel.
  • Full backward compatibility: agents that send http_response work exactly as before.

PHP CLI EdgeAgent (jetty-client/src/EdgeAgent.php)

  • Detects streaming responses via Transfer-Encoding: chunked or Content-Type: text/event-stream headers from the upstream.
  • Uses CURLOPT_HEADERFUNCTION and CURLOPT_WRITEFUNCTION callbacks to stream data.
  • For streaming: sends http_response_start with headers, then http_response_chunk for each chunk of data from the upstream, then http_response_end.
  • For normal responses: sends the existing http_response frame (backward compatible).
  • Returns a streamed flag so the caller knows whether the response was already sent over the WebSocket.

Send feedback

Found an issue or have a suggestion? Let us know.