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

Commit de96cea

Browse files
Gergweymanf
authored and
Greg Cobb
committed
Update Router to serve HTTP/2 traffic
- Add integration test. - We were not able to get a router/router test working because making HTTP/2 requests to the test Server resulted in broken pipes. We believe this is due to differences in the test Server setup and the main.go setup used in the integration tests. This will require additional investigation. - Add router/router test to confirm that Gorouter can still server HTTP/1.1 traffic - Update protocol checking middleware to accept HTTP/2 [#177586561] [cloudfoundry/routing-release#200] Co-authored-by: Weyman Fung <[email protected]> Co-authored-by: Greg Cobb <[email protected]> Co-authored-by: Weyman Fung <[email protected]>
1 parent d6a523c commit de96cea

File tree

5 files changed

+108
-13
lines changed

5 files changed

+108
-13
lines changed

handlers/protocolcheck.go

+1-1
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

+14-12
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

+48
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,52 @@ 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+
Expect(resp.Proto).To(Equal("HTTP/2.0"))
296+
})
297+
})
298+
251299
Context("Drain", func() {
252300

253301
BeforeEach(func() {

router/router.go

+1
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"},
231232
Certificates: r.config.SSLCertificates,
232233
CipherSuites: r.config.CipherSuites,
233234
MinVersion: r.config.MinTLSVersion,

router/router_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,50 @@ var _ = Describe("Router", func() {
13501350

13511351
})
13521352

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

0 commit comments

Comments
 (0)