blob: fa113961f2a9df6ea5d360c4d6fee6c3cf2c27c5 [file] [log] [blame]
Carl Mastrangelo4aca7962015-10-05 16:17:47 -07001package http2interop
2
3import (
4 "crypto/tls"
Carl Mastrangelode449102015-10-28 11:05:49 -07005 "crypto/x509"
Carl Mastrangelo4aca7962015-10-05 16:17:47 -07006 "fmt"
7 "io"
Carl Mastrangelode449102015-10-28 11:05:49 -07008 "net"
9 "testing"
10 "time"
Carl Mastrangelo4aca7962015-10-05 16:17:47 -070011)
12
13const (
14 Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
15)
16
Carl Mastrangelode449102015-10-28 11:05:49 -070017var (
18 defaultTimeout = 1 * time.Second
19)
20
21type HTTP2InteropCtx struct {
22 // Inputs
23 ServerHost string
24 ServerPort int
25 UseTLS bool
26 UseTestCa bool
27 ServerHostnameOverride string
28
29 T *testing.T
30
31 // Derived
32 serverSpec string
33 authority string
34 rootCAs *x509.CertPool
35}
36
Carl Mastrangelo4aca7962015-10-05 16:17:47 -070037func parseFrame(r io.Reader) (Frame, error) {
38 fh := FrameHeader{}
39 if err := fh.Parse(r); err != nil {
40 return nil, err
41 }
42 var f Frame
43 switch fh.Type {
44 case PingFrameType:
45 f = &PingFrame{
46 Header: fh,
47 }
48 case SettingsFrameType:
49 f = &SettingsFrame{
50 Header: fh,
51 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -080052 case HTTP1FrameType:
53 f = &HTTP1Frame{
54 Header: fh,
55 }
Carl Mastrangelo4aca7962015-10-05 16:17:47 -070056 default:
57 f = &UnknownFrame{
58 Header: fh,
59 }
60 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -080061
Carl Mastrangelo4aca7962015-10-05 16:17:47 -070062 if err := f.ParsePayload(r); err != nil {
63 return nil, err
64 }
65
66 return f, nil
67}
68
69func streamFrame(w io.Writer, f Frame) error {
70 raw, err := f.MarshalBinary()
71 if err != nil {
72 return err
73 }
74 if _, err := w.Write(raw); err != nil {
75 return err
76 }
77 return nil
78}
79
Carl Mastrangelode449102015-10-28 11:05:49 -070080func testClientShortSettings(ctx *HTTP2InteropCtx, length int) error {
Carl Mastrangelo945836e2015-11-20 17:43:15 -080081 conn, err := connect(ctx)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -070082 if err != nil {
83 return err
84 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -080085 defer conn.Close()
86 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -070087
Carl Mastrangelo945836e2015-11-20 17:43:15 -080088 if _, err := conn.Write([]byte(Preface)); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -070089 return err
90 }
91
92 // Bad, settings, non multiple of 6
93 sf := &UnknownFrame{
94 Header: FrameHeader{
95 Type: SettingsFrameType,
96 },
97 Data: make([]byte, length),
98 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -080099 if err := streamFrame(conn, sf); err != nil {
Carl Mastrangelode449102015-10-28 11:05:49 -0700100 ctx.T.Log("Unable to stream frame", sf)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700101 return err
102 }
103
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800104 if _, err := expectGoAwaySoon(conn); err != nil {
105 return err
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700106 }
107
108 return nil
109}
110
Carl Mastrangelode449102015-10-28 11:05:49 -0700111func testClientPrefaceWithStreamId(ctx *HTTP2InteropCtx) error {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800112 conn, err := connect(ctx)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700113 if err != nil {
114 return err
115 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800116 defer conn.Close()
117 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700118
119 // Good so far
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800120 if _, err := conn.Write([]byte(Preface)); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700121 return err
122 }
123
124 // Bad, settings do not have ids
125 sf := &SettingsFrame{
126 Header: FrameHeader{
127 StreamID: 1,
128 },
129 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800130 if err := streamFrame(conn, sf); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700131 return err
132 }
133
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800134 if _, err := expectGoAwaySoon(conn); err != nil {
135 return err
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700136 }
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700137 return nil
138}
139
Carl Mastrangelode449102015-10-28 11:05:49 -0700140func testUnknownFrameType(ctx *HTTP2InteropCtx) error {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800141 conn, err := connect(ctx)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700142 if err != nil {
143 return err
144 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800145 defer conn.Close()
146 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700147
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800148 if err := http2Connect(conn, nil); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700149 return err
150 }
151
152 // Write a bunch of invalid frame types.
Carl Mastrangelo30d39ab2016-04-07 16:10:25 -0700153 // Frame number 11 is the upcoming ALTSVC frame, and should not be tested.
154 for ft := ContinuationFrameType + 2; ft != 0; ft++ {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700155 fh := &UnknownFrame{
156 Header: FrameHeader{
157 Type: ft,
158 },
159 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800160 if err := streamFrame(conn, fh); err != nil {
Carl Mastrangelode449102015-10-28 11:05:49 -0700161 ctx.T.Log("Unable to stream frame", fh)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700162 return err
163 }
164 }
165
166 pf := &PingFrame{
167 Data: []byte("01234567"),
168 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800169 if err := streamFrame(conn, pf); err != nil {
170 ctx.T.Log("Unable to stream frame", pf)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700171 return err
172 }
173
174 for {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800175 frame, err := parseFrame(conn)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700176 if err != nil {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800177 ctx.T.Log("Unable to parse frame", err)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700178 return err
179 }
180 if npf, ok := frame.(*PingFrame); !ok {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800181 ctx.T.Log("Got frame", frame.GetHeader().Type)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700182 continue
183 } else {
184 if string(npf.Data) != string(pf.Data) || npf.Header.Flags&PING_ACK == 0 {
185 return fmt.Errorf("Bad ping %+v", *npf)
186 }
187 return nil
188 }
189 }
190
191 return nil
192}
193
Carl Mastrangelode449102015-10-28 11:05:49 -0700194func testShortPreface(ctx *HTTP2InteropCtx, prefacePrefix string) error {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800195 conn, err := connect(ctx)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700196 if err != nil {
197 return err
198 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800199 defer conn.Close()
200 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700201
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800202 if _, err := conn.Write([]byte(prefacePrefix)); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700203 return err
204 }
205
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800206 if _, err := expectGoAwaySoon(conn); err != nil {
207 return err
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700208 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800209
210 return nil
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700211}
212
Carl Mastrangelode449102015-10-28 11:05:49 -0700213func testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error {
214 config := buildTlsConfig(ctx)
215 config.MaxVersion = version
216 conn, err := connectWithTls(ctx, config)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700217 if err != nil {
218 return err
219 }
220 defer conn.Close()
Carl Mastrangelode449102015-10-28 11:05:49 -0700221 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700222
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800223 if err := http2Connect(conn, nil); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700224 return err
225 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800226
227 gf, err := expectGoAway(conn)
228 if err != nil {
229 return err
230 }
231 // TODO: make an enum out of this
232 if gf.Code != 0xC {
233 return fmt.Errorf("Expected an Inadequate security code: %v", gf)
234 }
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700235 return nil
236}
237
Carl Mastrangelode449102015-10-28 11:05:49 -0700238func testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error {
239 config := buildTlsConfig(ctx)
240 config.NextProtos = []string{"h2c"}
241 conn, err := connectWithTls(ctx, config)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700242 if err != nil {
243 return err
244 }
245 defer conn.Close()
Carl Mastrangelode449102015-10-28 11:05:49 -0700246 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700247
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800248 if err := http2Connect(conn, nil); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700249 return err
250 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800251
252 gf, err := expectGoAway(conn)
253 if err != nil {
254 return err
255 }
256 // TODO: make an enum out of this
257 if gf.Code != 0xC {
258 return fmt.Errorf("Expected an Inadequate security code: %v", gf)
259 }
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700260 return nil
261}
Carl Mastrangelode449102015-10-28 11:05:49 -0700262
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800263func testTLSBadCipherSuites(ctx *HTTP2InteropCtx) error {
264 config := buildTlsConfig(ctx)
265 // These are the suites that Go supports, but are forbidden by http2.
266 config.CipherSuites = []uint16{
267 tls.TLS_RSA_WITH_RC4_128_SHA,
268 tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
269 tls.TLS_RSA_WITH_AES_128_CBC_SHA,
270 tls.TLS_RSA_WITH_AES_256_CBC_SHA,
271 tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
272 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
273 tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
274 tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
275 tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
276 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
277 tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
278 }
279 conn, err := connectWithTls(ctx, config)
280 if err != nil {
281 return err
282 }
283 defer conn.Close()
284 conn.SetDeadline(time.Now().Add(defaultTimeout))
285
286 if err := http2Connect(conn, nil); err != nil {
287 return err
288 }
289
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800290 gf, err := expectGoAway(conn)
291 if err != nil {
292 return err
293 }
294 // TODO: make an enum out of this
295 if gf.Code != 0xC {
296 return fmt.Errorf("Expected an Inadequate security code: %v", gf)
297 }
298 return nil
299}
300
301func expectGoAway(conn net.Conn) (*GoAwayFrame, error) {
302 f, err := parseFrame(conn)
303 if err != nil {
304 return nil, err
305 }
306 if gf, ok := f.(*GoAwayFrame); !ok {
307 return nil, fmt.Errorf("Expected GoAway Frame %+v", f)
308 } else {
309 return gf, nil
310 }
311}
312
313// expectGoAwaySoon checks that a GOAWAY frame eventually comes. Servers usually send
314// the initial settings frames before any data has actually arrived. This function
315// checks that a go away shows.
316func expectGoAwaySoon(conn net.Conn) (*GoAwayFrame, error) {
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800317 for {
318 f, err := parseFrame(conn)
319 if err != nil {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800320 return nil, err
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800321 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800322 if gf, ok := f.(*GoAwayFrame); !ok {
323 continue
324 } else {
325 return gf, nil
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800326 }
327 }
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800328}
329
330func http2Connect(c net.Conn, sf *SettingsFrame) error {
331 if _, err := c.Write([]byte(Preface)); err != nil {
332 return err
333 }
Carl Mastrangelo368a3042015-12-01 16:19:23 -0800334
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800335 if sf == nil {
336 sf = &SettingsFrame{}
337 }
338 if err := streamFrame(c, sf); err != nil {
339 return err
340 }
341 return nil
342}
343
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800344// CapConn captures connection traffic if Log is non-nil
345type CapConn struct {
346 net.Conn
347 Log func(args ...interface{})
348}
349
350func (c *CapConn) Write(data []byte) (int, error) {
351 if c.Log != nil {
352 c.Log(" SEND: ", data)
353 }
354 return c.Conn.Write(data)
355}
356
357func (c *CapConn) Read(data []byte) (int, error) {
358 n, err := c.Conn.Read(data)
359 if c.Log != nil {
360 c.Log(" RECV: ", data[:n], err)
361 }
362 return n, err
363}
364
365func connect(ctx *HTTP2InteropCtx) (*CapConn, error) {
366 var conn *CapConn
Carl Mastrangelode449102015-10-28 11:05:49 -0700367 var err error
368 if !ctx.UseTLS {
369 conn, err = connectWithoutTls(ctx)
370 } else {
371 config := buildTlsConfig(ctx)
372 conn, err = connectWithTls(ctx, config)
373 }
374 if err != nil {
375 return nil, err
376 }
377 conn.SetDeadline(time.Now().Add(defaultTimeout))
378
379 return conn, nil
380}
381
382func buildTlsConfig(ctx *HTTP2InteropCtx) *tls.Config {
383 return &tls.Config{
384 RootCAs: ctx.rootCAs,
385 NextProtos: []string{"h2"},
386 ServerName: ctx.authority,
387 MinVersion: tls.VersionTLS12,
Carl Mastrangelode449102015-10-28 11:05:49 -0700388 }
389}
390
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800391func connectWithoutTls(ctx *HTTP2InteropCtx) (*CapConn, error) {
Carl Mastrangelode449102015-10-28 11:05:49 -0700392 conn, err := net.DialTimeout("tcp", ctx.serverSpec, defaultTimeout)
393 if err != nil {
394 return nil, err
395 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800396 return &CapConn{Conn: conn}, nil
Carl Mastrangelode449102015-10-28 11:05:49 -0700397}
398
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800399func connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*CapConn, error) {
Carl Mastrangelode449102015-10-28 11:05:49 -0700400 conn, err := connectWithoutTls(ctx)
401 if err != nil {
402 return nil, err
403 }
404
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800405 return &CapConn{Conn: tls.Client(conn, config)}, nil
Carl Mastrangelode449102015-10-28 11:05:49 -0700406}