func HttpHeaderFieldsTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("8.1.2", "HTTP Header Fields") tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains the header field name in uppercase letters", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("X-TEST", "test")) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestGroup(PseudoHeaderFieldsTestGroup(ctx)) tg.AddTestGroup(ConnectionSpecificHeaderFieldsTestGroup(ctx)) tg.AddTestGroup(RequestPseudoHeaderFieldsTestGroup(ctx)) tg.AddTestGroup(MalformedRequestsAndResponsesTestGroup(ctx)) return tg }
func FrameSizeTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("4.2", "Frame Size") tg.AddTestCase(NewTestCase( "Sends large size frame that exceeds the SETTINGS_MAX_FRAME_SIZE", "The endpoint MUST send a FRAME_SIZE_ERROR error.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) max_size, ok := http2Conn.Settings[http2.SettingMaxFrameSize] if !ok { max_size = 18384 } http2Conn.fr.WriteData(1, true, []byte(dummyData(int(max_size)+1))) actualCodes := []http2.ErrCode{http2.ErrCodeFrameSize} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func TestHTTPHeaderFields(ctx *Context) { PrintHeader("8.1.2. HTTP Header Fields", 1) func(ctx *Context) { desc := "Sends a HEADERS frame that contains the header field name in uppercase letters" msg := "the endpoint MUST respond with a stream error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("X-TEST", "test"), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: rf, ok := f.(*http2.RSTStreamFrame) if ok { if rf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 1) }(ctx) TestPseudoHeaderFields(ctx) TestConnectionSpecificHeaderFields(ctx) TestRequestPseudoHeaderFields(ctx) TestMalformedRequestsAndResponses(ctx) }
func RstStreamTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("6.4", "RST_STREAM") tg.AddTestCase(NewTestCase( "Sends a RST_STREAM frame with 0x0 stream identifier", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteRSTStream(0, http2.ErrCodeCancel) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a RST_STREAM frame on a idle stream", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteRSTStream(1, http2.ErrCodeCancel) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a RST_STREAM frame with a length other than 4 octets", "The endpoint MUST respond with a connection error of type FRAME_SIZE_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) // RST_STREAM Frame fmt.Fprintf(http2Conn.conn, "\x00\x00\x03\x03\x00\x00\x00\x00\x01") fmt.Fprintf(http2Conn.conn, "\x00\x00\x00") actualCodes := []http2.ErrCode{http2.ErrCodeFrameSize} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) return tg }
func TestPriority(ctx *Context) { PrintHeader("6.3. PRIORITY", 0) func(ctx *Context) { desc := "Sends a PRIORITY frame with 0x0 stream identifier" msg := "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) fmt.Fprintf(http2Conn.conn, "\x00\x00\x05\x02\x00\x00\x00\x00\x00") http2Conn.conn.Write(buf.Bytes()) fmt.Fprintf(http2Conn.conn, "\x80\x00\x00\x01\x0a") timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) PrintFooter() }
func TestMalformedRequestsAndResponses(ctx *Context) { PrintHeader("8.1.2.6. Malformed Requests and Responses", 2) // 8.1.2.6. ボディを構成する DATA フレームペイロードの長さの合計が "content-length" ヘッダーフィールドの値と等しくない場合、リクエストやレスポンスは不正な形式になります。 func(ctx *Context) { desc := "Sends a HEADERS frame that contains invalid \"content-length\" header field" msg := "the endpoint MUST respond with a stream error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "POST"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("content-length", "1"), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: rf, ok := f.(*http2.RSTStreamFrame) if ok { if rf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 2) }(ctx) }
func PriorityTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("6.3", "PRIORITY") tg.AddTestCase(NewTestCase( "Sends a PRIORITY frame with 0x0 stream identifier", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) // PRIORITY Frame fmt.Fprintf(http2Conn.conn, "\x00\x00\x05\x02\x00\x00\x00\x00\x00") fmt.Fprintf(http2Conn.conn, "\x80\x00\x00\x01\x0a") actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a PRIORITY frame with a length other than 5 octets", "The endpoint MUST respond with a stream error of type FRAME_SIZE_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) // PRIORITY Frame fmt.Fprintf(http2Conn.conn, "\x00\x00\x04\x02\x00\x00\x00\x00\x01") fmt.Fprintf(http2Conn.conn, "\x80\x00\x00\x01") actualCodes := []http2.ErrCode{http2.ErrCodeFrameSize} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func MalformedRequestsAndResponsesTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("8.1.2.6", "Malformed Requests and Responses") tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains the \"content-length\" header field which does not equal the sum of the DATA frame payload lengths", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("content-length", "1")) hdrs[0].Value = "POST" var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains the \"content-length\" header field which does not equal the sum of the multiple DATA frame payload lengths", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("content-length", "1")) hdrs[0].Value = "POST" var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, false, []byte("test")) http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func RequestPseudoHeaderFieldsTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("8.1.2.3", "Request Pseudo-Header Fields") tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that omits mandatory pseudo-header fields", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) tmp := hdrs[0:2] hdrs = append(tmp, hdrs[3]) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame containing more than one pseudo-header fields with the same name", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs1 := commonHeaderFields(ctx) hdrs2 := commonHeaderFields(ctx) hdrs := append(hdrs1, hdrs2...) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func ConnectionSpecificHeaderFieldsTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("8.1.2.2", "Connection-Specific Header Fields") tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains the connection-specific header field", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("connection", "keep-alive")) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains the TE header field that contain any value other than \"trailers\"", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("trailers", "test")) hdrs = append(hdrs, pair("te", "trailers, deflate")) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func StreamConcurrencyTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("5.1.2", "Stream Concurrency") tg.AddTestCase(NewTestCase( "Sends HEADERS frames that causes their advertised concurrent stream limit to be exceeded", "The endpoint MUST treat this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR or REFUSED_STREAM", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() // Skip this test when SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. _, ok := http2Conn.Settings[http2.SettingMaxConcurrentStreams] if !ok { actual = &ResultSkipped{"SETTINGS_MAX_CONCURRENT_STREAMS is unlimited."} return nil, actual } // Set INITIAL_WINDOW_SIZE to zero to prevent the peer from closing the stream settings := http2.Setting{http2.SettingInitialWindowSize, 0} http2Conn.fr.WriteSettings(settings) hdrs := commonHeaderFields(ctx) hbf := http2Conn.EncodeHeader(hdrs) var streamID uint32 = 1 for i := 0; i <= int(http2Conn.Settings[http2.SettingMaxConcurrentStreams]); i++ { var hp http2.HeadersFrameParam hp.StreamID = streamID hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = hbf http2Conn.fr.WriteHeaders(hp) streamID += 2 } actualCodes := []http2.ErrCode{ http2.ErrCodeProtocol, http2.ErrCodeRefusedStream, } return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func StreamDependenciesTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("5.3.1", "Stream Dependencies") tg.AddTestCase(NewTestCase( "Sends HEADERS frame that depend on itself", "The endpoint MUST treat this as a stream error of type PROTOCOL_ERROR", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var pp http2.PriorityParam pp.StreamDep = 3 pp.Exclusive = false pp.Weight = 255 var hp http2.HeadersFrameParam hp.StreamID = 3 hp.EndStream = true hp.EndHeaders = true hp.Priority = pp hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends PRIORITY frame that depend on itself", "The endpoint MUST treat this as a stream error of type PROTOCOL_ERROR", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var pp http2.PriorityParam pp.StreamDep = 2 pp.Exclusive = false pp.Weight = 255 http2Conn.fr.WritePriority(2, pp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func TestConnectionSpecificHeaderFields(ctx *Context) { PrintHeader("8.1.2.2. Connection-Specific Header Fields", 2) // 8.1.2.3. CONNECT リクエスト (8.3節) である場合を除き、":method"、":scheme"、そして ":path" 擬似ヘッダーフィールドに有効な値を1つ含まなければなりません (MUST)。これらの擬似ヘッダーフィールドが省略された HTTP リクエストは不正な形式 (8.1.2.6節) です。 // 8.1.2.6. ボディを構成する DATA フレームペイロードの長さの合計が "content-length" ヘッダーフィールドの値と等しくない場合、リクエストやレスポンスは不正な形式になります。 func(ctx *Context) { desc := "Sends a HEADERS frame that contains the connection-specific header field" msg := "the endpoint MUST respond with a stream error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("connection", "keep-alive"), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: rf, ok := f.(*http2.RSTStreamFrame) if ok { if rf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 2) }(ctx) func(ctx *Context) { desc := "Sends a HEADERS frame that contains the TE header field that contain any value other than \"trailers\"" msg := "the endpoint MUST respond with a stream error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("trailers", "test"), pair("te", "trailers, deflate"), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: rf, ok := f.(*http2.RSTStreamFrame) if ok { if rf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 2) }(ctx) }
func HeadersTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("6.2", "HEADERS") tg.AddTestCase(NewTestCase( "Sends a HEADERS frame followed by any frame other than CONTINUATION", "The endpoint MUST treat the receipt of any other type of frame as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = false hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame followed by a frame on a different stream", "The endpoint MUST treat the receipt of a frame on a different stream as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp1 http2.HeadersFrameParam hp1.StreamID = 1 hp1.EndStream = false hp1.EndHeaders = false hp1.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp1) var hp2 http2.HeadersFrameParam hp2.StreamID = 3 hp2.EndStream = true hp2.EndHeaders = true hp2.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp2) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame with 0x0 stream identifier", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 0 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame with invalid pad length", "The endpoint MUST treat this as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := commonHeaderFields(ctx) enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } fmt.Fprintf(http2Conn.conn, "\x00\x00\x0f\x01\x0c\x00\x00\x00\x01") http2Conn.conn.Write(buf.Bytes()) fmt.Fprintf(http2Conn.conn, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) return tg }
func TestHeaders(ctx *Context) { PrintHeader("6.2. HEADERS", 0) func(ctx *Context) { desc := "Sends a HEADERS frame followed by any frame other than CONTINUATION" msg := "The endpoint MUST treat the receipt of any other type of frame as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = false hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a HEADERS frame followed by a frame on a different stream" msg := "The endpoint MUST treat the receipt of a frame on a different stream as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp1 http2.HeadersFrameParam hp1.StreamID = 1 hp1.EndStream = false hp1.EndHeaders = false hp1.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp1) var hp2 http2.HeadersFrameParam hp2.StreamID = 3 hp2.EndStream = true hp2.EndHeaders = true hp2.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp2) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a HEADERS frame with 0x0 stream identifier" msg := "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 0 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a HEADERS frame with invalid pad length" msg := "The endpoint MUST treat this as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } fmt.Fprintf(http2Conn.conn, "\x00\x00\x0f\x01\x0c\x00\x00\x00\x01") http2Conn.conn.Write(buf.Bytes()) fmt.Fprintf(http2Conn.conn, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) PrintFooter() }
func StreamStatesTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("5.1", "Stream States") tg.AddTestCase(NewTestCase( "idle: Sends a DATA frame", "The endpoint MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "idle: Sends a RST_STREAM frame", "The endpoint MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteRSTStream(1, http2.ErrCodeCancel) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "idle: Sends a WINDOW_UPDATE frame", "The endpoint MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteWindowUpdate(1, 100) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "idle: Sends a CONTINUATION frame", "The endpoint MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) blockFragment := http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteContinuation(1, true, blockFragment) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "half closed (remote): Sends a DATA frame", "The endpoint MUST respond with a stream error (Section 5.4.2) of type STREAM_CLOSED.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = blockFragment http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeStreamClosed} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "half closed (remote): Sends a HEADERS frame", "The endpoint MUST respond with a stream error (Section 5.4.2) of type STREAM_CLOSED.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) blockFragment := http2Conn.EncodeHeader(hdrs) var hp1 http2.HeadersFrameParam hp1.StreamID = 1 hp1.EndStream = true hp1.EndHeaders = true hp1.BlockFragment = blockFragment http2Conn.fr.WriteHeaders(hp1) var hp2 http2.HeadersFrameParam hp2.StreamID = 1 hp2.EndStream = true hp2.EndHeaders = true hp2.BlockFragment = blockFragment http2Conn.fr.WriteHeaders(hp2) actualCodes := []http2.ErrCode{http2.ErrCodeStreamClosed} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "half closed (remote): Sends a CONTINUATION frame", "The endpoint MUST respond with a stream error (Section 5.4.2) of type STREAM_CLOSED.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, true, blockFragment[16384:]) actualCodes := []http2.ErrCode{http2.ErrCodeStreamClosed} return TestStreamError(ctx, http2Conn, actualCodes) }, )) if ctx.Strict { tg.AddTestCase(NewTestCase( "closed: Sends a DATA frame", "The endpoint MUST treat this as a stream error (Section 5.4.2) of type STREAM_CLOSED.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = blockFragment http2Conn.fr.WriteHeaders(hp) expected, actual = TestStreamClose(ctx, http2Conn) if !EvaluateResult(expected, actual) { return expected, actual } http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeStreamClosed} return TestStreamError(ctx, http2Conn, actualCodes) }, )) } if ctx.Strict { tg.AddTestCase(NewTestCase( "closed: Sends a HEADERS frame", "The endpoint MUST treat this as a stream error (Section 5.4.2) of type STREAM_CLOSED.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = blockFragment http2Conn.fr.WriteHeaders(hp) expected, actual = TestStreamClose(ctx, http2Conn) if !EvaluateResult(expected, actual) { return expected, actual } http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeStreamClosed} return TestStreamError(ctx, http2Conn, actualCodes) }, )) } tg.AddTestCase(NewTestCase( "closed: Sends a CONTINUATION frame", "The endpoint MUST treat this as a stream error (Section 5.4.2) of type STREAM_CLOSED.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, true, blockFragment[16384:]) expected, actual = TestStreamClose(ctx, http2Conn) if !EvaluateResult(expected, actual) { return expected, actual } http2Conn.fr.WriteContinuation(1, true, blockFragment[16384:]) actualCodes := []http2.ErrCode{http2.ErrCodeStreamClosed} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestGroup(StreamIdentifiersTestGroup(ctx)) tg.AddTestGroup(StreamConcurrencyTestGroup(ctx)) return tg }
func StreamIdentifiersTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("5.1.1", "Stream Identifiers") tg.AddTestCase(NewTestCase( "Sends even-numbered stream identifier", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 2 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) if ctx.Strict { tg.AddTestCase(NewTestCase( "Sends stream identifier that is numerically smaller than previous", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp1 http2.HeadersFrameParam hp1.StreamID = 5 hp1.EndStream = true hp1.EndHeaders = true hp1.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp1) var hp2 http2.HeadersFrameParam hp2.StreamID = 3 hp2.EndStream = true hp2.EndHeaders = true hp2.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp2) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) } return tg }
func HeaderCompressionAndDecompressionTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("4.3", "Header Compression and Decompression") tg.AddTestCase(NewTestCase( "Sends invalid header block fragment", "The endpoint MUST terminate the connection with a connection error of type COMPRESSION_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() // Literal Header Field with Incremental Indexing without Length and String segment fmt.Fprintf(http2Conn.conn, "\x00\x00\x01\x01\x05\x00\x00\x00\x01\x40") actualCodes := []http2.ErrCode{http2.ErrCodeCompression} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends Dynamic Table Size Update (RFC 7541, 6.3)", "The endpoint must accept Dynamic Table Size Update", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) // 2 Dynamic Table Size Updates, 0 and 4096. blockFragment := []byte{0x20, 0x3f, 0xe1, 0x1f} blockFragment = append(blockFragment, http2Conn.EncodeHeader(hdrs)...) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = blockFragment http2Conn.fr.WriteHeaders(hp) return TestStreamClose(ctx, http2Conn) }, )) tg.AddTestCase(NewTestCase( "Encodes Dynamic Table Size Update (RFC 7541, 6.3) after common header fields", "The endpoint MUST terminate the connection with a connection error of type COMPRESSION_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) blockFragment := http2Conn.EncodeHeader(hdrs) // append 2 Dynamic Table Size Updates, 0 and // 4096. this is illegal, since RFC 7541, // section 4.2 says that dynamic table size // update MUST occur at the beginning of the // first header block following the changes to // the dynamic table size. blockFragment = append(blockFragment, 0x20, 0x3f, 0xe1, 0x1f) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = blockFragment http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeCompression} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) return tg }
func TestStreamIdentifiers(ctx *Context) { PrintHeader("5.1.1. Stream Identifiers", 1) msg := "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR." func(ctx *Context) { desc := "Sends even-numbered stream identifier" result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 2 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 1) }(ctx) func(ctx *Context) { desc := "Sends stream identifier that is numerically smaller than previous" result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp1 http2.HeadersFrameParam hp1.StreamID = 5 hp1.EndStream = true hp1.EndHeaders = true hp1.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp1) var hp2 http2.HeadersFrameParam hp2.StreamID = 3 hp2.EndStream = true hp2.EndHeaders = true hp2.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp2) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 1) }(ctx) }
func WindowUpdateTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("6.9", "WINDOW_UPDATE") tg.AddTestCase(NewTestCase( "Sends a WINDOW_UPDATE frame", "The endpoint is expected to send the DATA frame based on the window size.", func(ctx *Context) (expected []Result, actual Result) { expected = []Result{ &ResultFrame{http2.FrameData, FlagDefault, ErrCodeDefault}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() settings := http2.Setting{http2.SettingInitialWindowSize, 1} http2Conn.fr.WriteSettings(settings) hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) winUpdated := false loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { actual = &ResultConnectionClose{} } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } switch f := f.(type) { case *http2.DataFrame: if winUpdated { if f.FrameHeader.Length > 10 { err := errors.New("The length of DATA frame is invalid.") actual = &ResultError{err} break loop } actual = &ResultFrame{f.Header().Type, FlagDefault, ErrCodeDefault} break loop } else { if f.FrameHeader.Length != 1 { err := errors.New("The length of DATA frame is invalid.") actual = &ResultError{err} break loop } http2Conn.fr.WriteWindowUpdate(1, 10) winUpdated = true } default: actual = &ResultFrame{f.Header().Type, FlagDefault, ErrCodeDefault} } } return expected, actual }, )) tg.AddTestCase(NewTestCase( "Sends a WINDOW_UPDATE frame with an flow control window increment of 0", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteWindowUpdate(0, 0) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a WINDOW_UPDATE frame with an flow control window increment of 0 on a stream", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteWindowUpdate(1, 0) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a WINDOW_UPDATE frame with a length other than a multiple of 4 octets", "The endpoint MUST respond with a connection error of type FRAME_SIZE_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() fmt.Fprintf(http2Conn.conn, "\x00\x00\x03\x08\x00\x00\x00\x00\x00") fmt.Fprintf(http2Conn.conn, "\x00\x00\x01") actualCodes := []http2.ErrCode{http2.ErrCodeFrameSize} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestGroup(TheFlowControlWindowTestGroup(ctx)) tg.AddTestGroup(InitialFlowControlWindowSizeTestGroup(ctx)) return tg }
func TestPseudoHeaderFields(ctx *Context) { PrintHeader("8.1.2.1. Pseudo-Header Fields", 2) func(ctx *Context) { desc := "Sends a HEADERS frame that contains the pseudo-header field defined for response" msg := "the endpoint MUST respond with a stream error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair(":status", "200"), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: rf, ok := f.(*http2.RSTStreamFrame) if ok { if rf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 2) }(ctx) func(ctx *Context) { desc := "Sends a HEADERS frame that contains the invalid pseudo-header field" msg := "the endpoint MUST respond with a stream error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair(":test", "test"), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: rf, ok := f.(*http2.RSTStreamFrame) if ok { if rf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 2) }(ctx) func(ctx *Context) { desc := "Sends a HEADERS frame that contains a pseudo-header field that appears in a header block after a regular header field" msg := "the endpoint MUST respond with a stream error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair("x-test", "test"), pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: rf, ok := f.(*http2.RSTStreamFrame) if ok { if rf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 2) }(ctx) }
func PseudoHeaderFieldsTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("8.1.2.1", "Pseudo-Header Fields") tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains the pseudo-header field defined for response", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair(":status", "200")) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains the invalid pseudo-header field", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair(":test", "test")) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame that contains a pseudo-header field that appears in a header block after a regular header field", "The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) tmp := []hpack.HeaderField{ pair("x-test", "test"), } hdrs = append(tmp, hdrs...) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func TheFlowControlWindowTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("6.9.1", "The Flow Control Window") tg.AddTestCase(NewTestCase( "Sends multiple WINDOW_UPDATE frames on a connection increasing the flow control window to above 2^31-1", "The endpoint MUST sends a GOAWAY frame with a FLOW_CONTROL_ERROR code.", func(ctx *Context) (expected []Result, actual Result) { expected = []Result{ &ResultFrame{http2.FrameGoAway, FlagDefault, http2.ErrCodeFlowControl}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteWindowUpdate(0, 2147483647) http2Conn.fr.WriteWindowUpdate(0, 2147483647) loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { actual = &ResultConnectionClose{} } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } switch f := f.(type) { case *http2.GoAwayFrame: actual = &ResultFrame{f.Header().Type, FlagDefault, f.ErrCode} if f.ErrCode == http2.ErrCodeFlowControl { break loop } default: actual = &ResultFrame{f.Header().Type, FlagDefault, ErrCodeDefault} } } return expected, actual }, )) tg.AddTestCase(NewTestCase( "Sends multiple WINDOW_UPDATE frames on a stream increasing the flow control window to above 2^31-1", "The endpoint MUST sends a RST_STREAM with the error code of FLOW_CONTROL_ERROR code.", func(ctx *Context) (expected []Result, actual Result) { expected = []Result{ &ResultFrame{http2.FrameRSTStream, FlagDefault, http2.ErrCodeFlowControl}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteWindowUpdate(1, 2147483647) http2Conn.fr.WriteWindowUpdate(1, 2147483647) loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { actual = &ResultConnectionClose{} } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } switch f := f.(type) { case *http2.RSTStreamFrame: actual = &ResultFrame{f.Header().Type, FlagDefault, f.ErrCode} if f.ErrCode == http2.ErrCodeFlowControl { break loop } default: actual = &ResultFrame{f.Header().Type, FlagDefault, ErrCodeDefault} } } return expected, actual }, )) return tg }
func HttpRequestResponseExchangeTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("8.1", "HTTP Request/Response Exchange") tg.AddTestCase(NewTestCase( "Sends a HEADERS frame as HEAD request", "The endpoint should respond with no DATA frame or empty DATA frame.", func(ctx *Context) (pass bool, expected []Result, actual Result) { pass = false expected = []Result{ &ResultFrame{LengthDefault, http2.FrameHeaders, http2.FlagHeadersEndStream, ErrCodeDefault}, &ResultFrame{0, http2.FrameData, http2.FlagDataEndStream, ErrCodeDefault}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs[0].Value = "HEAD" var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { rf, ok := actual.(*ResultFrame) if actual == nil || (ok && rf.Type != http2.FrameGoAway) { actual = &ResultConnectionClose{} } } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } switch f := f.(type) { case *http2.DataFrame: actual = CreateResultFrame(f) if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) && f.Header().Length == 0 { pass = true break loop } case *http2.HeadersFrame: actual = CreateResultFrame(f) if f.FrameHeader.Flags.Has(http2.FlagHeadersEndStream) { pass = true break loop } } actual = CreateResultFrame(f) } return pass, expected, actual }, )) tg.AddTestCase(NewTestCase( "Sends a HEADERS frame containing trailer part", "The endpoint should respond with HEADERS frame.", func(ctx *Context) (pass bool, expected []Result, actual Result) { pass = false expected = []Result{ &ResultFrame{LengthDefault, http2.FrameHeaders, http2.FlagHeadersEndStream, ErrCodeDefault}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs[0].Value = "POST" hdrs = append(hdrs, pair("content-length", "4")) hdrs = append(hdrs, pair("content-type", "text/plain")) hdrs = append(hdrs, pair("trailer", "x-test")) var hp1 http2.HeadersFrameParam hp1.StreamID = 1 hp1.EndStream = false hp1.EndHeaders = true hp1.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp1) http2Conn.fr.WriteData(1, false, []byte("test")) trailers := []hpack.HeaderField{ pair("x-test", "ok"), } var hp2 http2.HeadersFrameParam hp2.StreamID = 1 hp2.EndStream = true hp2.EndHeaders = true hp2.BlockFragment = http2Conn.EncodeHeader(trailers) http2Conn.fr.WriteHeaders(hp2) loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { rf, ok := actual.(*ResultFrame) if actual == nil || (ok && rf.Type != http2.FrameGoAway) { actual = &ResultConnectionClose{} } } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } switch f := f.(type) { case *http2.HeadersFrame: actual = CreateResultFrame(f) if f.FrameHeader.Flags.Has(http2.FlagHeadersEndHeaders) { pass = true break loop } } actual = CreateResultFrame(f) } return pass, expected, actual }, )) tg.AddTestGroup(HttpHeaderFieldsTestGroup(ctx)) return tg }
func TestWindowUpdate(ctx *Context) { PrintHeader("6.9. WINDOW_UPDATE", 0) func(ctx *Context) { desc := "Sends a WINDOW_UPDATE frame with an flow control window increment of 0" msg := "the endpoint MUST respond with a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteWindowUpdate(0, 0) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a WINDOW_UPDATE frame with an flow control window increment of 0 on a stream" msg := "the endpoint MUST respond with a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteWindowUpdate(1, 0) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) TestInitialFlowControlWindowSize(ctx) PrintFooter() }
func TestData(ctx *Context) { PrintHeader("6.1. DATA", 0) func(ctx *Context) { desc := "Sends a DATA frame with 0x0 stream identifier" msg := "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteData(0, true, []byte("test")) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a DATA frame on the stream that is not opend" msg := "The endpoint MUST respond with a stream error of type STREAM_CLOSED." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeStreamClosed { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) // bradfitz/http2 does not support padding of DATA frame. /* func(ctx *Context) { desc := "Sends a DATA frame with invalid pad length" msg := "The endpoint MUST treat this as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) */ PrintFooter() }
func TestContinuation(ctx *Context) { PrintHeader("6.10. CONTINUATION", 0) func(ctx *Context) { desc := "Sends a CONTINUATION frame" msg := "The endpoint must accept the frame." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("x-dummy1", GetDummyData(10000)), pair("x-dummy2", GetDummyData(10000)), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var blockFragment = buf.Bytes() var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, true, blockFragment[16384:]) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: _, ok := f.(*http2.HeadersFrame) if ok { result = true break loop } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends multiple CONTINUATION frames" msg := "The endpoint must accept the frames." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("x-dummy1", GetDummyData(10000)), pair("x-dummy2", GetDummyData(10000)), pair("x-dummy3", GetDummyData(10000)), pair("x-dummy4", GetDummyData(10000)), pair("x-dummy5", GetDummyData(10000)), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var blockFragment = buf.Bytes() var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteContinuation(1, true, blockFragment[32767:]) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: _, ok := f.(*http2.HeadersFrame) if ok { result = true break loop } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a CONTINUATION frame followed by any frame other than CONTINUATION" msg := "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("x-dummy1", GetDummyData(10000)), pair("x-dummy2", GetDummyData(10000)), pair("x-dummy3", GetDummyData(10000)), pair("x-dummy4", GetDummyData(10000)), pair("x-dummy5", GetDummyData(10000)), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var blockFragment = buf.Bytes() var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteData(1, true, []byte("test")) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a CONTINUATION frame followed by a frame on a different stream" msg := "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("x-dummy1", GetDummyData(10000)), pair("x-dummy2", GetDummyData(10000)), pair("x-dummy3", GetDummyData(10000)), pair("x-dummy4", GetDummyData(10000)), pair("x-dummy5", GetDummyData(10000)), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var blockFragment = buf.Bytes() var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteContinuation(3, true, blockFragment[32767:]) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a CONTINUATION frame with the stream identifier that is 0x0" msg := "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), pair("x-dummy1", GetDummyData(10000)), pair("x-dummy2", GetDummyData(10000)), pair("x-dummy3", GetDummyData(10000)), pair("x-dummy4", GetDummyData(10000)), pair("x-dummy5", GetDummyData(10000)), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var blockFragment = buf.Bytes() var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteContinuation(0, true, blockFragment[32767:]) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) func(ctx *Context) { desc := "Sends a CONTINUATION frame after the frame other than HEADERS, PUSH_PROMISE or CONTINUATION" msg := "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR." result := false http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() var buf bytes.Buffer hdrs := []hpack.HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", ctx.Authority()), } enc := hpack.NewEncoder(&buf) for _, hf := range hdrs { _ = enc.WriteField(hf) } var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = buf.Bytes() http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) http2Conn.fr.WriteContinuation(1, true, buf.Bytes()) timeCh := time.After(3 * time.Second) loop: for { select { case f := <-http2Conn.dataCh: gf, ok := f.(*http2.GoAwayFrame) if ok { if gf.ErrCode == http2.ErrCodeProtocol { result = true break loop } } case <-http2Conn.errCh: break loop case <-timeCh: break loop } } PrintResult(result, desc, msg, 0) }(ctx) PrintFooter() }
func ExtendingHttp2TestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("5.5", "Extending HTTP/2") tg.AddTestCase(NewTestCase( "Sends an unknown extension frame", "The endpoint MUST discard frames that have unknown or unsupported types", func(ctx *Context) (pass bool, expected []Result, actual Result) { pass = false expected = []Result{ &ResultFrame{LengthDefault, http2.FramePing, http2.FlagPingAck, ErrCodeDefault}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() // Write a frame of type 0xFF, which isn't yet defined // as an extension frame. This should be ignored; no GOAWAY, // RST_STREAM or closing the connection should occur http2Conn.fr.WriteRawFrame(0xFF, 0x00, 0, []byte("unknown")) // Now send a normal PING frame, and if this is processed // without error, then the preceeding unknown frame must have // been processed and ignored. data := [8]byte{'h', '2', 's', 'p', 'e', 'c'} http2Conn.fr.WritePing(false, data) loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { rf, ok := actual.(*ResultFrame) if actual == nil || (ok && rf.Type != http2.FrameGoAway) { actual = &ResultConnectionClose{} } } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } switch f := f.(type) { case *http2.PingFrame: actual = CreateResultFrame(f) if f.FrameHeader.Flags.Has(http2.FlagPingAck) { pass = true break loop } default: actual = CreateResultFrame(f) } } return pass, expected, actual }, )) tg.AddTestCase(NewTestCase( "Sends an unknown extension frame in the middle of a header block", "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteRawFrame(0xFF, 0x01, 0, []byte("unknown")) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) return tg }
func DataTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("6.1", "DATA") tg.AddTestCase(NewTestCase( "Sends a DATA frame with 0x0 stream identifier", "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() http2Conn.fr.WriteData(0, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a DATA frame on the stream that is not opend", "The endpoint MUST respond with a stream error of type STREAM_CLOSED.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs[0].Value = "POST" hdrs = append(hdrs, pair("content-type", "4")) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeStreamClosed} return TestStreamError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a DATA frame with invalid pad length", "The endpoint MUST treat this as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (pass bool, expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs[0].Value = "POST" hdrs = append(hdrs, pair("content-type", "4")) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) // Data length: 5, Pad length: 6 fmt.Fprintf(http2Conn.conn, "\x00\x00\x05\x00\x0b\x00\x00\x00\x01") fmt.Fprintf(http2Conn.conn, "\x06\x54\x65\x73\x74") actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestStreamError(ctx, http2Conn, actualCodes) }, )) return tg }
func ContinuationTestGroup(ctx *Context) *TestGroup { tg := NewTestGroup("6.10", "CONTINUATION") tg.AddTestCase(NewTestCase( "Sends a CONTINUATION frame", "The endpoint must accept the frame.", func(ctx *Context) (expected []Result, actual Result) { expected = []Result{ &ResultFrame{http2.FrameHeaders, FlagDefault, ErrCodeDefault}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, true, blockFragment[16384:]) loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { actual = &ResultConnectionClose{} } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } actual = &ResultFrame{f.Header().Type, FlagDefault, ErrCodeDefault} _, ok := f.(*http2.HeadersFrame) if ok { break loop } } return expected, actual }, )) tg.AddTestCase(NewTestCase( "Sends multiple CONTINUATION frames", "The endpoint must accept the frames.", func(ctx *Context) (expected []Result, actual Result) { expected = []Result{ &ResultFrame{http2.FrameHeaders, FlagDefault, ErrCodeDefault}, } http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy3", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy4", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy5", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteContinuation(1, true, blockFragment[32767:]) loop: for { f, err := http2Conn.ReadFrame(ctx.Timeout) if err != nil { opErr, ok := err.(*net.OpError) if err == io.EOF || (ok && opErr.Err == syscall.ECONNRESET) { actual = &ResultConnectionClose{} } else if err == TIMEOUT { if actual == nil { actual = &ResultTestTimeout{} } } else { actual = &ResultError{err} } break loop } actual = &ResultFrame{f.Header().Type, FlagDefault, ErrCodeDefault} _, ok := f.(*http2.HeadersFrame) if ok { break loop } } return expected, actual }, )) tg.AddTestCase(NewTestCase( "Sends a CONTINUATION frame followed by any frame other than CONTINUATION", "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy3", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy4", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy5", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteData(1, true, []byte("test")) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a CONTINUATION frame followed by a frame on a different stream", "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy3", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy4", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy5", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteContinuation(3, true, blockFragment[32767:]) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a CONTINUATION frame with the stream identifier that is 0x0", "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) hdrs = append(hdrs, pair("x-dummy1", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy2", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy3", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy4", dummyData(10000))) hdrs = append(hdrs, pair("x-dummy5", dummyData(10000))) blockFragment := http2Conn.EncodeHeader(hdrs) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = true hp.EndHeaders = false hp.BlockFragment = blockFragment[0:16384] http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteContinuation(1, false, blockFragment[16384:32767]) http2Conn.fr.WriteContinuation(0, true, blockFragment[32767:]) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) tg.AddTestCase(NewTestCase( "Sends a CONTINUATION frame after the frame other than HEADERS, PUSH_PROMISE or CONTINUATION", "The endpoint MUST treat as a connection error of type PROTOCOL_ERROR.", func(ctx *Context) (expected []Result, actual Result) { http2Conn := CreateHttp2Conn(ctx, true) defer http2Conn.conn.Close() hdrs := commonHeaderFields(ctx) var hp http2.HeadersFrameParam hp.StreamID = 1 hp.EndStream = false hp.EndHeaders = true hp.BlockFragment = http2Conn.EncodeHeader(hdrs) http2Conn.fr.WriteHeaders(hp) http2Conn.fr.WriteData(1, true, []byte("test")) http2Conn.fr.WriteContinuation(1, true, http2Conn.EncodeHeader(hdrs)) actualCodes := []http2.ErrCode{http2.ErrCodeProtocol} return TestConnectionError(ctx, http2Conn, actualCodes) }, )) return tg }