blob: 1276a71afc9849e790aa93e4bb9193f1cf04b639 [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.
153 for ft := ContinuationFrameType + 1; ft != 0; ft++ {
154 fh := &UnknownFrame{
155 Header: FrameHeader{
156 Type: ft,
157 },
158 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800159 if err := streamFrame(conn, fh); err != nil {
Carl Mastrangelode449102015-10-28 11:05:49 -0700160 ctx.T.Log("Unable to stream frame", fh)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700161 return err
162 }
163 }
164
165 pf := &PingFrame{
166 Data: []byte("01234567"),
167 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800168 if err := streamFrame(conn, pf); err != nil {
169 ctx.T.Log("Unable to stream frame", pf)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700170 return err
171 }
172
173 for {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800174 frame, err := parseFrame(conn)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700175 if err != nil {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800176 ctx.T.Log("Unable to parse frame", err)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700177 return err
178 }
179 if npf, ok := frame.(*PingFrame); !ok {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800180 ctx.T.Log("Got frame", frame.GetHeader().Type)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700181 continue
182 } else {
183 if string(npf.Data) != string(pf.Data) || npf.Header.Flags&PING_ACK == 0 {
184 return fmt.Errorf("Bad ping %+v", *npf)
185 }
186 return nil
187 }
188 }
189
190 return nil
191}
192
Carl Mastrangelode449102015-10-28 11:05:49 -0700193func testShortPreface(ctx *HTTP2InteropCtx, prefacePrefix string) error {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800194 conn, err := connect(ctx)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700195 if err != nil {
196 return err
197 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800198 defer conn.Close()
199 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700200
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800201 if _, err := conn.Write([]byte(prefacePrefix)); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700202 return err
203 }
204
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800205 if _, err := expectGoAwaySoon(conn); err != nil {
206 return err
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700207 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800208
209 return nil
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700210}
211
Carl Mastrangelode449102015-10-28 11:05:49 -0700212func testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error {
213 config := buildTlsConfig(ctx)
214 config.MaxVersion = version
215 conn, err := connectWithTls(ctx, config)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700216 if err != nil {
217 return err
218 }
219 defer conn.Close()
Carl Mastrangelode449102015-10-28 11:05:49 -0700220 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700221
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800222 if err := http2Connect(conn, nil); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700223 return err
224 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800225
226 gf, err := expectGoAway(conn)
227 if err != nil {
228 return err
229 }
230 // TODO: make an enum out of this
231 if gf.Code != 0xC {
232 return fmt.Errorf("Expected an Inadequate security code: %v", gf)
233 }
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700234 return nil
235}
236
Carl Mastrangelode449102015-10-28 11:05:49 -0700237func testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error {
238 config := buildTlsConfig(ctx)
239 config.NextProtos = []string{"h2c"}
240 conn, err := connectWithTls(ctx, config)
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700241 if err != nil {
242 return err
243 }
244 defer conn.Close()
Carl Mastrangelode449102015-10-28 11:05:49 -0700245 conn.SetDeadline(time.Now().Add(defaultTimeout))
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700246
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800247 if err := http2Connect(conn, nil); err != nil {
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700248 return err
249 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800250
251 gf, err := expectGoAway(conn)
252 if err != nil {
253 return err
254 }
255 // TODO: make an enum out of this
256 if gf.Code != 0xC {
257 return fmt.Errorf("Expected an Inadequate security code: %v", gf)
258 }
Carl Mastrangelo4aca7962015-10-05 16:17:47 -0700259 return nil
260}
Carl Mastrangelode449102015-10-28 11:05:49 -0700261
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800262func testTLSBadCipherSuites(ctx *HTTP2InteropCtx) error {
263 config := buildTlsConfig(ctx)
264 // These are the suites that Go supports, but are forbidden by http2.
265 config.CipherSuites = []uint16{
266 tls.TLS_RSA_WITH_RC4_128_SHA,
267 tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
268 tls.TLS_RSA_WITH_AES_128_CBC_SHA,
269 tls.TLS_RSA_WITH_AES_256_CBC_SHA,
270 tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
271 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
272 tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
273 tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
274 tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
275 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
276 tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
277 }
278 conn, err := connectWithTls(ctx, config)
279 if err != nil {
280 return err
281 }
282 defer conn.Close()
283 conn.SetDeadline(time.Now().Add(defaultTimeout))
284
285 if err := http2Connect(conn, nil); err != nil {
286 return err
287 }
288
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800289 gf, err := expectGoAway(conn)
290 if err != nil {
291 return err
292 }
293 // TODO: make an enum out of this
294 if gf.Code != 0xC {
295 return fmt.Errorf("Expected an Inadequate security code: %v", gf)
296 }
297 return nil
298}
299
300func expectGoAway(conn net.Conn) (*GoAwayFrame, error) {
301 f, err := parseFrame(conn)
302 if err != nil {
303 return nil, err
304 }
305 if gf, ok := f.(*GoAwayFrame); !ok {
306 return nil, fmt.Errorf("Expected GoAway Frame %+v", f)
307 } else {
308 return gf, nil
309 }
310}
311
312// expectGoAwaySoon checks that a GOAWAY frame eventually comes. Servers usually send
313// the initial settings frames before any data has actually arrived. This function
314// checks that a go away shows.
315func expectGoAwaySoon(conn net.Conn) (*GoAwayFrame, error) {
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800316 for {
317 f, err := parseFrame(conn)
318 if err != nil {
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800319 return nil, err
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800320 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800321 if gf, ok := f.(*GoAwayFrame); !ok {
322 continue
323 } else {
324 return gf, nil
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800325 }
326 }
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800327}
328
329func http2Connect(c net.Conn, sf *SettingsFrame) error {
330 if _, err := c.Write([]byte(Preface)); err != nil {
331 return err
332 }
Carl Mastrangelo368a3042015-12-01 16:19:23 -0800333
Carl Mastrangelo8a1cdec2015-11-18 16:48:57 -0800334 if sf == nil {
335 sf = &SettingsFrame{}
336 }
337 if err := streamFrame(c, sf); err != nil {
338 return err
339 }
340 return nil
341}
342
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800343// CapConn captures connection traffic if Log is non-nil
344type CapConn struct {
345 net.Conn
346 Log func(args ...interface{})
347}
348
349func (c *CapConn) Write(data []byte) (int, error) {
350 if c.Log != nil {
351 c.Log(" SEND: ", data)
352 }
353 return c.Conn.Write(data)
354}
355
356func (c *CapConn) Read(data []byte) (int, error) {
357 n, err := c.Conn.Read(data)
358 if c.Log != nil {
359 c.Log(" RECV: ", data[:n], err)
360 }
361 return n, err
362}
363
364func connect(ctx *HTTP2InteropCtx) (*CapConn, error) {
365 var conn *CapConn
Carl Mastrangelode449102015-10-28 11:05:49 -0700366 var err error
367 if !ctx.UseTLS {
368 conn, err = connectWithoutTls(ctx)
369 } else {
370 config := buildTlsConfig(ctx)
371 conn, err = connectWithTls(ctx, config)
372 }
373 if err != nil {
374 return nil, err
375 }
376 conn.SetDeadline(time.Now().Add(defaultTimeout))
377
378 return conn, nil
379}
380
381func buildTlsConfig(ctx *HTTP2InteropCtx) *tls.Config {
382 return &tls.Config{
383 RootCAs: ctx.rootCAs,
384 NextProtos: []string{"h2"},
385 ServerName: ctx.authority,
386 MinVersion: tls.VersionTLS12,
Carl Mastrangelode449102015-10-28 11:05:49 -0700387 }
388}
389
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800390func connectWithoutTls(ctx *HTTP2InteropCtx) (*CapConn, error) {
Carl Mastrangelode449102015-10-28 11:05:49 -0700391 conn, err := net.DialTimeout("tcp", ctx.serverSpec, defaultTimeout)
392 if err != nil {
393 return nil, err
394 }
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800395 return &CapConn{Conn: conn}, nil
Carl Mastrangelode449102015-10-28 11:05:49 -0700396}
397
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800398func connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*CapConn, error) {
Carl Mastrangelode449102015-10-28 11:05:49 -0700399 conn, err := connectWithoutTls(ctx)
400 if err != nil {
401 return nil, err
402 }
403
Carl Mastrangelo945836e2015-11-20 17:43:15 -0800404 return &CapConn{Conn: tls.Client(conn, config)}, nil
Carl Mastrangelode449102015-10-28 11:05:49 -0700405}