# CONNECT-UDP in Firefox ```{mermaid} flowchart LR Client[Client] Proxy[Proxy] Target[Target] subgraph OuterConn["Outer HTTP/3 Connection"] subgraph InnerConnClientToProxy["Inner HTTP/3 Connection"] InnerConnClientToProxy1["Inner Stream 1"] InnerConnClientToProxy2["Inner Stream 2"] end end subgraph UDPTunnel["UDPTunnel"] subgraph InnerConnProxyToTarget["Inner HTTP/3 Connection"] InnerConnProxyToTarget1["Inner Stream 1"] InnerConnProxyToTarget2["Inner Stream 2"] end end Client --> OuterConn OuterConn --> Proxy Proxy --> UDPTunnel UDPTunnel --> Target ``` ## Terminology and Concepts To clearly describe the design, we define two key terms that appear frequently throughout this document: ### Outer Connection The outer connection refers to the HTTP/3 connection between Firefox and the proxy. This connection is established once and can be reused for multiple HTTP/3 requests. ### Inner Connection The inner connection refers to the logical UDP tunnel established over an HTTP/3 stream via the CONNECT method. ### Connection Establishment Note: Firefox only supports CONNECT-UDP over HTTP/3. Support over HTTP/2 or HTTP/1.1 is not implemented. To establish a UDP tunnel over HTTP/3, Firefox initiates a request using the CONNECT method with the :protocol set to connect-udp. This request negotiates a stream that serves as the logical tunnel for encapsulated UDP datagrams between the client and the proxy. The tunnel setup process involves sending a HEADERS frame on a new HTTP/3 stream with the following pseudo-header and header fields: ``` :method = CONNECT :protocol = connect-udp :scheme = https :path = /.well-known/masque/udp/example.com/443/ :authority = proxy.org capsule-protocol = ?1 ``` ## Http3ConnectUDPStream Http3ConnectUDPStream is the core implementation of the CONNECT-UDP in Firefox. It behaves like a regular nsIUDPSocket, allowing the inner HTTP/3 connection to send and receive UDP datagrams. Internally, it encapsulates outgoing UDP datagrams into HTTP datagrams, which are then sent over the outer HTTP/3 connection to the proxy. Incoming HTTP datagrams from the proxy are decoded and delivered as UDP packets to the consumer. ### Data sending flow ```{mermaid} sequenceDiagram participant HttpConnectionUDP (inner) participant Http3Session (inner) participant Http3Stream (inner) participant nsHttpTransaction participant Http3Session (outer) participant Http3ConnectUDPStream participant NeqoHttp3Conn (outer) HttpConnectionUDP (inner)->>HttpConnectionUDP (inner): SendData() HttpConnectionUDP (inner)->>Http3Session (inner): SendData() Http3Session (inner)->>Http3Stream (inner): ReadSegments() Http3Stream (inner)->>nsHttpTransaction: ReadSegmentsAgain() nsHttpTransaction->>Http3Stream (inner): ReadRequestSegment() Http3Stream (inner)->>Http3Session (inner): TryActivating/SendRequestBody() Http3Session (inner)->>Http3ConnectUDPStream: SendWithAddress() Http3ConnectUDPStream->>Http3ConnectUDPStream: QueueDatagram() Http3ConnectUDPStream->>Http3Session (outer): StreamHasDataToWrite() Http3Session (outer)->>Http3ConnectUDPStream: ReadSegments() Http3ConnectUDPStream->>Http3Session (outer): SendHTTPDatagram() Http3Session (outer)->>NeqoHttp3Conn: NeqoProcessOutputAndSend() ``` ### Data reading flow ```{mermaid} sequenceDiagram participant NeqoHttp3Conn (outer) participant Http3Session (outer) participant Http3ConnectUDPStream participant Http3Session (inner) participant Http3Stream (inner) participant HttpConnectionUDP (inner) participant nsHttpTransaction NeqoHttp3Conn (outer)->>Http3Session (outer): Receive HTTP Datagram Http3Session (outer)->>Http3ConnectUDPStream: OnDatagramReceived() Http3ConnectUDPStream->>HttpConnectionUDP (inner): OnPacketReceived() HttpConnectionUDP (inner)->>Http3Session (inner): RecvData() Http3Session (inner)->>Http3ConnectUDPStream: RecvWithAddr() Http3Session (inner)->>Http3Session (inner): ProcessTransactionRead() Http3Session (inner)->>Http3Stream (inner): WriteSegments() Http3Stream (inner)->>nsHttpTransaction: WriteSegmentsAgain() ``` ## Fallback Mechanism This section describes the fallback mechanism for establishing proxy connections when using HTTP/3. The process is divided into two layers: the outer connection (between the browser and the proxy) and the inner connection (between the browser and the target server through the proxy). ### Outer Connection - The browser first attempts to establish this connection using HTTP/3. - If the HTTP/3 attempt fails, the connection falls back to HTTP/2 or HTTP/1. Current implementation: - The fallback logic is implemented in nsHttpTransaction (subject to future changes under the Happy Eyeballs project). - When a transaction is inserted into the pending queue: - A HTTP/3 backup timer is started. - An attempt to establish an HTTP/3 connection to the proxy is initiated. - If the backup timer fires before the HTTP/3 connection succeeds, a TCP connection to the proxy server is created. - If the TCP connection succeeds while HTTP/3 is still pending, we fall back to the TCP-based connection. - At this point, the connection info of the inner connection is also updated to disable HTTP/3, since the we do not support CONNECT-UDP over HTTP/2 or HTTP/1. ### Inner Connection Even if the outer connection is established with HTTP/3, the inner connection may still need to fall back. Current implementation: - This fallback logic is also implemented in nsHttpTransaction. - Once the proxy responds with 200 OK to the initial connect-udp setup, a HTTP/3 fallback timer for the inner connection is started. - If the fallback timer fires: - HTTP/3 for the inner connection is disabled. - The ongoing HTTP/3 inner connection is closed. - The inner connection falls back to HTTP/2 or HTTP/1 using a standard HTTP CONNECT tunnel.