Skip to content
This repository was archived by the owner on Apr 30, 2025. It is now read-only.

Commit 6f655a4

Browse files
MerricdeLauneyctlongGerg
committed
WIP: Supporting HTTP/2 ingress traffic
- Basic integration test for HTTP/2 traffic - Still need to backfill unit tests - Running into some difficulties sending HTTP/1.0 requests via http.Client :sweatsmile: [cloudfoundry/routing-release#200] Co-authored-by: Carson Long <[email protected]> Co-authored-by: Greg Cobb <[email protected]>
1 parent 379860d commit 6f655a4

File tree

6 files changed

+135
-13
lines changed

6 files changed

+135
-13
lines changed

handlers/protocolcheck.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ func (p *protocolCheck) hijack(rw http.ResponseWriter) (net.Conn, *bufio.ReadWri
5959
}
6060

6161
func isProtocolSupported(request *http.Request) bool {
62-
return request.ProtoMajor == 1 && (request.ProtoMinor == 0 || request.ProtoMinor == 1)
62+
return request.ProtoMajor == 2 || (request.ProtoMajor == 1 && (request.ProtoMinor == 0 || request.ProtoMinor == 1))
6363
}

handlers/protocolcheck_test.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ var _ = Describe("Protocolcheck", func() {
4848
server.Close()
4949
})
5050

51-
Context("http 1.1", func() {
51+
Context("http2", func() {
5252
It("passes the request through", func() {
5353
conn, err := net.Dial("tcp", server.Addr())
5454
defer conn.Close()
5555
Expect(err).ToNot(HaveOccurred())
5656
respReader := bufio.NewReader(conn)
5757

58-
conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"))
58+
conn.Write([]byte("PRI * HTTP/2.0\r\nHost: example.com\r\n\r\n"))
5959
resp, err := http.ReadResponse(respReader, nil)
6060
Expect(err).ToNot(HaveOccurred())
6161

@@ -64,14 +64,14 @@ var _ = Describe("Protocolcheck", func() {
6464
})
6565
})
6666

67-
Context("http 1.0", func() {
67+
Context("http 1.1", func() {
6868
It("passes the request through", func() {
6969
conn, err := net.Dial("tcp", server.Addr())
7070
defer conn.Close()
7171
Expect(err).ToNot(HaveOccurred())
7272
respReader := bufio.NewReader(conn)
7373

74-
conn.Write([]byte("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"))
74+
conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"))
7575
resp, err := http.ReadResponse(respReader, nil)
7676
Expect(err).ToNot(HaveOccurred())
7777

@@ -80,32 +80,34 @@ var _ = Describe("Protocolcheck", func() {
8080
})
8181
})
8282

83-
Context("unsupported versions of http", func() {
84-
It("returns a 400 bad request", func() {
83+
Context("http 1.0", func() {
84+
It("passes the request through", func() {
8585
conn, err := net.Dial("tcp", server.Addr())
86+
defer conn.Close()
8687
Expect(err).ToNot(HaveOccurred())
8788
respReader := bufio.NewReader(conn)
8889

89-
conn.Write([]byte("GET / HTTP/1.5\r\nHost: example.com\r\n\r\n"))
90+
conn.Write([]byte("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"))
9091
resp, err := http.ReadResponse(respReader, nil)
9192
Expect(err).ToNot(HaveOccurred())
92-
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
9393

94-
Expect(nextCalled).To(BeFalse())
94+
Expect(resp.StatusCode).To(Equal(200))
95+
Expect(nextCalled).To(BeTrue())
9596
})
9697
})
9798

98-
Context("http2", func() {
99+
Context("unsupported versions of http", func() {
99100
It("returns a 400 bad request", func() {
100101
conn, err := net.Dial("tcp", server.Addr())
101102
Expect(err).ToNot(HaveOccurred())
102103
respReader := bufio.NewReader(conn)
103104

104-
conn.Write([]byte("PRI * HTTP/2.0\r\nHost: example.com\r\n\r\n"))
105-
105+
conn.Write([]byte("GET / HTTP/1.5\r\nHost: example.com\r\n\r\n"))
106106
resp, err := http.ReadResponse(respReader, nil)
107107
Expect(err).ToNot(HaveOccurred())
108108
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
109+
110+
Expect(nextCalled).To(BeFalse())
109111
})
110112
})
111113
})

integration/main_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"syscall"
2121
"time"
2222

23+
"golang.org/x/net/http2"
24+
2325
tls_helpers "code.cloudfoundry.org/cf-routing-test-helpers/tls"
2426
"code.cloudfoundry.org/gorouter/config"
2527
"code.cloudfoundry.org/gorouter/mbus"
@@ -248,6 +250,51 @@ var _ = Describe("Router Integration", func() {
248250
})
249251
})
250252

253+
Describe("HTTP/2 traffic", func() {
254+
var (
255+
clientTLSConfig *tls.Config
256+
mbusClient *nats.Conn
257+
)
258+
BeforeEach(func() {
259+
cfg, clientTLSConfig = createSSLConfig(statusPort, proxyPort, sslPort, natsPort)
260+
261+
})
262+
JustBeforeEach(func() {
263+
var err error
264+
writeConfig(cfg, cfgFile)
265+
mbusClient, err = newMessageBus(cfg)
266+
Expect(err).ToNot(HaveOccurred())
267+
})
268+
269+
It("serves HTTP/2 traffic", func() {
270+
gorouterSession = startGorouterSession(cfgFile)
271+
runningApp1 := test.NewGreetApp([]route.Uri{"test." + test_util.LocalhostDNS}, proxyPort, mbusClient, nil)
272+
runningApp1.Register()
273+
runningApp1.Listen()
274+
routesUri := fmt.Sprintf("http://%s:%s@%s:%d/routes", cfg.Status.User, cfg.Status.Pass, localIP, statusPort)
275+
276+
heartbeatInterval := 200 * time.Millisecond
277+
runningTicker := time.NewTicker(heartbeatInterval)
278+
done := make(chan bool, 1)
279+
defer func() { done <- true }()
280+
go func() {
281+
for {
282+
select {
283+
case <-runningTicker.C:
284+
runningApp1.Register()
285+
case <-done:
286+
return
287+
}
288+
}
289+
}()
290+
Eventually(func() bool { return appRegistered(routesUri, runningApp1) }).Should(BeTrue())
291+
client := &http.Client{Transport: &http2.Transport{TLSClientConfig: clientTLSConfig}}
292+
resp, err := client.Get(fmt.Sprintf("https://test.%s:%d", test_util.LocalhostDNS, cfg.SSLPort))
293+
Expect(err).ToNot(HaveOccurred())
294+
Expect(resp.StatusCode).To(Equal(http.StatusOK))
295+
})
296+
})
297+
251298
Context("Drain", func() {
252299

253300
BeforeEach(func() {

proxy/proxy_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,25 @@ var _ = Describe("Proxy", func() {
7474
Expect(resp.StatusCode).To(Equal(http.StatusOK))
7575
})
7676

77+
// FIt("responds to HTTP/2", func() {
78+
// ln := test_util.RegisterHandler(r, "test", func(conn *test_util.HttpConn) {
79+
// conn.CheckLine("GET / HTTP/2")
80+
81+
// conn.WriteResponse(test_util.NewResponse(http.StatusOK))
82+
// })
83+
// defer ln.Close()
84+
85+
// conn := dialProxy(proxyServer)
86+
87+
// conn.WriteLines([]string{
88+
// "GET / HTTP/2",
89+
// "Host: test",
90+
// })
91+
92+
// resp, _ := conn.ReadResponse()
93+
// Expect(resp.StatusCode).To(Equal(http.StatusOK))
94+
// })
95+
7796
It("does not respond to unsupported HTTP versions", func() {
7897
conn := dialProxy(proxyServer)
7998

router/router.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ func (r *Router) serveHTTPS(server *http.Server, errChan chan error) error {
228228
}
229229

230230
tlsConfig := &tls.Config{
231+
NextProtos: []string{"h2", "http/1.1"},
231232
Certificates: r.config.SSLCertificates,
232233
CipherSuites: r.config.CipherSuites,
233234
MinVersion: r.config.MinTLSVersion,

router/router_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,59 @@ var _ = Describe("Router", func() {
13501350

13511351
})
13521352

1353+
Context("serving multiple http versions", func() {
1354+
var (
1355+
// cert []byte
1356+
1357+
rootCAs *x509.CertPool
1358+
)
1359+
BeforeEach(func() {
1360+
certChain := test_util.CreateSignedCertWithRootCA(test_util.CertNames{CommonName: "test." + test_util.LocalhostDNS})
1361+
config.CACerts = string(certChain.CACertPEM)
1362+
config.SSLCertificates = append(config.SSLCertificates, certChain.TLSCert())
1363+
// cert = certChain.CertPEM
1364+
1365+
rootCAs = x509.NewCertPool()
1366+
rootCAs.AddCert(certChain.CACert)
1367+
})
1368+
1369+
FIt("can serve HTTP/1.0 requests", func() {
1370+
tlsClientConfig := &tls.Config{
1371+
NextProtos: []string{"http/1.0"},
1372+
RootCAs: rootCAs,
1373+
}
1374+
client := &http.Client{Transport: &http.Transport{
1375+
TLSClientConfig: tlsClientConfig,
1376+
}}
1377+
1378+
app := test.NewGreetApp([]route.Uri{"test." + test_util.LocalhostDNS}, config.Port, mbusClient, nil)
1379+
app.RegisterAndListen()
1380+
Eventually(func() bool {
1381+
return appRegistered(registry, app)
1382+
}).Should(BeTrue())
1383+
1384+
uri := fmt.Sprintf("https://test.%s:%d/", test_util.LocalhostDNS, config.SSLPort)
1385+
req, _ := http.NewRequest("GET", uri, nil)
1386+
req.Proto = "HTTP/1.0"
1387+
1388+
resp, err := client.Do(req)
1389+
Expect(err).ToNot(HaveOccurred())
1390+
Expect(resp).ToNot(BeNil())
1391+
1392+
Expect(resp.Proto).To(Equal("HTTP/1.0"))
1393+
Expect(resp.StatusCode).To(Equal(http.StatusOK))
1394+
1395+
bytes, err := ioutil.ReadAll(resp.Body)
1396+
Expect(err).ToNot(HaveOccurred())
1397+
Expect(bytes).To(ContainSubstring("Hello"))
1398+
defer resp.Body.Close()
1399+
})
1400+
It("can serve HTTP/1.1 requests", func() {
1401+
})
1402+
It("can serve HTTP/2.0 requests", func() {
1403+
})
1404+
})
1405+
13531406
Context("serving https", func() {
13541407
var (
13551408
cert []byte

0 commit comments

Comments
 (0)