1*cc02d7e2SAndroid Build Coastguard Worker// Copyright 2019 The gRPC Authors 2*cc02d7e2SAndroid Build Coastguard Worker// 3*cc02d7e2SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*cc02d7e2SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*cc02d7e2SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*cc02d7e2SAndroid Build Coastguard Worker// 7*cc02d7e2SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*cc02d7e2SAndroid Build Coastguard Worker// 9*cc02d7e2SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*cc02d7e2SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*cc02d7e2SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*cc02d7e2SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*cc02d7e2SAndroid Build Coastguard Worker// limitations under the License. 14*cc02d7e2SAndroid Build Coastguard Worker 15*cc02d7e2SAndroid Build Coastguard Workerpackage http2interop 16*cc02d7e2SAndroid Build Coastguard Worker 17*cc02d7e2SAndroid Build Coastguard Workerimport ( 18*cc02d7e2SAndroid Build Coastguard Worker "crypto/tls" 19*cc02d7e2SAndroid Build Coastguard Worker "crypto/x509" 20*cc02d7e2SAndroid Build Coastguard Worker "fmt" 21*cc02d7e2SAndroid Build Coastguard Worker "io" 22*cc02d7e2SAndroid Build Coastguard Worker "net" 23*cc02d7e2SAndroid Build Coastguard Worker "testing" 24*cc02d7e2SAndroid Build Coastguard Worker "time" 25*cc02d7e2SAndroid Build Coastguard Worker) 26*cc02d7e2SAndroid Build Coastguard Worker 27*cc02d7e2SAndroid Build Coastguard Workerconst ( 28*cc02d7e2SAndroid Build Coastguard Worker Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" 29*cc02d7e2SAndroid Build Coastguard Worker) 30*cc02d7e2SAndroid Build Coastguard Worker 31*cc02d7e2SAndroid Build Coastguard Workervar ( 32*cc02d7e2SAndroid Build Coastguard Worker defaultTimeout = 1 * time.Second 33*cc02d7e2SAndroid Build Coastguard Worker) 34*cc02d7e2SAndroid Build Coastguard Worker 35*cc02d7e2SAndroid Build Coastguard Workertype HTTP2InteropCtx struct { 36*cc02d7e2SAndroid Build Coastguard Worker // Inputs 37*cc02d7e2SAndroid Build Coastguard Worker ServerHost string 38*cc02d7e2SAndroid Build Coastguard Worker ServerPort int 39*cc02d7e2SAndroid Build Coastguard Worker UseTLS bool 40*cc02d7e2SAndroid Build Coastguard Worker UseTestCa bool 41*cc02d7e2SAndroid Build Coastguard Worker ServerHostnameOverride string 42*cc02d7e2SAndroid Build Coastguard Worker 43*cc02d7e2SAndroid Build Coastguard Worker T *testing.T 44*cc02d7e2SAndroid Build Coastguard Worker 45*cc02d7e2SAndroid Build Coastguard Worker // Derived 46*cc02d7e2SAndroid Build Coastguard Worker serverSpec string 47*cc02d7e2SAndroid Build Coastguard Worker authority string 48*cc02d7e2SAndroid Build Coastguard Worker rootCAs *x509.CertPool 49*cc02d7e2SAndroid Build Coastguard Worker} 50*cc02d7e2SAndroid Build Coastguard Worker 51*cc02d7e2SAndroid Build Coastguard Workerfunc parseFrame(r io.Reader) (Frame, error) { 52*cc02d7e2SAndroid Build Coastguard Worker fh := FrameHeader{} 53*cc02d7e2SAndroid Build Coastguard Worker if err := fh.Parse(r); err != nil { 54*cc02d7e2SAndroid Build Coastguard Worker return nil, err 55*cc02d7e2SAndroid Build Coastguard Worker } 56*cc02d7e2SAndroid Build Coastguard Worker var f Frame 57*cc02d7e2SAndroid Build Coastguard Worker switch fh.Type { 58*cc02d7e2SAndroid Build Coastguard Worker case PingFrameType: 59*cc02d7e2SAndroid Build Coastguard Worker f = &PingFrame{ 60*cc02d7e2SAndroid Build Coastguard Worker Header: fh, 61*cc02d7e2SAndroid Build Coastguard Worker } 62*cc02d7e2SAndroid Build Coastguard Worker case SettingsFrameType: 63*cc02d7e2SAndroid Build Coastguard Worker f = &SettingsFrame{ 64*cc02d7e2SAndroid Build Coastguard Worker Header: fh, 65*cc02d7e2SAndroid Build Coastguard Worker } 66*cc02d7e2SAndroid Build Coastguard Worker case HTTP1FrameType: 67*cc02d7e2SAndroid Build Coastguard Worker f = &HTTP1Frame{ 68*cc02d7e2SAndroid Build Coastguard Worker Header: fh, 69*cc02d7e2SAndroid Build Coastguard Worker } 70*cc02d7e2SAndroid Build Coastguard Worker default: 71*cc02d7e2SAndroid Build Coastguard Worker f = &UnknownFrame{ 72*cc02d7e2SAndroid Build Coastguard Worker Header: fh, 73*cc02d7e2SAndroid Build Coastguard Worker } 74*cc02d7e2SAndroid Build Coastguard Worker } 75*cc02d7e2SAndroid Build Coastguard Worker 76*cc02d7e2SAndroid Build Coastguard Worker if err := f.ParsePayload(r); err != nil { 77*cc02d7e2SAndroid Build Coastguard Worker return nil, err 78*cc02d7e2SAndroid Build Coastguard Worker } 79*cc02d7e2SAndroid Build Coastguard Worker 80*cc02d7e2SAndroid Build Coastguard Worker return f, nil 81*cc02d7e2SAndroid Build Coastguard Worker} 82*cc02d7e2SAndroid Build Coastguard Worker 83*cc02d7e2SAndroid Build Coastguard Workerfunc streamFrame(w io.Writer, f Frame) error { 84*cc02d7e2SAndroid Build Coastguard Worker raw, err := f.MarshalBinary() 85*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 86*cc02d7e2SAndroid Build Coastguard Worker return err 87*cc02d7e2SAndroid Build Coastguard Worker } 88*cc02d7e2SAndroid Build Coastguard Worker if _, err := w.Write(raw); err != nil { 89*cc02d7e2SAndroid Build Coastguard Worker return err 90*cc02d7e2SAndroid Build Coastguard Worker } 91*cc02d7e2SAndroid Build Coastguard Worker return nil 92*cc02d7e2SAndroid Build Coastguard Worker} 93*cc02d7e2SAndroid Build Coastguard Worker 94*cc02d7e2SAndroid Build Coastguard Workerfunc testClientShortSettings(ctx *HTTP2InteropCtx, length int) error { 95*cc02d7e2SAndroid Build Coastguard Worker conn, err := connect(ctx) 96*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 97*cc02d7e2SAndroid Build Coastguard Worker return err 98*cc02d7e2SAndroid Build Coastguard Worker } 99*cc02d7e2SAndroid Build Coastguard Worker defer conn.Close() 100*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 101*cc02d7e2SAndroid Build Coastguard Worker 102*cc02d7e2SAndroid Build Coastguard Worker if _, err := conn.Write([]byte(Preface)); err != nil { 103*cc02d7e2SAndroid Build Coastguard Worker return err 104*cc02d7e2SAndroid Build Coastguard Worker } 105*cc02d7e2SAndroid Build Coastguard Worker 106*cc02d7e2SAndroid Build Coastguard Worker // Bad, settings, non multiple of 6 107*cc02d7e2SAndroid Build Coastguard Worker sf := &UnknownFrame{ 108*cc02d7e2SAndroid Build Coastguard Worker Header: FrameHeader{ 109*cc02d7e2SAndroid Build Coastguard Worker Type: SettingsFrameType, 110*cc02d7e2SAndroid Build Coastguard Worker }, 111*cc02d7e2SAndroid Build Coastguard Worker Data: make([]byte, length), 112*cc02d7e2SAndroid Build Coastguard Worker } 113*cc02d7e2SAndroid Build Coastguard Worker if err := streamFrame(conn, sf); err != nil { 114*cc02d7e2SAndroid Build Coastguard Worker ctx.T.Log("Unable to stream frame", sf) 115*cc02d7e2SAndroid Build Coastguard Worker return err 116*cc02d7e2SAndroid Build Coastguard Worker } 117*cc02d7e2SAndroid Build Coastguard Worker 118*cc02d7e2SAndroid Build Coastguard Worker if _, err := expectGoAwaySoon(conn); err != nil { 119*cc02d7e2SAndroid Build Coastguard Worker return err 120*cc02d7e2SAndroid Build Coastguard Worker } 121*cc02d7e2SAndroid Build Coastguard Worker 122*cc02d7e2SAndroid Build Coastguard Worker return nil 123*cc02d7e2SAndroid Build Coastguard Worker} 124*cc02d7e2SAndroid Build Coastguard Worker 125*cc02d7e2SAndroid Build Coastguard Workerfunc testClientPrefaceWithStreamId(ctx *HTTP2InteropCtx) error { 126*cc02d7e2SAndroid Build Coastguard Worker conn, err := connect(ctx) 127*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 128*cc02d7e2SAndroid Build Coastguard Worker return err 129*cc02d7e2SAndroid Build Coastguard Worker } 130*cc02d7e2SAndroid Build Coastguard Worker defer conn.Close() 131*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 132*cc02d7e2SAndroid Build Coastguard Worker 133*cc02d7e2SAndroid Build Coastguard Worker // Good so far 134*cc02d7e2SAndroid Build Coastguard Worker if _, err := conn.Write([]byte(Preface)); err != nil { 135*cc02d7e2SAndroid Build Coastguard Worker return err 136*cc02d7e2SAndroid Build Coastguard Worker } 137*cc02d7e2SAndroid Build Coastguard Worker 138*cc02d7e2SAndroid Build Coastguard Worker // Bad, settings do not have ids 139*cc02d7e2SAndroid Build Coastguard Worker sf := &SettingsFrame{ 140*cc02d7e2SAndroid Build Coastguard Worker Header: FrameHeader{ 141*cc02d7e2SAndroid Build Coastguard Worker StreamID: 1, 142*cc02d7e2SAndroid Build Coastguard Worker }, 143*cc02d7e2SAndroid Build Coastguard Worker } 144*cc02d7e2SAndroid Build Coastguard Worker if err := streamFrame(conn, sf); err != nil { 145*cc02d7e2SAndroid Build Coastguard Worker return err 146*cc02d7e2SAndroid Build Coastguard Worker } 147*cc02d7e2SAndroid Build Coastguard Worker 148*cc02d7e2SAndroid Build Coastguard Worker if _, err := expectGoAwaySoon(conn); err != nil { 149*cc02d7e2SAndroid Build Coastguard Worker return err 150*cc02d7e2SAndroid Build Coastguard Worker } 151*cc02d7e2SAndroid Build Coastguard Worker return nil 152*cc02d7e2SAndroid Build Coastguard Worker} 153*cc02d7e2SAndroid Build Coastguard Worker 154*cc02d7e2SAndroid Build Coastguard Workerfunc testUnknownFrameType(ctx *HTTP2InteropCtx) error { 155*cc02d7e2SAndroid Build Coastguard Worker conn, err := connect(ctx) 156*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 157*cc02d7e2SAndroid Build Coastguard Worker return err 158*cc02d7e2SAndroid Build Coastguard Worker } 159*cc02d7e2SAndroid Build Coastguard Worker defer conn.Close() 160*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 161*cc02d7e2SAndroid Build Coastguard Worker 162*cc02d7e2SAndroid Build Coastguard Worker if err := http2Connect(conn, nil); err != nil { 163*cc02d7e2SAndroid Build Coastguard Worker return err 164*cc02d7e2SAndroid Build Coastguard Worker } 165*cc02d7e2SAndroid Build Coastguard Worker 166*cc02d7e2SAndroid Build Coastguard Worker // Write a bunch of invalid frame types. 167*cc02d7e2SAndroid Build Coastguard Worker // Frame number 11 is the upcoming ALTSVC frame, and should not be tested. 168*cc02d7e2SAndroid Build Coastguard Worker for ft := ContinuationFrameType + 2; ft != 0; ft++ { 169*cc02d7e2SAndroid Build Coastguard Worker fh := &UnknownFrame{ 170*cc02d7e2SAndroid Build Coastguard Worker Header: FrameHeader{ 171*cc02d7e2SAndroid Build Coastguard Worker Type: ft, 172*cc02d7e2SAndroid Build Coastguard Worker }, 173*cc02d7e2SAndroid Build Coastguard Worker } 174*cc02d7e2SAndroid Build Coastguard Worker if err := streamFrame(conn, fh); err != nil { 175*cc02d7e2SAndroid Build Coastguard Worker ctx.T.Log("Unable to stream frame", fh) 176*cc02d7e2SAndroid Build Coastguard Worker return err 177*cc02d7e2SAndroid Build Coastguard Worker } 178*cc02d7e2SAndroid Build Coastguard Worker } 179*cc02d7e2SAndroid Build Coastguard Worker 180*cc02d7e2SAndroid Build Coastguard Worker pf := &PingFrame{ 181*cc02d7e2SAndroid Build Coastguard Worker Data: []byte("01234567"), 182*cc02d7e2SAndroid Build Coastguard Worker } 183*cc02d7e2SAndroid Build Coastguard Worker if err := streamFrame(conn, pf); err != nil { 184*cc02d7e2SAndroid Build Coastguard Worker ctx.T.Log("Unable to stream frame", pf) 185*cc02d7e2SAndroid Build Coastguard Worker return err 186*cc02d7e2SAndroid Build Coastguard Worker } 187*cc02d7e2SAndroid Build Coastguard Worker 188*cc02d7e2SAndroid Build Coastguard Worker for { 189*cc02d7e2SAndroid Build Coastguard Worker frame, err := parseFrame(conn) 190*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 191*cc02d7e2SAndroid Build Coastguard Worker ctx.T.Log("Unable to parse frame", err) 192*cc02d7e2SAndroid Build Coastguard Worker return err 193*cc02d7e2SAndroid Build Coastguard Worker } 194*cc02d7e2SAndroid Build Coastguard Worker if npf, ok := frame.(*PingFrame); !ok { 195*cc02d7e2SAndroid Build Coastguard Worker ctx.T.Log("Got frame", frame.GetHeader().Type) 196*cc02d7e2SAndroid Build Coastguard Worker continue 197*cc02d7e2SAndroid Build Coastguard Worker } else { 198*cc02d7e2SAndroid Build Coastguard Worker if string(npf.Data) != string(pf.Data) || npf.Header.Flags&PING_ACK == 0 { 199*cc02d7e2SAndroid Build Coastguard Worker return fmt.Errorf("Bad ping %+v", *npf) 200*cc02d7e2SAndroid Build Coastguard Worker } 201*cc02d7e2SAndroid Build Coastguard Worker return nil 202*cc02d7e2SAndroid Build Coastguard Worker } 203*cc02d7e2SAndroid Build Coastguard Worker } 204*cc02d7e2SAndroid Build Coastguard Worker 205*cc02d7e2SAndroid Build Coastguard Worker return nil 206*cc02d7e2SAndroid Build Coastguard Worker} 207*cc02d7e2SAndroid Build Coastguard Worker 208*cc02d7e2SAndroid Build Coastguard Workerfunc testShortPreface(ctx *HTTP2InteropCtx, prefacePrefix string) error { 209*cc02d7e2SAndroid Build Coastguard Worker conn, err := connect(ctx) 210*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 211*cc02d7e2SAndroid Build Coastguard Worker return err 212*cc02d7e2SAndroid Build Coastguard Worker } 213*cc02d7e2SAndroid Build Coastguard Worker defer conn.Close() 214*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 215*cc02d7e2SAndroid Build Coastguard Worker 216*cc02d7e2SAndroid Build Coastguard Worker if _, err := conn.Write([]byte(prefacePrefix)); err != nil { 217*cc02d7e2SAndroid Build Coastguard Worker return err 218*cc02d7e2SAndroid Build Coastguard Worker } 219*cc02d7e2SAndroid Build Coastguard Worker 220*cc02d7e2SAndroid Build Coastguard Worker if _, err := expectGoAwaySoon(conn); err != nil { 221*cc02d7e2SAndroid Build Coastguard Worker return err 222*cc02d7e2SAndroid Build Coastguard Worker } 223*cc02d7e2SAndroid Build Coastguard Worker 224*cc02d7e2SAndroid Build Coastguard Worker return nil 225*cc02d7e2SAndroid Build Coastguard Worker} 226*cc02d7e2SAndroid Build Coastguard Worker 227*cc02d7e2SAndroid Build Coastguard Workerfunc testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error { 228*cc02d7e2SAndroid Build Coastguard Worker config := buildTlsConfig(ctx) 229*cc02d7e2SAndroid Build Coastguard Worker config.MaxVersion = version 230*cc02d7e2SAndroid Build Coastguard Worker conn, err := connectWithTls(ctx, config) 231*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 232*cc02d7e2SAndroid Build Coastguard Worker return err 233*cc02d7e2SAndroid Build Coastguard Worker } 234*cc02d7e2SAndroid Build Coastguard Worker defer conn.Close() 235*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 236*cc02d7e2SAndroid Build Coastguard Worker 237*cc02d7e2SAndroid Build Coastguard Worker if err := http2Connect(conn, nil); err != nil { 238*cc02d7e2SAndroid Build Coastguard Worker return err 239*cc02d7e2SAndroid Build Coastguard Worker } 240*cc02d7e2SAndroid Build Coastguard Worker 241*cc02d7e2SAndroid Build Coastguard Worker gf, err := expectGoAway(conn) 242*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 243*cc02d7e2SAndroid Build Coastguard Worker return err 244*cc02d7e2SAndroid Build Coastguard Worker } 245*cc02d7e2SAndroid Build Coastguard Worker // TODO: make an enum out of this 246*cc02d7e2SAndroid Build Coastguard Worker if gf.Code != 0xC { 247*cc02d7e2SAndroid Build Coastguard Worker return fmt.Errorf("Expected an Inadequate security code: %v", gf) 248*cc02d7e2SAndroid Build Coastguard Worker } 249*cc02d7e2SAndroid Build Coastguard Worker return nil 250*cc02d7e2SAndroid Build Coastguard Worker} 251*cc02d7e2SAndroid Build Coastguard Worker 252*cc02d7e2SAndroid Build Coastguard Workerfunc testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error { 253*cc02d7e2SAndroid Build Coastguard Worker config := buildTlsConfig(ctx) 254*cc02d7e2SAndroid Build Coastguard Worker config.NextProtos = []string{"h2c"} 255*cc02d7e2SAndroid Build Coastguard Worker conn, err := connectWithTls(ctx, config) 256*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 257*cc02d7e2SAndroid Build Coastguard Worker return err 258*cc02d7e2SAndroid Build Coastguard Worker } 259*cc02d7e2SAndroid Build Coastguard Worker defer conn.Close() 260*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 261*cc02d7e2SAndroid Build Coastguard Worker 262*cc02d7e2SAndroid Build Coastguard Worker if err := http2Connect(conn, nil); err != nil { 263*cc02d7e2SAndroid Build Coastguard Worker return err 264*cc02d7e2SAndroid Build Coastguard Worker } 265*cc02d7e2SAndroid Build Coastguard Worker 266*cc02d7e2SAndroid Build Coastguard Worker gf, err := expectGoAway(conn) 267*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 268*cc02d7e2SAndroid Build Coastguard Worker return err 269*cc02d7e2SAndroid Build Coastguard Worker } 270*cc02d7e2SAndroid Build Coastguard Worker // TODO: make an enum out of this 271*cc02d7e2SAndroid Build Coastguard Worker if gf.Code != 0xC { 272*cc02d7e2SAndroid Build Coastguard Worker return fmt.Errorf("Expected an Inadequate security code: %v", gf) 273*cc02d7e2SAndroid Build Coastguard Worker } 274*cc02d7e2SAndroid Build Coastguard Worker return nil 275*cc02d7e2SAndroid Build Coastguard Worker} 276*cc02d7e2SAndroid Build Coastguard Worker 277*cc02d7e2SAndroid Build Coastguard Workerfunc testTLSBadCipherSuites(ctx *HTTP2InteropCtx) error { 278*cc02d7e2SAndroid Build Coastguard Worker config := buildTlsConfig(ctx) 279*cc02d7e2SAndroid Build Coastguard Worker // These are the suites that Go supports, but are forbidden by http2. 280*cc02d7e2SAndroid Build Coastguard Worker config.CipherSuites = []uint16{ 281*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_RSA_WITH_RC4_128_SHA, 282*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, 283*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_RSA_WITH_AES_128_CBC_SHA, 284*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_RSA_WITH_AES_256_CBC_SHA, 285*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 286*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 287*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 288*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, 289*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 290*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 291*cc02d7e2SAndroid Build Coastguard Worker tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 292*cc02d7e2SAndroid Build Coastguard Worker } 293*cc02d7e2SAndroid Build Coastguard Worker conn, err := connectWithTls(ctx, config) 294*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 295*cc02d7e2SAndroid Build Coastguard Worker return err 296*cc02d7e2SAndroid Build Coastguard Worker } 297*cc02d7e2SAndroid Build Coastguard Worker defer conn.Close() 298*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 299*cc02d7e2SAndroid Build Coastguard Worker 300*cc02d7e2SAndroid Build Coastguard Worker if err := http2Connect(conn, nil); err != nil { 301*cc02d7e2SAndroid Build Coastguard Worker return err 302*cc02d7e2SAndroid Build Coastguard Worker } 303*cc02d7e2SAndroid Build Coastguard Worker 304*cc02d7e2SAndroid Build Coastguard Worker gf, err := expectGoAway(conn) 305*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 306*cc02d7e2SAndroid Build Coastguard Worker return err 307*cc02d7e2SAndroid Build Coastguard Worker } 308*cc02d7e2SAndroid Build Coastguard Worker // TODO: make an enum out of this 309*cc02d7e2SAndroid Build Coastguard Worker if gf.Code != 0xC { 310*cc02d7e2SAndroid Build Coastguard Worker return fmt.Errorf("Expected an Inadequate security code: %v", gf) 311*cc02d7e2SAndroid Build Coastguard Worker } 312*cc02d7e2SAndroid Build Coastguard Worker return nil 313*cc02d7e2SAndroid Build Coastguard Worker} 314*cc02d7e2SAndroid Build Coastguard Worker 315*cc02d7e2SAndroid Build Coastguard Workerfunc expectGoAway(conn net.Conn) (*GoAwayFrame, error) { 316*cc02d7e2SAndroid Build Coastguard Worker f, err := parseFrame(conn) 317*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 318*cc02d7e2SAndroid Build Coastguard Worker return nil, err 319*cc02d7e2SAndroid Build Coastguard Worker } 320*cc02d7e2SAndroid Build Coastguard Worker if gf, ok := f.(*GoAwayFrame); !ok { 321*cc02d7e2SAndroid Build Coastguard Worker return nil, fmt.Errorf("Expected GoAway Frame %+v", f) 322*cc02d7e2SAndroid Build Coastguard Worker } else { 323*cc02d7e2SAndroid Build Coastguard Worker return gf, nil 324*cc02d7e2SAndroid Build Coastguard Worker } 325*cc02d7e2SAndroid Build Coastguard Worker} 326*cc02d7e2SAndroid Build Coastguard Worker 327*cc02d7e2SAndroid Build Coastguard Worker// expectGoAwaySoon checks that a GOAWAY frame eventually comes. Servers usually send 328*cc02d7e2SAndroid Build Coastguard Worker// the initial settings frames before any data has actually arrived. This function 329*cc02d7e2SAndroid Build Coastguard Worker// checks that a go away shows. 330*cc02d7e2SAndroid Build Coastguard Workerfunc expectGoAwaySoon(conn net.Conn) (*GoAwayFrame, error) { 331*cc02d7e2SAndroid Build Coastguard Worker for { 332*cc02d7e2SAndroid Build Coastguard Worker f, err := parseFrame(conn) 333*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 334*cc02d7e2SAndroid Build Coastguard Worker return nil, err 335*cc02d7e2SAndroid Build Coastguard Worker } 336*cc02d7e2SAndroid Build Coastguard Worker if gf, ok := f.(*GoAwayFrame); !ok { 337*cc02d7e2SAndroid Build Coastguard Worker continue 338*cc02d7e2SAndroid Build Coastguard Worker } else { 339*cc02d7e2SAndroid Build Coastguard Worker return gf, nil 340*cc02d7e2SAndroid Build Coastguard Worker } 341*cc02d7e2SAndroid Build Coastguard Worker } 342*cc02d7e2SAndroid Build Coastguard Worker} 343*cc02d7e2SAndroid Build Coastguard Worker 344*cc02d7e2SAndroid Build Coastguard Workerfunc http2Connect(c net.Conn, sf *SettingsFrame) error { 345*cc02d7e2SAndroid Build Coastguard Worker if _, err := c.Write([]byte(Preface)); err != nil { 346*cc02d7e2SAndroid Build Coastguard Worker return err 347*cc02d7e2SAndroid Build Coastguard Worker } 348*cc02d7e2SAndroid Build Coastguard Worker 349*cc02d7e2SAndroid Build Coastguard Worker if sf == nil { 350*cc02d7e2SAndroid Build Coastguard Worker sf = &SettingsFrame{} 351*cc02d7e2SAndroid Build Coastguard Worker } 352*cc02d7e2SAndroid Build Coastguard Worker if err := streamFrame(c, sf); err != nil { 353*cc02d7e2SAndroid Build Coastguard Worker return err 354*cc02d7e2SAndroid Build Coastguard Worker } 355*cc02d7e2SAndroid Build Coastguard Worker return nil 356*cc02d7e2SAndroid Build Coastguard Worker} 357*cc02d7e2SAndroid Build Coastguard Worker 358*cc02d7e2SAndroid Build Coastguard Worker// CapConn captures connection traffic if Log is non-nil 359*cc02d7e2SAndroid Build Coastguard Workertype CapConn struct { 360*cc02d7e2SAndroid Build Coastguard Worker net.Conn 361*cc02d7e2SAndroid Build Coastguard Worker Log func(args ...interface{}) 362*cc02d7e2SAndroid Build Coastguard Worker} 363*cc02d7e2SAndroid Build Coastguard Worker 364*cc02d7e2SAndroid Build Coastguard Workerfunc (c *CapConn) Write(data []byte) (int, error) { 365*cc02d7e2SAndroid Build Coastguard Worker if c.Log != nil { 366*cc02d7e2SAndroid Build Coastguard Worker c.Log(" SEND: ", data) 367*cc02d7e2SAndroid Build Coastguard Worker } 368*cc02d7e2SAndroid Build Coastguard Worker return c.Conn.Write(data) 369*cc02d7e2SAndroid Build Coastguard Worker} 370*cc02d7e2SAndroid Build Coastguard Worker 371*cc02d7e2SAndroid Build Coastguard Workerfunc (c *CapConn) Read(data []byte) (int, error) { 372*cc02d7e2SAndroid Build Coastguard Worker n, err := c.Conn.Read(data) 373*cc02d7e2SAndroid Build Coastguard Worker if c.Log != nil { 374*cc02d7e2SAndroid Build Coastguard Worker c.Log(" RECV: ", data[:n], err) 375*cc02d7e2SAndroid Build Coastguard Worker } 376*cc02d7e2SAndroid Build Coastguard Worker return n, err 377*cc02d7e2SAndroid Build Coastguard Worker} 378*cc02d7e2SAndroid Build Coastguard Worker 379*cc02d7e2SAndroid Build Coastguard Workerfunc connect(ctx *HTTP2InteropCtx) (*CapConn, error) { 380*cc02d7e2SAndroid Build Coastguard Worker var conn *CapConn 381*cc02d7e2SAndroid Build Coastguard Worker var err error 382*cc02d7e2SAndroid Build Coastguard Worker if !ctx.UseTLS { 383*cc02d7e2SAndroid Build Coastguard Worker conn, err = connectWithoutTls(ctx) 384*cc02d7e2SAndroid Build Coastguard Worker } else { 385*cc02d7e2SAndroid Build Coastguard Worker config := buildTlsConfig(ctx) 386*cc02d7e2SAndroid Build Coastguard Worker conn, err = connectWithTls(ctx, config) 387*cc02d7e2SAndroid Build Coastguard Worker } 388*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 389*cc02d7e2SAndroid Build Coastguard Worker return nil, err 390*cc02d7e2SAndroid Build Coastguard Worker } 391*cc02d7e2SAndroid Build Coastguard Worker conn.SetDeadline(time.Now().Add(defaultTimeout)) 392*cc02d7e2SAndroid Build Coastguard Worker 393*cc02d7e2SAndroid Build Coastguard Worker return conn, nil 394*cc02d7e2SAndroid Build Coastguard Worker} 395*cc02d7e2SAndroid Build Coastguard Worker 396*cc02d7e2SAndroid Build Coastguard Workerfunc buildTlsConfig(ctx *HTTP2InteropCtx) *tls.Config { 397*cc02d7e2SAndroid Build Coastguard Worker return &tls.Config{ 398*cc02d7e2SAndroid Build Coastguard Worker RootCAs: ctx.rootCAs, 399*cc02d7e2SAndroid Build Coastguard Worker NextProtos: []string{"h2"}, 400*cc02d7e2SAndroid Build Coastguard Worker ServerName: ctx.authority, 401*cc02d7e2SAndroid Build Coastguard Worker MinVersion: tls.VersionTLS12, 402*cc02d7e2SAndroid Build Coastguard Worker } 403*cc02d7e2SAndroid Build Coastguard Worker} 404*cc02d7e2SAndroid Build Coastguard Worker 405*cc02d7e2SAndroid Build Coastguard Workerfunc connectWithoutTls(ctx *HTTP2InteropCtx) (*CapConn, error) { 406*cc02d7e2SAndroid Build Coastguard Worker conn, err := net.DialTimeout("tcp", ctx.serverSpec, defaultTimeout) 407*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 408*cc02d7e2SAndroid Build Coastguard Worker return nil, err 409*cc02d7e2SAndroid Build Coastguard Worker } 410*cc02d7e2SAndroid Build Coastguard Worker return &CapConn{Conn: conn}, nil 411*cc02d7e2SAndroid Build Coastguard Worker} 412*cc02d7e2SAndroid Build Coastguard Worker 413*cc02d7e2SAndroid Build Coastguard Workerfunc connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*CapConn, error) { 414*cc02d7e2SAndroid Build Coastguard Worker conn, err := connectWithoutTls(ctx) 415*cc02d7e2SAndroid Build Coastguard Worker if err != nil { 416*cc02d7e2SAndroid Build Coastguard Worker return nil, err 417*cc02d7e2SAndroid Build Coastguard Worker } 418*cc02d7e2SAndroid Build Coastguard Worker 419*cc02d7e2SAndroid Build Coastguard Worker return &CapConn{Conn: tls.Client(conn, config)}, nil 420*cc02d7e2SAndroid Build Coastguard Worker} 421