Skip to content

Commit b06fe0f

Browse files
committed
TUN-4571: Fix proxying to unix sockets when using HTTP2 transport to Cloudflare Edge
1 parent bf068e7 commit b06fe0f

File tree

3 files changed

+86
-20
lines changed

3 files changed

+86
-20
lines changed

component-tests/test_reconnect.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#!/usr/bin/env python
22
import copy
3+
import platform
34
from time import sleep
45

6+
import pytest
57
from flaky import flaky
68

79
from util import start_cloudflared, wait_tunnel_ready, check_tunnel_not_connected
@@ -15,6 +17,7 @@ class TestReconnect:
1517
"stdin-control": True,
1618
}
1719

20+
@pytest.mark.skipif(platform.system() == "Windows", reason=f"Currently buggy on Windows TUN-4584")
1821
def test_named_reconnect(self, tmp_path, component_tests_config):
1922
config = component_tests_config(self.extra_config)
2023
with start_cloudflared(tmp_path, config, new_process=True, allow_input=True, capture_output=False) as cloudflared:

connection/http2.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ func (c *http2Connection) ServeHTTP(w http.ResponseWriter, r *http.Request) {
9898
defer c.activeRequestsWG.Done()
9999

100100
connType := determineHTTP2Type(r)
101+
handleMissingRequestParts(connType, r)
102+
101103
respWriter, err := newHTTP2RespWriter(r, w, connType)
102104
if err != nil {
103105
c.observer.log.Error().Msg(err.Error())
@@ -255,6 +257,20 @@ func determineHTTP2Type(r *http.Request) Type {
255257
}
256258
}
257259

260+
func handleMissingRequestParts(connType Type, r *http.Request) {
261+
if connType == TypeHTTP {
262+
// http library has no guarantees that we receive a filled URL. If not, then we fill it, as we reuse the request
263+
// for proxying. We use the same values as we used to in h2mux. For proxying they should not matter since we
264+
// control the dialer on every egress proxied.
265+
if len(r.URL.Scheme) == 0 {
266+
r.URL.Scheme = "http"
267+
}
268+
if len(r.URL.Host) == 0 {
269+
r.URL.Host = "localhost:8080"
270+
}
271+
}
272+
}
273+
258274
func isControlStreamUpgrade(r *http.Request) bool {
259275
return r.Header.Get(InternalUpgradeHeader) == ControlStreamUpgrade
260276
}

origin/proxy_test.go

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import (
66
"flag"
77
"fmt"
88
"io"
9+
"io/ioutil"
910
"net"
1011
"net/http"
1112
"net/http/httptest"
13+
"os"
1214
"sync"
1315
"testing"
1416
"time"
@@ -273,26 +275,7 @@ func TestProxyMultipleOrigins(t *testing.T) {
273275
},
274276
}
275277

276-
ingress, err := ingress.ParseIngress(&config.Configuration{
277-
TunnelID: t.Name(),
278-
Ingress: unvalidatedIngress,
279-
})
280-
require.NoError(t, err)
281-
282-
log := zerolog.Nop()
283-
284-
ctx, cancel := context.WithCancel(context.Background())
285-
errC := make(chan error)
286-
var wg sync.WaitGroup
287-
require.NoError(t, ingress.StartOrigins(&wg, &log, ctx.Done(), errC))
288-
289-
proxy := NewOriginProxy(ingress, unusedWarpRoutingService, testTags, &log)
290-
291-
tests := []struct {
292-
url string
293-
expectedStatus int
294-
expectedBody []byte
295-
}{
278+
tests := []MultipleIngressTest{
296279
{
297280
url: "http://api.example.com",
298281
expectedStatus: http.StatusCreated,
@@ -317,6 +300,31 @@ func TestProxyMultipleOrigins(t *testing.T) {
317300
},
318301
}
319302

303+
runIngressTestScenarios(t, unvalidatedIngress, tests)
304+
}
305+
306+
type MultipleIngressTest struct {
307+
url string
308+
expectedStatus int
309+
expectedBody []byte
310+
}
311+
312+
func runIngressTestScenarios(t *testing.T, unvalidatedIngress []config.UnvalidatedIngressRule, tests []MultipleIngressTest) {
313+
ingress, err := ingress.ParseIngress(&config.Configuration{
314+
TunnelID: t.Name(),
315+
Ingress: unvalidatedIngress,
316+
})
317+
require.NoError(t, err)
318+
319+
log := zerolog.Nop()
320+
321+
ctx, cancel := context.WithCancel(context.Background())
322+
errC := make(chan error)
323+
var wg sync.WaitGroup
324+
require.NoError(t, ingress.StartOrigins(&wg, &log, ctx.Done(), errC))
325+
326+
proxy := NewOriginProxy(ingress, unusedWarpRoutingService, testTags, &log)
327+
320328
for _, test := range tests {
321329
responseWriter := newMockHTTPRespWriter()
322330
req, err := http.NewRequest(http.MethodGet, test.url, nil)
@@ -633,6 +641,45 @@ func TestConnections(t *testing.T) {
633641
}
634642
}
635643

644+
func TestUnixSocketOrigin(t *testing.T) {
645+
file, err := ioutil.TempFile("", "unix.sock")
646+
require.NoError(t, err)
647+
os.Remove(file.Name()) // remove the file since binding the socket expects to create it
648+
649+
l, err := net.Listen("unix", file.Name())
650+
require.NoError(t, err)
651+
defer l.Close()
652+
defer os.Remove(file.Name())
653+
654+
api := &httptest.Server{
655+
Listener: l,
656+
Config: &http.Server{Handler: mockAPI{}},
657+
}
658+
api.Start()
659+
defer api.Close()
660+
661+
unvalidatedIngress := []config.UnvalidatedIngressRule{
662+
{
663+
Hostname: "unix.example.com",
664+
Service: "unix:" + file.Name(),
665+
},
666+
{
667+
Hostname: "*",
668+
Service: "http_status:404",
669+
},
670+
}
671+
672+
tests := []MultipleIngressTest{
673+
{
674+
url: "http://unix.example.com",
675+
expectedStatus: http.StatusCreated,
676+
expectedBody: []byte("Created"),
677+
},
678+
}
679+
680+
runIngressTestScenarios(t, unvalidatedIngress, tests)
681+
}
682+
636683
type requestBody struct {
637684
pw *io.PipeWriter
638685
pr *io.PipeReader

0 commit comments

Comments
 (0)