mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 19:59:58 +00:00
TUN-4626: Proxy non-stream based origin websockets with http Roundtrip.
Reuses HTTPProxy's Roundtrip method to directly proxy websockets from eyeball clients (determined by websocket type and ingress not being connection oriented , i.e. Not ssh or smb for example) to proxy websocket traffic.
This commit is contained in:
@@ -2,10 +2,8 @@ package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -36,7 +34,15 @@ func (o *unixSocketPath) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
func (o *httpService) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// Rewrite the request URL so that it goes to the origin service.
|
||||
req.URL.Host = o.url.Host
|
||||
req.URL.Scheme = o.url.Scheme
|
||||
switch o.url.Scheme {
|
||||
case "ws":
|
||||
req.URL.Scheme = "http"
|
||||
case "wss":
|
||||
req.URL.Scheme = "https"
|
||||
default:
|
||||
req.URL.Scheme = o.url.Scheme
|
||||
}
|
||||
|
||||
if o.hostHeader != "" {
|
||||
// For incoming requests, the Host header is promoted to the Request.Host field and removed from the Header map.
|
||||
req.Host = o.hostHeader
|
||||
@@ -44,67 +50,6 @@ func (o *httpService) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return o.transport.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (o *httpService) EstablishConnection(req *http.Request) (OriginConnection, *http.Response, error) {
|
||||
req = req.Clone(req.Context())
|
||||
|
||||
req.URL.Host = o.url.Host
|
||||
req.URL.Scheme = o.url.Scheme
|
||||
// allow ws(s) scheme for websocket-only origins, normal http(s) requests will fail
|
||||
switch req.URL.Scheme {
|
||||
case "ws":
|
||||
req.URL.Scheme = "http"
|
||||
case "wss":
|
||||
req.URL.Scheme = "https"
|
||||
}
|
||||
|
||||
if o.hostHeader != "" {
|
||||
// For incoming requests, the Host header is promoted to the Request.Host field and removed from the Header map.
|
||||
req.Host = o.hostHeader
|
||||
}
|
||||
|
||||
return o.newWebsocketProxyConnection(req)
|
||||
}
|
||||
|
||||
func (o *httpService) newWebsocketProxyConnection(req *http.Request) (OriginConnection, *http.Response, error) {
|
||||
req.Header.Set("Connection", "Upgrade")
|
||||
req.Header.Set("Upgrade", "websocket")
|
||||
req.Header.Set("Sec-WebSocket-Version", "13")
|
||||
|
||||
req.ContentLength = 0
|
||||
req.Body = nil
|
||||
|
||||
resp, err := o.transport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
toClose := resp.Body
|
||||
defer func() {
|
||||
if toClose != nil {
|
||||
_ = toClose.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusSwitchingProtocols {
|
||||
return nil, nil, fmt.Errorf("unexpected origin response: %s", resp.Status)
|
||||
}
|
||||
if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" {
|
||||
return nil, nil, fmt.Errorf("unexpected upgrade: %q", resp.Header.Get("Upgrade"))
|
||||
}
|
||||
|
||||
rwc, ok := resp.Body.(io.ReadWriteCloser)
|
||||
if !ok {
|
||||
return nil, nil, errUnsupportedConnectionType
|
||||
}
|
||||
conn := wsProxyConnection{
|
||||
rwc: rwc,
|
||||
}
|
||||
// clear to prevent defer from closing
|
||||
toClose = nil
|
||||
|
||||
return &conn, resp, nil
|
||||
}
|
||||
|
||||
func (o *statusCode) RoundTrip(_ *http.Request) (*http.Response, error) {
|
||||
return o.resp, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user