46
46
ts *httptest.Server
49
logFilter []string // substrings to filter out
50
scMu sync.Mutex // guards sc
48
serverLogBuf bytes.Buffer // logger for httptest.Server
49
logFilter []string // substrings to filter out
50
scMu sync.Mutex // guards sc
52
52
hpackDec *hpack.Decoder
53
53
decodedHeaders [][2]string
55
// If http2debug!=2, then we capture Frame debug logs that will be written
56
// to t.Log after a test fails. The read and write logs use separate locks
57
// and buffers so we don't accidentally introduce synchronization between
58
// the read and write goroutines, which may hide data races.
59
frameReadLogMu sync.Mutex
60
frameReadLogBuf bytes.Buffer
61
frameWriteLogMu sync.Mutex
62
frameWriteLogBuf bytes.Buffer
55
64
// writing headers:
56
65
headerBuf bytes.Buffer
57
66
hpackEnc *hpack.Encoder
75
84
func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester {
78
logBuf := new(bytes.Buffer)
79
87
ts := httptest.NewUnstartedServer(handler)
81
89
tlsConfig := &tls.Config{
82
90
InsecureSkipVerify: true,
83
// The h2-14 is temporary, until curl is updated. (as used by unit tests
85
NextProtos: []string{NextProtoTLS, "h2-14"},
91
NextProtos: []string{NextProtoTLS},
88
94
var onlyServer, quiet bool
95
h2server := new(Server)
89
96
for _, opt := range opts {
90
97
switch v := opt.(type) {
91
98
case func(*tls.Config):
93
100
case func(*httptest.Server):
95
104
case serverTesterOpt:
97
106
case optOnlyServer:
121
129
ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
123
ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, logBuf), "", log.LstdFlags)
131
ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, &st.serverLogBuf), "", log.LstdFlags)
143
151
st.fr = NewFramer(cc, cc)
152
if !logFrameReads && !logFrameWrites {
153
st.fr.debugReadLoggerf = func(m string, v ...interface{}) {
154
m = time.Now().Format("2006-01-02 15:04:05.999999999 ") + strings.TrimPrefix(m, "http2: ") + "\n"
155
st.frameReadLogMu.Lock()
156
fmt.Fprintf(&st.frameReadLogBuf, m, v...)
157
st.frameReadLogMu.Unlock()
159
st.fr.debugWriteLoggerf = func(m string, v ...interface{}) {
160
m = time.Now().Format("2006-01-02 15:04:05.999999999 ") + strings.TrimPrefix(m, "http2: ") + "\n"
161
st.frameWriteLogMu.Lock()
162
fmt.Fprintf(&st.frameWriteLogBuf, m, v...)
163
st.frameWriteLogMu.Unlock()
165
st.fr.logReads = true
166
st.fr.logWrites = true
201
225
func (st *serverTester) Close() {
202
226
if st.t.Failed() {
227
st.frameReadLogMu.Lock()
228
if st.frameReadLogBuf.Len() > 0 {
229
st.t.Logf("Framer read log:\n%s", st.frameReadLogBuf.String())
231
st.frameReadLogMu.Unlock()
233
st.frameWriteLogMu.Lock()
234
if st.frameWriteLogBuf.Len() > 0 {
235
st.t.Logf("Framer write log:\n%s", st.frameWriteLogBuf.String())
237
st.frameWriteLogMu.Unlock()
203
239
// If we failed already (and are likely in a Fatal,
204
240
// unwindowing), force close the connection, so the
205
241
// httptest.Server doesn't wait forever for the conn
292
func (st *serverTester) writePriority(id uint32, p PriorityParam) {
293
if err := st.fr.WritePriority(id, p); err != nil {
294
st.t.Fatalf("Error writing PRIORITY: %v", err)
256
298
func (st *serverTester) encodeHeaderField(k, v string) {
257
299
err := st.hpackEnc.WriteField(hpack.HeaderField{Name: k, Value: v})
278
320
// encodeHeader encodes headers and returns their HPACK bytes. headers
279
321
// must contain an even number of key/value pairs. There may be
280
322
// multiple pairs for keys (e.g. "cookie"). The :method, :path, and
281
// :scheme headers default to GET, / and https.
323
// :scheme headers default to GET, / and https. The :authority header
324
// defaults to st.ts.Listener.Addr().
282
325
func (st *serverTester) encodeHeader(headers ...string) []byte {
283
326
if len(headers)%2 == 1 {
284
327
panic("odd number of kv args")
287
330
st.headerBuf.Reset()
331
defaultAuthority := st.ts.Listener.Addr().String()
289
333
if len(headers) == 0 {
290
334
// Fast path, mostly for benchmarks, so test code doesn't pollute
291
335
// profiles when we're looking to improve server allocations.
292
336
st.encodeHeaderField(":method", "GET")
337
st.encodeHeaderField(":scheme", "https")
338
st.encodeHeaderField(":authority", defaultAuthority)
293
339
st.encodeHeaderField(":path", "/")
294
st.encodeHeaderField(":scheme", "https")
295
340
return st.headerBuf.Bytes()
298
343
if len(headers) == 2 && headers[0] == ":method" {
299
344
// Another fast path for benchmarks.
300
345
st.encodeHeaderField(":method", headers[1])
346
st.encodeHeaderField(":scheme", "https")
347
st.encodeHeaderField(":authority", defaultAuthority)
301
348
st.encodeHeaderField(":path", "/")
302
st.encodeHeaderField(":scheme", "https")
303
349
return st.headerBuf.Bytes()
306
352
pseudoCount := map[string]int{}
307
keys := []string{":method", ":path", ":scheme"}
353
keys := []string{":method", ":scheme", ":authority", ":path"}
308
354
vals := map[string][]string{
311
":scheme": {"https"},
356
":scheme": {"https"},
357
":authority": {defaultAuthority},
313
360
for len(headers) > 0 {
314
361
k, v := headers[0], headers[1]
503
550
if !sf.Header().Flags.Has(FlagSettingsAck) {
504
551
st.t.Fatal("Settings Frame didn't have ACK set")
555
func (st *serverTester) wantPushPromise() *PushPromiseFrame {
556
f, err := st.readFrame()
560
ppf, ok := f.(*PushPromiseFrame)
562
st.t.Fatalf("Wanted PushPromise, received %T", ppf)
509
567
func TestServer(t *testing.T) {
758
816
testServerRequest(t, func(st *serverTester) {
759
817
st.writeHeaders(HeadersFrameParam{
760
818
StreamID: 1, // clients send odd numbers
761
BlockFragment: st.encodeHeader("host", host),
819
BlockFragment: st.encodeHeader(":authority", "", "host", host),
763
821
EndHeaders: true,
946
1004
st.wantRSTStream(1, ErrCodeProtocol)
1007
func testRejectRequestWithProtocolError(t *testing.T, send func(*serverTester)) {
1008
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
1009
t.Error("server request made it to handler; should've been rejected")
1015
gf := st.wantGoAway()
1016
if gf.ErrCode != ErrCodeProtocol {
1017
t.Errorf("err code = %v; want %v", gf.ErrCode, ErrCodeProtocol)
1021
// Section 5.1, on idle connections: "Receiving any frame other than
1022
// HEADERS or PRIORITY on a stream in this state MUST be treated as a
1023
// connection error (Section 5.4.1) of type PROTOCOL_ERROR."
1024
func TestRejectFrameOnIdle_WindowUpdate(t *testing.T) {
1025
testRejectRequestWithProtocolError(t, func(st *serverTester) {
1026
st.fr.WriteWindowUpdate(123, 456)
1029
func TestRejectFrameOnIdle_Data(t *testing.T) {
1030
testRejectRequestWithProtocolError(t, func(st *serverTester) {
1031
st.fr.WriteData(123, true, nil)
1034
func TestRejectFrameOnIdle_RSTStream(t *testing.T) {
1035
testRejectRequestWithProtocolError(t, func(st *serverTester) {
1036
st.fr.WriteRSTStream(123, ErrCodeCancel)
949
1040
func TestServer_Request_Connect(t *testing.T) {
950
1041
testServerRequest(t, func(st *serverTester) {
951
1042
st.writeHeaders(HeadersFrameParam{
1044
1135
if gf.ErrCode != ErrCodeFrameSize {
1045
1136
t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFrameSize)
1047
if st.logBuf.Len() != 0 {
1138
if st.serverLogBuf.Len() != 0 {
1048
1139
// Previously we spun here for a bit until the GOAWAY disconnect
1049
1140
// timer fired, logging while we fired.
1050
t.Errorf("unexpected server output: %.500s\n", st.logBuf.Bytes())
1141
t.Errorf("unexpected server output: %.500s\n", st.serverLogBuf.Bytes())
1539
// No PRIORITY on stream 0.
1540
func TestServer_Rejects_Priority0(t *testing.T) {
1541
testServerRejectsConn(t, func(st *serverTester) {
1542
st.fr.AllowIllegalWrites = true
1543
st.writePriority(0, PriorityParam{StreamDep: 1})
1547
// No HEADERS frame with a self-dependence.
1548
func TestServer_Rejects_HeadersSelfDependence(t *testing.T) {
1549
testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
1550
st.fr.AllowIllegalWrites = true
1551
st.writeHeaders(HeadersFrameParam{
1553
BlockFragment: st.encodeHeader(),
1556
Priority: PriorityParam{StreamDep: 1},
1561
// No PRIORTY frame with a self-dependence.
1562
func TestServer_Rejects_PrioritySelfDependence(t *testing.T) {
1563
testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
1564
st.fr.AllowIllegalWrites = true
1565
st.writePriority(1, PriorityParam{StreamDep: 1})
1448
1569
func TestServer_Rejects_PushPromise(t *testing.T) {
1449
1570
testServerRejectsConn(t, func(st *serverTester) {
1450
1571
pp := PushPromiseParam{
2841
2962
const msg = "Hello, world"
2842
2963
st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
2964
// Consume the (empty) body from th peer before replying, otherwise
2965
// the server will sometimes (depending on scheduling) send the peer a
2966
// a RST_STREAM with the CANCEL error code.
2967
if n, err := io.Copy(ioutil.Discard, r.Body); n != 0 || err != nil {
2968
b.Errorf("Copy error; got %v, %v; want 0, nil", n, err)
2843
2970
io.WriteString(w, msg)
2845
2972
defer st.Close()
3237
3364
func TestCheckValidHTTP2Request(t *testing.T) {
3238
3365
tests := []struct {
3243
req: &http.Request{Header: http.Header{"Te": {"trailers"}}},
3370
h: http.Header{"Te": {"trailers"}},
3247
req: &http.Request{Header: http.Header{"Te": {"trailers", "bogus"}}},
3374
h: http.Header{"Te": {"trailers", "bogus"}},
3248
3375
want: errors.New(`request header "TE" may only be "trailers" in HTTP/2`),
3251
req: &http.Request{Header: http.Header{"Foo": {""}}},
3378
h: http.Header{"Foo": {""}},
3255
req: &http.Request{Header: http.Header{"Connection": {""}}},
3382
h: http.Header{"Connection": {""}},
3256
3383
want: errors.New(`request header "Connection" is not valid in HTTP/2`),
3259
req: &http.Request{Header: http.Header{"Proxy-Connection": {""}}},
3386
h: http.Header{"Proxy-Connection": {""}},
3260
3387
want: errors.New(`request header "Proxy-Connection" is not valid in HTTP/2`),
3263
req: &http.Request{Header: http.Header{"Keep-Alive": {""}}},
3390
h: http.Header{"Keep-Alive": {""}},
3264
3391
want: errors.New(`request header "Keep-Alive" is not valid in HTTP/2`),
3267
req: &http.Request{Header: http.Header{"Upgrade": {""}}},
3394
h: http.Header{"Upgrade": {""}},
3268
3395
want: errors.New(`request header "Upgrade" is not valid in HTTP/2`),
3271
3398
for i, tt := range tests {
3272
got := checkValidHTTP2Request(tt.req)
3399
got := checkValidHTTP2RequestHeaders(tt.h)
3273
3400
if !reflect.DeepEqual(got, tt.want) {
3274
3401
t.Errorf("%d. checkValidHTTP2Request = %v; want %v", i, got, tt.want)
3497
func TestServerIdleTimeout(t *testing.T) {
3498
if testing.Short() {
3499
t.Skip("skipping in short mode")
3502
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
3503
}, func(h2s *Server) {
3504
h2s.IdleTimeout = 500 * time.Millisecond
3509
ga := st.wantGoAway()
3510
if ga.ErrCode != ErrCodeNo {
3511
t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
3515
func TestServerIdleTimeout_AfterRequest(t *testing.T) {
3516
if testing.Short() {
3517
t.Skip("skipping in short mode")
3519
const timeout = 250 * time.Millisecond
3521
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
3522
time.Sleep(timeout * 2)
3523
}, func(h2s *Server) {
3524
h2s.IdleTimeout = timeout
3530
// Send a request which takes twice the timeout. Verifies the
3531
// idle timeout doesn't fire while we're in a request:
3535
// But the idle timeout should be rearmed after the request
3537
ga := st.wantGoAway()
3538
if ga.ErrCode != ErrCodeNo {
3539
t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
3543
// grpc-go closes the Request.Body currently with a Read.
3544
// Verify that it doesn't race.
3545
// See https://github.com/grpc/grpc-go/pull/938
3546
func TestRequestBodyReadCloseRace(t *testing.T) {
3547
for i := 0; i < 100; i++ {
3548
body := &requestBody{
3550
b: new(bytes.Buffer),
3553
body.pipe.CloseWithError(io.EOF)
3555
done := make(chan bool, 1)
3556
buf := make([]byte, 10)
3558
time.Sleep(1 * time.Millisecond)
3567
func TestServerGracefulShutdown(t *testing.T) {
3568
shutdownCh := make(chan struct{})
3569
defer func() { testh1ServerShutdownChan = nil }()
3570
testh1ServerShutdownChan = func(*http.Server) <-chan struct{} { return shutdownCh }
3572
var st *serverTester
3573
handlerDone := make(chan struct{})
3574
st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
3575
defer close(handlerDone)
3578
ga := st.wantGoAway()
3579
if ga.ErrCode != ErrCodeNo {
3580
t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
3582
if ga.LastStreamID != 1 {
3583
t.Errorf("GOAWAY LastStreamID = %v; want 1", ga.LastStreamID)
3586
w.Header().Set("x-foo", "bar")
3594
hf := st.wantHeaders()
3595
goth := st.decodeHeader(hf.HeaderBlockFragment())
3596
wanth := [][2]string{
3599
{"content-type", "text/plain; charset=utf-8"},
3600
{"content-length", "0"},
3602
if !reflect.DeepEqual(goth, wanth) {
3603
t.Errorf("Got headers %v; want %v", goth, wanth)
3606
n, err := st.cc.Read([]byte{0})
3607
if n != 0 || err == nil {
3608
t.Errorf("Read = %v, %v; want 0, non-nil", n, err)