TUN-5836: QUIC transport no longer sets body to nil in any condition
Setting the body to nil was rendering cloudflared to crashing with a SIGSEGV in the odd case where the hostname accessed maps to a TCP origin (e.g. SSH/RDP/...) but the eyeball sends a plain HTTP request that does not go through cloudflared access (thus not wrapped in websocket as it should). Instead, QUIC transport now sets http.noBody in that condition, which deals with the situation gracefully.
This commit is contained in:
parent
9d9627f645
commit
3aebaaad01
|
@ -342,7 +342,7 @@ func buildHTTPRequest(connectRequest *quicpogs.ConnectRequest, body io.ReadClose
|
||||||
// * there is no transfer-encoding=chunked already set.
|
// * there is no transfer-encoding=chunked already set.
|
||||||
// So, if transfer cannot be chunked and content length is 0, we dont set a request body.
|
// So, if transfer cannot be chunked and content length is 0, we dont set a request body.
|
||||||
if !isWebsocket && !isTransferEncodingChunked(req) && req.ContentLength == 0 {
|
if !isWebsocket && !isTransferEncodingChunked(req) && req.ContentLength == 0 {
|
||||||
req.Body = nil
|
req.Body = http.NoBody
|
||||||
}
|
}
|
||||||
stripWebsocketUpgradeHeader(req)
|
stripWebsocketUpgradeHeader(req)
|
||||||
return req, err
|
return req, err
|
||||||
|
|
|
@ -345,7 +345,7 @@ func TestBuildHTTPRequest(t *testing.T) {
|
||||||
},
|
},
|
||||||
ContentLength: 0,
|
ContentLength: 0,
|
||||||
Host: "cf.host",
|
Host: "cf.host",
|
||||||
Body: nil,
|
Body: http.NoBody,
|
||||||
},
|
},
|
||||||
body: io.NopCloser(&bytes.Buffer{}),
|
body: io.NopCloser(&bytes.Buffer{}),
|
||||||
},
|
},
|
||||||
|
|
|
@ -60,6 +60,11 @@ func (w *mockHTTPRespWriter) Read(data []byte) (int, error) {
|
||||||
return 0, fmt.Errorf("mockHTTPRespWriter doesn't implement io.Reader")
|
return 0, fmt.Errorf("mockHTTPRespWriter doesn't implement io.Reader")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// respHeaders is a test function to read respHeaders
|
||||||
|
func (w *mockHTTPRespWriter) headers() http.Header {
|
||||||
|
return w.Header()
|
||||||
|
}
|
||||||
|
|
||||||
type mockWSRespWriter struct {
|
type mockWSRespWriter struct {
|
||||||
*mockHTTPRespWriter
|
*mockHTTPRespWriter
|
||||||
writeNotification chan []byte
|
writeNotification chan []byte
|
||||||
|
@ -554,6 +559,24 @@ func TestConnections(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Send (unexpected) HTTP when origin expects WS (to unwrap for raw TCP)
|
||||||
|
name: "http-(ws)tcp proxy",
|
||||||
|
args: args{
|
||||||
|
ingressServiceScheme: "tcp://",
|
||||||
|
originService: runEchoTCPService,
|
||||||
|
eyeballResponseWriter: newMockHTTPRespWriter(),
|
||||||
|
eyeballRequestBody: http.NoBody,
|
||||||
|
connectionType: connection.TypeHTTP,
|
||||||
|
requestHeaders: map[string][]string{
|
||||||
|
"Cf-Cloudflared-Proxy-Src": {"non-blank-value"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: want{
|
||||||
|
message: []byte{},
|
||||||
|
headers: map[string][]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "tcp-tcp proxy without warpRoutingService enabled",
|
name: "tcp-tcp proxy without warpRoutingService enabled",
|
||||||
args: args{
|
args: args{
|
||||||
|
@ -650,8 +673,8 @@ func TestConnections(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if test.args.connectionType == connection.TypeTCP {
|
if test.args.connectionType == connection.TypeTCP {
|
||||||
rws := connection.NewHTTPResponseReadWriterAcker(respWriter, req)
|
rwa := connection.NewHTTPResponseReadWriterAcker(respWriter, req)
|
||||||
err = proxy.ProxyTCP(ctx, rws, &connection.TCPRequest{Dest: dest})
|
err = proxy.ProxyTCP(ctx, rwa, &connection.TCPRequest{Dest: dest})
|
||||||
} else {
|
} else {
|
||||||
err = proxy.ProxyHTTP(respWriter, req, test.args.connectionType == connection.TypeWebsocket)
|
err = proxy.ProxyHTTP(respWriter, req, test.args.connectionType == connection.TypeWebsocket)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue