xref: /aosp_15_r20/external/grpc-grpc/tools/http2_interop/http2interop.go (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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