Browse Source

Merge pull request #4639 from xiang90/grpc

*: update gRPC dependency
Xiang Li 9 years ago
parent
commit
7bd850a65c
84 changed files with 2271 additions and 18577 deletions
  1. 5 5
      Godeps/Godeps.json
  2. 0 575
      Godeps/_workspace/src/golang.org/x/net/context/context_test.go
  3. 0 176
      Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
  4. 0 26
      Godeps/_workspace/src/golang.org/x/net/context/withtimeout_test.go
  5. 33 1
      Godeps/_workspace/src/golang.org/x/net/http2/errors.go
  6. 0 24
      Godeps/_workspace/src/golang.org/x/net/http2/errors_test.go
  7. 0 128
      Godeps/_workspace/src/golang.org/x/net/http2/fixed_buffer_test.go
  8. 0 53
      Godeps/_workspace/src/golang.org/x/net/http2/flow_test.go
  9. 229 2
      Godeps/_workspace/src/golang.org/x/net/http2/frame.go
  10. 0 735
      Godeps/_workspace/src/golang.org/x/net/http2/frame_test.go
  11. 0 33
      Godeps/_workspace/src/golang.org/x/net/http2/gotrack_test.go
  12. 34 2
      Godeps/_workspace/src/golang.org/x/net/http2/h2demo/h2demo.go
  13. 1 1
      Godeps/_workspace/src/golang.org/x/net/http2/h2i/h2i.go
  14. 1 1
      Godeps/_workspace/src/golang.org/x/net/http2/hpack/encode.go
  15. 0 330
      Godeps/_workspace/src/golang.org/x/net/http2/hpack/encode_test.go
  16. 12 3
      Godeps/_workspace/src/golang.org/x/net/http2/hpack/hpack.go
  17. 0 813
      Godeps/_workspace/src/golang.org/x/net/http2/hpack/hpack_test.go
  18. 5 0
      Godeps/_workspace/src/golang.org/x/net/http2/http2.go
  19. 0 174
      Godeps/_workspace/src/golang.org/x/net/http2/http2_test.go
  20. 0 109
      Godeps/_workspace/src/golang.org/x/net/http2/pipe_test.go
  21. 0 118
      Godeps/_workspace/src/golang.org/x/net/http2/priority_test.go
  22. 172 229
      Godeps/_workspace/src/golang.org/x/net/http2/server.go
  23. 0 2940
      Godeps/_workspace/src/golang.org/x/net/http2/server_test.go
  24. 0 5021
      Godeps/_workspace/src/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml
  25. 183 230
      Godeps/_workspace/src/golang.org/x/net/http2/transport.go
  26. 0 1551
      Godeps/_workspace/src/golang.org/x/net/http2/transport_test.go
  27. 10 0
      Godeps/_workspace/src/golang.org/x/net/http2/write.go
  28. 0 356
      Godeps/_workspace/src/golang.org/x/net/http2/z_spec_test.go
  29. 0 170
      Godeps/_workspace/src/golang.org/x/net/internal/timeseries/timeseries_test.go
  30. 0 325
      Godeps/_workspace/src/golang.org/x/net/trace/histogram_test.go
  31. 0 46
      Godeps/_workspace/src/golang.org/x/net/trace/trace_test.go
  32. 0 1
      Godeps/_workspace/src/google.golang.org/grpc/.travis.yml
  33. 0 197
      Godeps/_workspace/src/google.golang.org/grpc/benchmark/benchmark_test.go
  34. 358 58
      Godeps/_workspace/src/google.golang.org/grpc/benchmark/grpc_testing/test.pb.go
  35. 1 1
      Godeps/_workspace/src/google.golang.org/grpc/benchmark/grpc_testing/test.proto
  36. 5 9
      Godeps/_workspace/src/google.golang.org/grpc/call.go
  37. 0 215
      Godeps/_workspace/src/google.golang.org/grpc/call_test.go
  38. 8 7
      Godeps/_workspace/src/google.golang.org/grpc/clientconn.go
  39. 0 82
      Godeps/_workspace/src/google.golang.org/grpc/clientconn_test.go
  40. 1 1
      Godeps/_workspace/src/google.golang.org/grpc/doc.go
  41. 38 10
      Godeps/_workspace/src/google.golang.org/grpc/examples/helloworld/helloworld/helloworld.pb.go
  42. 3 1
      Godeps/_workspace/src/google.golang.org/grpc/examples/helloworld/helloworld/helloworld.proto
  43. 68 21
      Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/routeguide/route_guide.pb.go
  44. 7 2
      Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/routeguide/route_guide.proto
  45. 0 15
      Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/ca.pem
  46. 0 601
      Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/route_guide_db.json
  47. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/server1.key
  48. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/server1.pem
  49. 4 1
      Godeps/_workspace/src/google.golang.org/grpc/grpclog/logger.go
  50. 41 12
      Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1/health.pb.go
  51. 1 1
      Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1/health.proto
  52. 1 1
      Godeps/_workspace/src/google.golang.org/grpc/health/health.go
  53. 0 15
      Godeps/_workspace/src/google.golang.org/grpc/interop/client/testdata/ca.pem
  54. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/interop/client/testdata/server1.key
  55. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/interop/client/testdata/server1.pem
  56. 96 31
      Godeps/_workspace/src/google.golang.org/grpc/interop/grpc_testing/test.pb.go
  57. 0 15
      Godeps/_workspace/src/google.golang.org/grpc/interop/server/testdata/ca.pem
  58. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/interop/server/testdata/server1.key
  59. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/interop/server/testdata/server1.pem
  60. 0 107
      Godeps/_workspace/src/google.golang.org/grpc/metadata/metadata_test.go
  61. 0 188
      Godeps/_workspace/src/google.golang.org/grpc/picker_test.go
  62. 28 24
      Godeps/_workspace/src/google.golang.org/grpc/rpc_util.go
  63. 0 217
      Godeps/_workspace/src/google.golang.org/grpc/rpc_util_test.go
  64. 235 89
      Godeps/_workspace/src/google.golang.org/grpc/server.go
  65. 23 17
      Godeps/_workspace/src/google.golang.org/grpc/stream.go
  66. 20 3
      Godeps/_workspace/src/google.golang.org/grpc/test/codec_perf/perf.pb.go
  67. 0 1226
      Godeps/_workspace/src/google.golang.org/grpc/test/end2end_test.go
  68. 96 31
      Godeps/_workspace/src/google.golang.org/grpc/test/grpc_testing/test.pb.go
  69. 0 15
      Godeps/_workspace/src/google.golang.org/grpc/test/testdata/ca.pem
  70. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/test/testdata/server1.key
  71. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/test/testdata/server1.pem
  72. 0 15
      Godeps/_workspace/src/google.golang.org/grpc/testdata/ca.pem
  73. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/testdata/server1.key
  74. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/testdata/server1.pem
  75. 377 0
      Godeps/_workspace/src/google.golang.org/grpc/transport/handler_server.go
  76. 45 50
      Godeps/_workspace/src/google.golang.org/grpc/transport/http2_client.go
  77. 34 50
      Godeps/_workspace/src/google.golang.org/grpc/transport/http2_server.go
  78. 56 104
      Godeps/_workspace/src/google.golang.org/grpc/transport/http_util.go
  79. 0 87
      Godeps/_workspace/src/google.golang.org/grpc/transport/http_util_test.go
  80. 0 15
      Godeps/_workspace/src/google.golang.org/grpc/transport/testdata/ca.pem
  81. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/transport/testdata/server1.key
  82. 0 16
      Godeps/_workspace/src/google.golang.org/grpc/transport/testdata/server1.pem
  83. 40 14
      Godeps/_workspace/src/google.golang.org/grpc/transport/transport.go
  84. 0 659
      Godeps/_workspace/src/google.golang.org/grpc/transport/transport_test.go

+ 5 - 5
Godeps/Godeps.json

@@ -175,19 +175,19 @@
 		},
 		{
 			"ImportPath": "golang.org/x/net/context",
-			"Rev": "04b9de9b512f58addf28c9853d50ebef61c3953e"
+			"Rev": "6acef71eb69611914f7a30939ea9f6e194c78172"
 		},
 		{
 			"ImportPath": "golang.org/x/net/http2",
-			"Rev": "04b9de9b512f58addf28c9853d50ebef61c3953e"
+			"Rev": "6acef71eb69611914f7a30939ea9f6e194c78172"
 		},
 		{
 			"ImportPath": "golang.org/x/net/internal/timeseries",
-			"Rev": "04b9de9b512f58addf28c9853d50ebef61c3953e"
+			"Rev": "6acef71eb69611914f7a30939ea9f6e194c78172"
 		},
 		{
 			"ImportPath": "golang.org/x/net/trace",
-			"Rev": "04b9de9b512f58addf28c9853d50ebef61c3953e"
+			"Rev": "6acef71eb69611914f7a30939ea9f6e194c78172"
 		},
 		{
 			"ImportPath": "golang.org/x/sys/unix",
@@ -195,7 +195,7 @@
 		},
 		{
 			"ImportPath": "google.golang.org/grpc",
-			"Rev": "e29d659177655e589850ba7d3d83f7ce12ef23dd"
+			"Rev": "b88c12e7caf74af3928de99a864aaa9916fa5aad"
 		}
 	]
 }

+ 0 - 575
Godeps/_workspace/src/golang.org/x/net/context/context_test.go

@@ -1,575 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package context
-
-import (
-	"fmt"
-	"math/rand"
-	"runtime"
-	"strings"
-	"sync"
-	"testing"
-	"time"
-)
-
-// otherContext is a Context that's not one of the types defined in context.go.
-// This lets us test code paths that differ based on the underlying type of the
-// Context.
-type otherContext struct {
-	Context
-}
-
-func TestBackground(t *testing.T) {
-	c := Background()
-	if c == nil {
-		t.Fatalf("Background returned nil")
-	}
-	select {
-	case x := <-c.Done():
-		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
-	default:
-	}
-	if got, want := fmt.Sprint(c), "context.Background"; got != want {
-		t.Errorf("Background().String() = %q want %q", got, want)
-	}
-}
-
-func TestTODO(t *testing.T) {
-	c := TODO()
-	if c == nil {
-		t.Fatalf("TODO returned nil")
-	}
-	select {
-	case x := <-c.Done():
-		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
-	default:
-	}
-	if got, want := fmt.Sprint(c), "context.TODO"; got != want {
-		t.Errorf("TODO().String() = %q want %q", got, want)
-	}
-}
-
-func TestWithCancel(t *testing.T) {
-	c1, cancel := WithCancel(Background())
-
-	if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
-		t.Errorf("c1.String() = %q want %q", got, want)
-	}
-
-	o := otherContext{c1}
-	c2, _ := WithCancel(o)
-	contexts := []Context{c1, o, c2}
-
-	for i, c := range contexts {
-		if d := c.Done(); d == nil {
-			t.Errorf("c[%d].Done() == %v want non-nil", i, d)
-		}
-		if e := c.Err(); e != nil {
-			t.Errorf("c[%d].Err() == %v want nil", i, e)
-		}
-
-		select {
-		case x := <-c.Done():
-			t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
-		default:
-		}
-	}
-
-	cancel()
-	time.Sleep(100 * time.Millisecond) // let cancelation propagate
-
-	for i, c := range contexts {
-		select {
-		case <-c.Done():
-		default:
-			t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
-		}
-		if e := c.Err(); e != Canceled {
-			t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
-		}
-	}
-}
-
-func TestParentFinishesChild(t *testing.T) {
-	// Context tree:
-	// parent -> cancelChild
-	// parent -> valueChild -> timerChild
-	parent, cancel := WithCancel(Background())
-	cancelChild, stop := WithCancel(parent)
-	defer stop()
-	valueChild := WithValue(parent, "key", "value")
-	timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
-	defer stop()
-
-	select {
-	case x := <-parent.Done():
-		t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
-	case x := <-cancelChild.Done():
-		t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
-	case x := <-timerChild.Done():
-		t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
-	case x := <-valueChild.Done():
-		t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
-	default:
-	}
-
-	// The parent's children should contain the two cancelable children.
-	pc := parent.(*cancelCtx)
-	cc := cancelChild.(*cancelCtx)
-	tc := timerChild.(*timerCtx)
-	pc.mu.Lock()
-	if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
-		t.Errorf("bad linkage: pc.children = %v, want %v and %v",
-			pc.children, cc, tc)
-	}
-	pc.mu.Unlock()
-
-	if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
-		t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
-	}
-	if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
-		t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
-	}
-
-	cancel()
-
-	pc.mu.Lock()
-	if len(pc.children) != 0 {
-		t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
-	}
-	pc.mu.Unlock()
-
-	// parent and children should all be finished.
-	check := func(ctx Context, name string) {
-		select {
-		case <-ctx.Done():
-		default:
-			t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
-		}
-		if e := ctx.Err(); e != Canceled {
-			t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
-		}
-	}
-	check(parent, "parent")
-	check(cancelChild, "cancelChild")
-	check(valueChild, "valueChild")
-	check(timerChild, "timerChild")
-
-	// WithCancel should return a canceled context on a canceled parent.
-	precanceledChild := WithValue(parent, "key", "value")
-	select {
-	case <-precanceledChild.Done():
-	default:
-		t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
-	}
-	if e := precanceledChild.Err(); e != Canceled {
-		t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
-	}
-}
-
-func TestChildFinishesFirst(t *testing.T) {
-	cancelable, stop := WithCancel(Background())
-	defer stop()
-	for _, parent := range []Context{Background(), cancelable} {
-		child, cancel := WithCancel(parent)
-
-		select {
-		case x := <-parent.Done():
-			t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
-		case x := <-child.Done():
-			t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
-		default:
-		}
-
-		cc := child.(*cancelCtx)
-		pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
-		if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
-			t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
-		}
-
-		if pcok {
-			pc.mu.Lock()
-			if len(pc.children) != 1 || !pc.children[cc] {
-				t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
-			}
-			pc.mu.Unlock()
-		}
-
-		cancel()
-
-		if pcok {
-			pc.mu.Lock()
-			if len(pc.children) != 0 {
-				t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
-			}
-			pc.mu.Unlock()
-		}
-
-		// child should be finished.
-		select {
-		case <-child.Done():
-		default:
-			t.Errorf("<-child.Done() blocked, but shouldn't have")
-		}
-		if e := child.Err(); e != Canceled {
-			t.Errorf("child.Err() == %v want %v", e, Canceled)
-		}
-
-		// parent should not be finished.
-		select {
-		case x := <-parent.Done():
-			t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
-		default:
-		}
-		if e := parent.Err(); e != nil {
-			t.Errorf("parent.Err() == %v want nil", e)
-		}
-	}
-}
-
-func testDeadline(c Context, wait time.Duration, t *testing.T) {
-	select {
-	case <-time.After(wait):
-		t.Fatalf("context should have timed out")
-	case <-c.Done():
-	}
-	if e := c.Err(); e != DeadlineExceeded {
-		t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded)
-	}
-}
-
-func TestDeadline(t *testing.T) {
-	c, _ := WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
-	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
-		t.Errorf("c.String() = %q want prefix %q", got, prefix)
-	}
-	testDeadline(c, 200*time.Millisecond, t)
-
-	c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
-	o := otherContext{c}
-	testDeadline(o, 200*time.Millisecond, t)
-
-	c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
-	o = otherContext{c}
-	c, _ = WithDeadline(o, time.Now().Add(300*time.Millisecond))
-	testDeadline(c, 200*time.Millisecond, t)
-}
-
-func TestTimeout(t *testing.T) {
-	c, _ := WithTimeout(Background(), 100*time.Millisecond)
-	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
-		t.Errorf("c.String() = %q want prefix %q", got, prefix)
-	}
-	testDeadline(c, 200*time.Millisecond, t)
-
-	c, _ = WithTimeout(Background(), 100*time.Millisecond)
-	o := otherContext{c}
-	testDeadline(o, 200*time.Millisecond, t)
-
-	c, _ = WithTimeout(Background(), 100*time.Millisecond)
-	o = otherContext{c}
-	c, _ = WithTimeout(o, 300*time.Millisecond)
-	testDeadline(c, 200*time.Millisecond, t)
-}
-
-func TestCanceledTimeout(t *testing.T) {
-	c, _ := WithTimeout(Background(), 200*time.Millisecond)
-	o := otherContext{c}
-	c, cancel := WithTimeout(o, 400*time.Millisecond)
-	cancel()
-	time.Sleep(100 * time.Millisecond) // let cancelation propagate
-	select {
-	case <-c.Done():
-	default:
-		t.Errorf("<-c.Done() blocked, but shouldn't have")
-	}
-	if e := c.Err(); e != Canceled {
-		t.Errorf("c.Err() == %v want %v", e, Canceled)
-	}
-}
-
-type key1 int
-type key2 int
-
-var k1 = key1(1)
-var k2 = key2(1) // same int as k1, different type
-var k3 = key2(3) // same type as k2, different int
-
-func TestValues(t *testing.T) {
-	check := func(c Context, nm, v1, v2, v3 string) {
-		if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
-			t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
-		}
-		if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
-			t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
-		}
-		if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
-			t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
-		}
-	}
-
-	c0 := Background()
-	check(c0, "c0", "", "", "")
-
-	c1 := WithValue(Background(), k1, "c1k1")
-	check(c1, "c1", "c1k1", "", "")
-
-	if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
-		t.Errorf("c.String() = %q want %q", got, want)
-	}
-
-	c2 := WithValue(c1, k2, "c2k2")
-	check(c2, "c2", "c1k1", "c2k2", "")
-
-	c3 := WithValue(c2, k3, "c3k3")
-	check(c3, "c2", "c1k1", "c2k2", "c3k3")
-
-	c4 := WithValue(c3, k1, nil)
-	check(c4, "c4", "", "c2k2", "c3k3")
-
-	o0 := otherContext{Background()}
-	check(o0, "o0", "", "", "")
-
-	o1 := otherContext{WithValue(Background(), k1, "c1k1")}
-	check(o1, "o1", "c1k1", "", "")
-
-	o2 := WithValue(o1, k2, "o2k2")
-	check(o2, "o2", "c1k1", "o2k2", "")
-
-	o3 := otherContext{c4}
-	check(o3, "o3", "", "c2k2", "c3k3")
-
-	o4 := WithValue(o3, k3, nil)
-	check(o4, "o4", "", "c2k2", "")
-}
-
-func TestAllocs(t *testing.T) {
-	bg := Background()
-	for _, test := range []struct {
-		desc       string
-		f          func()
-		limit      float64
-		gccgoLimit float64
-	}{
-		{
-			desc:       "Background()",
-			f:          func() { Background() },
-			limit:      0,
-			gccgoLimit: 0,
-		},
-		{
-			desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
-			f: func() {
-				c := WithValue(bg, k1, nil)
-				c.Value(k1)
-			},
-			limit:      3,
-			gccgoLimit: 3,
-		},
-		{
-			desc: "WithTimeout(bg, 15*time.Millisecond)",
-			f: func() {
-				c, _ := WithTimeout(bg, 15*time.Millisecond)
-				<-c.Done()
-			},
-			limit:      8,
-			gccgoLimit: 15,
-		},
-		{
-			desc: "WithCancel(bg)",
-			f: func() {
-				c, cancel := WithCancel(bg)
-				cancel()
-				<-c.Done()
-			},
-			limit:      5,
-			gccgoLimit: 8,
-		},
-		{
-			desc: "WithTimeout(bg, 100*time.Millisecond)",
-			f: func() {
-				c, cancel := WithTimeout(bg, 100*time.Millisecond)
-				cancel()
-				<-c.Done()
-			},
-			limit:      8,
-			gccgoLimit: 25,
-		},
-	} {
-		limit := test.limit
-		if runtime.Compiler == "gccgo" {
-			// gccgo does not yet do escape analysis.
-			// TOOD(iant): Remove this when gccgo does do escape analysis.
-			limit = test.gccgoLimit
-		}
-		if n := testing.AllocsPerRun(100, test.f); n > limit {
-			t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
-		}
-	}
-}
-
-func TestSimultaneousCancels(t *testing.T) {
-	root, cancel := WithCancel(Background())
-	m := map[Context]CancelFunc{root: cancel}
-	q := []Context{root}
-	// Create a tree of contexts.
-	for len(q) != 0 && len(m) < 100 {
-		parent := q[0]
-		q = q[1:]
-		for i := 0; i < 4; i++ {
-			ctx, cancel := WithCancel(parent)
-			m[ctx] = cancel
-			q = append(q, ctx)
-		}
-	}
-	// Start all the cancels in a random order.
-	var wg sync.WaitGroup
-	wg.Add(len(m))
-	for _, cancel := range m {
-		go func(cancel CancelFunc) {
-			cancel()
-			wg.Done()
-		}(cancel)
-	}
-	// Wait on all the contexts in a random order.
-	for ctx := range m {
-		select {
-		case <-ctx.Done():
-		case <-time.After(1 * time.Second):
-			buf := make([]byte, 10<<10)
-			n := runtime.Stack(buf, true)
-			t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
-		}
-	}
-	// Wait for all the cancel functions to return.
-	done := make(chan struct{})
-	go func() {
-		wg.Wait()
-		close(done)
-	}()
-	select {
-	case <-done:
-	case <-time.After(1 * time.Second):
-		buf := make([]byte, 10<<10)
-		n := runtime.Stack(buf, true)
-		t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
-	}
-}
-
-func TestInterlockedCancels(t *testing.T) {
-	parent, cancelParent := WithCancel(Background())
-	child, cancelChild := WithCancel(parent)
-	go func() {
-		parent.Done()
-		cancelChild()
-	}()
-	cancelParent()
-	select {
-	case <-child.Done():
-	case <-time.After(1 * time.Second):
-		buf := make([]byte, 10<<10)
-		n := runtime.Stack(buf, true)
-		t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
-	}
-}
-
-func TestLayersCancel(t *testing.T) {
-	testLayers(t, time.Now().UnixNano(), false)
-}
-
-func TestLayersTimeout(t *testing.T) {
-	testLayers(t, time.Now().UnixNano(), true)
-}
-
-func testLayers(t *testing.T, seed int64, testTimeout bool) {
-	rand.Seed(seed)
-	errorf := func(format string, a ...interface{}) {
-		t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
-	}
-	const (
-		timeout   = 200 * time.Millisecond
-		minLayers = 30
-	)
-	type value int
-	var (
-		vals      []*value
-		cancels   []CancelFunc
-		numTimers int
-		ctx       = Background()
-	)
-	for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
-		switch rand.Intn(3) {
-		case 0:
-			v := new(value)
-			ctx = WithValue(ctx, v, v)
-			vals = append(vals, v)
-		case 1:
-			var cancel CancelFunc
-			ctx, cancel = WithCancel(ctx)
-			cancels = append(cancels, cancel)
-		case 2:
-			var cancel CancelFunc
-			ctx, cancel = WithTimeout(ctx, timeout)
-			cancels = append(cancels, cancel)
-			numTimers++
-		}
-	}
-	checkValues := func(when string) {
-		for _, key := range vals {
-			if val := ctx.Value(key).(*value); key != val {
-				errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
-			}
-		}
-	}
-	select {
-	case <-ctx.Done():
-		errorf("ctx should not be canceled yet")
-	default:
-	}
-	if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
-		t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
-	}
-	t.Log(ctx)
-	checkValues("before cancel")
-	if testTimeout {
-		select {
-		case <-ctx.Done():
-		case <-time.After(timeout + 100*time.Millisecond):
-			errorf("ctx should have timed out")
-		}
-		checkValues("after timeout")
-	} else {
-		cancel := cancels[rand.Intn(len(cancels))]
-		cancel()
-		select {
-		case <-ctx.Done():
-		default:
-			errorf("ctx should be canceled")
-		}
-		checkValues("after cancel")
-	}
-}
-
-func TestCancelRemoves(t *testing.T) {
-	checkChildren := func(when string, ctx Context, want int) {
-		if got := len(ctx.(*cancelCtx).children); got != want {
-			t.Errorf("%s: context has %d children, want %d", when, got, want)
-		}
-	}
-
-	ctx, _ := WithCancel(Background())
-	checkChildren("after creation", ctx, 0)
-	_, cancel := WithCancel(ctx)
-	checkChildren("with WithCancel child ", ctx, 1)
-	cancel()
-	checkChildren("after cancelling WithCancel child", ctx, 0)
-
-	ctx, _ = WithCancel(Background())
-	checkChildren("after creation", ctx, 0)
-	_, cancel = WithTimeout(ctx, 60*time.Minute)
-	checkChildren("with WithTimeout child ", ctx, 1)
-	cancel()
-	checkChildren("after cancelling WithTimeout child", ctx, 0)
-}

+ 0 - 176
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp_test.go

@@ -1,176 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !plan9
-
-package ctxhttp
-
-import (
-	"io/ioutil"
-	"net"
-	"net/http"
-	"net/http/httptest"
-	"sync"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-)
-
-const (
-	requestDuration = 100 * time.Millisecond
-	requestBody     = "ok"
-)
-
-func TestNoTimeout(t *testing.T) {
-	ctx := context.Background()
-	resp, err := doRequest(ctx)
-
-	if resp == nil || err != nil {
-		t.Fatalf("error received from client: %v %v", err, resp)
-	}
-}
-
-func TestCancel(t *testing.T) {
-	ctx, cancel := context.WithCancel(context.Background())
-	go func() {
-		time.Sleep(requestDuration / 2)
-		cancel()
-	}()
-
-	resp, err := doRequest(ctx)
-
-	if resp != nil || err == nil {
-		t.Fatalf("expected error, didn't get one. resp: %v", resp)
-	}
-	if err != ctx.Err() {
-		t.Fatalf("expected error from context but got: %v", err)
-	}
-}
-
-func TestCancelAfterRequest(t *testing.T) {
-	ctx, cancel := context.WithCancel(context.Background())
-
-	resp, err := doRequest(ctx)
-
-	// Cancel before reading the body.
-	// Request.Body should still be readable after the context is canceled.
-	cancel()
-
-	b, err := ioutil.ReadAll(resp.Body)
-	if err != nil || string(b) != requestBody {
-		t.Fatalf("could not read body: %q %v", b, err)
-	}
-}
-
-func TestCancelAfterHangingRequest(t *testing.T) {
-	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		w.WriteHeader(http.StatusOK)
-		w.(http.Flusher).Flush()
-		<-w.(http.CloseNotifier).CloseNotify()
-	})
-
-	serv := httptest.NewServer(handler)
-	defer serv.Close()
-
-	ctx, cancel := context.WithCancel(context.Background())
-	resp, err := Get(ctx, nil, serv.URL)
-	if err != nil {
-		t.Fatalf("unexpected error in Get: %v", err)
-	}
-
-	// Cancel befer reading the body.
-	// Reading Request.Body should fail, since the request was
-	// canceled before anything was written.
-	cancel()
-
-	done := make(chan struct{})
-
-	go func() {
-		b, err := ioutil.ReadAll(resp.Body)
-		if len(b) != 0 || err == nil {
-			t.Errorf(`Read got (%q, %v); want ("", error)`, b, err)
-		}
-		close(done)
-	}()
-
-	select {
-	case <-time.After(1 * time.Second):
-		t.Errorf("Test timed out")
-	case <-done:
-	}
-}
-
-func doRequest(ctx context.Context) (*http.Response, error) {
-	var okHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		time.Sleep(requestDuration)
-		w.Write([]byte(requestBody))
-	})
-
-	serv := httptest.NewServer(okHandler)
-	defer serv.Close()
-
-	return Get(ctx, nil, serv.URL)
-}
-
-// golang.org/issue/14065
-func TestClosesResponseBodyOnCancel(t *testing.T) {
-	defer func() { testHookContextDoneBeforeHeaders = nop }()
-	defer func() { testHookDoReturned = nop }()
-	defer func() { testHookDidBodyClose = nop }()
-
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
-	defer ts.Close()
-
-	ctx, cancel := context.WithCancel(context.Background())
-
-	// closed when Do enters select case <-ctx.Done()
-	enteredDonePath := make(chan struct{})
-
-	testHookContextDoneBeforeHeaders = func() {
-		close(enteredDonePath)
-	}
-
-	testHookDoReturned = func() {
-		// We now have the result (the Flush'd headers) at least,
-		// so we can cancel the request.
-		cancel()
-
-		// But block the client.Do goroutine from sending
-		// until Do enters into the <-ctx.Done() path, since
-		// otherwise if both channels are readable, select
-		// picks a random one.
-		<-enteredDonePath
-	}
-
-	sawBodyClose := make(chan struct{})
-	testHookDidBodyClose = func() { close(sawBodyClose) }
-
-	tr := &http.Transport{}
-	defer tr.CloseIdleConnections()
-	c := &http.Client{Transport: tr}
-	req, _ := http.NewRequest("GET", ts.URL, nil)
-	_, doErr := Do(ctx, c, req)
-
-	select {
-	case <-sawBodyClose:
-	case <-time.After(5 * time.Second):
-		t.Fatal("timeout waiting for body to close")
-	}
-
-	if doErr != ctx.Err() {
-		t.Errorf("Do error = %v; want %v", doErr, ctx.Err())
-	}
-}
-
-type noteCloseConn struct {
-	net.Conn
-	onceClose sync.Once
-	closefn   func()
-}
-
-func (c *noteCloseConn) Close() error {
-	c.onceClose.Do(c.closefn)
-	return c.Conn.Close()
-}

+ 0 - 26
Godeps/_workspace/src/golang.org/x/net/context/withtimeout_test.go

@@ -1,26 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package context_test
-
-import (
-	"fmt"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-)
-
-func ExampleWithTimeout() {
-	// Pass a context with a timeout to tell a blocking function that it
-	// should abandon its work after the timeout elapses.
-	ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond)
-	select {
-	case <-time.After(200 * time.Millisecond):
-		fmt.Println("overslept")
-	case <-ctx.Done():
-		fmt.Println(ctx.Err()) // prints "context deadline exceeded"
-	}
-	// Output:
-	// context deadline exceeded
-}

+ 33 - 1
Godeps/_workspace/src/golang.org/x/net/http2/errors.go

@@ -4,7 +4,10 @@
 
 package http2
 
-import "fmt"
+import (
+	"errors"
+	"fmt"
+)
 
 // An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
 type ErrCode uint32
@@ -88,3 +91,32 @@ type connError struct {
 func (e connError) Error() string {
 	return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
 }
+
+type pseudoHeaderError string
+
+func (e pseudoHeaderError) Error() string {
+	return fmt.Sprintf("invalid pseudo-header %q", string(e))
+}
+
+type duplicatePseudoHeaderError string
+
+func (e duplicatePseudoHeaderError) Error() string {
+	return fmt.Sprintf("duplicate pseudo-header %q", string(e))
+}
+
+type headerFieldNameError string
+
+func (e headerFieldNameError) Error() string {
+	return fmt.Sprintf("invalid header field name %q", string(e))
+}
+
+type headerFieldValueError string
+
+func (e headerFieldValueError) Error() string {
+	return fmt.Sprintf("invalid header field value %q", string(e))
+}
+
+var (
+	errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
+	errPseudoAfterRegular   = errors.New("pseudo header field after regular")
+)

+ 0 - 24
Godeps/_workspace/src/golang.org/x/net/http2/errors_test.go

@@ -1,24 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import "testing"
-
-func TestErrCodeString(t *testing.T) {
-	tests := []struct {
-		err  ErrCode
-		want string
-	}{
-		{ErrCodeProtocol, "PROTOCOL_ERROR"},
-		{0xd, "HTTP_1_1_REQUIRED"},
-		{0xf, "unknown error code 0xf"},
-	}
-	for i, tt := range tests {
-		got := tt.err.String()
-		if got != tt.want {
-			t.Errorf("%d. Error = %q; want %q", i, got, tt.want)
-		}
-	}
-}

+ 0 - 128
Godeps/_workspace/src/golang.org/x/net/http2/fixed_buffer_test.go

@@ -1,128 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"reflect"
-	"testing"
-)
-
-var bufferReadTests = []struct {
-	buf      fixedBuffer
-	read, wn int
-	werr     error
-	wp       []byte
-	wbuf     fixedBuffer
-}{
-	{
-		fixedBuffer{[]byte{'a', 0}, 0, 1},
-		5, 1, nil, []byte{'a'},
-		fixedBuffer{[]byte{'a', 0}, 0, 0},
-	},
-	{
-		fixedBuffer{[]byte{0, 'a'}, 1, 2},
-		5, 1, nil, []byte{'a'},
-		fixedBuffer{[]byte{0, 'a'}, 0, 0},
-	},
-	{
-		fixedBuffer{[]byte{'a', 'b'}, 0, 2},
-		1, 1, nil, []byte{'a'},
-		fixedBuffer{[]byte{'a', 'b'}, 1, 2},
-	},
-	{
-		fixedBuffer{[]byte{}, 0, 0},
-		5, 0, errReadEmpty, []byte{},
-		fixedBuffer{[]byte{}, 0, 0},
-	},
-}
-
-func TestBufferRead(t *testing.T) {
-	for i, tt := range bufferReadTests {
-		read := make([]byte, tt.read)
-		n, err := tt.buf.Read(read)
-		if n != tt.wn {
-			t.Errorf("#%d: wn = %d want %d", i, n, tt.wn)
-			continue
-		}
-		if err != tt.werr {
-			t.Errorf("#%d: werr = %v want %v", i, err, tt.werr)
-			continue
-		}
-		read = read[:n]
-		if !reflect.DeepEqual(read, tt.wp) {
-			t.Errorf("#%d: read = %+v want %+v", i, read, tt.wp)
-		}
-		if !reflect.DeepEqual(tt.buf, tt.wbuf) {
-			t.Errorf("#%d: buf = %+v want %+v", i, tt.buf, tt.wbuf)
-		}
-	}
-}
-
-var bufferWriteTests = []struct {
-	buf       fixedBuffer
-	write, wn int
-	werr      error
-	wbuf      fixedBuffer
-}{
-	{
-		buf: fixedBuffer{
-			buf: []byte{},
-		},
-		wbuf: fixedBuffer{
-			buf: []byte{},
-		},
-	},
-	{
-		buf: fixedBuffer{
-			buf: []byte{1, 'a'},
-		},
-		write: 1,
-		wn:    1,
-		wbuf: fixedBuffer{
-			buf: []byte{0, 'a'},
-			w:   1,
-		},
-	},
-	{
-		buf: fixedBuffer{
-			buf: []byte{'a', 1},
-			r:   1,
-			w:   1,
-		},
-		write: 2,
-		wn:    2,
-		wbuf: fixedBuffer{
-			buf: []byte{0, 0},
-			w:   2,
-		},
-	},
-	{
-		buf: fixedBuffer{
-			buf: []byte{},
-		},
-		write: 5,
-		werr:  errWriteFull,
-		wbuf: fixedBuffer{
-			buf: []byte{},
-		},
-	},
-}
-
-func TestBufferWrite(t *testing.T) {
-	for i, tt := range bufferWriteTests {
-		n, err := tt.buf.Write(make([]byte, tt.write))
-		if n != tt.wn {
-			t.Errorf("#%d: wrote %d bytes; want %d", i, n, tt.wn)
-			continue
-		}
-		if err != tt.werr {
-			t.Errorf("#%d: error = %v; want %v", i, err, tt.werr)
-			continue
-		}
-		if !reflect.DeepEqual(tt.buf, tt.wbuf) {
-			t.Errorf("#%d: buf = %+v; want %+v", i, tt.buf, tt.wbuf)
-		}
-	}
-}

+ 0 - 53
Godeps/_workspace/src/golang.org/x/net/http2/flow_test.go

@@ -1,53 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import "testing"
-
-func TestFlow(t *testing.T) {
-	var st flow
-	var conn flow
-	st.add(3)
-	conn.add(2)
-
-	if got, want := st.available(), int32(3); got != want {
-		t.Errorf("available = %d; want %d", got, want)
-	}
-	st.setConnFlow(&conn)
-	if got, want := st.available(), int32(2); got != want {
-		t.Errorf("after parent setup, available = %d; want %d", got, want)
-	}
-
-	st.take(2)
-	if got, want := conn.available(), int32(0); got != want {
-		t.Errorf("after taking 2, conn = %d; want %d", got, want)
-	}
-	if got, want := st.available(), int32(0); got != want {
-		t.Errorf("after taking 2, stream = %d; want %d", got, want)
-	}
-}
-
-func TestFlowAdd(t *testing.T) {
-	var f flow
-	if !f.add(1) {
-		t.Fatal("failed to add 1")
-	}
-	if !f.add(-1) {
-		t.Fatal("failed to add -1")
-	}
-	if got, want := f.available(), int32(0); got != want {
-		t.Fatalf("size = %d; want %d", got, want)
-	}
-	if !f.add(1<<31 - 1) {
-		t.Fatal("failed to add 2^31-1")
-	}
-	if got, want := f.available(), int32(1<<31-1); got != want {
-		t.Fatalf("size = %d; want %d", got, want)
-	}
-	if f.add(1) {
-		t.Fatal("adding 1 to max shouldn't be allowed")
-	}
-
-}

+ 229 - 2
Godeps/_workspace/src/golang.org/x/net/http2/frame.go

@@ -11,7 +11,10 @@ import (
 	"fmt"
 	"io"
 	"log"
+	"strings"
 	"sync"
+
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2/hpack"
 )
 
 const frameHeaderLen = 9
@@ -261,7 +264,7 @@ type Frame interface {
 type Framer struct {
 	r         io.Reader
 	lastFrame Frame
-	errReason string
+	errDetail error
 
 	// lastHeaderStream is non-zero if the last frame was an
 	// unfinished HEADERS/CONTINUATION.
@@ -293,8 +296,20 @@ type Framer struct {
 	// to return non-compliant frames or frame orders.
 	// This is for testing and permits using the Framer to test
 	// other HTTP/2 implementations' conformance to the spec.
+	// It is not compatible with ReadMetaHeaders.
 	AllowIllegalReads bool
 
+	// ReadMetaHeaders if non-nil causes ReadFrame to merge
+	// HEADERS and CONTINUATION frames together and return
+	// MetaHeadersFrame instead.
+	ReadMetaHeaders *hpack.Decoder
+
+	// MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
+	// It's used only if ReadMetaHeaders is set; 0 means a sane default
+	// (currently 16MB)
+	// If the limit is hit, MetaHeadersFrame.Truncated is set true.
+	MaxHeaderListSize uint32
+
 	// TODO: track which type of frame & with which flags was sent
 	// last.  Then return an error (unless AllowIllegalWrites) if
 	// we're in the middle of a header block and a
@@ -307,6 +322,13 @@ type Framer struct {
 	debugFramerBuf *bytes.Buffer
 }
 
+func (fr *Framer) maxHeaderListSize() uint32 {
+	if fr.MaxHeaderListSize == 0 {
+		return 16 << 20 // sane default, per docs
+	}
+	return fr.MaxHeaderListSize
+}
+
 func (f *Framer) startWrite(ftype FrameType, flags Flags, streamID uint32) {
 	// Write the FrameHeader.
 	f.wbuf = append(f.wbuf[:0],
@@ -402,6 +424,17 @@ func (fr *Framer) SetMaxReadFrameSize(v uint32) {
 	fr.maxReadSize = v
 }
 
+// ErrorDetail returns a more detailed error of the last error
+// returned by Framer.ReadFrame. For instance, if ReadFrame
+// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
+// will say exactly what was invalid. ErrorDetail is not guaranteed
+// to return a non-nil value and like the rest of the http2 package,
+// its return value is not protected by an API compatibility promise.
+// ErrorDetail is reset after the next call to ReadFrame.
+func (fr *Framer) ErrorDetail() error {
+	return fr.errDetail
+}
+
 // ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
 // sends a frame that is larger than declared with SetMaxReadFrameSize.
 var ErrFrameTooLarge = errors.New("http2: frame too large")
@@ -423,6 +456,7 @@ func terminalReadFrameError(err error) bool {
 // ConnectionError, StreamError, or anything else from from the underlying
 // reader.
 func (fr *Framer) ReadFrame() (Frame, error) {
+	fr.errDetail = nil
 	if fr.lastFrame != nil {
 		fr.lastFrame.invalidate()
 	}
@@ -450,6 +484,9 @@ func (fr *Framer) ReadFrame() (Frame, error) {
 	if fr.logReads {
 		log.Printf("http2: Framer %p: read %v", fr, summarizeFrame(f))
 	}
+	if fh.Type == FrameHeaders && fr.ReadMetaHeaders != nil {
+		return fr.readMetaFrame(f.(*HeadersFrame))
+	}
 	return f, nil
 }
 
@@ -458,7 +495,7 @@ func (fr *Framer) ReadFrame() (Frame, error) {
 // to the peer before hanging up on them. This might help others debug
 // their implementations.
 func (fr *Framer) connError(code ErrCode, reason string) error {
-	fr.errReason = reason
+	fr.errDetail = errors.New(reason)
 	return ConnectionError(code)
 }
 
@@ -1225,6 +1262,196 @@ type headersEnder interface {
 	HeadersEnded() bool
 }
 
+type headersOrContinuation interface {
+	headersEnder
+	HeaderBlockFragment() []byte
+}
+
+// A MetaHeadersFrame is the representation of one HEADERS frame and
+// zero or more contiguous CONTINUATION frames and the decoding of
+// their HPACK-encoded contents.
+//
+// This type of frame does not appear on the wire and is only returned
+// by the Framer when Framer.ReadMetaHeaders is set.
+type MetaHeadersFrame struct {
+	*HeadersFrame
+
+	// Fields are the fields contained in the HEADERS and
+	// CONTINUATION frames. The underlying slice is owned by the
+	// Framer and must not be retained after the next call to
+	// ReadFrame.
+	//
+	// Fields are guaranteed to be in the correct http2 order and
+	// not have unknown pseudo header fields or invalid header
+	// field names or values. Required pseudo header fields may be
+	// missing, however. Use the MetaHeadersFrame.Pseudo accessor
+	// method access pseudo headers.
+	Fields []hpack.HeaderField
+
+	// Truncated is whether the max header list size limit was hit
+	// and Fields is incomplete. The hpack decoder state is still
+	// valid, however.
+	Truncated bool
+}
+
+// PseudoValue returns the given pseudo header field's value.
+// The provided pseudo field should not contain the leading colon.
+func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string {
+	for _, hf := range mh.Fields {
+		if !hf.IsPseudo() {
+			return ""
+		}
+		if hf.Name[1:] == pseudo {
+			return hf.Value
+		}
+	}
+	return ""
+}
+
+// RegularFields returns the regular (non-pseudo) header fields of mh.
+// The caller does not own the returned slice.
+func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField {
+	for i, hf := range mh.Fields {
+		if !hf.IsPseudo() {
+			return mh.Fields[i:]
+		}
+	}
+	return nil
+}
+
+// PseudoFields returns the pseudo header fields of mh.
+// The caller does not own the returned slice.
+func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
+	for i, hf := range mh.Fields {
+		if !hf.IsPseudo() {
+			return mh.Fields[:i]
+		}
+	}
+	return mh.Fields
+}
+
+func (mh *MetaHeadersFrame) checkPseudos() error {
+	var isRequest, isResponse bool
+	pf := mh.PseudoFields()
+	for i, hf := range pf {
+		switch hf.Name {
+		case ":method", ":path", ":scheme", ":authority":
+			isRequest = true
+		case ":status":
+			isResponse = true
+		default:
+			return pseudoHeaderError(hf.Name)
+		}
+		// Check for duplicates.
+		// This would be a bad algorithm, but N is 4.
+		// And this doesn't allocate.
+		for _, hf2 := range pf[:i] {
+			if hf.Name == hf2.Name {
+				return duplicatePseudoHeaderError(hf.Name)
+			}
+		}
+	}
+	if isRequest && isResponse {
+		return errMixPseudoHeaderTypes
+	}
+	return nil
+}
+
+func (fr *Framer) maxHeaderStringLen() int {
+	v := fr.maxHeaderListSize()
+	if uint32(int(v)) == v {
+		return int(v)
+	}
+	// They had a crazy big number for MaxHeaderBytes anyway,
+	// so give them unlimited header lengths:
+	return 0
+}
+
+// readMetaFrame returns 0 or more CONTINUATION frames from fr and
+// merge them into into the provided hf and returns a MetaHeadersFrame
+// with the decoded hpack values.
+func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
+	if fr.AllowIllegalReads {
+		return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
+	}
+	mh := &MetaHeadersFrame{
+		HeadersFrame: hf,
+	}
+	var remainSize = fr.maxHeaderListSize()
+	var sawRegular bool
+
+	var invalid error // pseudo header field errors
+	hdec := fr.ReadMetaHeaders
+	hdec.SetEmitEnabled(true)
+	hdec.SetMaxStringLength(fr.maxHeaderStringLen())
+	hdec.SetEmitFunc(func(hf hpack.HeaderField) {
+		if !validHeaderFieldValue(hf.Value) {
+			invalid = headerFieldValueError(hf.Value)
+		}
+		isPseudo := strings.HasPrefix(hf.Name, ":")
+		if isPseudo {
+			if sawRegular {
+				invalid = errPseudoAfterRegular
+			}
+		} else {
+			sawRegular = true
+			if !validHeaderFieldName(hf.Name) {
+				invalid = headerFieldNameError(hf.Name)
+			}
+		}
+
+		if invalid != nil {
+			hdec.SetEmitEnabled(false)
+			return
+		}
+
+		size := hf.Size()
+		if size > remainSize {
+			hdec.SetEmitEnabled(false)
+			mh.Truncated = true
+			return
+		}
+		remainSize -= size
+
+		mh.Fields = append(mh.Fields, hf)
+	})
+	// Lose reference to MetaHeadersFrame:
+	defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
+
+	var hc headersOrContinuation = hf
+	for {
+		frag := hc.HeaderBlockFragment()
+		if _, err := hdec.Write(frag); err != nil {
+			return nil, ConnectionError(ErrCodeCompression)
+		}
+
+		if hc.HeadersEnded() {
+			break
+		}
+		if f, err := fr.ReadFrame(); err != nil {
+			return nil, err
+		} else {
+			hc = f.(*ContinuationFrame) // guaranteed by checkFrameOrder
+		}
+	}
+
+	mh.HeadersFrame.headerFragBuf = nil
+	mh.HeadersFrame.invalidate()
+
+	if err := hdec.Close(); err != nil {
+		return nil, ConnectionError(ErrCodeCompression)
+	}
+	if invalid != nil {
+		fr.errDetail = invalid
+		return nil, StreamError{mh.StreamID, ErrCodeProtocol}
+	}
+	if err := mh.checkPseudos(); err != nil {
+		fr.errDetail = err
+		return nil, StreamError{mh.StreamID, ErrCodeProtocol}
+	}
+	return mh, nil
+}
+
 func summarizeFrame(f Frame) string {
 	var buf bytes.Buffer
 	f.Header().writeDebug(&buf)

+ 0 - 735
Godeps/_workspace/src/golang.org/x/net/http2/frame_test.go

@@ -1,735 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"bytes"
-	"fmt"
-	"io"
-	"reflect"
-	"strings"
-	"testing"
-	"unsafe"
-)
-
-func testFramer() (*Framer, *bytes.Buffer) {
-	buf := new(bytes.Buffer)
-	return NewFramer(buf, buf), buf
-}
-
-func TestFrameSizes(t *testing.T) {
-	// Catch people rearranging the FrameHeader fields.
-	if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want {
-		t.Errorf("FrameHeader size = %d; want %d", got, want)
-	}
-}
-
-func TestFrameTypeString(t *testing.T) {
-	tests := []struct {
-		ft   FrameType
-		want string
-	}{
-		{FrameData, "DATA"},
-		{FramePing, "PING"},
-		{FrameGoAway, "GOAWAY"},
-		{0xf, "UNKNOWN_FRAME_TYPE_15"},
-	}
-
-	for i, tt := range tests {
-		got := tt.ft.String()
-		if got != tt.want {
-			t.Errorf("%d. String(FrameType %d) = %q; want %q", i, int(tt.ft), got, tt.want)
-		}
-	}
-}
-
-func TestWriteRST(t *testing.T) {
-	fr, buf := testFramer()
-	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
-	var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4
-	fr.WriteRSTStream(streamID, ErrCode(errCode))
-	const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04"
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-	f, err := fr.ReadFrame()
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := &RSTStreamFrame{
-		FrameHeader: FrameHeader{
-			valid:    true,
-			Type:     0x3,
-			Flags:    0x0,
-			Length:   0x4,
-			StreamID: 0x1020304,
-		},
-		ErrCode: 0x7060504,
-	}
-	if !reflect.DeepEqual(f, want) {
-		t.Errorf("parsed back %#v; want %#v", f, want)
-	}
-}
-
-func TestWriteData(t *testing.T) {
-	fr, buf := testFramer()
-	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
-	data := []byte("ABC")
-	fr.WriteData(streamID, true, data)
-	const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC"
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-	f, err := fr.ReadFrame()
-	if err != nil {
-		t.Fatal(err)
-	}
-	df, ok := f.(*DataFrame)
-	if !ok {
-		t.Fatalf("got %T; want *DataFrame", f)
-	}
-	if !bytes.Equal(df.Data(), data) {
-		t.Errorf("got %q; want %q", df.Data(), data)
-	}
-	if f.Header().Flags&1 == 0 {
-		t.Errorf("didn't see END_STREAM flag")
-	}
-}
-
-func TestWriteHeaders(t *testing.T) {
-	tests := []struct {
-		name      string
-		p         HeadersFrameParam
-		wantEnc   string
-		wantFrame *HeadersFrame
-	}{
-		{
-			"basic",
-			HeadersFrameParam{
-				StreamID:      42,
-				BlockFragment: []byte("abc"),
-				Priority:      PriorityParam{},
-			},
-			"\x00\x00\x03\x01\x00\x00\x00\x00*abc",
-			&HeadersFrame{
-				FrameHeader: FrameHeader{
-					valid:    true,
-					StreamID: 42,
-					Type:     FrameHeaders,
-					Length:   uint32(len("abc")),
-				},
-				Priority:      PriorityParam{},
-				headerFragBuf: []byte("abc"),
-			},
-		},
-		{
-			"basic + end flags",
-			HeadersFrameParam{
-				StreamID:      42,
-				BlockFragment: []byte("abc"),
-				EndStream:     true,
-				EndHeaders:    true,
-				Priority:      PriorityParam{},
-			},
-			"\x00\x00\x03\x01\x05\x00\x00\x00*abc",
-			&HeadersFrame{
-				FrameHeader: FrameHeader{
-					valid:    true,
-					StreamID: 42,
-					Type:     FrameHeaders,
-					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders,
-					Length:   uint32(len("abc")),
-				},
-				Priority:      PriorityParam{},
-				headerFragBuf: []byte("abc"),
-			},
-		},
-		{
-			"with padding",
-			HeadersFrameParam{
-				StreamID:      42,
-				BlockFragment: []byte("abc"),
-				EndStream:     true,
-				EndHeaders:    true,
-				PadLength:     5,
-				Priority:      PriorityParam{},
-			},
-			"\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00",
-			&HeadersFrame{
-				FrameHeader: FrameHeader{
-					valid:    true,
-					StreamID: 42,
-					Type:     FrameHeaders,
-					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded,
-					Length:   uint32(1 + len("abc") + 5), // pad length + contents + padding
-				},
-				Priority:      PriorityParam{},
-				headerFragBuf: []byte("abc"),
-			},
-		},
-		{
-			"with priority",
-			HeadersFrameParam{
-				StreamID:      42,
-				BlockFragment: []byte("abc"),
-				EndStream:     true,
-				EndHeaders:    true,
-				PadLength:     2,
-				Priority: PriorityParam{
-					StreamDep: 15,
-					Exclusive: true,
-					Weight:    127,
-				},
-			},
-			"\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00",
-			&HeadersFrame{
-				FrameHeader: FrameHeader{
-					valid:    true,
-					StreamID: 42,
-					Type:     FrameHeaders,
-					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
-					Length:   uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding
-				},
-				Priority: PriorityParam{
-					StreamDep: 15,
-					Exclusive: true,
-					Weight:    127,
-				},
-				headerFragBuf: []byte("abc"),
-			},
-		},
-	}
-	for _, tt := range tests {
-		fr, buf := testFramer()
-		if err := fr.WriteHeaders(tt.p); err != nil {
-			t.Errorf("test %q: %v", tt.name, err)
-			continue
-		}
-		if buf.String() != tt.wantEnc {
-			t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc)
-		}
-		f, err := fr.ReadFrame()
-		if err != nil {
-			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
-			continue
-		}
-		if !reflect.DeepEqual(f, tt.wantFrame) {
-			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
-		}
-	}
-}
-
-func TestWriteContinuation(t *testing.T) {
-	const streamID = 42
-	tests := []struct {
-		name string
-		end  bool
-		frag []byte
-
-		wantFrame *ContinuationFrame
-	}{
-		{
-			"not end",
-			false,
-			[]byte("abc"),
-			&ContinuationFrame{
-				FrameHeader: FrameHeader{
-					valid:    true,
-					StreamID: streamID,
-					Type:     FrameContinuation,
-					Length:   uint32(len("abc")),
-				},
-				headerFragBuf: []byte("abc"),
-			},
-		},
-		{
-			"end",
-			true,
-			[]byte("def"),
-			&ContinuationFrame{
-				FrameHeader: FrameHeader{
-					valid:    true,
-					StreamID: streamID,
-					Type:     FrameContinuation,
-					Flags:    FlagContinuationEndHeaders,
-					Length:   uint32(len("def")),
-				},
-				headerFragBuf: []byte("def"),
-			},
-		},
-	}
-	for _, tt := range tests {
-		fr, _ := testFramer()
-		if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil {
-			t.Errorf("test %q: %v", tt.name, err)
-			continue
-		}
-		fr.AllowIllegalReads = true
-		f, err := fr.ReadFrame()
-		if err != nil {
-			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
-			continue
-		}
-		if !reflect.DeepEqual(f, tt.wantFrame) {
-			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
-		}
-	}
-}
-
-func TestWritePriority(t *testing.T) {
-	const streamID = 42
-	tests := []struct {
-		name      string
-		priority  PriorityParam
-		wantFrame *PriorityFrame
-	}{
-		{
-			"not exclusive",
-			PriorityParam{
-				StreamDep: 2,
-				Exclusive: false,
-				Weight:    127,
-			},
-			&PriorityFrame{
-				FrameHeader{
-					valid:    true,
-					StreamID: streamID,
-					Type:     FramePriority,
-					Length:   5,
-				},
-				PriorityParam{
-					StreamDep: 2,
-					Exclusive: false,
-					Weight:    127,
-				},
-			},
-		},
-
-		{
-			"exclusive",
-			PriorityParam{
-				StreamDep: 3,
-				Exclusive: true,
-				Weight:    77,
-			},
-			&PriorityFrame{
-				FrameHeader{
-					valid:    true,
-					StreamID: streamID,
-					Type:     FramePriority,
-					Length:   5,
-				},
-				PriorityParam{
-					StreamDep: 3,
-					Exclusive: true,
-					Weight:    77,
-				},
-			},
-		},
-	}
-	for _, tt := range tests {
-		fr, _ := testFramer()
-		if err := fr.WritePriority(streamID, tt.priority); err != nil {
-			t.Errorf("test %q: %v", tt.name, err)
-			continue
-		}
-		f, err := fr.ReadFrame()
-		if err != nil {
-			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
-			continue
-		}
-		if !reflect.DeepEqual(f, tt.wantFrame) {
-			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
-		}
-	}
-}
-
-func TestWriteSettings(t *testing.T) {
-	fr, buf := testFramer()
-	settings := []Setting{{1, 2}, {3, 4}}
-	fr.WriteSettings(settings...)
-	const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04"
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-	f, err := fr.ReadFrame()
-	if err != nil {
-		t.Fatal(err)
-	}
-	sf, ok := f.(*SettingsFrame)
-	if !ok {
-		t.Fatalf("Got a %T; want a SettingsFrame", f)
-	}
-	var got []Setting
-	sf.ForeachSetting(func(s Setting) error {
-		got = append(got, s)
-		valBack, ok := sf.Value(s.ID)
-		if !ok || valBack != s.Val {
-			t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val)
-		}
-		return nil
-	})
-	if !reflect.DeepEqual(settings, got) {
-		t.Errorf("Read settings %+v != written settings %+v", got, settings)
-	}
-}
-
-func TestWriteSettingsAck(t *testing.T) {
-	fr, buf := testFramer()
-	fr.WriteSettingsAck()
-	const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00"
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-}
-
-func TestWriteWindowUpdate(t *testing.T) {
-	fr, buf := testFramer()
-	const streamID = 1<<24 + 2<<16 + 3<<8 + 4
-	const incr = 7<<24 + 6<<16 + 5<<8 + 4
-	if err := fr.WriteWindowUpdate(streamID, incr); err != nil {
-		t.Fatal(err)
-	}
-	const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04"
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-	f, err := fr.ReadFrame()
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := &WindowUpdateFrame{
-		FrameHeader: FrameHeader{
-			valid:    true,
-			Type:     0x8,
-			Flags:    0x0,
-			Length:   0x4,
-			StreamID: 0x1020304,
-		},
-		Increment: 0x7060504,
-	}
-	if !reflect.DeepEqual(f, want) {
-		t.Errorf("parsed back %#v; want %#v", f, want)
-	}
-}
-
-func TestWritePing(t *testing.T)    { testWritePing(t, false) }
-func TestWritePingAck(t *testing.T) { testWritePing(t, true) }
-
-func testWritePing(t *testing.T, ack bool) {
-	fr, buf := testFramer()
-	if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil {
-		t.Fatal(err)
-	}
-	var wantFlags Flags
-	if ack {
-		wantFlags = FlagPingAck
-	}
-	var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08"
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-
-	f, err := fr.ReadFrame()
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := &PingFrame{
-		FrameHeader: FrameHeader{
-			valid:    true,
-			Type:     0x6,
-			Flags:    wantFlags,
-			Length:   0x8,
-			StreamID: 0,
-		},
-		Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
-	}
-	if !reflect.DeepEqual(f, want) {
-		t.Errorf("parsed back %#v; want %#v", f, want)
-	}
-}
-
-func TestReadFrameHeader(t *testing.T) {
-	tests := []struct {
-		in   string
-		want FrameHeader
-	}{
-		{in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}},
-		{in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{
-			Length: 66051, Type: 4, Flags: 5, StreamID: 101124105,
-		}},
-		// Ignore high bit:
-		{in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{
-			Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
-		{in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{
-			Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
-	}
-	for i, tt := range tests {
-		got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in))
-		if err != nil {
-			t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err)
-			continue
-		}
-		tt.want.valid = true
-		if got != tt.want {
-			t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want)
-		}
-	}
-}
-
-func TestReadWriteFrameHeader(t *testing.T) {
-	tests := []struct {
-		len      uint32
-		typ      FrameType
-		flags    Flags
-		streamID uint32
-	}{
-		{len: 0, typ: 255, flags: 1, streamID: 0},
-		{len: 0, typ: 255, flags: 1, streamID: 1},
-		{len: 0, typ: 255, flags: 1, streamID: 255},
-		{len: 0, typ: 255, flags: 1, streamID: 256},
-		{len: 0, typ: 255, flags: 1, streamID: 65535},
-		{len: 0, typ: 255, flags: 1, streamID: 65536},
-
-		{len: 0, typ: 1, flags: 255, streamID: 1},
-		{len: 255, typ: 1, flags: 255, streamID: 1},
-		{len: 256, typ: 1, flags: 255, streamID: 1},
-		{len: 65535, typ: 1, flags: 255, streamID: 1},
-		{len: 65536, typ: 1, flags: 255, streamID: 1},
-		{len: 16777215, typ: 1, flags: 255, streamID: 1},
-	}
-	for _, tt := range tests {
-		fr, buf := testFramer()
-		fr.startWrite(tt.typ, tt.flags, tt.streamID)
-		fr.writeBytes(make([]byte, tt.len))
-		fr.endWrite()
-		fh, err := ReadFrameHeader(buf)
-		if err != nil {
-			t.Errorf("ReadFrameHeader(%+v) = %v", tt, err)
-			continue
-		}
-		if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID {
-			t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh)
-		}
-	}
-
-}
-
-func TestWriteTooLargeFrame(t *testing.T) {
-	fr, _ := testFramer()
-	fr.startWrite(0, 1, 1)
-	fr.writeBytes(make([]byte, 1<<24))
-	err := fr.endWrite()
-	if err != ErrFrameTooLarge {
-		t.Errorf("endWrite = %v; want errFrameTooLarge", err)
-	}
-}
-
-func TestWriteGoAway(t *testing.T) {
-	const debug = "foo"
-	fr, buf := testFramer()
-	if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil {
-		t.Fatal(err)
-	}
-	const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-	f, err := fr.ReadFrame()
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := &GoAwayFrame{
-		FrameHeader: FrameHeader{
-			valid:    true,
-			Type:     0x7,
-			Flags:    0,
-			Length:   uint32(4 + 4 + len(debug)),
-			StreamID: 0,
-		},
-		LastStreamID: 0x01020304,
-		ErrCode:      0x05060708,
-		debugData:    []byte(debug),
-	}
-	if !reflect.DeepEqual(f, want) {
-		t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
-	}
-	if got := string(f.(*GoAwayFrame).DebugData()); got != debug {
-		t.Errorf("debug data = %q; want %q", got, debug)
-	}
-}
-
-func TestWritePushPromise(t *testing.T) {
-	pp := PushPromiseParam{
-		StreamID:      42,
-		PromiseID:     42,
-		BlockFragment: []byte("abc"),
-	}
-	fr, buf := testFramer()
-	if err := fr.WritePushPromise(pp); err != nil {
-		t.Fatal(err)
-	}
-	const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc"
-	if buf.String() != wantEnc {
-		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
-	}
-	f, err := fr.ReadFrame()
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, ok := f.(*PushPromiseFrame)
-	if !ok {
-		t.Fatalf("got %T; want *PushPromiseFrame", f)
-	}
-	want := &PushPromiseFrame{
-		FrameHeader: FrameHeader{
-			valid:    true,
-			Type:     0x5,
-			Flags:    0x0,
-			Length:   0x7,
-			StreamID: 42,
-		},
-		PromiseID:     42,
-		headerFragBuf: []byte("abc"),
-	}
-	if !reflect.DeepEqual(f, want) {
-		t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
-	}
-}
-
-// test checkFrameOrder and that HEADERS and CONTINUATION frames can't be intermingled.
-func TestReadFrameOrder(t *testing.T) {
-	head := func(f *Framer, id uint32, end bool) {
-		f.WriteHeaders(HeadersFrameParam{
-			StreamID:      id,
-			BlockFragment: []byte("foo"), // unused, but non-empty
-			EndHeaders:    end,
-		})
-	}
-	cont := func(f *Framer, id uint32, end bool) {
-		f.WriteContinuation(id, end, []byte("foo"))
-	}
-
-	tests := [...]struct {
-		name    string
-		w       func(*Framer)
-		atLeast int
-		wantErr string
-	}{
-		0: {
-			w: func(f *Framer) {
-				head(f, 1, true)
-			},
-		},
-		1: {
-			w: func(f *Framer) {
-				head(f, 1, true)
-				head(f, 2, true)
-			},
-		},
-		2: {
-			wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1",
-			w: func(f *Framer) {
-				head(f, 1, false)
-				head(f, 2, true)
-			},
-		},
-		3: {
-			wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1",
-			w: func(f *Framer) {
-				head(f, 1, false)
-			},
-		},
-		4: {
-			w: func(f *Framer) {
-				head(f, 1, false)
-				cont(f, 1, true)
-				head(f, 2, true)
-			},
-		},
-		5: {
-			wantErr: "got CONTINUATION for stream 2; expected stream 1",
-			w: func(f *Framer) {
-				head(f, 1, false)
-				cont(f, 2, true)
-				head(f, 2, true)
-			},
-		},
-		6: {
-			wantErr: "unexpected CONTINUATION for stream 1",
-			w: func(f *Framer) {
-				cont(f, 1, true)
-			},
-		},
-		7: {
-			wantErr: "unexpected CONTINUATION for stream 1",
-			w: func(f *Framer) {
-				cont(f, 1, false)
-			},
-		},
-		8: {
-			wantErr: "HEADERS frame with stream ID 0",
-			w: func(f *Framer) {
-				head(f, 0, true)
-			},
-		},
-		9: {
-			wantErr: "CONTINUATION frame with stream ID 0",
-			w: func(f *Framer) {
-				cont(f, 0, true)
-			},
-		},
-		10: {
-			wantErr: "unexpected CONTINUATION for stream 1",
-			atLeast: 5,
-			w: func(f *Framer) {
-				head(f, 1, false)
-				cont(f, 1, false)
-				cont(f, 1, false)
-				cont(f, 1, false)
-				cont(f, 1, true)
-				cont(f, 1, false)
-			},
-		},
-	}
-	for i, tt := range tests {
-		buf := new(bytes.Buffer)
-		f := NewFramer(buf, buf)
-		f.AllowIllegalWrites = true
-		tt.w(f)
-		f.WriteData(1, true, nil) // to test transition away from last step
-
-		var err error
-		n := 0
-		var log bytes.Buffer
-		for {
-			var got Frame
-			got, err = f.ReadFrame()
-			fmt.Fprintf(&log, "  read %v, %v\n", got, err)
-			if err != nil {
-				break
-			}
-			n++
-		}
-		if err == io.EOF {
-			err = nil
-		}
-		ok := tt.wantErr == ""
-		if ok && err != nil {
-			t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes())
-			continue
-		}
-		if !ok && err != ConnectionError(ErrCodeProtocol) {
-			t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes())
-			continue
-		}
-		if f.errReason != tt.wantErr {
-			t.Errorf("%d. framer eror = %q; want %q\n%s", i, f.errReason, tt.wantErr, log.Bytes())
-		}
-		if n < tt.atLeast {
-			t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes())
-		}
-	}
-}

+ 0 - 33
Godeps/_workspace/src/golang.org/x/net/http2/gotrack_test.go

@@ -1,33 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"fmt"
-	"strings"
-	"testing"
-)
-
-func TestGoroutineLock(t *testing.T) {
-	oldDebug := DebugGoroutines
-	DebugGoroutines = true
-	defer func() { DebugGoroutines = oldDebug }()
-
-	g := newGoroutineLock()
-	g.check()
-
-	sawPanic := make(chan interface{})
-	go func() {
-		defer func() { sawPanic <- recover() }()
-		g.check() // should panic
-	}()
-	e := <-sawPanic
-	if e == nil {
-		t.Fatal("did not see panic from check in other goroutine")
-	}
-	if !strings.Contains(fmt.Sprint(e), "wrong goroutine") {
-		t.Errorf("expected on see panic about running on the wrong goroutine; got %v", e)
-	}
-}

+ 34 - 2
Godeps/_workspace/src/golang.org/x/net/http2/h2demo/h2demo.go

@@ -28,8 +28,8 @@ import (
 	"time"
 
 	"camlistore.org/pkg/googlestorage"
-	"camlistore.org/pkg/singleflight"
 	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2"
+	"go4.org/syncutil/singleflight"
 )
 
 var (
@@ -79,7 +79,7 @@ is used transparently by the Go standard library from Go 1.6 and later.
 </p>
 
 <p>Contact info: <i>bradfitz@golang.org</i>, or <a
-href="https://golang.org/issues">file a bug</a>.</p>
+href="https://golang.org/s/http2bug">file a bug</a>.</p>
 
 <h2>Handlers for testing</h2>
 <ul>
@@ -440,11 +440,43 @@ func serveProd() error {
 	return <-errc
 }
 
+const idleTimeout = 5 * time.Minute
+const activeTimeout = 10 * time.Minute
+
+// TODO: put this into the standard library and actually send
+// PING frames and GOAWAY, etc: golang.org/issue/14204
+func idleTimeoutHook() func(net.Conn, http.ConnState) {
+	var mu sync.Mutex
+	m := map[net.Conn]*time.Timer{}
+	return func(c net.Conn, cs http.ConnState) {
+		mu.Lock()
+		defer mu.Unlock()
+		if t, ok := m[c]; ok {
+			delete(m, c)
+			t.Stop()
+		}
+		var d time.Duration
+		switch cs {
+		case http.StateNew, http.StateIdle:
+			d = idleTimeout
+		case http.StateActive:
+			d = activeTimeout
+		default:
+			return
+		}
+		m[c] = time.AfterFunc(d, func() {
+			log.Printf("closing idle conn %v after %v", c.RemoteAddr(), d)
+			go c.Close()
+		})
+	}
+}
+
 func main() {
 	var srv http.Server
 	flag.BoolVar(&http2.VerboseLogs, "verbose", false, "Verbose HTTP/2 debugging.")
 	flag.Parse()
 	srv.Addr = *httpsAddr
+	srv.ConnState = idleTimeoutHook()
 
 	registerHandlers()
 

+ 1 - 1
Godeps/_workspace/src/golang.org/x/net/http2/h2i/h2i.go

@@ -78,7 +78,6 @@ var commands = map[string]command{
 func usage() {
 	fmt.Fprintf(os.Stderr, "Usage: h2i <hostname>\n\n")
 	flag.PrintDefaults()
-	os.Exit(1)
 }
 
 // withPort adds ":443" if another port isn't already present.
@@ -111,6 +110,7 @@ func main() {
 	flag.Parse()
 	if flag.NArg() != 1 {
 		usage()
+		os.Exit(2)
 	}
 	log.SetFlags(0)
 

+ 1 - 1
Godeps/_workspace/src/golang.org/x/net/http2/hpack/encode.go

@@ -144,7 +144,7 @@ func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
 
 // shouldIndex reports whether f should be indexed.
 func (e *Encoder) shouldIndex(f HeaderField) bool {
-	return !f.Sensitive && f.size() <= e.dynTab.maxSize
+	return !f.Sensitive && f.Size() <= e.dynTab.maxSize
 }
 
 // appendIndexed appends index i, as encoded in "Indexed Header Field"

+ 0 - 330
Godeps/_workspace/src/golang.org/x/net/http2/hpack/encode_test.go

@@ -1,330 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package hpack
-
-import (
-	"bytes"
-	"encoding/hex"
-	"reflect"
-	"strings"
-	"testing"
-)
-
-func TestEncoderTableSizeUpdate(t *testing.T) {
-	tests := []struct {
-		size1, size2 uint32
-		wantHex      string
-	}{
-		// Should emit 2 table size updates (2048 and 4096)
-		{2048, 4096, "3fe10f 3fe11f 82"},
-
-		// Should emit 1 table size update (2048)
-		{16384, 2048, "3fe10f 82"},
-	}
-	for _, tt := range tests {
-		var buf bytes.Buffer
-		e := NewEncoder(&buf)
-		e.SetMaxDynamicTableSize(tt.size1)
-		e.SetMaxDynamicTableSize(tt.size2)
-		if err := e.WriteField(pair(":method", "GET")); err != nil {
-			t.Fatal(err)
-		}
-		want := removeSpace(tt.wantHex)
-		if got := hex.EncodeToString(buf.Bytes()); got != want {
-			t.Errorf("e.SetDynamicTableSize %v, %v = %q; want %q", tt.size1, tt.size2, got, want)
-		}
-	}
-}
-
-func TestEncoderWriteField(t *testing.T) {
-	var buf bytes.Buffer
-	e := NewEncoder(&buf)
-	var got []HeaderField
-	d := NewDecoder(4<<10, func(f HeaderField) {
-		got = append(got, f)
-	})
-
-	tests := []struct {
-		hdrs []HeaderField
-	}{
-		{[]HeaderField{
-			pair(":method", "GET"),
-			pair(":scheme", "http"),
-			pair(":path", "/"),
-			pair(":authority", "www.example.com"),
-		}},
-		{[]HeaderField{
-			pair(":method", "GET"),
-			pair(":scheme", "http"),
-			pair(":path", "/"),
-			pair(":authority", "www.example.com"),
-			pair("cache-control", "no-cache"),
-		}},
-		{[]HeaderField{
-			pair(":method", "GET"),
-			pair(":scheme", "https"),
-			pair(":path", "/index.html"),
-			pair(":authority", "www.example.com"),
-			pair("custom-key", "custom-value"),
-		}},
-	}
-	for i, tt := range tests {
-		buf.Reset()
-		got = got[:0]
-		for _, hf := range tt.hdrs {
-			if err := e.WriteField(hf); err != nil {
-				t.Fatal(err)
-			}
-		}
-		_, err := d.Write(buf.Bytes())
-		if err != nil {
-			t.Errorf("%d. Decoder Write = %v", i, err)
-		}
-		if !reflect.DeepEqual(got, tt.hdrs) {
-			t.Errorf("%d. Decoded %+v; want %+v", i, got, tt.hdrs)
-		}
-	}
-}
-
-func TestEncoderSearchTable(t *testing.T) {
-	e := NewEncoder(nil)
-
-	e.dynTab.add(pair("foo", "bar"))
-	e.dynTab.add(pair("blake", "miz"))
-	e.dynTab.add(pair(":method", "GET"))
-
-	tests := []struct {
-		hf        HeaderField
-		wantI     uint64
-		wantMatch bool
-	}{
-		// Name and Value match
-		{pair("foo", "bar"), uint64(len(staticTable) + 3), true},
-		{pair("blake", "miz"), uint64(len(staticTable) + 2), true},
-		{pair(":method", "GET"), 2, true},
-
-		// Only name match because Sensitive == true
-		{HeaderField{":method", "GET", true}, 2, false},
-
-		// Only Name matches
-		{pair("foo", "..."), uint64(len(staticTable) + 3), false},
-		{pair("blake", "..."), uint64(len(staticTable) + 2), false},
-		{pair(":method", "..."), 2, false},
-
-		// None match
-		{pair("foo-", "bar"), 0, false},
-	}
-	for _, tt := range tests {
-		if gotI, gotMatch := e.searchTable(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
-			t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
-		}
-	}
-}
-
-func TestAppendVarInt(t *testing.T) {
-	tests := []struct {
-		n    byte
-		i    uint64
-		want []byte
-	}{
-		// Fits in a byte:
-		{1, 0, []byte{0}},
-		{2, 2, []byte{2}},
-		{3, 6, []byte{6}},
-		{4, 14, []byte{14}},
-		{5, 30, []byte{30}},
-		{6, 62, []byte{62}},
-		{7, 126, []byte{126}},
-		{8, 254, []byte{254}},
-
-		// Multiple bytes:
-		{5, 1337, []byte{31, 154, 10}},
-	}
-	for _, tt := range tests {
-		got := appendVarInt(nil, tt.n, tt.i)
-		if !bytes.Equal(got, tt.want) {
-			t.Errorf("appendVarInt(nil, %v, %v) = %v; want %v", tt.n, tt.i, got, tt.want)
-		}
-	}
-}
-
-func TestAppendHpackString(t *testing.T) {
-	tests := []struct {
-		s, wantHex string
-	}{
-		// Huffman encoded
-		{"www.example.com", "8c f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
-
-		// Not Huffman encoded
-		{"a", "01 61"},
-
-		// zero length
-		{"", "00"},
-	}
-	for _, tt := range tests {
-		want := removeSpace(tt.wantHex)
-		buf := appendHpackString(nil, tt.s)
-		if got := hex.EncodeToString(buf); want != got {
-			t.Errorf("appendHpackString(nil, %q) = %q; want %q", tt.s, got, want)
-		}
-	}
-}
-
-func TestAppendIndexed(t *testing.T) {
-	tests := []struct {
-		i       uint64
-		wantHex string
-	}{
-		// 1 byte
-		{1, "81"},
-		{126, "fe"},
-
-		// 2 bytes
-		{127, "ff00"},
-		{128, "ff01"},
-	}
-	for _, tt := range tests {
-		want := removeSpace(tt.wantHex)
-		buf := appendIndexed(nil, tt.i)
-		if got := hex.EncodeToString(buf); want != got {
-			t.Errorf("appendIndex(nil, %v) = %q; want %q", tt.i, got, want)
-		}
-	}
-}
-
-func TestAppendNewName(t *testing.T) {
-	tests := []struct {
-		f        HeaderField
-		indexing bool
-		wantHex  string
-	}{
-		// Incremental indexing
-		{HeaderField{"custom-key", "custom-value", false}, true, "40 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
-
-		// Without indexing
-		{HeaderField{"custom-key", "custom-value", false}, false, "00 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
-
-		// Never indexed
-		{HeaderField{"custom-key", "custom-value", true}, true, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
-		{HeaderField{"custom-key", "custom-value", true}, false, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
-	}
-	for _, tt := range tests {
-		want := removeSpace(tt.wantHex)
-		buf := appendNewName(nil, tt.f, tt.indexing)
-		if got := hex.EncodeToString(buf); want != got {
-			t.Errorf("appendNewName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
-		}
-	}
-}
-
-func TestAppendIndexedName(t *testing.T) {
-	tests := []struct {
-		f        HeaderField
-		i        uint64
-		indexing bool
-		wantHex  string
-	}{
-		// Incremental indexing
-		{HeaderField{":status", "302", false}, 8, true, "48 82 6402"},
-
-		// Without indexing
-		{HeaderField{":status", "302", false}, 8, false, "08 82 6402"},
-
-		// Never indexed
-		{HeaderField{":status", "302", true}, 8, true, "18 82 6402"},
-		{HeaderField{":status", "302", true}, 8, false, "18 82 6402"},
-	}
-	for _, tt := range tests {
-		want := removeSpace(tt.wantHex)
-		buf := appendIndexedName(nil, tt.f, tt.i, tt.indexing)
-		if got := hex.EncodeToString(buf); want != got {
-			t.Errorf("appendIndexedName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
-		}
-	}
-}
-
-func TestAppendTableSize(t *testing.T) {
-	tests := []struct {
-		i       uint32
-		wantHex string
-	}{
-		// Fits into 1 byte
-		{30, "3e"},
-
-		// Extra byte
-		{31, "3f00"},
-		{32, "3f01"},
-	}
-	for _, tt := range tests {
-		want := removeSpace(tt.wantHex)
-		buf := appendTableSize(nil, tt.i)
-		if got := hex.EncodeToString(buf); want != got {
-			t.Errorf("appendTableSize(nil, %v) = %q; want %q", tt.i, got, want)
-		}
-	}
-}
-
-func TestEncoderSetMaxDynamicTableSize(t *testing.T) {
-	var buf bytes.Buffer
-	e := NewEncoder(&buf)
-	tests := []struct {
-		v           uint32
-		wantUpdate  bool
-		wantMinSize uint32
-		wantMaxSize uint32
-	}{
-		// Set new table size to 2048
-		{2048, true, 2048, 2048},
-
-		// Set new table size to 16384, but still limited to
-		// 4096
-		{16384, true, 2048, 4096},
-	}
-	for _, tt := range tests {
-		e.SetMaxDynamicTableSize(tt.v)
-		if got := e.tableSizeUpdate; tt.wantUpdate != got {
-			t.Errorf("e.tableSizeUpdate = %v; want %v", got, tt.wantUpdate)
-		}
-		if got := e.minSize; tt.wantMinSize != got {
-			t.Errorf("e.minSize = %v; want %v", got, tt.wantMinSize)
-		}
-		if got := e.dynTab.maxSize; tt.wantMaxSize != got {
-			t.Errorf("e.maxSize = %v; want %v", got, tt.wantMaxSize)
-		}
-	}
-}
-
-func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) {
-	e := NewEncoder(nil)
-	// 4095 < initialHeaderTableSize means maxSize is truncated to
-	// 4095.
-	e.SetMaxDynamicTableSizeLimit(4095)
-	if got, want := e.dynTab.maxSize, uint32(4095); got != want {
-		t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
-	}
-	if got, want := e.maxSizeLimit, uint32(4095); got != want {
-		t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
-	}
-	if got, want := e.tableSizeUpdate, true; got != want {
-		t.Errorf("e.tableSizeUpdate = %v; want %v", got, want)
-	}
-	// maxSize will be truncated to maxSizeLimit
-	e.SetMaxDynamicTableSize(16384)
-	if got, want := e.dynTab.maxSize, uint32(4095); got != want {
-		t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
-	}
-	// 8192 > current maxSizeLimit, so maxSize does not change.
-	e.SetMaxDynamicTableSizeLimit(8192)
-	if got, want := e.dynTab.maxSize, uint32(4095); got != want {
-		t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
-	}
-	if got, want := e.maxSizeLimit, uint32(8192); got != want {
-		t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
-	}
-}
-
-func removeSpace(s string) string {
-	return strings.Replace(s, " ", "", -1)
-}

+ 12 - 3
Godeps/_workspace/src/golang.org/x/net/http2/hpack/hpack.go

@@ -41,6 +41,14 @@ type HeaderField struct {
 	Sensitive bool
 }
 
+// IsPseudo reports whether the header field is an http2 pseudo header.
+// That is, it reports whether it starts with a colon.
+// It is not otherwise guaranteed to be a valid psuedo header field,
+// though.
+func (hf HeaderField) IsPseudo() bool {
+	return len(hf.Name) != 0 && hf.Name[0] == ':'
+}
+
 func (hf HeaderField) String() string {
 	var suffix string
 	if hf.Sensitive {
@@ -49,7 +57,8 @@ func (hf HeaderField) String() string {
 	return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
 }
 
-func (hf *HeaderField) size() uint32 {
+// Size returns the size of an entry per RFC 7540 section 5.2.
+func (hf HeaderField) Size() uint32 {
 	// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
 	// "The size of the dynamic table is the sum of the size of
 	// its entries.  The size of an entry is the sum of its name's
@@ -171,7 +180,7 @@ func (dt *dynamicTable) setMaxSize(v uint32) {
 
 func (dt *dynamicTable) add(f HeaderField) {
 	dt.ents = append(dt.ents, f)
-	dt.size += f.size()
+	dt.size += f.Size()
 	dt.evict()
 }
 
@@ -179,7 +188,7 @@ func (dt *dynamicTable) add(f HeaderField) {
 func (dt *dynamicTable) evict() {
 	base := dt.ents // keep base pointer of slice
 	for dt.size > dt.maxSize {
-		dt.size -= dt.ents[0].size()
+		dt.size -= dt.ents[0].Size()
 		dt.ents = dt.ents[1:]
 	}
 

+ 0 - 813
Godeps/_workspace/src/golang.org/x/net/http2/hpack/hpack_test.go

@@ -1,813 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package hpack
-
-import (
-	"bufio"
-	"bytes"
-	"encoding/hex"
-	"fmt"
-	"math/rand"
-	"reflect"
-	"regexp"
-	"strconv"
-	"strings"
-	"testing"
-	"time"
-)
-
-func TestStaticTable(t *testing.T) {
-	fromSpec := `
-          +-------+-----------------------------+---------------+
-          | 1     | :authority                  |               |
-          | 2     | :method                     | GET           |
-          | 3     | :method                     | POST          |
-          | 4     | :path                       | /             |
-          | 5     | :path                       | /index.html   |
-          | 6     | :scheme                     | http          |
-          | 7     | :scheme                     | https         |
-          | 8     | :status                     | 200           |
-          | 9     | :status                     | 204           |
-          | 10    | :status                     | 206           |
-          | 11    | :status                     | 304           |
-          | 12    | :status                     | 400           |
-          | 13    | :status                     | 404           |
-          | 14    | :status                     | 500           |
-          | 15    | accept-charset              |               |
-          | 16    | accept-encoding             | gzip, deflate |
-          | 17    | accept-language             |               |
-          | 18    | accept-ranges               |               |
-          | 19    | accept                      |               |
-          | 20    | access-control-allow-origin |               |
-          | 21    | age                         |               |
-          | 22    | allow                       |               |
-          | 23    | authorization               |               |
-          | 24    | cache-control               |               |
-          | 25    | content-disposition         |               |
-          | 26    | content-encoding            |               |
-          | 27    | content-language            |               |
-          | 28    | content-length              |               |
-          | 29    | content-location            |               |
-          | 30    | content-range               |               |
-          | 31    | content-type                |               |
-          | 32    | cookie                      |               |
-          | 33    | date                        |               |
-          | 34    | etag                        |               |
-          | 35    | expect                      |               |
-          | 36    | expires                     |               |
-          | 37    | from                        |               |
-          | 38    | host                        |               |
-          | 39    | if-match                    |               |
-          | 40    | if-modified-since           |               |
-          | 41    | if-none-match               |               |
-          | 42    | if-range                    |               |
-          | 43    | if-unmodified-since         |               |
-          | 44    | last-modified               |               |
-          | 45    | link                        |               |
-          | 46    | location                    |               |
-          | 47    | max-forwards                |               |
-          | 48    | proxy-authenticate          |               |
-          | 49    | proxy-authorization         |               |
-          | 50    | range                       |               |
-          | 51    | referer                     |               |
-          | 52    | refresh                     |               |
-          | 53    | retry-after                 |               |
-          | 54    | server                      |               |
-          | 55    | set-cookie                  |               |
-          | 56    | strict-transport-security   |               |
-          | 57    | transfer-encoding           |               |
-          | 58    | user-agent                  |               |
-          | 59    | vary                        |               |
-          | 60    | via                         |               |
-          | 61    | www-authenticate            |               |
-          +-------+-----------------------------+---------------+
-`
-	bs := bufio.NewScanner(strings.NewReader(fromSpec))
-	re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
-	for bs.Scan() {
-		l := bs.Text()
-		if !strings.Contains(l, "|") {
-			continue
-		}
-		m := re.FindStringSubmatch(l)
-		if m == nil {
-			continue
-		}
-		i, err := strconv.Atoi(m[1])
-		if err != nil {
-			t.Errorf("Bogus integer on line %q", l)
-			continue
-		}
-		if i < 1 || i > len(staticTable) {
-			t.Errorf("Bogus index %d on line %q", i, l)
-			continue
-		}
-		if got, want := staticTable[i-1].Name, m[2]; got != want {
-			t.Errorf("header index %d name = %q; want %q", i, got, want)
-		}
-		if got, want := staticTable[i-1].Value, m[3]; got != want {
-			t.Errorf("header index %d value = %q; want %q", i, got, want)
-		}
-	}
-	if err := bs.Err(); err != nil {
-		t.Error(err)
-	}
-}
-
-func (d *Decoder) mustAt(idx int) HeaderField {
-	if hf, ok := d.at(uint64(idx)); !ok {
-		panic(fmt.Sprintf("bogus index %d", idx))
-	} else {
-		return hf
-	}
-}
-
-func TestDynamicTableAt(t *testing.T) {
-	d := NewDecoder(4096, nil)
-	at := d.mustAt
-	if got, want := at(2), (pair(":method", "GET")); got != want {
-		t.Errorf("at(2) = %v; want %v", got, want)
-	}
-	d.dynTab.add(pair("foo", "bar"))
-	d.dynTab.add(pair("blake", "miz"))
-	if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want {
-		t.Errorf("at(dyn 1) = %v; want %v", got, want)
-	}
-	if got, want := at(len(staticTable)+2), (pair("foo", "bar")); got != want {
-		t.Errorf("at(dyn 2) = %v; want %v", got, want)
-	}
-	if got, want := at(3), (pair(":method", "POST")); got != want {
-		t.Errorf("at(3) = %v; want %v", got, want)
-	}
-}
-
-func TestDynamicTableSearch(t *testing.T) {
-	dt := dynamicTable{}
-	dt.setMaxSize(4096)
-
-	dt.add(pair("foo", "bar"))
-	dt.add(pair("blake", "miz"))
-	dt.add(pair(":method", "GET"))
-
-	tests := []struct {
-		hf        HeaderField
-		wantI     uint64
-		wantMatch bool
-	}{
-		// Name and Value match
-		{pair("foo", "bar"), 3, true},
-		{pair(":method", "GET"), 1, true},
-
-		// Only name match because of Sensitive == true
-		{HeaderField{"blake", "miz", true}, 2, false},
-
-		// Only Name matches
-		{pair("foo", "..."), 3, false},
-		{pair("blake", "..."), 2, false},
-		{pair(":method", "..."), 1, false},
-
-		// None match
-		{pair("foo-", "bar"), 0, false},
-	}
-	for _, tt := range tests {
-		if gotI, gotMatch := dt.search(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
-			t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
-		}
-	}
-}
-
-func TestDynamicTableSizeEvict(t *testing.T) {
-	d := NewDecoder(4096, nil)
-	if want := uint32(0); d.dynTab.size != want {
-		t.Fatalf("size = %d; want %d", d.dynTab.size, want)
-	}
-	add := d.dynTab.add
-	add(pair("blake", "eats pizza"))
-	if want := uint32(15 + 32); d.dynTab.size != want {
-		t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
-	}
-	add(pair("foo", "bar"))
-	if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
-		t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
-	}
-	d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
-	if want := uint32(6 + 32); d.dynTab.size != want {
-		t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
-	}
-	if got, want := d.mustAt(len(staticTable)+1), (pair("foo", "bar")); got != want {
-		t.Errorf("at(dyn 1) = %v; want %v", got, want)
-	}
-	add(pair("long", strings.Repeat("x", 500)))
-	if want := uint32(0); d.dynTab.size != want {
-		t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
-	}
-}
-
-func TestDecoderDecode(t *testing.T) {
-	tests := []struct {
-		name       string
-		in         []byte
-		want       []HeaderField
-		wantDynTab []HeaderField // newest entry first
-	}{
-		// C.2.1 Literal Header Field with Indexing
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1
-		{"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"),
-			[]HeaderField{pair("custom-key", "custom-header")},
-			[]HeaderField{pair("custom-key", "custom-header")},
-		},
-
-		// C.2.2 Literal Header Field without Indexing
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2
-		{"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"),
-			[]HeaderField{pair(":path", "/sample/path")},
-			[]HeaderField{}},
-
-		// C.2.3 Literal Header Field never Indexed
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3
-		{"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"),
-			[]HeaderField{{"password", "secret", true}},
-			[]HeaderField{}},
-
-		// C.2.4 Indexed Header Field
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
-		{"C.2.4", []byte("\x82"),
-			[]HeaderField{pair(":method", "GET")},
-			[]HeaderField{}},
-	}
-	for _, tt := range tests {
-		d := NewDecoder(4096, nil)
-		hf, err := d.DecodeFull(tt.in)
-		if err != nil {
-			t.Errorf("%s: %v", tt.name, err)
-			continue
-		}
-		if !reflect.DeepEqual(hf, tt.want) {
-			t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want)
-		}
-		gotDynTab := d.dynTab.reverseCopy()
-		if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) {
-			t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab)
-		}
-	}
-}
-
-func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
-	hf = make([]HeaderField, len(dt.ents))
-	for i := range hf {
-		hf[i] = dt.ents[len(dt.ents)-1-i]
-	}
-	return
-}
-
-type encAndWant struct {
-	enc         []byte
-	want        []HeaderField
-	wantDynTab  []HeaderField
-	wantDynSize uint32
-}
-
-// C.3 Request Examples without Huffman Coding
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.3
-func TestDecodeC3_NoHuffman(t *testing.T) {
-	testDecodeSeries(t, 4096, []encAndWant{
-		{dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-			},
-			[]HeaderField{
-				pair(":authority", "www.example.com"),
-			},
-			57,
-		},
-		{dehex("8286 84be 5808 6e6f 2d63 6163 6865"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-				pair("cache-control", "no-cache"),
-			},
-			[]HeaderField{
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			110,
-		},
-		{dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "https"),
-				pair(":path", "/index.html"),
-				pair(":authority", "www.example.com"),
-				pair("custom-key", "custom-value"),
-			},
-			[]HeaderField{
-				pair("custom-key", "custom-value"),
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			164,
-		},
-	})
-}
-
-// C.4 Request Examples with Huffman Coding
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.4
-func TestDecodeC4_Huffman(t *testing.T) {
-	testDecodeSeries(t, 4096, []encAndWant{
-		{dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-			},
-			[]HeaderField{
-				pair(":authority", "www.example.com"),
-			},
-			57,
-		},
-		{dehex("8286 84be 5886 a8eb 1064 9cbf"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-				pair("cache-control", "no-cache"),
-			},
-			[]HeaderField{
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			110,
-		},
-		{dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "https"),
-				pair(":path", "/index.html"),
-				pair(":authority", "www.example.com"),
-				pair("custom-key", "custom-value"),
-			},
-			[]HeaderField{
-				pair("custom-key", "custom-value"),
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			164,
-		},
-	})
-}
-
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.5
-// "This section shows several consecutive header lists, corresponding
-// to HTTP responses, on the same connection. The HTTP/2 setting
-// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
-// octets, causing some evictions to occur."
-func TestDecodeC5_ResponsesNoHuff(t *testing.T) {
-	testDecodeSeries(t, 256, []encAndWant{
-		{dehex(`
-4803 3330 3258 0770 7269 7661 7465 611d
-4d6f 6e2c 2032 3120 4f63 7420 3230 3133
-2032 303a 3133 3a32 3120 474d 546e 1768
-7474 7073 3a2f 2f77 7777 2e65 7861 6d70
-6c65 2e63 6f6d
-`),
-			[]HeaderField{
-				pair(":status", "302"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-				pair(":status", "302"),
-			},
-			222,
-		},
-		{dehex("4803 3330 37c1 c0bf"),
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-			},
-			222,
-		},
-		{dehex(`
-88c1 611d 4d6f 6e2c 2032 3120 4f63 7420
-3230 3133 2032 303a 3133 3a32 3220 474d
-54c0 5a04 677a 6970 7738 666f 6f3d 4153
-444a 4b48 514b 425a 584f 5157 454f 5049
-5541 5851 5745 4f49 553b 206d 6178 2d61
-6765 3d33 3630 303b 2076 6572 7369 6f6e
-3d31
-`),
-			[]HeaderField{
-				pair(":status", "200"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-				pair("location", "https://www.example.com"),
-				pair("content-encoding", "gzip"),
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-			},
-			[]HeaderField{
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-				pair("content-encoding", "gzip"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-			},
-			215,
-		},
-	})
-}
-
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.6
-// "This section shows the same examples as the previous section, but
-// using Huffman encoding for the literal values. The HTTP/2 setting
-// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
-// octets, causing some evictions to occur. The eviction mechanism
-// uses the length of the decoded literal values, so the same
-// evictions occurs as in the previous section."
-func TestDecodeC6_ResponsesHuffman(t *testing.T) {
-	testDecodeSeries(t, 256, []encAndWant{
-		{dehex(`
-4882 6402 5885 aec3 771a 4b61 96d0 7abe
-9410 54d4 44a8 2005 9504 0b81 66e0 82a6
-2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
-e9ae 82ae 43d3
-`),
-			[]HeaderField{
-				pair(":status", "302"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-				pair(":status", "302"),
-			},
-			222,
-		},
-		{dehex("4883 640e ffc1 c0bf"),
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-			},
-			222,
-		},
-		{dehex(`
-88c1 6196 d07a be94 1054 d444 a820 0595
-040b 8166 e084 a62d 1bff c05a 839b d9ab
-77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
-3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
-9587 3160 65c0 03ed 4ee5 b106 3d50 07
-`),
-			[]HeaderField{
-				pair(":status", "200"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-				pair("location", "https://www.example.com"),
-				pair("content-encoding", "gzip"),
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-			},
-			[]HeaderField{
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-				pair("content-encoding", "gzip"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-			},
-			215,
-		},
-	})
-}
-
-func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) {
-	d := NewDecoder(size, nil)
-	for i, step := range steps {
-		hf, err := d.DecodeFull(step.enc)
-		if err != nil {
-			t.Fatalf("Error at step index %d: %v", i, err)
-		}
-		if !reflect.DeepEqual(hf, step.want) {
-			t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want)
-		}
-		gotDynTab := d.dynTab.reverseCopy()
-		if !reflect.DeepEqual(gotDynTab, step.wantDynTab) {
-			t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab)
-		}
-		if d.dynTab.size != step.wantDynSize {
-			t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize)
-		}
-	}
-}
-
-func TestHuffmanDecode(t *testing.T) {
-	tests := []struct {
-		inHex, want string
-	}{
-		{"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
-		{"a8eb 1064 9cbf", "no-cache"},
-		{"25a8 49e9 5ba9 7d7f", "custom-key"},
-		{"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
-		{"6402", "302"},
-		{"aec3 771a 4b", "private"},
-		{"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
-		{"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
-		{"9bd9 ab", "gzip"},
-		{"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
-			"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
-	}
-	for i, tt := range tests {
-		var buf bytes.Buffer
-		in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
-		if err != nil {
-			t.Errorf("%d. hex input error: %v", i, err)
-			continue
-		}
-		if _, err := HuffmanDecode(&buf, in); err != nil {
-			t.Errorf("%d. decode error: %v", i, err)
-			continue
-		}
-		if got := buf.String(); tt.want != got {
-			t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
-		}
-	}
-}
-
-func TestAppendHuffmanString(t *testing.T) {
-	tests := []struct {
-		in, want string
-	}{
-		{"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
-		{"no-cache", "a8eb 1064 9cbf"},
-		{"custom-key", "25a8 49e9 5ba9 7d7f"},
-		{"custom-value", "25a8 49e9 5bb8 e8b4 bf"},
-		{"302", "6402"},
-		{"private", "aec3 771a 4b"},
-		{"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"},
-		{"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"},
-		{"gzip", "9bd9 ab"},
-		{"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
-			"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"},
-	}
-	for i, tt := range tests {
-		buf := []byte{}
-		want := strings.Replace(tt.want, " ", "", -1)
-		buf = AppendHuffmanString(buf, tt.in)
-		if got := hex.EncodeToString(buf); want != got {
-			t.Errorf("%d. encode = %q; want %q", i, got, want)
-		}
-	}
-}
-
-func TestHuffmanMaxStrLen(t *testing.T) {
-	const msg = "Some string"
-	huff := AppendHuffmanString(nil, msg)
-
-	testGood := func(max int) {
-		var out bytes.Buffer
-		if err := huffmanDecode(&out, max, huff); err != nil {
-			t.Errorf("For maxLen=%d, unexpected error: %v", max, err)
-		}
-		if out.String() != msg {
-			t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg)
-		}
-	}
-	testGood(0)
-	testGood(len(msg))
-	testGood(len(msg) + 1)
-
-	var out bytes.Buffer
-	if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength {
-		t.Errorf("err = %v; want ErrStringLength", err)
-	}
-}
-
-func TestHuffmanRoundtripStress(t *testing.T) {
-	const Len = 50 // of uncompressed string
-	input := make([]byte, Len)
-	var output bytes.Buffer
-	var huff []byte
-
-	n := 5000
-	if testing.Short() {
-		n = 100
-	}
-	seed := time.Now().UnixNano()
-	t.Logf("Seed = %v", seed)
-	src := rand.New(rand.NewSource(seed))
-	var encSize int64
-	for i := 0; i < n; i++ {
-		for l := range input {
-			input[l] = byte(src.Intn(256))
-		}
-		huff = AppendHuffmanString(huff[:0], string(input))
-		encSize += int64(len(huff))
-		output.Reset()
-		if err := huffmanDecode(&output, 0, huff); err != nil {
-			t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err)
-			continue
-		}
-		if !bytes.Equal(output.Bytes(), input) {
-			t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes())
-		}
-	}
-	t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize)
-}
-
-func TestHuffmanDecodeFuzz(t *testing.T) {
-	const Len = 50 // of compressed
-	var buf, zbuf bytes.Buffer
-
-	n := 5000
-	if testing.Short() {
-		n = 100
-	}
-	seed := time.Now().UnixNano()
-	t.Logf("Seed = %v", seed)
-	src := rand.New(rand.NewSource(seed))
-	numFail := 0
-	for i := 0; i < n; i++ {
-		zbuf.Reset()
-		if i == 0 {
-			// Start with at least one invalid one.
-			zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8")
-		} else {
-			for l := 0; l < Len; l++ {
-				zbuf.WriteByte(byte(src.Intn(256)))
-			}
-		}
-
-		buf.Reset()
-		if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil {
-			if err == ErrInvalidHuffman {
-				numFail++
-				continue
-			}
-			t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err)
-			continue
-		}
-	}
-	t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n)
-	if numFail < 1 {
-		t.Error("expected at least one invalid huffman encoding (test starts with one)")
-	}
-}
-
-func TestReadVarInt(t *testing.T) {
-	type res struct {
-		i        uint64
-		consumed int
-		err      error
-	}
-	tests := []struct {
-		n    byte
-		p    []byte
-		want res
-	}{
-		// Fits in a byte:
-		{1, []byte{0}, res{0, 1, nil}},
-		{2, []byte{2}, res{2, 1, nil}},
-		{3, []byte{6}, res{6, 1, nil}},
-		{4, []byte{14}, res{14, 1, nil}},
-		{5, []byte{30}, res{30, 1, nil}},
-		{6, []byte{62}, res{62, 1, nil}},
-		{7, []byte{126}, res{126, 1, nil}},
-		{8, []byte{254}, res{254, 1, nil}},
-
-		// Doesn't fit in a byte:
-		{1, []byte{1}, res{0, 0, errNeedMore}},
-		{2, []byte{3}, res{0, 0, errNeedMore}},
-		{3, []byte{7}, res{0, 0, errNeedMore}},
-		{4, []byte{15}, res{0, 0, errNeedMore}},
-		{5, []byte{31}, res{0, 0, errNeedMore}},
-		{6, []byte{63}, res{0, 0, errNeedMore}},
-		{7, []byte{127}, res{0, 0, errNeedMore}},
-		{8, []byte{255}, res{0, 0, errNeedMore}},
-
-		// Ignoring top bits:
-		{5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
-		{5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
-		{5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101
-
-		// Extra byte:
-		{5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte
-
-		// Short a byte:
-		{5, []byte{191, 154}, res{0, 0, errNeedMore}},
-
-		// integer overflow:
-		{1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
-	}
-	for _, tt := range tests {
-		i, remain, err := readVarInt(tt.n, tt.p)
-		consumed := len(tt.p) - len(remain)
-		got := res{i, consumed, err}
-		if got != tt.want {
-			t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
-		}
-	}
-}
-
-// Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56
-func TestHuffmanFuzzCrash(t *testing.T) {
-	got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8"))
-	if got != "" {
-		t.Errorf("Got %q; want empty string", got)
-	}
-	if err != ErrInvalidHuffman {
-		t.Errorf("Err = %v; want ErrInvalidHuffman", err)
-	}
-}
-
-func dehex(s string) []byte {
-	s = strings.Replace(s, " ", "", -1)
-	s = strings.Replace(s, "\n", "", -1)
-	b, err := hex.DecodeString(s)
-	if err != nil {
-		panic(err)
-	}
-	return b
-}
-
-func TestEmitEnabled(t *testing.T) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
-	enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
-	enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
-
-	numCallback := 0
-	var dec *Decoder
-	dec = NewDecoder(8<<20, func(HeaderField) {
-		numCallback++
-		dec.SetEmitEnabled(false)
-	})
-	if !dec.EmitEnabled() {
-		t.Errorf("initial emit enabled = false; want true")
-	}
-	if _, err := dec.Write(buf.Bytes()); err != nil {
-		t.Error(err)
-	}
-	if numCallback != 1 {
-		t.Errorf("num callbacks = %d; want 1", numCallback)
-	}
-	if dec.EmitEnabled() {
-		t.Errorf("emit enabled = true; want false")
-	}
-}
-
-func TestSaveBufLimit(t *testing.T) {
-	const maxStr = 1 << 10
-	var got []HeaderField
-	dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) {
-		got = append(got, hf)
-	})
-	dec.SetMaxStringLength(maxStr)
-	var frag []byte
-	frag = append(frag[:0], encodeTypeByte(false, false))
-	frag = appendVarInt(frag, 7, 3)
-	frag = append(frag, "foo"...)
-	frag = appendVarInt(frag, 7, 3)
-	frag = append(frag, "bar"...)
-
-	if _, err := dec.Write(frag); err != nil {
-		t.Fatal(err)
-	}
-
-	want := []HeaderField{{Name: "foo", Value: "bar"}}
-	if !reflect.DeepEqual(got, want) {
-		t.Errorf("After small writes, got %v; want %v", got, want)
-	}
-
-	frag = append(frag[:0], encodeTypeByte(false, false))
-	frag = appendVarInt(frag, 7, maxStr*3)
-	frag = append(frag, make([]byte, maxStr*3)...)
-
-	_, err := dec.Write(frag)
-	if err != ErrStringLength {
-		t.Fatalf("Write error = %v; want ErrStringLength", err)
-	}
-}

+ 5 - 0
Godeps/_workspace/src/golang.org/x/net/http2/http2.go

@@ -17,6 +17,7 @@ package http2
 
 import (
 	"bufio"
+	"crypto/tls"
 	"errors"
 	"fmt"
 	"io"
@@ -422,3 +423,7 @@ var isTokenTable = [127]bool{
 	'|':  true,
 	'~':  true,
 }
+
+type connectionStater interface {
+	ConnectionState() tls.ConnectionState
+}

+ 0 - 174
Godeps/_workspace/src/golang.org/x/net/http2/http2_test.go

@@ -1,174 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"bytes"
-	"errors"
-	"flag"
-	"fmt"
-	"net/http"
-	"os/exec"
-	"strconv"
-	"strings"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2/hpack"
-)
-
-var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.")
-
-func condSkipFailingTest(t *testing.T) {
-	if !*knownFailing {
-		t.Skip("Skipping known-failing test without --known_failing")
-	}
-}
-
-func init() {
-	DebugGoroutines = true
-	flag.BoolVar(&VerboseLogs, "verboseh2", false, "Verbose HTTP/2 debug logging")
-}
-
-func TestSettingString(t *testing.T) {
-	tests := []struct {
-		s    Setting
-		want string
-	}{
-		{Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
-		{Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
-	}
-	for i, tt := range tests {
-		got := fmt.Sprint(tt.s)
-		if got != tt.want {
-			t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
-		}
-	}
-}
-
-type twriter struct {
-	t  testing.TB
-	st *serverTester // optional
-}
-
-func (w twriter) Write(p []byte) (n int, err error) {
-	if w.st != nil {
-		ps := string(p)
-		for _, phrase := range w.st.logFilter {
-			if strings.Contains(ps, phrase) {
-				return len(p), nil // no logging
-			}
-		}
-	}
-	w.t.Logf("%s", p)
-	return len(p), nil
-}
-
-// like encodeHeader, but don't add implicit psuedo headers.
-func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte {
-	var buf bytes.Buffer
-	enc := hpack.NewEncoder(&buf)
-	for len(headers) > 0 {
-		k, v := headers[0], headers[1]
-		headers = headers[2:]
-		if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil {
-			t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
-		}
-	}
-	return buf.Bytes()
-}
-
-// Verify that curl has http2.
-func requireCurl(t *testing.T) {
-	out, err := dockerLogs(curl(t, "--version"))
-	if err != nil {
-		t.Skipf("failed to determine curl features; skipping test")
-	}
-	if !strings.Contains(string(out), "HTTP2") {
-		t.Skip("curl doesn't support HTTP2; skipping test")
-	}
-}
-
-func curl(t *testing.T, args ...string) (container string) {
-	out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).Output()
-	if err != nil {
-		t.Skipf("Failed to run curl in docker: %v, %s", err, out)
-	}
-	return strings.TrimSpace(string(out))
-}
-
-// Verify that h2load exists.
-func requireH2load(t *testing.T) {
-	out, err := dockerLogs(h2load(t, "--version"))
-	if err != nil {
-		t.Skipf("failed to probe h2load; skipping test: %s", out)
-	}
-	if !strings.Contains(string(out), "h2load nghttp2/") {
-		t.Skipf("h2load not present; skipping test. (Output=%q)", out)
-	}
-}
-
-func h2load(t *testing.T, args ...string) (container string) {
-	out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl"}, args...)...).Output()
-	if err != nil {
-		t.Skipf("Failed to run h2load in docker: %v, %s", err, out)
-	}
-	return strings.TrimSpace(string(out))
-}
-
-type puppetCommand struct {
-	fn   func(w http.ResponseWriter, r *http.Request)
-	done chan<- bool
-}
-
-type handlerPuppet struct {
-	ch chan puppetCommand
-}
-
-func newHandlerPuppet() *handlerPuppet {
-	return &handlerPuppet{
-		ch: make(chan puppetCommand),
-	}
-}
-
-func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) {
-	for cmd := range p.ch {
-		cmd.fn(w, r)
-		cmd.done <- true
-	}
-}
-
-func (p *handlerPuppet) done() { close(p.ch) }
-func (p *handlerPuppet) do(fn func(http.ResponseWriter, *http.Request)) {
-	done := make(chan bool)
-	p.ch <- puppetCommand{fn, done}
-	<-done
-}
-func dockerLogs(container string) ([]byte, error) {
-	out, err := exec.Command("docker", "wait", container).CombinedOutput()
-	if err != nil {
-		return out, err
-	}
-	exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
-	if err != nil {
-		return out, errors.New("unexpected exit status from docker wait")
-	}
-	out, err = exec.Command("docker", "logs", container).CombinedOutput()
-	exec.Command("docker", "rm", container).Run()
-	if err == nil && exitStatus != 0 {
-		err = fmt.Errorf("exit status %d: %s", exitStatus, out)
-	}
-	return out, err
-}
-
-func kill(container string) {
-	exec.Command("docker", "kill", container).Run()
-	exec.Command("docker", "rm", container).Run()
-}
-
-func cleanDate(res *http.Response) {
-	if d := res.Header["Date"]; len(d) == 1 {
-		d[0] = "XXX"
-	}
-}

+ 0 - 109
Godeps/_workspace/src/golang.org/x/net/http2/pipe_test.go

@@ -1,109 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"bytes"
-	"errors"
-	"io"
-	"io/ioutil"
-	"testing"
-)
-
-func TestPipeClose(t *testing.T) {
-	var p pipe
-	p.b = new(bytes.Buffer)
-	a := errors.New("a")
-	b := errors.New("b")
-	p.CloseWithError(a)
-	p.CloseWithError(b)
-	_, err := p.Read(make([]byte, 1))
-	if err != a {
-		t.Errorf("err = %v want %v", err, a)
-	}
-}
-
-func TestPipeDoneChan(t *testing.T) {
-	var p pipe
-	done := p.Done()
-	select {
-	case <-done:
-		t.Fatal("done too soon")
-	default:
-	}
-	p.CloseWithError(io.EOF)
-	select {
-	case <-done:
-	default:
-		t.Fatal("should be done")
-	}
-}
-
-func TestPipeDoneChan_ErrFirst(t *testing.T) {
-	var p pipe
-	p.CloseWithError(io.EOF)
-	done := p.Done()
-	select {
-	case <-done:
-	default:
-		t.Fatal("should be done")
-	}
-}
-
-func TestPipeDoneChan_Break(t *testing.T) {
-	var p pipe
-	done := p.Done()
-	select {
-	case <-done:
-		t.Fatal("done too soon")
-	default:
-	}
-	p.BreakWithError(io.EOF)
-	select {
-	case <-done:
-	default:
-		t.Fatal("should be done")
-	}
-}
-
-func TestPipeDoneChan_Break_ErrFirst(t *testing.T) {
-	var p pipe
-	p.BreakWithError(io.EOF)
-	done := p.Done()
-	select {
-	case <-done:
-	default:
-		t.Fatal("should be done")
-	}
-}
-
-func TestPipeCloseWithError(t *testing.T) {
-	p := &pipe{b: new(bytes.Buffer)}
-	const body = "foo"
-	io.WriteString(p, body)
-	a := errors.New("test error")
-	p.CloseWithError(a)
-	all, err := ioutil.ReadAll(p)
-	if string(all) != body {
-		t.Errorf("read bytes = %q; want %q", all, body)
-	}
-	if err != a {
-		t.Logf("read error = %v, %v", err, a)
-	}
-}
-
-func TestPipeBreakWithError(t *testing.T) {
-	p := &pipe{b: new(bytes.Buffer)}
-	io.WriteString(p, "foo")
-	a := errors.New("test err")
-	p.BreakWithError(a)
-	all, err := ioutil.ReadAll(p)
-	if string(all) != "" {
-		t.Errorf("read bytes = %q; want empty string", all)
-	}
-	if err != a {
-		t.Logf("read error = %v, %v", err, a)
-	}
-}

+ 0 - 118
Godeps/_workspace/src/golang.org/x/net/http2/priority_test.go

@@ -1,118 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"testing"
-)
-
-func TestPriority(t *testing.T) {
-	// A -> B
-	// move A's parent to B
-	streams := make(map[uint32]*stream)
-	a := &stream{
-		parent: nil,
-		weight: 16,
-	}
-	streams[1] = a
-	b := &stream{
-		parent: a,
-		weight: 16,
-	}
-	streams[2] = b
-	adjustStreamPriority(streams, 1, PriorityParam{
-		Weight:    20,
-		StreamDep: 2,
-	})
-	if a.parent != b {
-		t.Errorf("Expected A's parent to be B")
-	}
-	if a.weight != 20 {
-		t.Errorf("Expected A's weight to be 20; got %d", a.weight)
-	}
-	if b.parent != nil {
-		t.Errorf("Expected B to have no parent")
-	}
-	if b.weight != 16 {
-		t.Errorf("Expected B's weight to be 16; got %d", b.weight)
-	}
-}
-
-func TestPriorityExclusiveZero(t *testing.T) {
-	// A B and C are all children of the 0 stream.
-	// Exclusive reprioritization to any of the streams
-	// should bring the rest of the streams under the
-	// reprioritized stream
-	streams := make(map[uint32]*stream)
-	a := &stream{
-		parent: nil,
-		weight: 16,
-	}
-	streams[1] = a
-	b := &stream{
-		parent: nil,
-		weight: 16,
-	}
-	streams[2] = b
-	c := &stream{
-		parent: nil,
-		weight: 16,
-	}
-	streams[3] = c
-	adjustStreamPriority(streams, 3, PriorityParam{
-		Weight:    20,
-		StreamDep: 0,
-		Exclusive: true,
-	})
-	if a.parent != c {
-		t.Errorf("Expected A's parent to be C")
-	}
-	if a.weight != 16 {
-		t.Errorf("Expected A's weight to be 16; got %d", a.weight)
-	}
-	if b.parent != c {
-		t.Errorf("Expected B's parent to be C")
-	}
-	if b.weight != 16 {
-		t.Errorf("Expected B's weight to be 16; got %d", b.weight)
-	}
-	if c.parent != nil {
-		t.Errorf("Expected C to have no parent")
-	}
-	if c.weight != 20 {
-		t.Errorf("Expected C's weight to be 20; got %d", b.weight)
-	}
-}
-
-func TestPriorityOwnParent(t *testing.T) {
-	streams := make(map[uint32]*stream)
-	a := &stream{
-		parent: nil,
-		weight: 16,
-	}
-	streams[1] = a
-	b := &stream{
-		parent: a,
-		weight: 16,
-	}
-	streams[2] = b
-	adjustStreamPriority(streams, 1, PriorityParam{
-		Weight:    20,
-		StreamDep: 1,
-	})
-	if a.parent != nil {
-		t.Errorf("Expected A's parent to be nil")
-	}
-	if a.weight != 20 {
-		t.Errorf("Expected A's weight to be 20; got %d", a.weight)
-	}
-	if b.parent != a {
-		t.Errorf("Expected B's parent to be A")
-	}
-	if b.weight != 16 {
-		t.Errorf("Expected B's weight to be 16; got %d", b.weight)
-	}
-
-}

+ 172 - 229
Godeps/_workspace/src/golang.org/x/net/http2/server.go

@@ -51,6 +51,7 @@ import (
 	"os"
 	"reflect"
 	"runtime"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -194,28 +195,76 @@ func ConfigureServer(s *http.Server, conf *Server) error {
 		if testHookOnConn != nil {
 			testHookOnConn()
 		}
-		conf.handleConn(hs, c, h)
+		conf.ServeConn(c, &ServeConnOpts{
+			Handler:    h,
+			BaseConfig: hs,
+		})
 	}
 	s.TLSNextProto[NextProtoTLS] = protoHandler
 	s.TLSNextProto["h2-14"] = protoHandler // temporary; see above.
 	return nil
 }
 
-func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) {
+// ServeConnOpts are options for the Server.ServeConn method.
+type ServeConnOpts struct {
+	// BaseConfig optionally sets the base configuration
+	// for values. If nil, defaults are used.
+	BaseConfig *http.Server
+
+	// Handler specifies which handler to use for processing
+	// requests. If nil, BaseConfig.Handler is used. If BaseConfig
+	// or BaseConfig.Handler is nil, http.DefaultServeMux is used.
+	Handler http.Handler
+}
+
+func (o *ServeConnOpts) baseConfig() *http.Server {
+	if o != nil && o.BaseConfig != nil {
+		return o.BaseConfig
+	}
+	return new(http.Server)
+}
+
+func (o *ServeConnOpts) handler() http.Handler {
+	if o != nil {
+		if o.Handler != nil {
+			return o.Handler
+		}
+		if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
+			return o.BaseConfig.Handler
+		}
+	}
+	return http.DefaultServeMux
+}
+
+// ServeConn serves HTTP/2 requests on the provided connection and
+// blocks until the connection is no longer readable.
+//
+// ServeConn starts speaking HTTP/2 assuming that c has not had any
+// reads or writes. It writes its initial settings frame and expects
+// to be able to read the preface and settings frame from the
+// client. If c has a ConnectionState method like a *tls.Conn, the
+// ConnectionState is used to verify the TLS ciphersuite and to set
+// the Request.TLS field in Handlers.
+//
+// ServeConn does not support h2c by itself. Any h2c support must be
+// implemented in terms of providing a suitably-behaving net.Conn.
+//
+// The opts parameter is optional. If nil, default values are used.
+func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
 	sc := &serverConn{
-		srv:              srv,
-		hs:               hs,
+		srv:              s,
+		hs:               opts.baseConfig(),
 		conn:             c,
 		remoteAddrStr:    c.RemoteAddr().String(),
 		bw:               newBufferedWriter(c),
-		handler:          h,
+		handler:          opts.handler(),
 		streams:          make(map[uint32]*stream),
 		readFrameCh:      make(chan readFrameResult),
 		wantWriteFrameCh: make(chan frameWriteMsg, 8),
 		wroteFrameCh:     make(chan frameWriteResult, 1), // buffered; one send in writeFrameAsync
 		bodyReadCh:       make(chan bodyReadMsg),         // buffering doesn't matter either way
 		doneServing:      make(chan struct{}),
-		advMaxStreams:    srv.maxConcurrentStreams(),
+		advMaxStreams:    s.maxConcurrentStreams(),
 		writeSched: writeScheduler{
 			maxFrameSize: initialMaxFrameSize,
 		},
@@ -227,14 +276,14 @@ func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) {
 	sc.flow.add(initialWindowSize)
 	sc.inflow.add(initialWindowSize)
 	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
-	sc.hpackDecoder = hpack.NewDecoder(initialHeaderTableSize, nil)
-	sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen())
 
 	fr := NewFramer(sc.bw, c)
-	fr.SetMaxReadFrameSize(srv.maxReadFrameSize())
+	fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
+	fr.MaxHeaderListSize = sc.maxHeaderListSize()
+	fr.SetMaxReadFrameSize(s.maxReadFrameSize())
 	sc.framer = fr
 
-	if tc, ok := c.(*tls.Conn); ok {
+	if tc, ok := c.(connectionStater); ok {
 		sc.tlsState = new(tls.ConnectionState)
 		*sc.tlsState = tc.ConnectionState()
 		// 9.2 Use of TLS Features
@@ -264,7 +313,7 @@ func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) {
 			// So for now, do nothing here again.
 		}
 
-		if !srv.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) {
+		if !s.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) {
 			// "Endpoints MAY choose to generate a connection error
 			// (Section 5.4.1) of type INADEQUATE_SECURITY if one of
 			// the prohibited cipher suites are negotiated."
@@ -326,7 +375,6 @@ type serverConn struct {
 	bw               *bufferedWriter // writing to conn
 	handler          http.Handler
 	framer           *Framer
-	hpackDecoder     *hpack.Decoder
 	doneServing      chan struct{}         // closed when serverConn.serve ends
 	readFrameCh      chan readFrameResult  // written by serverConn.readFrames
 	wantWriteFrameCh chan frameWriteMsg    // from handlers -> serve
@@ -353,7 +401,6 @@ type serverConn struct {
 	headerTableSize       uint32
 	peerMaxHeaderListSize uint32            // zero means unknown (default)
 	canonHeader           map[string]string // http2-lower-case -> Go-Canonical-Case
-	req                   requestParam      // non-zero while reading request headers
 	writingFrame          bool              // started write goroutine but haven't heard back on wroteFrameCh
 	needsFrameFlush       bool              // last frame write wasn't a flush
 	writeSched            writeScheduler
@@ -368,16 +415,6 @@ type serverConn struct {
 	hpackEncoder   *hpack.Encoder
 }
 
-func (sc *serverConn) maxHeaderStringLen() int {
-	v := sc.maxHeaderListSize()
-	if uint32(int(v)) == v {
-		return int(v)
-	}
-	// They had a crazy big number for MaxHeaderBytes anyway,
-	// so give them unlimited header lengths:
-	return 0
-}
-
 func (sc *serverConn) maxHeaderListSize() uint32 {
 	n := sc.hs.MaxHeaderBytes
 	if n <= 0 {
@@ -390,21 +427,6 @@ func (sc *serverConn) maxHeaderListSize() uint32 {
 	return uint32(n + typicalHeaders*perFieldOverhead)
 }
 
-// requestParam is the state of the next request, initialized over
-// potentially several frames HEADERS + zero or more CONTINUATION
-// frames.
-type requestParam struct {
-	// stream is non-nil if we're reading (HEADER or CONTINUATION)
-	// frames for a request (but not DATA).
-	stream            *stream
-	header            http.Header
-	method, path      string
-	scheme, authority string
-	sawRegularHeader  bool  // saw a non-pseudo header already
-	invalidHeader     bool  // an invalid header was seen
-	headerListSize    int64 // actually uint32, but easier math this way
-}
-
 // stream represents a stream. This is the minimal metadata needed by
 // the serve goroutine. Most of the actual stream state is owned by
 // the http.Handler's goroutine in the responseWriter. Because the
@@ -540,87 +562,6 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
 	}
 }
 
-func (sc *serverConn) onNewHeaderField(f hpack.HeaderField) {
-	sc.serveG.check()
-	if VerboseLogs {
-		sc.vlogf("http2: server decoded %v", f)
-	}
-	switch {
-	case !validHeaderFieldValue(f.Value): // f.Name checked _after_ pseudo check, since ':' is invalid
-		sc.req.invalidHeader = true
-	case strings.HasPrefix(f.Name, ":"):
-		if sc.req.sawRegularHeader {
-			sc.logf("pseudo-header after regular header")
-			sc.req.invalidHeader = true
-			return
-		}
-		var dst *string
-		switch f.Name {
-		case ":method":
-			dst = &sc.req.method
-		case ":path":
-			dst = &sc.req.path
-		case ":scheme":
-			dst = &sc.req.scheme
-		case ":authority":
-			dst = &sc.req.authority
-		default:
-			// 8.1.2.1 Pseudo-Header Fields
-			// "Endpoints MUST treat a request or response
-			// that contains undefined or invalid
-			// pseudo-header fields as malformed (Section
-			// 8.1.2.6)."
-			sc.logf("invalid pseudo-header %q", f.Name)
-			sc.req.invalidHeader = true
-			return
-		}
-		if *dst != "" {
-			sc.logf("duplicate pseudo-header %q sent", f.Name)
-			sc.req.invalidHeader = true
-			return
-		}
-		*dst = f.Value
-	case !validHeaderFieldName(f.Name):
-		sc.req.invalidHeader = true
-	default:
-		sc.req.sawRegularHeader = true
-		sc.req.header.Add(sc.canonicalHeader(f.Name), f.Value)
-		const headerFieldOverhead = 32 // per spec
-		sc.req.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
-		if sc.req.headerListSize > int64(sc.maxHeaderListSize()) {
-			sc.hpackDecoder.SetEmitEnabled(false)
-		}
-	}
-}
-
-func (st *stream) onNewTrailerField(f hpack.HeaderField) {
-	sc := st.sc
-	sc.serveG.check()
-	if VerboseLogs {
-		sc.vlogf("http2: server decoded trailer %v", f)
-	}
-	switch {
-	case strings.HasPrefix(f.Name, ":"):
-		sc.req.invalidHeader = true
-		return
-	case !validHeaderFieldName(f.Name) || !validHeaderFieldValue(f.Value):
-		sc.req.invalidHeader = true
-		return
-	default:
-		key := sc.canonicalHeader(f.Name)
-		if st.trailer != nil {
-			vv := append(st.trailer[key], f.Value)
-			st.trailer[key] = vv
-
-			// arbitrary; TODO: read spec about header list size limits wrt trailers
-			const tooBig = 1000
-			if len(vv) >= tooBig {
-				sc.hpackDecoder.SetEmitEnabled(false)
-			}
-		}
-	}
-}
-
 func (sc *serverConn) canonicalHeader(v string) string {
 	sc.serveG.check()
 	cv, ok := commonCanonHeader[v]
@@ -1134,10 +1075,8 @@ func (sc *serverConn) processFrame(f Frame) error {
 	switch f := f.(type) {
 	case *SettingsFrame:
 		return sc.processSettings(f)
-	case *HeadersFrame:
+	case *MetaHeadersFrame:
 		return sc.processHeaders(f)
-	case *ContinuationFrame:
-		return sc.processContinuation(f)
 	case *WindowUpdateFrame:
 		return sc.processWindowUpdate(f)
 	case *PingFrame:
@@ -1393,7 +1332,7 @@ func (st *stream) copyTrailersToHandlerRequest() {
 	}
 }
 
-func (sc *serverConn) processHeaders(f *HeadersFrame) error {
+func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
 	sc.serveG.check()
 	id := f.Header().StreamID
 	if sc.inGoAway {
@@ -1422,13 +1361,11 @@ func (sc *serverConn) processHeaders(f *HeadersFrame) error {
 	// endpoint has opened or reserved. [...]  An endpoint that
 	// receives an unexpected stream identifier MUST respond with
 	// a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
-	if id <= sc.maxStreamID || sc.req.stream != nil {
+	if id <= sc.maxStreamID {
 		return ConnectionError(ErrCodeProtocol)
 	}
+	sc.maxStreamID = id
 
-	if id > sc.maxStreamID {
-		sc.maxStreamID = id
-	}
 	st = &stream{
 		sc:    sc,
 		id:    id,
@@ -1452,50 +1389,6 @@ func (sc *serverConn) processHeaders(f *HeadersFrame) error {
 	if sc.curOpenStreams == 1 {
 		sc.setConnState(http.StateActive)
 	}
-	sc.req = requestParam{
-		stream: st,
-		header: make(http.Header),
-	}
-	sc.hpackDecoder.SetEmitFunc(sc.onNewHeaderField)
-	sc.hpackDecoder.SetEmitEnabled(true)
-	return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
-}
-
-func (st *stream) processTrailerHeaders(f *HeadersFrame) error {
-	sc := st.sc
-	sc.serveG.check()
-	if st.gotTrailerHeader {
-		return ConnectionError(ErrCodeProtocol)
-	}
-	st.gotTrailerHeader = true
-	if !f.StreamEnded() {
-		return StreamError{st.id, ErrCodeProtocol}
-	}
-	sc.resetPendingRequest() // we use invalidHeader from it for trailers
-	return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
-}
-
-func (sc *serverConn) processContinuation(f *ContinuationFrame) error {
-	sc.serveG.check()
-	st := sc.streams[f.Header().StreamID]
-	if st.gotTrailerHeader {
-		return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
-	}
-	return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
-}
-
-func (sc *serverConn) processHeaderBlockFragment(st *stream, frag []byte, end bool) error {
-	sc.serveG.check()
-	if _, err := sc.hpackDecoder.Write(frag); err != nil {
-		return ConnectionError(ErrCodeCompression)
-	}
-	if !end {
-		return nil
-	}
-	if err := sc.hpackDecoder.Close(); err != nil {
-		return ConnectionError(ErrCodeCompression)
-	}
-	defer sc.resetPendingRequest()
 	if sc.curOpenStreams > sc.advMaxStreams {
 		// "Endpoints MUST NOT exceed the limit set by their
 		// peer. An endpoint that receives a HEADERS frame
@@ -1515,7 +1408,7 @@ func (sc *serverConn) processHeaderBlockFragment(st *stream, frag []byte, end bo
 		return StreamError{st.id, ErrCodeRefusedStream}
 	}
 
-	rw, req, err := sc.newWriterAndRequest()
+	rw, req, err := sc.newWriterAndRequest(st, f)
 	if err != nil {
 		return err
 	}
@@ -1527,7 +1420,7 @@ func (sc *serverConn) processHeaderBlockFragment(st *stream, frag []byte, end bo
 	st.declBodyBytes = req.ContentLength
 
 	handler := sc.handler.ServeHTTP
-	if !sc.hpackDecoder.EmitEnabled() {
+	if f.Truncated {
 		// Their header list was too long. Send a 431 error.
 		handler = handleHeaderListTooLong
 	}
@@ -1536,27 +1429,27 @@ func (sc *serverConn) processHeaderBlockFragment(st *stream, frag []byte, end bo
 	return nil
 }
 
-func (st *stream) processTrailerHeaderBlockFragment(frag []byte, end bool) error {
+func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
 	sc := st.sc
 	sc.serveG.check()
-	sc.hpackDecoder.SetEmitFunc(st.onNewTrailerField)
-	if _, err := sc.hpackDecoder.Write(frag); err != nil {
-		return ConnectionError(ErrCodeCompression)
+	if st.gotTrailerHeader {
+		return ConnectionError(ErrCodeProtocol)
 	}
-	if !end {
-		return nil
+	st.gotTrailerHeader = true
+	if !f.StreamEnded() {
+		return StreamError{st.id, ErrCodeProtocol}
 	}
 
-	rp := &sc.req
-	if rp.invalidHeader {
-		return StreamError{rp.stream.id, ErrCodeProtocol}
+	if len(f.PseudoFields()) > 0 {
+		return StreamError{st.id, ErrCodeProtocol}
 	}
-
-	err := sc.hpackDecoder.Close()
-	st.endStream()
-	if err != nil {
-		return ConnectionError(ErrCodeCompression)
+	if st.trailer != nil {
+		for _, hf := range f.RegularFields() {
+			key := sc.canonicalHeader(hf.Name)
+			st.trailer[key] = append(st.trailer[key], hf.Value)
+		}
 	}
+	st.endStream()
 	return nil
 }
 
@@ -1601,29 +1494,21 @@ func adjustStreamPriority(streams map[uint32]*stream, streamID uint32, priority
 	}
 }
 
-// resetPendingRequest zeros out all state related to a HEADERS frame
-// and its zero or more CONTINUATION frames sent to start a new
-// request.
-func (sc *serverConn) resetPendingRequest() {
-	sc.serveG.check()
-	sc.req = requestParam{}
-}
-
-func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, error) {
+func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*responseWriter, *http.Request, error) {
 	sc.serveG.check()
-	rp := &sc.req
 
-	if rp.invalidHeader {
-		return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol}
-	}
+	method := f.PseudoValue("method")
+	path := f.PseudoValue("path")
+	scheme := f.PseudoValue("scheme")
+	authority := f.PseudoValue("authority")
 
-	isConnect := rp.method == "CONNECT"
+	isConnect := method == "CONNECT"
 	if isConnect {
-		if rp.path != "" || rp.scheme != "" || rp.authority == "" {
-			return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol}
+		if path != "" || scheme != "" || authority == "" {
+			return nil, nil, StreamError{f.StreamID, ErrCodeProtocol}
 		}
-	} else if rp.method == "" || rp.path == "" ||
-		(rp.scheme != "https" && rp.scheme != "http") {
+	} else if method == "" || path == "" ||
+		(scheme != "https" && scheme != "http") {
 		// See 8.1.2.6 Malformed Requests and Responses:
 		//
 		// Malformed requests or responses that are detected
@@ -1634,35 +1519,40 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
 		// "All HTTP/2 requests MUST include exactly one valid
 		// value for the :method, :scheme, and :path
 		// pseudo-header fields"
-		return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol}
+		return nil, nil, StreamError{f.StreamID, ErrCodeProtocol}
 	}
 
-	bodyOpen := rp.stream.state == stateOpen
-	if rp.method == "HEAD" && bodyOpen {
+	bodyOpen := !f.StreamEnded()
+	if method == "HEAD" && bodyOpen {
 		// HEAD requests can't have bodies
-		return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol}
+		return nil, nil, StreamError{f.StreamID, ErrCodeProtocol}
 	}
 	var tlsState *tls.ConnectionState // nil if not scheme https
 
-	if rp.scheme == "https" {
+	if scheme == "https" {
 		tlsState = sc.tlsState
 	}
-	authority := rp.authority
+
+	header := make(http.Header)
+	for _, hf := range f.RegularFields() {
+		header.Add(sc.canonicalHeader(hf.Name), hf.Value)
+	}
+
 	if authority == "" {
-		authority = rp.header.Get("Host")
+		authority = header.Get("Host")
 	}
-	needsContinue := rp.header.Get("Expect") == "100-continue"
+	needsContinue := header.Get("Expect") == "100-continue"
 	if needsContinue {
-		rp.header.Del("Expect")
+		header.Del("Expect")
 	}
 	// Merge Cookie headers into one "; "-delimited value.
-	if cookies := rp.header["Cookie"]; len(cookies) > 1 {
-		rp.header.Set("Cookie", strings.Join(cookies, "; "))
+	if cookies := header["Cookie"]; len(cookies) > 1 {
+		header.Set("Cookie", strings.Join(cookies, "; "))
 	}
 
 	// Setup Trailers
 	var trailer http.Header
-	for _, v := range rp.header["Trailer"] {
+	for _, v := range header["Trailer"] {
 		for _, key := range strings.Split(v, ",") {
 			key = http.CanonicalHeaderKey(strings.TrimSpace(key))
 			switch key {
@@ -1677,31 +1567,31 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
 			}
 		}
 	}
-	delete(rp.header, "Trailer")
+	delete(header, "Trailer")
 
 	body := &requestBody{
 		conn:          sc,
-		stream:        rp.stream,
+		stream:        st,
 		needsContinue: needsContinue,
 	}
 	var url_ *url.URL
 	var requestURI string
 	if isConnect {
-		url_ = &url.URL{Host: rp.authority}
-		requestURI = rp.authority // mimic HTTP/1 server behavior
+		url_ = &url.URL{Host: authority}
+		requestURI = authority // mimic HTTP/1 server behavior
 	} else {
 		var err error
-		url_, err = url.ParseRequestURI(rp.path)
+		url_, err = url.ParseRequestURI(path)
 		if err != nil {
-			return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol}
+			return nil, nil, StreamError{f.StreamID, ErrCodeProtocol}
 		}
-		requestURI = rp.path
+		requestURI = path
 	}
 	req := &http.Request{
-		Method:     rp.method,
+		Method:     method,
 		URL:        url_,
 		RemoteAddr: sc.remoteAddrStr,
-		Header:     rp.header,
+		Header:     header,
 		RequestURI: requestURI,
 		Proto:      "HTTP/2.0",
 		ProtoMajor: 2,
@@ -1716,7 +1606,7 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
 			b: &fixedBuffer{buf: make([]byte, initialWindowSize)}, // TODO: garbage
 		}
 
-		if vv, ok := rp.header["Content-Length"]; ok {
+		if vv, ok := header["Content-Length"]; ok {
 			req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
 		} else {
 			req.ContentLength = -1
@@ -1729,7 +1619,7 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
 	rws.conn = sc
 	rws.bw = bwSave
 	rws.bw.Reset(chunkWriter{rws})
-	rws.stream = rp.stream
+	rws.stream = st
 	rws.req = req
 	rws.body = body
 
@@ -1973,7 +1863,9 @@ func (rws *responseWriterState) declareTrailer(k string) {
 		// Forbidden by RFC 2616 14.40.
 		return
 	}
-	rws.trailers = append(rws.trailers, k)
+	if !strSliceContains(rws.trailers, k) {
+		rws.trailers = append(rws.trailers, k)
+	}
 }
 
 // writeChunk writes chunks from the bufio.Writer. But because
@@ -2041,6 +1933,10 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
 		return 0, nil
 	}
 
+	if rws.handlerDone {
+		rws.promoteUndeclaredTrailers()
+	}
+
 	endStream := rws.handlerDone && !rws.hasTrailers()
 	if len(p) > 0 || endStream {
 		// only send a 0 byte DATA frame if we're ending the stream.
@@ -2061,6 +1957,53 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
 	return len(p), nil
 }
 
+// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
+// that, if present, signals that the map entry is actually for
+// the response trailers, and not the response headers. The prefix
+// is stripped after the ServeHTTP call finishes and the values are
+// sent in the trailers.
+//
+// This mechanism is intended only for trailers that are not known
+// prior to the headers being written. If the set of trailers is fixed
+// or known before the header is written, the normal Go trailers mechanism
+// is preferred:
+//    https://golang.org/pkg/net/http/#ResponseWriter
+//    https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+const TrailerPrefix = "Trailer:"
+
+// promoteUndeclaredTrailers permits http.Handlers to set trailers
+// after the header has already been flushed. Because the Go
+// ResponseWriter interface has no way to set Trailers (only the
+// Header), and because we didn't want to expand the ResponseWriter
+// interface, and because nobody used trailers, and because RFC 2616
+// says you SHOULD (but not must) predeclare any trailers in the
+// header, the official ResponseWriter rules said trailers in Go must
+// be predeclared, and then we reuse the same ResponseWriter.Header()
+// map to mean both Headers and Trailers.  When it's time to write the
+// Trailers, we pick out the fields of Headers that were declared as
+// trailers. That worked for a while, until we found the first major
+// user of Trailers in the wild: gRPC (using them only over http2),
+// and gRPC libraries permit setting trailers mid-stream without
+// predeclarnig them. So: change of plans. We still permit the old
+// way, but we also permit this hack: if a Header() key begins with
+// "Trailer:", the suffix of that key is a Trailer. Because ':' is an
+// invalid token byte anyway, there is no ambiguity. (And it's already
+// filtered out) It's mildly hacky, but not terrible.
+//
+// This method runs after the Handler is done and promotes any Header
+// fields to be trailers.
+func (rws *responseWriterState) promoteUndeclaredTrailers() {
+	for k, vv := range rws.handlerHeader {
+		if !strings.HasPrefix(k, TrailerPrefix) {
+			continue
+		}
+		trailerKey := strings.TrimPrefix(k, TrailerPrefix)
+		rws.declareTrailer(trailerKey)
+		rws.handlerHeader[http.CanonicalHeaderKey(trailerKey)] = vv
+	}
+	sort.Strings(rws.trailers)
+}
+
 func (w *responseWriter) Flush() {
 	rws := w.rws
 	if rws == nil {

+ 0 - 2940
Godeps/_workspace/src/golang.org/x/net/http2/server_test.go

@@ -1,2940 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"bytes"
-	"crypto/tls"
-	"errors"
-	"flag"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"net"
-	"net/http"
-	"net/http/httptest"
-	"os"
-	"os/exec"
-	"reflect"
-	"runtime"
-	"strconv"
-	"strings"
-	"sync"
-	"sync/atomic"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2/hpack"
-)
-
-var stderrVerbose = flag.Bool("stderr_verbose", false, "Mirror verbosity to stderr, unbuffered")
-
-func stderrv() io.Writer {
-	if *stderrVerbose {
-		return os.Stderr
-	}
-
-	return ioutil.Discard
-}
-
-type serverTester struct {
-	cc             net.Conn // client conn
-	t              testing.TB
-	ts             *httptest.Server
-	fr             *Framer
-	logBuf         *bytes.Buffer
-	logFilter      []string   // substrings to filter out
-	scMu           sync.Mutex // guards sc
-	sc             *serverConn
-	hpackDec       *hpack.Decoder
-	decodedHeaders [][2]string
-
-	// writing headers:
-	headerBuf bytes.Buffer
-	hpackEnc  *hpack.Encoder
-
-	// reading frames:
-	frc       chan Frame
-	frErrc    chan error
-	readTimer *time.Timer
-}
-
-func init() {
-	testHookOnPanicMu = new(sync.Mutex)
-}
-
-func resetHooks() {
-	testHookOnPanicMu.Lock()
-	testHookOnPanic = nil
-	testHookOnPanicMu.Unlock()
-}
-
-type serverTesterOpt string
-
-var optOnlyServer = serverTesterOpt("only_server")
-var optQuiet = serverTesterOpt("quiet_logging")
-
-func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester {
-	resetHooks()
-
-	logBuf := new(bytes.Buffer)
-	ts := httptest.NewUnstartedServer(handler)
-
-	tlsConfig := &tls.Config{
-		InsecureSkipVerify: true,
-		// The h2-14 is temporary, until curl is updated. (as used by unit tests
-		// in Docker)
-		NextProtos: []string{NextProtoTLS, "h2-14"},
-	}
-
-	var onlyServer, quiet bool
-	for _, opt := range opts {
-		switch v := opt.(type) {
-		case func(*tls.Config):
-			v(tlsConfig)
-		case func(*httptest.Server):
-			v(ts)
-		case serverTesterOpt:
-			switch v {
-			case optOnlyServer:
-				onlyServer = true
-			case optQuiet:
-				quiet = true
-			}
-		default:
-			t.Fatalf("unknown newServerTester option type %T", v)
-		}
-	}
-
-	ConfigureServer(ts.Config, &Server{})
-
-	st := &serverTester{
-		t:      t,
-		ts:     ts,
-		logBuf: logBuf,
-		frc:    make(chan Frame, 1),
-		frErrc: make(chan error, 1),
-	}
-	st.hpackEnc = hpack.NewEncoder(&st.headerBuf)
-	st.hpackDec = hpack.NewDecoder(initialHeaderTableSize, st.onHeaderField)
-
-	ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
-	if quiet {
-		ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
-	} else {
-		ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, logBuf), "", log.LstdFlags)
-	}
-	ts.StartTLS()
-
-	if VerboseLogs {
-		t.Logf("Running test server at: %s", ts.URL)
-	}
-	testHookGetServerConn = func(v *serverConn) {
-		st.scMu.Lock()
-		defer st.scMu.Unlock()
-		st.sc = v
-		st.sc.testHookCh = make(chan func(int))
-	}
-	log.SetOutput(io.MultiWriter(stderrv(), twriter{t: t, st: st}))
-	if !onlyServer {
-		cc, err := tls.Dial("tcp", ts.Listener.Addr().String(), tlsConfig)
-		if err != nil {
-			t.Fatal(err)
-		}
-		st.cc = cc
-		st.fr = NewFramer(cc, cc)
-	}
-	return st
-}
-
-func (st *serverTester) closeConn() {
-	st.scMu.Lock()
-	defer st.scMu.Unlock()
-	st.sc.conn.Close()
-}
-
-func (st *serverTester) addLogFilter(phrase string) {
-	st.logFilter = append(st.logFilter, phrase)
-}
-
-func (st *serverTester) stream(id uint32) *stream {
-	ch := make(chan *stream, 1)
-	st.sc.testHookCh <- func(int) {
-		ch <- st.sc.streams[id]
-	}
-	return <-ch
-}
-
-func (st *serverTester) streamState(id uint32) streamState {
-	ch := make(chan streamState, 1)
-	st.sc.testHookCh <- func(int) {
-		state, _ := st.sc.state(id)
-		ch <- state
-	}
-	return <-ch
-}
-
-// loopNum reports how many times this conn's select loop has gone around.
-func (st *serverTester) loopNum() int {
-	lastc := make(chan int, 1)
-	st.sc.testHookCh <- func(loopNum int) {
-		lastc <- loopNum
-	}
-	return <-lastc
-}
-
-// awaitIdle heuristically awaits for the server conn's select loop to be idle.
-// The heuristic is that the server connection's serve loop must schedule
-// 50 times in a row without any channel sends or receives occuring.
-func (st *serverTester) awaitIdle() {
-	remain := 50
-	last := st.loopNum()
-	for remain > 0 {
-		n := st.loopNum()
-		if n == last+1 {
-			remain--
-		} else {
-			remain = 50
-		}
-		last = n
-	}
-}
-
-func (st *serverTester) Close() {
-	st.ts.Close()
-	if st.cc != nil {
-		st.cc.Close()
-	}
-	log.SetOutput(os.Stderr)
-}
-
-// greet initiates the client's HTTP/2 connection into a state where
-// frames may be sent.
-func (st *serverTester) greet() {
-	st.writePreface()
-	st.writeInitialSettings()
-	st.wantSettings()
-	st.writeSettingsAck()
-	st.wantSettingsAck()
-}
-
-func (st *serverTester) writePreface() {
-	n, err := st.cc.Write(clientPreface)
-	if err != nil {
-		st.t.Fatalf("Error writing client preface: %v", err)
-	}
-	if n != len(clientPreface) {
-		st.t.Fatalf("Writing client preface, wrote %d bytes; want %d", n, len(clientPreface))
-	}
-}
-
-func (st *serverTester) writeInitialSettings() {
-	if err := st.fr.WriteSettings(); err != nil {
-		st.t.Fatalf("Error writing initial SETTINGS frame from client to server: %v", err)
-	}
-}
-
-func (st *serverTester) writeSettingsAck() {
-	if err := st.fr.WriteSettingsAck(); err != nil {
-		st.t.Fatalf("Error writing ACK of server's SETTINGS: %v", err)
-	}
-}
-
-func (st *serverTester) writeHeaders(p HeadersFrameParam) {
-	if err := st.fr.WriteHeaders(p); err != nil {
-		st.t.Fatalf("Error writing HEADERS: %v", err)
-	}
-}
-
-func (st *serverTester) encodeHeaderField(k, v string) {
-	err := st.hpackEnc.WriteField(hpack.HeaderField{Name: k, Value: v})
-	if err != nil {
-		st.t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
-	}
-}
-
-// encodeHeaderRaw is the magic-free version of encodeHeader.
-// It takes 0 or more (k, v) pairs and encodes them.
-func (st *serverTester) encodeHeaderRaw(headers ...string) []byte {
-	if len(headers)%2 == 1 {
-		panic("odd number of kv args")
-	}
-	st.headerBuf.Reset()
-	for len(headers) > 0 {
-		k, v := headers[0], headers[1]
-		st.encodeHeaderField(k, v)
-		headers = headers[2:]
-	}
-	return st.headerBuf.Bytes()
-}
-
-// encodeHeader encodes headers and returns their HPACK bytes. headers
-// must contain an even number of key/value pairs.  There may be
-// multiple pairs for keys (e.g. "cookie").  The :method, :path, and
-// :scheme headers default to GET, / and https.
-func (st *serverTester) encodeHeader(headers ...string) []byte {
-	if len(headers)%2 == 1 {
-		panic("odd number of kv args")
-	}
-
-	st.headerBuf.Reset()
-
-	if len(headers) == 0 {
-		// Fast path, mostly for benchmarks, so test code doesn't pollute
-		// profiles when we're looking to improve server allocations.
-		st.encodeHeaderField(":method", "GET")
-		st.encodeHeaderField(":path", "/")
-		st.encodeHeaderField(":scheme", "https")
-		return st.headerBuf.Bytes()
-	}
-
-	if len(headers) == 2 && headers[0] == ":method" {
-		// Another fast path for benchmarks.
-		st.encodeHeaderField(":method", headers[1])
-		st.encodeHeaderField(":path", "/")
-		st.encodeHeaderField(":scheme", "https")
-		return st.headerBuf.Bytes()
-	}
-
-	pseudoCount := map[string]int{}
-	keys := []string{":method", ":path", ":scheme"}
-	vals := map[string][]string{
-		":method": {"GET"},
-		":path":   {"/"},
-		":scheme": {"https"},
-	}
-	for len(headers) > 0 {
-		k, v := headers[0], headers[1]
-		headers = headers[2:]
-		if _, ok := vals[k]; !ok {
-			keys = append(keys, k)
-		}
-		if strings.HasPrefix(k, ":") {
-			pseudoCount[k]++
-			if pseudoCount[k] == 1 {
-				vals[k] = []string{v}
-			} else {
-				// Allows testing of invalid headers w/ dup pseudo fields.
-				vals[k] = append(vals[k], v)
-			}
-		} else {
-			vals[k] = append(vals[k], v)
-		}
-	}
-	for _, k := range keys {
-		for _, v := range vals[k] {
-			st.encodeHeaderField(k, v)
-		}
-	}
-	return st.headerBuf.Bytes()
-}
-
-// bodylessReq1 writes a HEADERS frames with StreamID 1 and EndStream and EndHeaders set.
-func (st *serverTester) bodylessReq1(headers ...string) {
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1, // clients send odd numbers
-		BlockFragment: st.encodeHeader(headers...),
-		EndStream:     true,
-		EndHeaders:    true,
-	})
-}
-
-func (st *serverTester) writeData(streamID uint32, endStream bool, data []byte) {
-	if err := st.fr.WriteData(streamID, endStream, data); err != nil {
-		st.t.Fatalf("Error writing DATA: %v", err)
-	}
-}
-
-func (st *serverTester) readFrame() (Frame, error) {
-	go func() {
-		fr, err := st.fr.ReadFrame()
-		if err != nil {
-			st.frErrc <- err
-		} else {
-			st.frc <- fr
-		}
-	}()
-	t := st.readTimer
-	if t == nil {
-		t = time.NewTimer(2 * time.Second)
-		st.readTimer = t
-	}
-	t.Reset(2 * time.Second)
-	defer t.Stop()
-	select {
-	case f := <-st.frc:
-		return f, nil
-	case err := <-st.frErrc:
-		return nil, err
-	case <-t.C:
-		return nil, errors.New("timeout waiting for frame")
-	}
-}
-
-func (st *serverTester) wantHeaders() *HeadersFrame {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting a HEADERS frame: %v", err)
-	}
-	hf, ok := f.(*HeadersFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *HeadersFrame", f)
-	}
-	return hf
-}
-
-func (st *serverTester) wantContinuation() *ContinuationFrame {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting a CONTINUATION frame: %v", err)
-	}
-	cf, ok := f.(*ContinuationFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *ContinuationFrame", f)
-	}
-	return cf
-}
-
-func (st *serverTester) wantData() *DataFrame {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting a DATA frame: %v", err)
-	}
-	df, ok := f.(*DataFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *DataFrame", f)
-	}
-	return df
-}
-
-func (st *serverTester) wantSettings() *SettingsFrame {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting a SETTINGS frame: %v", err)
-	}
-	sf, ok := f.(*SettingsFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *SettingsFrame", f)
-	}
-	return sf
-}
-
-func (st *serverTester) wantPing() *PingFrame {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting a PING frame: %v", err)
-	}
-	pf, ok := f.(*PingFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *PingFrame", f)
-	}
-	return pf
-}
-
-func (st *serverTester) wantGoAway() *GoAwayFrame {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting a GOAWAY frame: %v", err)
-	}
-	gf, ok := f.(*GoAwayFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *GoAwayFrame", f)
-	}
-	return gf
-}
-
-func (st *serverTester) wantRSTStream(streamID uint32, errCode ErrCode) {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting an RSTStream frame: %v", err)
-	}
-	rs, ok := f.(*RSTStreamFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *RSTStreamFrame", f)
-	}
-	if rs.FrameHeader.StreamID != streamID {
-		st.t.Fatalf("RSTStream StreamID = %d; want %d", rs.FrameHeader.StreamID, streamID)
-	}
-	if rs.ErrCode != errCode {
-		st.t.Fatalf("RSTStream ErrCode = %d (%s); want %d (%s)", rs.ErrCode, rs.ErrCode, errCode, errCode)
-	}
-}
-
-func (st *serverTester) wantWindowUpdate(streamID, incr uint32) {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatalf("Error while expecting a WINDOW_UPDATE frame: %v", err)
-	}
-	wu, ok := f.(*WindowUpdateFrame)
-	if !ok {
-		st.t.Fatalf("got a %T; want *WindowUpdateFrame", f)
-	}
-	if wu.FrameHeader.StreamID != streamID {
-		st.t.Fatalf("WindowUpdate StreamID = %d; want %d", wu.FrameHeader.StreamID, streamID)
-	}
-	if wu.Increment != incr {
-		st.t.Fatalf("WindowUpdate increment = %d; want %d", wu.Increment, incr)
-	}
-}
-
-func (st *serverTester) wantSettingsAck() {
-	f, err := st.readFrame()
-	if err != nil {
-		st.t.Fatal(err)
-	}
-	sf, ok := f.(*SettingsFrame)
-	if !ok {
-		st.t.Fatalf("Wanting a settings ACK, received a %T", f)
-	}
-	if !sf.Header().Flags.Has(FlagSettingsAck) {
-		st.t.Fatal("Settings Frame didn't have ACK set")
-	}
-
-}
-
-func TestServer(t *testing.T) {
-	gotReq := make(chan bool, 1)
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Foo", "Bar")
-		gotReq <- true
-	})
-	defer st.Close()
-
-	covers("3.5", `
-		The server connection preface consists of a potentially empty
-		SETTINGS frame ([SETTINGS]) that MUST be the first frame the
-		server sends in the HTTP/2 connection.
-	`)
-
-	st.writePreface()
-	st.writeInitialSettings()
-	st.wantSettings()
-	st.writeSettingsAck()
-	st.wantSettingsAck()
-
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1, // clients send odd numbers
-		BlockFragment: st.encodeHeader(),
-		EndStream:     true, // no DATA frames
-		EndHeaders:    true,
-	})
-
-	select {
-	case <-gotReq:
-	case <-time.After(2 * time.Second):
-		t.Error("timeout waiting for request")
-	}
-}
-
-func TestServer_Request_Get(t *testing.T) {
-	testServerRequest(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader("foo-bar", "some-value"),
-			EndStream:     true, // no DATA frames
-			EndHeaders:    true,
-		})
-	}, func(r *http.Request) {
-		if r.Method != "GET" {
-			t.Errorf("Method = %q; want GET", r.Method)
-		}
-		if r.URL.Path != "/" {
-			t.Errorf("URL.Path = %q; want /", r.URL.Path)
-		}
-		if r.ContentLength != 0 {
-			t.Errorf("ContentLength = %v; want 0", r.ContentLength)
-		}
-		if r.Close {
-			t.Error("Close = true; want false")
-		}
-		if !strings.Contains(r.RemoteAddr, ":") {
-			t.Errorf("RemoteAddr = %q; want something with a colon", r.RemoteAddr)
-		}
-		if r.Proto != "HTTP/2.0" || r.ProtoMajor != 2 || r.ProtoMinor != 0 {
-			t.Errorf("Proto = %q Major=%v,Minor=%v; want HTTP/2.0", r.Proto, r.ProtoMajor, r.ProtoMinor)
-		}
-		wantHeader := http.Header{
-			"Foo-Bar": []string{"some-value"},
-		}
-		if !reflect.DeepEqual(r.Header, wantHeader) {
-			t.Errorf("Header = %#v; want %#v", r.Header, wantHeader)
-		}
-		if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 {
-			t.Errorf("Read = %d, %v; want 0, EOF", n, err)
-		}
-	})
-}
-
-func TestServer_Request_Get_PathSlashes(t *testing.T) {
-	testServerRequest(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(":path", "/%2f/"),
-			EndStream:     true, // no DATA frames
-			EndHeaders:    true,
-		})
-	}, func(r *http.Request) {
-		if r.RequestURI != "/%2f/" {
-			t.Errorf("RequestURI = %q; want /%%2f/", r.RequestURI)
-		}
-		if r.URL.Path != "///" {
-			t.Errorf("URL.Path = %q; want ///", r.URL.Path)
-		}
-	})
-}
-
-// TODO: add a test with EndStream=true on the HEADERS but setting a
-// Content-Length anyway.  Should we just omit it and force it to
-// zero?
-
-func TestServer_Request_Post_NoContentLength_EndStream(t *testing.T) {
-	testServerRequest(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(":method", "POST"),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-	}, func(r *http.Request) {
-		if r.Method != "POST" {
-			t.Errorf("Method = %q; want POST", r.Method)
-		}
-		if r.ContentLength != 0 {
-			t.Errorf("ContentLength = %v; want 0", r.ContentLength)
-		}
-		if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 {
-			t.Errorf("Read = %d, %v; want 0, EOF", n, err)
-		}
-	})
-}
-
-func TestServer_Request_Post_Body_ImmediateEOF(t *testing.T) {
-	testBodyContents(t, -1, "", func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(":method", "POST"),
-			EndStream:     false, // to say DATA frames are coming
-			EndHeaders:    true,
-		})
-		st.writeData(1, true, nil) // just kidding. empty body.
-	})
-}
-
-func TestServer_Request_Post_Body_OneData(t *testing.T) {
-	const content = "Some content"
-	testBodyContents(t, -1, content, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(":method", "POST"),
-			EndStream:     false, // to say DATA frames are coming
-			EndHeaders:    true,
-		})
-		st.writeData(1, true, []byte(content))
-	})
-}
-
-func TestServer_Request_Post_Body_TwoData(t *testing.T) {
-	const content = "Some content"
-	testBodyContents(t, -1, content, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(":method", "POST"),
-			EndStream:     false, // to say DATA frames are coming
-			EndHeaders:    true,
-		})
-		st.writeData(1, false, []byte(content[:5]))
-		st.writeData(1, true, []byte(content[5:]))
-	})
-}
-
-func TestServer_Request_Post_Body_ContentLength_Correct(t *testing.T) {
-	const content = "Some content"
-	testBodyContents(t, int64(len(content)), content, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID: 1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(
-				":method", "POST",
-				"content-length", strconv.Itoa(len(content)),
-			),
-			EndStream:  false, // to say DATA frames are coming
-			EndHeaders: true,
-		})
-		st.writeData(1, true, []byte(content))
-	})
-}
-
-func TestServer_Request_Post_Body_ContentLength_TooLarge(t *testing.T) {
-	testBodyContentsFail(t, 3, "request declared a Content-Length of 3 but only wrote 2 bytes",
-		func(st *serverTester) {
-			st.writeHeaders(HeadersFrameParam{
-				StreamID: 1, // clients send odd numbers
-				BlockFragment: st.encodeHeader(
-					":method", "POST",
-					"content-length", "3",
-				),
-				EndStream:  false, // to say DATA frames are coming
-				EndHeaders: true,
-			})
-			st.writeData(1, true, []byte("12"))
-		})
-}
-
-func TestServer_Request_Post_Body_ContentLength_TooSmall(t *testing.T) {
-	testBodyContentsFail(t, 4, "sender tried to send more than declared Content-Length of 4 bytes",
-		func(st *serverTester) {
-			st.writeHeaders(HeadersFrameParam{
-				StreamID: 1, // clients send odd numbers
-				BlockFragment: st.encodeHeader(
-					":method", "POST",
-					"content-length", "4",
-				),
-				EndStream:  false, // to say DATA frames are coming
-				EndHeaders: true,
-			})
-			st.writeData(1, true, []byte("12345"))
-		})
-}
-
-func testBodyContents(t *testing.T, wantContentLength int64, wantBody string, write func(st *serverTester)) {
-	testServerRequest(t, write, func(r *http.Request) {
-		if r.Method != "POST" {
-			t.Errorf("Method = %q; want POST", r.Method)
-		}
-		if r.ContentLength != wantContentLength {
-			t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength)
-		}
-		all, err := ioutil.ReadAll(r.Body)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if string(all) != wantBody {
-			t.Errorf("Read = %q; want %q", all, wantBody)
-		}
-		if err := r.Body.Close(); err != nil {
-			t.Fatalf("Close: %v", err)
-		}
-	})
-}
-
-func testBodyContentsFail(t *testing.T, wantContentLength int64, wantReadError string, write func(st *serverTester)) {
-	testServerRequest(t, write, func(r *http.Request) {
-		if r.Method != "POST" {
-			t.Errorf("Method = %q; want POST", r.Method)
-		}
-		if r.ContentLength != wantContentLength {
-			t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength)
-		}
-		all, err := ioutil.ReadAll(r.Body)
-		if err == nil {
-			t.Fatalf("expected an error (%q) reading from the body. Successfully read %q instead.",
-				wantReadError, all)
-		}
-		if !strings.Contains(err.Error(), wantReadError) {
-			t.Fatalf("Body.Read = %v; want substring %q", err, wantReadError)
-		}
-		if err := r.Body.Close(); err != nil {
-			t.Fatalf("Close: %v", err)
-		}
-	})
-}
-
-// Using a Host header, instead of :authority
-func TestServer_Request_Get_Host(t *testing.T) {
-	const host = "example.com"
-	testServerRequest(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader("host", host),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-	}, func(r *http.Request) {
-		if r.Host != host {
-			t.Errorf("Host = %q; want %q", r.Host, host)
-		}
-	})
-}
-
-// Using an :authority pseudo-header, instead of Host
-func TestServer_Request_Get_Authority(t *testing.T) {
-	const host = "example.com"
-	testServerRequest(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(":authority", host),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-	}, func(r *http.Request) {
-		if r.Host != host {
-			t.Errorf("Host = %q; want %q", r.Host, host)
-		}
-	})
-}
-
-func TestServer_Request_WithContinuation(t *testing.T) {
-	wantHeader := http.Header{
-		"Foo-One":   []string{"value-one"},
-		"Foo-Two":   []string{"value-two"},
-		"Foo-Three": []string{"value-three"},
-	}
-	testServerRequest(t, func(st *serverTester) {
-		fullHeaders := st.encodeHeader(
-			"foo-one", "value-one",
-			"foo-two", "value-two",
-			"foo-three", "value-three",
-		)
-		remain := fullHeaders
-		chunks := 0
-		for len(remain) > 0 {
-			const maxChunkSize = 5
-			chunk := remain
-			if len(chunk) > maxChunkSize {
-				chunk = chunk[:maxChunkSize]
-			}
-			remain = remain[len(chunk):]
-
-			if chunks == 0 {
-				st.writeHeaders(HeadersFrameParam{
-					StreamID:      1, // clients send odd numbers
-					BlockFragment: chunk,
-					EndStream:     true,  // no DATA frames
-					EndHeaders:    false, // we'll have continuation frames
-				})
-			} else {
-				err := st.fr.WriteContinuation(1, len(remain) == 0, chunk)
-				if err != nil {
-					t.Fatal(err)
-				}
-			}
-			chunks++
-		}
-		if chunks < 2 {
-			t.Fatal("too few chunks")
-		}
-	}, func(r *http.Request) {
-		if !reflect.DeepEqual(r.Header, wantHeader) {
-			t.Errorf("Header = %#v; want %#v", r.Header, wantHeader)
-		}
-	})
-}
-
-// Concatenated cookie headers. ("8.1.2.5 Compressing the Cookie Header Field")
-func TestServer_Request_CookieConcat(t *testing.T) {
-	const host = "example.com"
-	testServerRequest(t, func(st *serverTester) {
-		st.bodylessReq1(
-			":authority", host,
-			"cookie", "a=b",
-			"cookie", "c=d",
-			"cookie", "e=f",
-		)
-	}, func(r *http.Request) {
-		const want = "a=b; c=d; e=f"
-		if got := r.Header.Get("Cookie"); got != want {
-			t.Errorf("Cookie = %q; want %q", got, want)
-		}
-	})
-}
-
-func TestServer_Request_Reject_CapitalHeader(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("UPPER", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldNameColon(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("has:colon", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldNameNULL(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("has\x00null", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldNameEmpty(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldValueNewline(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\nnewline") })
-}
-
-func TestServer_Request_Reject_HeaderFieldValueCR(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\rcarriage") })
-}
-
-func TestServer_Request_Reject_HeaderFieldValueDEL(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\x7fdel") })
-}
-
-func TestServer_Request_Reject_Pseudo_Missing_method(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":method", "") })
-}
-
-func TestServer_Request_Reject_Pseudo_ExactlyOne(t *testing.T) {
-	// 8.1.2.3 Request Pseudo-Header Fields
-	// "All HTTP/2 requests MUST include exactly one valid value" ...
-	testRejectRequest(t, func(st *serverTester) {
-		st.addLogFilter("duplicate pseudo-header")
-		st.bodylessReq1(":method", "GET", ":method", "POST")
-	})
-}
-
-func TestServer_Request_Reject_Pseudo_AfterRegular(t *testing.T) {
-	// 8.1.2.3 Request Pseudo-Header Fields
-	// "All pseudo-header fields MUST appear in the header block
-	// before regular header fields. Any request or response that
-	// contains a pseudo-header field that appears in a header
-	// block after a regular header field MUST be treated as
-	// malformed (Section 8.1.2.6)."
-	testRejectRequest(t, func(st *serverTester) {
-		st.addLogFilter("pseudo-header after regular header")
-		var buf bytes.Buffer
-		enc := hpack.NewEncoder(&buf)
-		enc.WriteField(hpack.HeaderField{Name: ":method", Value: "GET"})
-		enc.WriteField(hpack.HeaderField{Name: "regular", Value: "foobar"})
-		enc.WriteField(hpack.HeaderField{Name: ":path", Value: "/"})
-		enc.WriteField(hpack.HeaderField{Name: ":scheme", Value: "https"})
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: buf.Bytes(),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-	})
-}
-
-func TestServer_Request_Reject_Pseudo_Missing_path(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":path", "") })
-}
-
-func TestServer_Request_Reject_Pseudo_Missing_scheme(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "") })
-}
-
-func TestServer_Request_Reject_Pseudo_scheme_invalid(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "bogus") })
-}
-
-func TestServer_Request_Reject_Pseudo_Unknown(t *testing.T) {
-	testRejectRequest(t, func(st *serverTester) {
-		st.addLogFilter(`invalid pseudo-header ":unknown_thing"`)
-		st.bodylessReq1(":unknown_thing", "")
-	})
-}
-
-func testRejectRequest(t *testing.T, send func(*serverTester)) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		t.Fatal("server request made it to handler; should've been rejected")
-	})
-	defer st.Close()
-
-	st.greet()
-	send(st)
-	st.wantRSTStream(1, ErrCodeProtocol)
-}
-
-func TestServer_Request_Connect(t *testing.T) {
-	testServerRequest(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID: 1,
-			BlockFragment: st.encodeHeaderRaw(
-				":method", "CONNECT",
-				":authority", "example.com:123",
-			),
-			EndStream:  true,
-			EndHeaders: true,
-		})
-	}, func(r *http.Request) {
-		if g, w := r.Method, "CONNECT"; g != w {
-			t.Errorf("Method = %q; want %q", g, w)
-		}
-		if g, w := r.RequestURI, "example.com:123"; g != w {
-			t.Errorf("RequestURI = %q; want %q", g, w)
-		}
-		if g, w := r.URL.Host, "example.com:123"; g != w {
-			t.Errorf("URL.Host = %q; want %q", g, w)
-		}
-	})
-}
-
-func TestServer_Request_Connect_InvalidPath(t *testing.T) {
-	testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID: 1,
-			BlockFragment: st.encodeHeaderRaw(
-				":method", "CONNECT",
-				":authority", "example.com:123",
-				":path", "/bogus",
-			),
-			EndStream:  true,
-			EndHeaders: true,
-		})
-	})
-}
-
-func TestServer_Request_Connect_InvalidScheme(t *testing.T) {
-	testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID: 1,
-			BlockFragment: st.encodeHeaderRaw(
-				":method", "CONNECT",
-				":authority", "example.com:123",
-				":scheme", "https",
-			),
-			EndStream:  true,
-			EndHeaders: true,
-		})
-	})
-}
-
-func TestServer_Ping(t *testing.T) {
-	st := newServerTester(t, nil)
-	defer st.Close()
-	st.greet()
-
-	// Server should ignore this one, since it has ACK set.
-	ackPingData := [8]byte{1, 2, 4, 8, 16, 32, 64, 128}
-	if err := st.fr.WritePing(true, ackPingData); err != nil {
-		t.Fatal(err)
-	}
-
-	// But the server should reply to this one, since ACK is false.
-	pingData := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
-	if err := st.fr.WritePing(false, pingData); err != nil {
-		t.Fatal(err)
-	}
-
-	pf := st.wantPing()
-	if !pf.Flags.Has(FlagPingAck) {
-		t.Error("response ping doesn't have ACK set")
-	}
-	if pf.Data != pingData {
-		t.Errorf("response ping has data %q; want %q", pf.Data, pingData)
-	}
-}
-
-func TestServer_RejectsLargeFrames(t *testing.T) {
-	if runtime.GOOS == "windows" {
-		t.Skip("see golang.org/issue/13434")
-	}
-
-	st := newServerTester(t, nil)
-	defer st.Close()
-	st.greet()
-
-	// Write too large of a frame (too large by one byte)
-	// We ignore the return value because it's expected that the server
-	// will only read the first 9 bytes (the headre) and then disconnect.
-	st.fr.WriteRawFrame(0xff, 0, 0, make([]byte, defaultMaxReadFrameSize+1))
-
-	gf := st.wantGoAway()
-	if gf.ErrCode != ErrCodeFrameSize {
-		t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFrameSize)
-	}
-	if st.logBuf.Len() != 0 {
-		// Previously we spun here for a bit until the GOAWAY disconnect
-		// timer fired, logging while we fired.
-		t.Errorf("unexpected server output: %.500s\n", st.logBuf.Bytes())
-	}
-}
-
-func TestServer_Handler_Sends_WindowUpdate(t *testing.T) {
-	puppet := newHandlerPuppet()
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		puppet.act(w, r)
-	})
-	defer st.Close()
-	defer puppet.done()
-
-	st.greet()
-
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1, // clients send odd numbers
-		BlockFragment: st.encodeHeader(":method", "POST"),
-		EndStream:     false, // data coming
-		EndHeaders:    true,
-	})
-	st.writeData(1, false, []byte("abcdef"))
-	puppet.do(readBodyHandler(t, "abc"))
-	st.wantWindowUpdate(0, 3)
-	st.wantWindowUpdate(1, 3)
-
-	puppet.do(readBodyHandler(t, "def"))
-	st.wantWindowUpdate(0, 3)
-	st.wantWindowUpdate(1, 3)
-
-	st.writeData(1, true, []byte("ghijkl")) // END_STREAM here
-	puppet.do(readBodyHandler(t, "ghi"))
-	puppet.do(readBodyHandler(t, "jkl"))
-	st.wantWindowUpdate(0, 3)
-	st.wantWindowUpdate(0, 3) // no more stream-level, since END_STREAM
-}
-
-func TestServer_Send_GoAway_After_Bogus_WindowUpdate(t *testing.T) {
-	st := newServerTester(t, nil)
-	defer st.Close()
-	st.greet()
-	if err := st.fr.WriteWindowUpdate(0, 1<<31-1); err != nil {
-		t.Fatal(err)
-	}
-	gf := st.wantGoAway()
-	if gf.ErrCode != ErrCodeFlowControl {
-		t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFlowControl)
-	}
-	if gf.LastStreamID != 0 {
-		t.Errorf("GOAWAY last stream ID = %v; want %v", gf.LastStreamID, 0)
-	}
-}
-
-func TestServer_Send_RstStream_After_Bogus_WindowUpdate(t *testing.T) {
-	inHandler := make(chan bool)
-	blockHandler := make(chan bool)
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		inHandler <- true
-		<-blockHandler
-	})
-	defer st.Close()
-	defer close(blockHandler)
-	st.greet()
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: st.encodeHeader(":method", "POST"),
-		EndStream:     false, // keep it open
-		EndHeaders:    true,
-	})
-	<-inHandler
-	// Send a bogus window update:
-	if err := st.fr.WriteWindowUpdate(1, 1<<31-1); err != nil {
-		t.Fatal(err)
-	}
-	st.wantRSTStream(1, ErrCodeFlowControl)
-}
-
-// testServerPostUnblock sends a hanging POST with unsent data to handler,
-// then runs fn once in the handler, and verifies that the error returned from
-// handler is acceptable. It fails if takes over 5 seconds for handler to exit.
-func testServerPostUnblock(t *testing.T,
-	handler func(http.ResponseWriter, *http.Request) error,
-	fn func(*serverTester),
-	checkErr func(error),
-	otherHeaders ...string) {
-	inHandler := make(chan bool)
-	errc := make(chan error, 1)
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		inHandler <- true
-		errc <- handler(w, r)
-	})
-	st.greet()
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: st.encodeHeader(append([]string{":method", "POST"}, otherHeaders...)...),
-		EndStream:     false, // keep it open
-		EndHeaders:    true,
-	})
-	<-inHandler
-	fn(st)
-	select {
-	case err := <-errc:
-		if checkErr != nil {
-			checkErr(err)
-		}
-	case <-time.After(5 * time.Second):
-		t.Fatal("timeout waiting for Handler to return")
-	}
-	st.Close()
-}
-
-func TestServer_RSTStream_Unblocks_Read(t *testing.T) {
-	testServerPostUnblock(t,
-		func(w http.ResponseWriter, r *http.Request) (err error) {
-			_, err = r.Body.Read(make([]byte, 1))
-			return
-		},
-		func(st *serverTester) {
-			if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
-				t.Fatal(err)
-			}
-		},
-		func(err error) {
-			want := StreamError{StreamID: 0x1, Code: 0x8}
-			if !reflect.DeepEqual(err, want) {
-				t.Errorf("Read error = %v; want %v", err, want)
-			}
-		},
-	)
-}
-
-func TestServer_RSTStream_Unblocks_Header_Write(t *testing.T) {
-	// Run this test a bunch, because it doesn't always
-	// deadlock. But with a bunch, it did.
-	n := 50
-	if testing.Short() {
-		n = 5
-	}
-	for i := 0; i < n; i++ {
-		testServer_RSTStream_Unblocks_Header_Write(t)
-	}
-}
-
-func testServer_RSTStream_Unblocks_Header_Write(t *testing.T) {
-	inHandler := make(chan bool, 1)
-	unblockHandler := make(chan bool, 1)
-	headerWritten := make(chan bool, 1)
-	wroteRST := make(chan bool, 1)
-
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		inHandler <- true
-		<-wroteRST
-		w.Header().Set("foo", "bar")
-		w.WriteHeader(200)
-		w.(http.Flusher).Flush()
-		headerWritten <- true
-		<-unblockHandler
-	})
-	defer st.Close()
-
-	st.greet()
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: st.encodeHeader(":method", "POST"),
-		EndStream:     false, // keep it open
-		EndHeaders:    true,
-	})
-	<-inHandler
-	if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
-		t.Fatal(err)
-	}
-	wroteRST <- true
-	st.awaitIdle()
-	select {
-	case <-headerWritten:
-	case <-time.After(2 * time.Second):
-		t.Error("timeout waiting for header write")
-	}
-	unblockHandler <- true
-}
-
-func TestServer_DeadConn_Unblocks_Read(t *testing.T) {
-	testServerPostUnblock(t,
-		func(w http.ResponseWriter, r *http.Request) (err error) {
-			_, err = r.Body.Read(make([]byte, 1))
-			return
-		},
-		func(st *serverTester) { st.cc.Close() },
-		func(err error) {
-			if err == nil {
-				t.Error("unexpected nil error from Request.Body.Read")
-			}
-		},
-	)
-}
-
-var blockUntilClosed = func(w http.ResponseWriter, r *http.Request) error {
-	<-w.(http.CloseNotifier).CloseNotify()
-	return nil
-}
-
-func TestServer_CloseNotify_After_RSTStream(t *testing.T) {
-	testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) {
-		if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
-			t.Fatal(err)
-		}
-	}, nil)
-}
-
-func TestServer_CloseNotify_After_ConnClose(t *testing.T) {
-	testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { st.cc.Close() }, nil)
-}
-
-// that CloseNotify unblocks after a stream error due to the client's
-// problem that's unrelated to them explicitly canceling it (which is
-// TestServer_CloseNotify_After_RSTStream above)
-func TestServer_CloseNotify_After_StreamError(t *testing.T) {
-	testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) {
-		// data longer than declared Content-Length => stream error
-		st.writeData(1, true, []byte("1234"))
-	}, nil, "content-length", "3")
-}
-
-func TestServer_StateTransitions(t *testing.T) {
-	var st *serverTester
-	inHandler := make(chan bool)
-	writeData := make(chan bool)
-	leaveHandler := make(chan bool)
-	st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		inHandler <- true
-		if st.stream(1) == nil {
-			t.Errorf("nil stream 1 in handler")
-		}
-		if got, want := st.streamState(1), stateOpen; got != want {
-			t.Errorf("in handler, state is %v; want %v", got, want)
-		}
-		writeData <- true
-		if n, err := r.Body.Read(make([]byte, 1)); n != 0 || err != io.EOF {
-			t.Errorf("body read = %d, %v; want 0, EOF", n, err)
-		}
-		if got, want := st.streamState(1), stateHalfClosedRemote; got != want {
-			t.Errorf("in handler, state is %v; want %v", got, want)
-		}
-
-		<-leaveHandler
-	})
-	st.greet()
-	if st.stream(1) != nil {
-		t.Fatal("stream 1 should be empty")
-	}
-	if got := st.streamState(1); got != stateIdle {
-		t.Fatalf("stream 1 should be idle; got %v", got)
-	}
-
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: st.encodeHeader(":method", "POST"),
-		EndStream:     false, // keep it open
-		EndHeaders:    true,
-	})
-	<-inHandler
-	<-writeData
-	st.writeData(1, true, nil)
-
-	leaveHandler <- true
-	hf := st.wantHeaders()
-	if !hf.StreamEnded() {
-		t.Fatal("expected END_STREAM flag")
-	}
-
-	if got, want := st.streamState(1), stateClosed; got != want {
-		t.Errorf("at end, state is %v; want %v", got, want)
-	}
-	if st.stream(1) != nil {
-		t.Fatal("at end, stream 1 should be gone")
-	}
-}
-
-// test HEADERS w/o EndHeaders + another HEADERS (should get rejected)
-func TestServer_Rejects_HeadersNoEnd_Then_Headers(t *testing.T) {
-	testServerRejectsConn(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     true,
-			EndHeaders:    false,
-		})
-		st.writeHeaders(HeadersFrameParam{ // Not a continuation.
-			StreamID:      3, // different stream.
-			BlockFragment: st.encodeHeader(),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-	})
-}
-
-// test HEADERS w/o EndHeaders + PING (should get rejected)
-func TestServer_Rejects_HeadersNoEnd_Then_Ping(t *testing.T) {
-	testServerRejectsConn(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     true,
-			EndHeaders:    false,
-		})
-		if err := st.fr.WritePing(false, [8]byte{}); err != nil {
-			t.Fatal(err)
-		}
-	})
-}
-
-// test HEADERS w/ EndHeaders + a continuation HEADERS (should get rejected)
-func TestServer_Rejects_HeadersEnd_Then_Continuation(t *testing.T) {
-	testServerRejectsConn(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-		st.wantHeaders()
-		if err := st.fr.WriteContinuation(1, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil {
-			t.Fatal(err)
-		}
-	})
-}
-
-// test HEADERS w/o EndHeaders + a continuation HEADERS on wrong stream ID
-func TestServer_Rejects_HeadersNoEnd_Then_ContinuationWrongStream(t *testing.T) {
-	testServerRejectsConn(t, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     true,
-			EndHeaders:    false,
-		})
-		if err := st.fr.WriteContinuation(3, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil {
-			t.Fatal(err)
-		}
-	})
-}
-
-// No HEADERS on stream 0.
-func TestServer_Rejects_Headers0(t *testing.T) {
-	testServerRejectsConn(t, func(st *serverTester) {
-		st.fr.AllowIllegalWrites = true
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      0,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-	})
-}
-
-// No CONTINUATION on stream 0.
-func TestServer_Rejects_Continuation0(t *testing.T) {
-	testServerRejectsConn(t, func(st *serverTester) {
-		st.fr.AllowIllegalWrites = true
-		if err := st.fr.WriteContinuation(0, true, st.encodeHeader()); err != nil {
-			t.Fatal(err)
-		}
-	})
-}
-
-func TestServer_Rejects_PushPromise(t *testing.T) {
-	testServerRejectsConn(t, func(st *serverTester) {
-		pp := PushPromiseParam{
-			StreamID:  1,
-			PromiseID: 3,
-		}
-		if err := st.fr.WritePushPromise(pp); err != nil {
-			t.Fatal(err)
-		}
-	})
-}
-
-// testServerRejectsConn tests that the server hangs up with a GOAWAY
-// frame and a server close after the client does something
-// deserving a CONNECTION_ERROR.
-func testServerRejectsConn(t *testing.T, writeReq func(*serverTester)) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {})
-	st.addLogFilter("connection error: PROTOCOL_ERROR")
-	defer st.Close()
-	st.greet()
-	writeReq(st)
-
-	st.wantGoAway()
-	errc := make(chan error, 1)
-	go func() {
-		fr, err := st.fr.ReadFrame()
-		if err == nil {
-			err = fmt.Errorf("got frame of type %T", fr)
-		}
-		errc <- err
-	}()
-	select {
-	case err := <-errc:
-		if err != io.EOF {
-			t.Errorf("ReadFrame = %v; want io.EOF", err)
-		}
-	case <-time.After(2 * time.Second):
-		t.Error("timeout waiting for disconnect")
-	}
-}
-
-// testServerRejectsStream tests that the server sends a RST_STREAM with the provided
-// error code after a client sends a bogus request.
-func testServerRejectsStream(t *testing.T, code ErrCode, writeReq func(*serverTester)) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {})
-	defer st.Close()
-	st.greet()
-	writeReq(st)
-	st.wantRSTStream(1, code)
-}
-
-// testServerRequest sets up an idle HTTP/2 connection and lets you
-// write a single request with writeReq, and then verify that the
-// *http.Request is built correctly in checkReq.
-func testServerRequest(t *testing.T, writeReq func(*serverTester), checkReq func(*http.Request)) {
-	gotReq := make(chan bool, 1)
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		if r.Body == nil {
-			t.Fatal("nil Body")
-		}
-		checkReq(r)
-		gotReq <- true
-	})
-	defer st.Close()
-
-	st.greet()
-	writeReq(st)
-
-	select {
-	case <-gotReq:
-	case <-time.After(2 * time.Second):
-		t.Error("timeout waiting for request")
-	}
-}
-
-func getSlash(st *serverTester) { st.bodylessReq1() }
-
-func TestServer_Response_NoData(t *testing.T) {
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		// Nothing.
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if !hf.StreamEnded() {
-			t.Fatal("want END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-	})
-}
-
-func TestServer_Response_NoData_Header_FooBar(t *testing.T) {
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.Header().Set("Foo-Bar", "some-value")
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if !hf.StreamEnded() {
-			t.Fatal("want END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"foo-bar", "some-value"},
-			{"content-type", "text/plain; charset=utf-8"},
-			{"content-length", "0"},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-	})
-}
-
-func TestServer_Response_Data_Sniff_DoesntOverride(t *testing.T) {
-	const msg = "<html>this is HTML."
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.Header().Set("Content-Type", "foo/bar")
-		io.WriteString(w, msg)
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("don't want END_STREAM, expecting data")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"content-type", "foo/bar"},
-			{"content-length", strconv.Itoa(len(msg))},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-		df := st.wantData()
-		if !df.StreamEnded() {
-			t.Error("expected DATA to have END_STREAM flag")
-		}
-		if got := string(df.Data()); got != msg {
-			t.Errorf("got DATA %q; want %q", got, msg)
-		}
-	})
-}
-
-func TestServer_Response_TransferEncoding_chunked(t *testing.T) {
-	const msg = "hi"
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.Header().Set("Transfer-Encoding", "chunked") // should be stripped
-		io.WriteString(w, msg)
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"content-type", "text/plain; charset=utf-8"},
-			{"content-length", strconv.Itoa(len(msg))},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-	})
-}
-
-// Header accessed only after the initial write.
-func TestServer_Response_Data_IgnoreHeaderAfterWrite_After(t *testing.T) {
-	const msg = "<html>this is HTML."
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		io.WriteString(w, msg)
-		w.Header().Set("foo", "should be ignored")
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"content-type", "text/html; charset=utf-8"},
-			{"content-length", strconv.Itoa(len(msg))},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-	})
-}
-
-// Header accessed before the initial write and later mutated.
-func TestServer_Response_Data_IgnoreHeaderAfterWrite_Overwrite(t *testing.T) {
-	const msg = "<html>this is HTML."
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.Header().Set("foo", "proper value")
-		io.WriteString(w, msg)
-		w.Header().Set("foo", "should be ignored")
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"foo", "proper value"},
-			{"content-type", "text/html; charset=utf-8"},
-			{"content-length", strconv.Itoa(len(msg))},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-	})
-}
-
-func TestServer_Response_Data_SniffLenType(t *testing.T) {
-	const msg = "<html>this is HTML."
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		io.WriteString(w, msg)
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("don't want END_STREAM, expecting data")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"content-type", "text/html; charset=utf-8"},
-			{"content-length", strconv.Itoa(len(msg))},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-		df := st.wantData()
-		if !df.StreamEnded() {
-			t.Error("expected DATA to have END_STREAM flag")
-		}
-		if got := string(df.Data()); got != msg {
-			t.Errorf("got DATA %q; want %q", got, msg)
-		}
-	})
-}
-
-func TestServer_Response_Header_Flush_MidWrite(t *testing.T) {
-	const msg = "<html>this is HTML"
-	const msg2 = ", and this is the next chunk"
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		io.WriteString(w, msg)
-		w.(http.Flusher).Flush()
-		io.WriteString(w, msg2)
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"content-type", "text/html; charset=utf-8"}, // sniffed
-			// and no content-length
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-		{
-			df := st.wantData()
-			if df.StreamEnded() {
-				t.Error("unexpected END_STREAM flag")
-			}
-			if got := string(df.Data()); got != msg {
-				t.Errorf("got DATA %q; want %q", got, msg)
-			}
-		}
-		{
-			df := st.wantData()
-			if !df.StreamEnded() {
-				t.Error("wanted END_STREAM flag on last data chunk")
-			}
-			if got := string(df.Data()); got != msg2 {
-				t.Errorf("got DATA %q; want %q", got, msg2)
-			}
-		}
-	})
-}
-
-func TestServer_Response_LargeWrite(t *testing.T) {
-	const size = 1 << 20
-	const maxFrameSize = 16 << 10
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		n, err := w.Write(bytes.Repeat([]byte("a"), size))
-		if err != nil {
-			return fmt.Errorf("Write error: %v", err)
-		}
-		if n != size {
-			return fmt.Errorf("wrong size %d from Write", n)
-		}
-		return nil
-	}, func(st *serverTester) {
-		if err := st.fr.WriteSettings(
-			Setting{SettingInitialWindowSize, 0},
-			Setting{SettingMaxFrameSize, maxFrameSize},
-		); err != nil {
-			t.Fatal(err)
-		}
-		st.wantSettingsAck()
-
-		getSlash(st) // make the single request
-
-		// Give the handler quota to write:
-		if err := st.fr.WriteWindowUpdate(1, size); err != nil {
-			t.Fatal(err)
-		}
-		// Give the handler quota to write to connection-level
-		// window as well
-		if err := st.fr.WriteWindowUpdate(0, size); err != nil {
-			t.Fatal(err)
-		}
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"content-type", "text/plain; charset=utf-8"}, // sniffed
-			// and no content-length
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-		var bytes, frames int
-		for {
-			df := st.wantData()
-			bytes += len(df.Data())
-			frames++
-			for _, b := range df.Data() {
-				if b != 'a' {
-					t.Fatal("non-'a' byte seen in DATA")
-				}
-			}
-			if df.StreamEnded() {
-				break
-			}
-		}
-		if bytes != size {
-			t.Errorf("Got %d bytes; want %d", bytes, size)
-		}
-		if want := int(size / maxFrameSize); frames < want || frames > want*2 {
-			t.Errorf("Got %d frames; want %d", frames, size)
-		}
-	})
-}
-
-// Test that the handler can't write more than the client allows
-func TestServer_Response_LargeWrite_FlowControlled(t *testing.T) {
-	const size = 1 << 20
-	const maxFrameSize = 16 << 10
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.(http.Flusher).Flush()
-		n, err := w.Write(bytes.Repeat([]byte("a"), size))
-		if err != nil {
-			return fmt.Errorf("Write error: %v", err)
-		}
-		if n != size {
-			return fmt.Errorf("wrong size %d from Write", n)
-		}
-		return nil
-	}, func(st *serverTester) {
-		// Set the window size to something explicit for this test.
-		// It's also how much initial data we expect.
-		const initWindowSize = 123
-		if err := st.fr.WriteSettings(
-			Setting{SettingInitialWindowSize, initWindowSize},
-			Setting{SettingMaxFrameSize, maxFrameSize},
-		); err != nil {
-			t.Fatal(err)
-		}
-		st.wantSettingsAck()
-
-		getSlash(st) // make the single request
-		defer func() { st.fr.WriteRSTStream(1, ErrCodeCancel) }()
-
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-
-		df := st.wantData()
-		if got := len(df.Data()); got != initWindowSize {
-			t.Fatalf("Initial window size = %d but got DATA with %d bytes", initWindowSize, got)
-		}
-
-		for _, quota := range []int{1, 13, 127} {
-			if err := st.fr.WriteWindowUpdate(1, uint32(quota)); err != nil {
-				t.Fatal(err)
-			}
-			df := st.wantData()
-			if int(quota) != len(df.Data()) {
-				t.Fatalf("read %d bytes after giving %d quota", len(df.Data()), quota)
-			}
-		}
-
-		if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
-			t.Fatal(err)
-		}
-	})
-}
-
-// Test that the handler blocked in a Write is unblocked if the server sends a RST_STREAM.
-func TestServer_Response_RST_Unblocks_LargeWrite(t *testing.T) {
-	const size = 1 << 20
-	const maxFrameSize = 16 << 10
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.(http.Flusher).Flush()
-		errc := make(chan error, 1)
-		go func() {
-			_, err := w.Write(bytes.Repeat([]byte("a"), size))
-			errc <- err
-		}()
-		select {
-		case err := <-errc:
-			if err == nil {
-				return errors.New("unexpected nil error from Write in handler")
-			}
-			return nil
-		case <-time.After(2 * time.Second):
-			return errors.New("timeout waiting for Write in handler")
-		}
-	}, func(st *serverTester) {
-		if err := st.fr.WriteSettings(
-			Setting{SettingInitialWindowSize, 0},
-			Setting{SettingMaxFrameSize, maxFrameSize},
-		); err != nil {
-			t.Fatal(err)
-		}
-		st.wantSettingsAck()
-
-		getSlash(st) // make the single request
-
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-
-		if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
-			t.Fatal(err)
-		}
-	})
-}
-
-func TestServer_Response_Empty_Data_Not_FlowControlled(t *testing.T) {
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.(http.Flusher).Flush()
-		// Nothing; send empty DATA
-		return nil
-	}, func(st *serverTester) {
-		// Handler gets no data quota:
-		if err := st.fr.WriteSettings(Setting{SettingInitialWindowSize, 0}); err != nil {
-			t.Fatal(err)
-		}
-		st.wantSettingsAck()
-
-		getSlash(st) // make the single request
-
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-
-		df := st.wantData()
-		if got := len(df.Data()); got != 0 {
-			t.Fatalf("unexpected %d DATA bytes; want 0", got)
-		}
-		if !df.StreamEnded() {
-			t.Fatal("DATA didn't have END_STREAM")
-		}
-	})
-}
-
-func TestServer_Response_Automatic100Continue(t *testing.T) {
-	const msg = "foo"
-	const reply = "bar"
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		if v := r.Header.Get("Expect"); v != "" {
-			t.Errorf("Expect header = %q; want empty", v)
-		}
-		buf := make([]byte, len(msg))
-		// This read should trigger the 100-continue being sent.
-		if n, err := io.ReadFull(r.Body, buf); err != nil || n != len(msg) || string(buf) != msg {
-			return fmt.Errorf("ReadFull = %q, %v; want %q, nil", buf[:n], err, msg)
-		}
-		_, err := io.WriteString(w, reply)
-		return err
-	}, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader(":method", "POST", "expect", "100-continue"),
-			EndStream:     false,
-			EndHeaders:    true,
-		})
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "100"},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Fatalf("Got headers %v; want %v", goth, wanth)
-		}
-
-		// Okay, they sent status 100, so we can send our
-		// gigantic and/or sensitive "foo" payload now.
-		st.writeData(1, true, []byte(msg))
-
-		st.wantWindowUpdate(0, uint32(len(msg)))
-
-		hf = st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("expected data to follow")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		goth = st.decodeHeader(hf.HeaderBlockFragment())
-		wanth = [][2]string{
-			{":status", "200"},
-			{"content-type", "text/plain; charset=utf-8"},
-			{"content-length", strconv.Itoa(len(reply))},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Got headers %v; want %v", goth, wanth)
-		}
-
-		df := st.wantData()
-		if string(df.Data()) != reply {
-			t.Errorf("Client read %q; want %q", df.Data(), reply)
-		}
-		if !df.StreamEnded() {
-			t.Errorf("expect data stream end")
-		}
-	})
-}
-
-func TestServer_HandlerWriteErrorOnDisconnect(t *testing.T) {
-	errc := make(chan error, 1)
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		p := []byte("some data.\n")
-		for {
-			_, err := w.Write(p)
-			if err != nil {
-				errc <- err
-				return nil
-			}
-		}
-	}, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     false,
-			EndHeaders:    true,
-		})
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("unexpected END_STREAM flag")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("want END_HEADERS flag")
-		}
-		// Close the connection and wait for the handler to (hopefully) notice.
-		st.cc.Close()
-		select {
-		case <-errc:
-		case <-time.After(5 * time.Second):
-			t.Error("timeout")
-		}
-	})
-}
-
-func TestServer_Rejects_Too_Many_Streams(t *testing.T) {
-	const testPath = "/some/path"
-
-	inHandler := make(chan uint32)
-	leaveHandler := make(chan bool)
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		id := w.(*responseWriter).rws.stream.id
-		inHandler <- id
-		if id == 1+(defaultMaxStreams+1)*2 && r.URL.Path != testPath {
-			t.Errorf("decoded final path as %q; want %q", r.URL.Path, testPath)
-		}
-		<-leaveHandler
-	})
-	defer st.Close()
-	st.greet()
-	nextStreamID := uint32(1)
-	streamID := func() uint32 {
-		defer func() { nextStreamID += 2 }()
-		return nextStreamID
-	}
-	sendReq := func(id uint32, headers ...string) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      id,
-			BlockFragment: st.encodeHeader(headers...),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-	}
-	for i := 0; i < defaultMaxStreams; i++ {
-		sendReq(streamID())
-		<-inHandler
-	}
-	defer func() {
-		for i := 0; i < defaultMaxStreams; i++ {
-			leaveHandler <- true
-		}
-	}()
-
-	// And this one should cross the limit:
-	// (It's also sent as a CONTINUATION, to verify we still track the decoder context,
-	// even if we're rejecting it)
-	rejectID := streamID()
-	headerBlock := st.encodeHeader(":path", testPath)
-	frag1, frag2 := headerBlock[:3], headerBlock[3:]
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      rejectID,
-		BlockFragment: frag1,
-		EndStream:     true,
-		EndHeaders:    false, // CONTINUATION coming
-	})
-	if err := st.fr.WriteContinuation(rejectID, true, frag2); err != nil {
-		t.Fatal(err)
-	}
-	st.wantRSTStream(rejectID, ErrCodeProtocol)
-
-	// But let a handler finish:
-	leaveHandler <- true
-	st.wantHeaders()
-
-	// And now another stream should be able to start:
-	goodID := streamID()
-	sendReq(goodID, ":path", testPath)
-	select {
-	case got := <-inHandler:
-		if got != goodID {
-			t.Errorf("Got stream %d; want %d", got, goodID)
-		}
-	case <-time.After(3 * time.Second):
-		t.Error("timeout waiting for handler")
-	}
-}
-
-// So many response headers that the server needs to use CONTINUATION frames:
-func TestServer_Response_ManyHeaders_With_Continuation(t *testing.T) {
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		h := w.Header()
-		for i := 0; i < 5000; i++ {
-			h.Set(fmt.Sprintf("x-header-%d", i), fmt.Sprintf("x-value-%d", i))
-		}
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if hf.HeadersEnded() {
-			t.Fatal("got unwanted END_HEADERS flag")
-		}
-		n := 0
-		for {
-			n++
-			cf := st.wantContinuation()
-			if cf.HeadersEnded() {
-				break
-			}
-		}
-		if n < 5 {
-			t.Errorf("Only got %d CONTINUATION frames; expected 5+ (currently 6)", n)
-		}
-	})
-}
-
-// This previously crashed (reported by Mathieu Lonjaret as observed
-// while using Camlistore) because we got a DATA frame from the client
-// after the handler exited and our logic at the time was wrong,
-// keeping a stream in the map in stateClosed, which tickled an
-// invariant check later when we tried to remove that stream (via
-// defer sc.closeAllStreamsOnConnClose) when the serverConn serve loop
-// ended.
-func TestServer_NoCrash_HandlerClose_Then_ClientClose(t *testing.T) {
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		// nothing
-		return nil
-	}, func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     false, // DATA is coming
-			EndHeaders:    true,
-		})
-		hf := st.wantHeaders()
-		if !hf.HeadersEnded() || !hf.StreamEnded() {
-			t.Fatalf("want END_HEADERS+END_STREAM, got %v", hf)
-		}
-
-		// Sent when the a Handler closes while a client has
-		// indicated it's still sending DATA:
-		st.wantRSTStream(1, ErrCodeCancel)
-
-		// Now the handler has ended, so it's ended its
-		// stream, but the client hasn't closed its side
-		// (stateClosedLocal).  So send more data and verify
-		// it doesn't crash with an internal invariant panic, like
-		// it did before.
-		st.writeData(1, true, []byte("foo"))
-
-		// Sent after a peer sends data anyway (admittedly the
-		// previous RST_STREAM might've still been in-flight),
-		// but they'll get the more friendly 'cancel' code
-		// first.
-		st.wantRSTStream(1, ErrCodeStreamClosed)
-
-		// Set up a bunch of machinery to record the panic we saw
-		// previously.
-		var (
-			panMu    sync.Mutex
-			panicVal interface{}
-		)
-
-		testHookOnPanicMu.Lock()
-		testHookOnPanic = func(sc *serverConn, pv interface{}) bool {
-			panMu.Lock()
-			panicVal = pv
-			panMu.Unlock()
-			return true
-		}
-		testHookOnPanicMu.Unlock()
-
-		// Now force the serve loop to end, via closing the connection.
-		st.cc.Close()
-		select {
-		case <-st.sc.doneServing:
-			// Loop has exited.
-			panMu.Lock()
-			got := panicVal
-			panMu.Unlock()
-			if got != nil {
-				t.Errorf("Got panic: %v", got)
-			}
-		case <-time.After(5 * time.Second):
-			t.Error("timeout")
-		}
-	})
-}
-
-func TestServer_Rejects_TLS10(t *testing.T) { testRejectTLS(t, tls.VersionTLS10) }
-func TestServer_Rejects_TLS11(t *testing.T) { testRejectTLS(t, tls.VersionTLS11) }
-
-func testRejectTLS(t *testing.T, max uint16) {
-	st := newServerTester(t, nil, func(c *tls.Config) {
-		c.MaxVersion = max
-	})
-	defer st.Close()
-	gf := st.wantGoAway()
-	if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want {
-		t.Errorf("Got error code %v; want %v", got, want)
-	}
-}
-
-func TestServer_Rejects_TLSBadCipher(t *testing.T) {
-	st := newServerTester(t, nil, func(c *tls.Config) {
-		// Only list bad ones:
-		c.CipherSuites = []uint16{
-			tls.TLS_RSA_WITH_RC4_128_SHA,
-			tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-			tls.TLS_RSA_WITH_AES_128_CBC_SHA,
-			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
-			tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
-			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
-			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
-			tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
-			tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
-			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
-		}
-	})
-	defer st.Close()
-	gf := st.wantGoAway()
-	if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want {
-		t.Errorf("Got error code %v; want %v", got, want)
-	}
-}
-
-func TestServer_Advertises_Common_Cipher(t *testing.T) {
-	const requiredSuite = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-	st := newServerTester(t, nil, func(c *tls.Config) {
-		// Have the client only support the one required by the spec.
-		c.CipherSuites = []uint16{requiredSuite}
-	}, func(ts *httptest.Server) {
-		var srv *http.Server = ts.Config
-		// Have the server configured with no specific cipher suites.
-		// This tests that Go's defaults include the required one.
-		srv.TLSConfig = nil
-	})
-	defer st.Close()
-	st.greet()
-}
-
-func (st *serverTester) onHeaderField(f hpack.HeaderField) {
-	if f.Name == "date" {
-		return
-	}
-	st.decodedHeaders = append(st.decodedHeaders, [2]string{f.Name, f.Value})
-}
-
-func (st *serverTester) decodeHeader(headerBlock []byte) (pairs [][2]string) {
-	st.decodedHeaders = nil
-	if _, err := st.hpackDec.Write(headerBlock); err != nil {
-		st.t.Fatalf("hpack decoding error: %v", err)
-	}
-	if err := st.hpackDec.Close(); err != nil {
-		st.t.Fatalf("hpack decoding error: %v", err)
-	}
-	return st.decodedHeaders
-}
-
-// testServerResponse sets up an idle HTTP/2 connection and lets you
-// write a single request with writeReq, and then reply to it in some way with the provided handler,
-// and then verify the output with the serverTester again (assuming the handler returns nil)
-func testServerResponse(t testing.TB,
-	handler func(http.ResponseWriter, *http.Request) error,
-	client func(*serverTester),
-) {
-	errc := make(chan error, 1)
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		if r.Body == nil {
-			t.Fatal("nil Body")
-		}
-		errc <- handler(w, r)
-	})
-	defer st.Close()
-
-	donec := make(chan bool)
-	go func() {
-		defer close(donec)
-		st.greet()
-		client(st)
-	}()
-
-	select {
-	case <-donec:
-		return
-	case <-time.After(5 * time.Second):
-		t.Fatal("timeout")
-	}
-
-	select {
-	case err := <-errc:
-		if err != nil {
-			t.Fatalf("Error in handler: %v", err)
-		}
-	case <-time.After(2 * time.Second):
-		t.Error("timeout waiting for handler to finish")
-	}
-}
-
-// readBodyHandler returns an http Handler func that reads len(want)
-// bytes from r.Body and fails t if the contents read were not
-// the value of want.
-func readBodyHandler(t *testing.T, want string) func(w http.ResponseWriter, r *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		buf := make([]byte, len(want))
-		_, err := io.ReadFull(r.Body, buf)
-		if err != nil {
-			t.Error(err)
-			return
-		}
-		if string(buf) != want {
-			t.Errorf("read %q; want %q", buf, want)
-		}
-	}
-}
-
-// TestServerWithCurl currently fails, hence the LenientCipherSuites test. See:
-//   https://github.com/tatsuhiro-t/nghttp2/issues/140 &
-//   http://sourceforge.net/p/curl/bugs/1472/
-func TestServerWithCurl(t *testing.T)                     { testServerWithCurl(t, false) }
-func TestServerWithCurl_LenientCipherSuites(t *testing.T) { testServerWithCurl(t, true) }
-
-func testServerWithCurl(t *testing.T, permitProhibitedCipherSuites bool) {
-	if runtime.GOOS != "linux" {
-		t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway")
-	}
-	if testing.Short() {
-		t.Skip("skipping curl test in short mode")
-	}
-	requireCurl(t)
-	var gotConn int32
-	testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) }
-
-	const msg = "Hello from curl!\n"
-	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Foo", "Bar")
-		w.Header().Set("Client-Proto", r.Proto)
-		io.WriteString(w, msg)
-	}))
-	ConfigureServer(ts.Config, &Server{
-		PermitProhibitedCipherSuites: permitProhibitedCipherSuites,
-	})
-	ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
-	ts.StartTLS()
-	defer ts.Close()
-
-	t.Logf("Running test server for curl to hit at: %s", ts.URL)
-	container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL)
-	defer kill(container)
-	resc := make(chan interface{}, 1)
-	go func() {
-		res, err := dockerLogs(container)
-		if err != nil {
-			resc <- err
-		} else {
-			resc <- res
-		}
-	}()
-	select {
-	case res := <-resc:
-		if err, ok := res.(error); ok {
-			t.Fatal(err)
-		}
-		body := string(res.([]byte))
-		// Search for both "key: value" and "key:value", since curl changed their format
-		// Our Dockerfile contains the latest version (no space), but just in case people
-		// didn't rebuild, check both.
-		if !strings.Contains(body, "foo: Bar") && !strings.Contains(body, "foo:Bar") {
-			t.Errorf("didn't see foo: Bar header")
-			t.Logf("Got: %s", body)
-		}
-		if !strings.Contains(body, "client-proto: HTTP/2") && !strings.Contains(body, "client-proto:HTTP/2") {
-			t.Errorf("didn't see client-proto: HTTP/2 header")
-			t.Logf("Got: %s", res)
-		}
-		if !strings.Contains(string(res.([]byte)), msg) {
-			t.Errorf("didn't see %q content", msg)
-			t.Logf("Got: %s", res)
-		}
-	case <-time.After(3 * time.Second):
-		t.Errorf("timeout waiting for curl")
-	}
-
-	if atomic.LoadInt32(&gotConn) == 0 {
-		t.Error("never saw an http2 connection")
-	}
-}
-
-var doh2load = flag.Bool("h2load", false, "Run h2load test")
-
-func TestServerWithH2Load(t *testing.T) {
-	if !*doh2load {
-		t.Skip("Skipping without --h2load flag.")
-	}
-	if runtime.GOOS != "linux" {
-		t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway")
-	}
-	requireH2load(t)
-
-	msg := strings.Repeat("Hello, h2load!\n", 5000)
-	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		io.WriteString(w, msg)
-		w.(http.Flusher).Flush()
-		io.WriteString(w, msg)
-	}))
-	ts.StartTLS()
-	defer ts.Close()
-
-	cmd := exec.Command("docker", "run", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl",
-		"-n100000", "-c100", "-m100", ts.URL)
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	if err := cmd.Run(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-// Issue 12843
-func TestServerDoS_MaxHeaderListSize(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {})
-	defer st.Close()
-
-	// shake hands
-	st.writePreface()
-	st.writeInitialSettings()
-	frameSize := defaultMaxReadFrameSize
-	var advHeaderListSize *uint32
-	st.wantSettings().ForeachSetting(func(s Setting) error {
-		switch s.ID {
-		case SettingMaxFrameSize:
-			if s.Val < minMaxFrameSize {
-				frameSize = minMaxFrameSize
-			} else if s.Val > maxFrameSize {
-				frameSize = maxFrameSize
-			} else {
-				frameSize = int(s.Val)
-			}
-		case SettingMaxHeaderListSize:
-			advHeaderListSize = &s.Val
-		}
-		return nil
-	})
-	st.writeSettingsAck()
-	st.wantSettingsAck()
-
-	if advHeaderListSize == nil {
-		t.Errorf("server didn't advertise a max header list size")
-	} else if *advHeaderListSize == 0 {
-		t.Errorf("server advertised a max header list size of 0")
-	}
-
-	st.encodeHeaderField(":method", "GET")
-	st.encodeHeaderField(":path", "/")
-	st.encodeHeaderField(":scheme", "https")
-	cookie := strings.Repeat("*", 4058)
-	st.encodeHeaderField("cookie", cookie)
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: st.headerBuf.Bytes(),
-		EndStream:     true,
-		EndHeaders:    false,
-	})
-
-	// Capture the short encoding of a duplicate ~4K cookie, now
-	// that we've already sent it once.
-	st.headerBuf.Reset()
-	st.encodeHeaderField("cookie", cookie)
-
-	// Now send 1MB of it.
-	const size = 1 << 20
-	b := bytes.Repeat(st.headerBuf.Bytes(), size/st.headerBuf.Len())
-	for len(b) > 0 {
-		chunk := b
-		if len(chunk) > frameSize {
-			chunk = chunk[:frameSize]
-		}
-		b = b[len(chunk):]
-		st.fr.WriteContinuation(1, len(b) == 0, chunk)
-	}
-
-	h := st.wantHeaders()
-	if !h.HeadersEnded() {
-		t.Fatalf("Got HEADERS without END_HEADERS set: %v", h)
-	}
-	headers := st.decodeHeader(h.HeaderBlockFragment())
-	want := [][2]string{
-		{":status", "431"},
-		{"content-type", "text/html; charset=utf-8"},
-		{"content-length", "63"},
-	}
-	if !reflect.DeepEqual(headers, want) {
-		t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
-	}
-}
-
-func TestCompressionErrorOnWrite(t *testing.T) {
-	const maxStrLen = 8 << 10
-	var serverConfig *http.Server
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		// No response body.
-	}, func(ts *httptest.Server) {
-		serverConfig = ts.Config
-		serverConfig.MaxHeaderBytes = maxStrLen
-	})
-	st.addLogFilter("connection error: COMPRESSION_ERROR")
-	defer st.Close()
-	st.greet()
-
-	maxAllowed := st.sc.maxHeaderStringLen()
-
-	// Crank this up, now that we have a conn connected with the
-	// hpack.Decoder's max string length set has been initialized
-	// from the earlier low ~8K value. We want this higher so don't
-	// hit the max header list size. We only want to test hitting
-	// the max string size.
-	serverConfig.MaxHeaderBytes = 1 << 20
-
-	// First a request with a header that's exactly the max allowed size.
-	hbf := st.encodeHeader("foo", strings.Repeat("a", maxAllowed))
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: hbf,
-		EndStream:     true,
-		EndHeaders:    true,
-	})
-	h := st.wantHeaders()
-	if !h.HeadersEnded() || !h.StreamEnded() {
-		t.Errorf("Unexpected HEADER frame %v", h)
-	}
-
-	// And now send one that's just one byte too big.
-	hbf = st.encodeHeader("bar", strings.Repeat("b", maxAllowed+1))
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      3,
-		BlockFragment: hbf,
-		EndStream:     true,
-		EndHeaders:    true,
-	})
-	ga := st.wantGoAway()
-	if ga.ErrCode != ErrCodeCompression {
-		t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode)
-	}
-}
-
-func TestCompressionErrorOnClose(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		// No response body.
-	})
-	st.addLogFilter("connection error: COMPRESSION_ERROR")
-	defer st.Close()
-	st.greet()
-
-	hbf := st.encodeHeader("foo", "bar")
-	hbf = hbf[:len(hbf)-1] // truncate one byte from the end, so hpack.Decoder.Close fails.
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: hbf,
-		EndStream:     true,
-		EndHeaders:    true,
-	})
-	ga := st.wantGoAway()
-	if ga.ErrCode != ErrCodeCompression {
-		t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode)
-	}
-}
-
-// test that a server handler can read trailers from a client
-func TestServerReadsTrailers(t *testing.T) {
-	const testBody = "some test body"
-	writeReq := func(st *serverTester) {
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      1, // clients send odd numbers
-			BlockFragment: st.encodeHeader("trailer", "Foo, Bar", "trailer", "Baz"),
-			EndStream:     false,
-			EndHeaders:    true,
-		})
-		st.writeData(1, false, []byte(testBody))
-		st.writeHeaders(HeadersFrameParam{
-			StreamID: 1, // clients send odd numbers
-			BlockFragment: st.encodeHeaderRaw(
-				"foo", "foov",
-				"bar", "barv",
-				"baz", "bazv",
-				"surprise", "wasn't declared; shouldn't show up",
-			),
-			EndStream:  true,
-			EndHeaders: true,
-		})
-	}
-	checkReq := func(r *http.Request) {
-		wantTrailer := http.Header{
-			"Foo": nil,
-			"Bar": nil,
-			"Baz": nil,
-		}
-		if !reflect.DeepEqual(r.Trailer, wantTrailer) {
-			t.Errorf("initial Trailer = %v; want %v", r.Trailer, wantTrailer)
-		}
-		slurp, err := ioutil.ReadAll(r.Body)
-		if string(slurp) != testBody {
-			t.Errorf("read body %q; want %q", slurp, testBody)
-		}
-		if err != nil {
-			t.Fatalf("Body slurp: %v", err)
-		}
-		wantTrailerAfter := http.Header{
-			"Foo": {"foov"},
-			"Bar": {"barv"},
-			"Baz": {"bazv"},
-		}
-		if !reflect.DeepEqual(r.Trailer, wantTrailerAfter) {
-			t.Errorf("final Trailer = %v; want %v", r.Trailer, wantTrailerAfter)
-		}
-	}
-	testServerRequest(t, writeReq, checkReq)
-}
-
-// test that a server handler can send trailers
-func TestServerWritesTrailers_WithFlush(t *testing.T)    { testServerWritesTrailers(t, true) }
-func TestServerWritesTrailers_WithoutFlush(t *testing.T) { testServerWritesTrailers(t, false) }
-
-func testServerWritesTrailers(t *testing.T, withFlush bool) {
-	// See https://httpwg.github.io/specs/rfc7540.html#rfc.section.8.1.3
-	testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
-		w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
-		w.Header().Add("Trailer", "Server-Trailer-C")
-
-		// TODO: decide if the server should filter these while
-		// writing the Trailer header in the response. Currently it
-		// appears net/http doesn't do this for http/1.1
-		w.Header().Add("Trailer", "Transfer-Encoding, Content-Length, Trailer") // filtered
-		w.Header().Set("Foo", "Bar")
-		w.Header().Set("Content-Length", "5")
-
-		io.WriteString(w, "Hello")
-		if withFlush {
-			w.(http.Flusher).Flush()
-		}
-		w.Header().Set("Server-Trailer-A", "valuea")
-		w.Header().Set("Server-Trailer-C", "valuec") // skipping B
-		w.Header().Set("Server-Surpise", "surprise! this isn't predeclared!")
-		w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 2616 14.40")
-		w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 2616 14.40")
-		w.Header().Set("Trailer", "should not be included; Forbidden by RFC 2616 14.40")
-		return nil
-	}, func(st *serverTester) {
-		getSlash(st)
-		hf := st.wantHeaders()
-		if hf.StreamEnded() {
-			t.Fatal("response HEADERS had END_STREAM")
-		}
-		if !hf.HeadersEnded() {
-			t.Fatal("response HEADERS didn't have END_HEADERS")
-		}
-		goth := st.decodeHeader(hf.HeaderBlockFragment())
-		wanth := [][2]string{
-			{":status", "200"},
-			{"foo", "Bar"},
-			{"trailer", "Server-Trailer-A, Server-Trailer-B"},
-			{"trailer", "Server-Trailer-C"},
-			{"trailer", "Transfer-Encoding, Content-Length, Trailer"},
-			{"content-type", "text/plain; charset=utf-8"},
-			{"content-length", "5"},
-		}
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth)
-		}
-		df := st.wantData()
-		if string(df.Data()) != "Hello" {
-			t.Fatalf("Client read %q; want Hello", df.Data())
-		}
-		if df.StreamEnded() {
-			t.Fatalf("data frame had STREAM_ENDED")
-		}
-		tf := st.wantHeaders() // for the trailers
-		if !tf.StreamEnded() {
-			t.Fatalf("trailers HEADERS lacked END_STREAM")
-		}
-		if !tf.HeadersEnded() {
-			t.Fatalf("trailers HEADERS lacked END_HEADERS")
-		}
-		wanth = [][2]string{
-			{"server-trailer-a", "valuea"},
-			{"server-trailer-c", "valuec"},
-		}
-		goth = st.decodeHeader(tf.HeaderBlockFragment())
-		if !reflect.DeepEqual(goth, wanth) {
-			t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth)
-		}
-	})
-}
-
-func BenchmarkServerGets(b *testing.B) {
-	b.ReportAllocs()
-
-	const msg = "Hello, world"
-	st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
-		io.WriteString(w, msg)
-	})
-	defer st.Close()
-	st.greet()
-
-	// Give the server quota to reply. (plus it has the the 64KB)
-	if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
-		b.Fatal(err)
-	}
-
-	for i := 0; i < b.N; i++ {
-		id := 1 + uint32(i)*2
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      id,
-			BlockFragment: st.encodeHeader(),
-			EndStream:     true,
-			EndHeaders:    true,
-		})
-		st.wantHeaders()
-		df := st.wantData()
-		if !df.StreamEnded() {
-			b.Fatalf("DATA didn't have END_STREAM; got %v", df)
-		}
-	}
-}
-
-func BenchmarkServerPosts(b *testing.B) {
-	b.ReportAllocs()
-
-	const msg = "Hello, world"
-	st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
-		io.WriteString(w, msg)
-	})
-	defer st.Close()
-	st.greet()
-
-	// Give the server quota to reply. (plus it has the the 64KB)
-	if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
-		b.Fatal(err)
-	}
-
-	for i := 0; i < b.N; i++ {
-		id := 1 + uint32(i)*2
-		st.writeHeaders(HeadersFrameParam{
-			StreamID:      id,
-			BlockFragment: st.encodeHeader(":method", "POST"),
-			EndStream:     false,
-			EndHeaders:    true,
-		})
-		st.writeData(id, true, nil)
-		st.wantHeaders()
-		df := st.wantData()
-		if !df.StreamEnded() {
-			b.Fatalf("DATA didn't have END_STREAM; got %v", df)
-		}
-	}
-}
-
-// go-fuzz bug, originally reported at https://github.com/bradfitz/http2/issues/53
-// Verify we don't hang.
-func TestIssue53(t *testing.T) {
-	const data = "PRI * HTTP/2.0\r\n\r\nSM" +
-		"\r\n\r\n\x00\x00\x00\x01\ainfinfin\ad"
-	s := &http.Server{
-		ErrorLog: log.New(io.MultiWriter(stderrv(), twriter{t: t}), "", log.LstdFlags),
-	}
-	s2 := &Server{MaxReadFrameSize: 1 << 16, PermitProhibitedCipherSuites: true}
-	c := &issue53Conn{[]byte(data), false, false}
-	s2.handleConn(s, c, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
-		w.Write([]byte("hello"))
-	}))
-	if !c.closed {
-		t.Fatal("connection is not closed")
-	}
-}
-
-type issue53Conn struct {
-	data    []byte
-	closed  bool
-	written bool
-}
-
-func (c *issue53Conn) Read(b []byte) (n int, err error) {
-	if len(c.data) == 0 {
-		return 0, io.EOF
-	}
-	n = copy(b, c.data)
-	c.data = c.data[n:]
-	return
-}
-
-func (c *issue53Conn) Write(b []byte) (n int, err error) {
-	c.written = true
-	return len(b), nil
-}
-
-func (c *issue53Conn) Close() error {
-	c.closed = true
-	return nil
-}
-
-func (c *issue53Conn) LocalAddr() net.Addr                { return &net.TCPAddr{net.IP{127, 0, 0, 1}, 49706, ""} }
-func (c *issue53Conn) RemoteAddr() net.Addr               { return &net.TCPAddr{net.IP{127, 0, 0, 1}, 49706, ""} }
-func (c *issue53Conn) SetDeadline(t time.Time) error      { return nil }
-func (c *issue53Conn) SetReadDeadline(t time.Time) error  { return nil }
-func (c *issue53Conn) SetWriteDeadline(t time.Time) error { return nil }
-
-// golang.org/issue/12895
-func TestConfigureServer(t *testing.T) {
-	tests := []struct {
-		name    string
-		in      http.Server
-		wantErr string
-	}{
-		{
-			name: "empty server",
-			in:   http.Server{},
-		},
-		{
-			name: "just the required cipher suite",
-			in: http.Server{
-				TLSConfig: &tls.Config{
-					CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
-				},
-			},
-		},
-		{
-			name: "missing required cipher suite",
-			in: http.Server{
-				TLSConfig: &tls.Config{
-					CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
-				},
-			},
-			wantErr: "is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
-		},
-		{
-			name: "required after bad",
-			in: http.Server{
-				TLSConfig: &tls.Config{
-					CipherSuites: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
-				},
-			},
-			wantErr: "contains an HTTP/2-approved cipher suite (0xc02f), but it comes after",
-		},
-		{
-			name: "bad after required",
-			in: http.Server{
-				TLSConfig: &tls.Config{
-					CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_RC4_128_SHA},
-				},
-			},
-		},
-	}
-	for _, tt := range tests {
-		err := ConfigureServer(&tt.in, nil)
-		if (err != nil) != (tt.wantErr != "") {
-			if tt.wantErr != "" {
-				t.Errorf("%s: success, but want error", tt.name)
-			} else {
-				t.Errorf("%s: unexpected error: %v", tt.name, err)
-			}
-		}
-		if err != nil && tt.wantErr != "" && !strings.Contains(err.Error(), tt.wantErr) {
-			t.Errorf("%s: err = %v; want substring %q", tt.name, err, tt.wantErr)
-		}
-		if err == nil && !tt.in.TLSConfig.PreferServerCipherSuites {
-			t.Errorf("%s: PreferServerCipherSuite is false; want true", tt.name)
-		}
-	}
-}
-
-func TestServerRejectHeadWithBody(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		// No response body.
-	})
-	defer st.Close()
-	st.greet()
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1, // clients send odd numbers
-		BlockFragment: st.encodeHeader(":method", "HEAD"),
-		EndStream:     false, // what we're testing, a bogus HEAD request with body
-		EndHeaders:    true,
-	})
-	st.wantRSTStream(1, ErrCodeProtocol)
-}
-
-func TestServerNoAutoContentLengthOnHead(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		// No response body. (or smaller than one frame)
-	})
-	defer st.Close()
-	st.greet()
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1, // clients send odd numbers
-		BlockFragment: st.encodeHeader(":method", "HEAD"),
-		EndStream:     true,
-		EndHeaders:    true,
-	})
-	h := st.wantHeaders()
-	headers := st.decodeHeader(h.HeaderBlockFragment())
-	want := [][2]string{
-		{":status", "200"},
-		{"content-type", "text/plain; charset=utf-8"},
-	}
-	if !reflect.DeepEqual(headers, want) {
-		t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
-	}
-}
-
-// golang.org/issue/13495
-func TestServerNoDuplicateContentType(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		w.Header()["Content-Type"] = []string{""}
-		fmt.Fprintf(w, "<html><head></head><body>hi</body></html>")
-	})
-	defer st.Close()
-	st.greet()
-	st.writeHeaders(HeadersFrameParam{
-		StreamID:      1,
-		BlockFragment: st.encodeHeader(),
-		EndStream:     true,
-		EndHeaders:    true,
-	})
-	h := st.wantHeaders()
-	headers := st.decodeHeader(h.HeaderBlockFragment())
-	want := [][2]string{
-		{":status", "200"},
-		{"content-type", ""},
-		{"content-length", "41"},
-	}
-	if !reflect.DeepEqual(headers, want) {
-		t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
-	}
-}

+ 0 - 5021
Godeps/_workspace/src/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml

@@ -1,5021 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/xsl" href="lib/rfc2629.xslt"?>
-<?rfc toc="yes" ?>
-<?rfc symrefs="yes" ?>
-<?rfc sortrefs="yes" ?>
-<?rfc compact="yes"?>
-<?rfc subcompact="no" ?>
-<?rfc linkmailto="no" ?>
-<?rfc editing="no" ?>
-<?rfc comments="yes" ?>
-<?rfc inline="yes"?>
-<?rfc rfcedstyle="yes"?>
-<?rfc-ext allow-markup-in-artwork="yes" ?>
-<?rfc-ext include-index="no" ?>
-
-<rfc ipr="trust200902"
-     category="std"
-     docName="draft-ietf-httpbis-http2-latest"
-     x:maturity-level="proposed"
-     xmlns:x="http://purl.org/net/xml2rfc/ext">
-  <x:feedback template="mailto:ietf-http-wg@w3.org?subject={docname},%20%22{section}%22&amp;body=&lt;{ref}&gt;:"/>
-  <front>
-    <title abbrev="HTTP/2">Hypertext Transfer Protocol version 2</title>
-
-    <author initials="M." surname="Belshe" fullname="Mike Belshe">
-      <organization>Twist</organization>
-      <address>
-        <email>mbelshe@chromium.org</email>
-      </address>
-    </author>
-
-    <author initials="R." surname="Peon" fullname="Roberto Peon">
-      <organization>Google, Inc</organization>
-      <address>
-        <email>fenix@google.com</email>
-      </address>
-    </author>
-
-    <author initials="M." surname="Thomson" fullname="Martin Thomson" role="editor">
-      <organization>Mozilla</organization>
-      <address>
-        <postal>
-          <street>331 E Evelyn Street</street>
-          <city>Mountain View</city>
-          <region>CA</region>
-          <code>94041</code>
-          <country>US</country>
-        </postal>
-        <email>martin.thomson@gmail.com</email>
-      </address>
-    </author>
-
-    <date year="2014" />
-    <area>Applications</area>
-    <workgroup>HTTPbis</workgroup>
-    <keyword>HTTP</keyword>
-    <keyword>SPDY</keyword>
-    <keyword>Web</keyword>
-
-    <abstract>
-      <t>
-        This specification describes an optimized expression of the semantics of the Hypertext
-        Transfer Protocol (HTTP). HTTP/2 enables a more efficient use of network resources and a
-        reduced perception of latency by introducing header field compression and allowing multiple
-        concurrent messages on the same connection. It also introduces unsolicited push of
-        representations from servers to clients.
-      </t>
-      <t>
-        This specification is an alternative to, but does not obsolete, the HTTP/1.1 message syntax.
-        HTTP's existing semantics remain unchanged.
-      </t>
-    </abstract>
-
-    <note title="Editorial Note (To be removed by RFC Editor)">
-      <t>
-        Discussion of this draft takes place on the HTTPBIS working group mailing list
-        (ietf-http-wg@w3.org), which is archived at <eref
-        target="https://lists.w3.org/Archives/Public/ietf-http-wg/"/>.
-      </t>
-      <t>
-        Working Group information can be found at <eref
-        target="https://tools.ietf.org/wg/httpbis/"/>; that specific to HTTP/2 are at <eref
-        target="https://http2.github.io/"/>.
-      </t>
-      <t>
-        The changes in this draft are summarized in <xref
-        target="change.log"/>.
-      </t>
-    </note>
-
-  </front>
-
-  <middle>
-    <section anchor="intro" title="Introduction">
-
-      <t>
-        The Hypertext Transfer Protocol (HTTP) is a wildly successful protocol. However, the
-        HTTP/1.1 message format (<xref target="RFC7230" x:fmt="," x:rel="#http.message"/>) has
-        several characteristics that have a negative overall effect on application performance
-        today.
-      </t>
-      <t>
-        In particular, HTTP/1.0 allowed only one request to be outstanding at a time on a given
-        TCP connection. HTTP/1.1 added request pipelining, but this only partially addressed
-        request concurrency and still suffers from head-of-line blocking. Therefore, HTTP/1.1
-        clients that need to make many requests typically use multiple connections to a server in
-        order to achieve concurrency and thereby reduce latency.
-      </t>
-      <t>
-        Furthermore, HTTP header fields are often repetitive and verbose, causing unnecessary
-        network traffic, as well as causing the initial <xref target="TCP">TCP</xref> congestion
-        window to quickly fill. This can result in excessive latency when multiple requests are
-        made on a new TCP connection.
-      </t>
-      <t>
-        HTTP/2 addresses these issues by defining an optimized mapping of HTTP's semantics to an
-        underlying connection. Specifically, it allows interleaving of request and response
-        messages on the same connection and uses an efficient coding for HTTP header fields. It
-        also allows prioritization of requests, letting more important requests complete more
-        quickly, further improving performance.
-      </t>
-      <t>
-        The resulting protocol is more friendly to the network, because fewer TCP connections can
-        be used in comparison to HTTP/1.x. This means less competition with other flows, and
-        longer-lived connections, which in turn leads to better utilization of available network
-        capacity.
-      </t>
-      <t>
-        Finally, HTTP/2 also enables more efficient processing of messages through use of binary
-        message framing.
-      </t>
-    </section>
-
-    <section anchor="Overview" title="HTTP/2 Protocol Overview">
-      <t>
-        HTTP/2 provides an optimized transport for HTTP semantics.  HTTP/2 supports all of the core
-        features of HTTP/1.1, but aims to be more efficient in several ways.
-      </t>
-      <t>
-        The basic protocol unit in HTTP/2 is a <xref target="FrameHeader">frame</xref>.  Each frame
-        type serves a different purpose.  For example, <x:ref>HEADERS</x:ref> and
-        <x:ref>DATA</x:ref> frames form the basis of <xref target="HttpSequence">HTTP requests and
-        responses</xref>; other frame types like <x:ref>SETTINGS</x:ref>,
-        <x:ref>WINDOW_UPDATE</x:ref>, and <x:ref>PUSH_PROMISE</x:ref> are used in support of other
-        HTTP/2 features.
-      </t>
-      <t>
-        Multiplexing of requests is achieved by having each HTTP request-response exchange
-        associated with its own <xref target="StreamsLayer">stream</xref>. Streams are largely
-        independent of each other, so a blocked or stalled request or response does not prevent
-        progress on other streams.
-      </t>
-      <t>
-        Flow control and prioritization ensure that it is possible to efficiently use multiplexed
-        streams.  <xref target="FlowControl">Flow control</xref> helps to ensure that only data that
-        can be used by a receiver is transmitted.  <xref
-        target="StreamPriority">Prioritization</xref> ensures that limited resources can be directed
-        to the most important streams first.
-      </t>
-      <t>
-        HTTP/2 adds a new interaction mode, whereby a server can <xref target="PushResources">push
-        responses to a client</xref>.  Server push allows a server to speculatively send a client
-        data that the server anticipates the client will need, trading off some network usage
-        against a potential latency gain.  The server does this by synthesizing a request, which it
-        sends as a <x:ref>PUSH_PROMISE</x:ref> frame.  The server is then able to send a response to
-        the synthetic request on a separate stream.
-      </t>
-      <t>
-        Frames that contain HTTP header fields are <xref target="HeaderBlock">compressed</xref>.
-        HTTP requests can be highly redundant, so compression can reduce the size of requests and
-        responses significantly.
-      </t>
-
-      <section title="Document Organization">
-        <t>
-          The HTTP/2 specification is split into four parts:
-          <list style="symbols">
-            <t>
-              <xref target="starting">Starting HTTP/2</xref> covers how an HTTP/2 connection is
-              initiated.
-            </t>
-            <t>
-              The <xref target="FramingLayer">framing</xref> and <xref
-              target="StreamsLayer">streams</xref> layers describe the way HTTP/2 frames are
-              structured and formed into multiplexed streams.
-            </t>
-            <t>
-              <xref target="FrameTypes">Frame</xref> and <xref target="ErrorCodes">error</xref>
-              definitions include details of the frame and error types used in HTTP/2.
-            </t>
-            <t>
-              <xref target="HTTPLayer">HTTP mappings</xref> and <xref target="HttpExtra">additional
-              requirements</xref> describe how HTTP semantics are expressed using frames and
-              streams.
-          </t>
-          </list>
-        </t>
-        <t>
-          While some of the frame and stream layer concepts are isolated from HTTP, this
-          specification does not define a completely generic framing layer. The framing and streams
-          layers are tailored to the needs of the HTTP protocol and server push.
-        </t>
-      </section>
-
-      <section title="Conventions and Terminology">
-        <t>
-          The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD
-          NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as
-          described in <xref target="RFC2119">RFC 2119</xref>.
-        </t>
-        <t>
-          All numeric values are in network byte order.  Values are unsigned unless otherwise
-          indicated.  Literal values are provided in decimal or hexadecimal as appropriate.
-          Hexadecimal literals are prefixed with <spanx style="verb">0x</spanx> to distinguish them
-          from decimal literals.
-        </t>
-        <t>
-          The following terms are used:
-          <list style="hanging">
-            <t hangText="client:">
-              The endpoint initiating the HTTP/2 connection.
-            </t>
-            <t hangText="connection:">
-              A transport-layer connection between two endpoints.
-            </t>
-            <t hangText="connection error:">
-              An error that affects the entire HTTP/2 connection.
-            </t>
-            <t hangText="endpoint:">
-              Either the client or server of the connection.
-            </t>
-            <t hangText="frame:">
-              The smallest unit of communication within an HTTP/2 connection, consisting of a header
-              and a variable-length sequence of octets structured according to the frame type.
-            </t>
-            <t hangText="peer:">
-              An endpoint.  When discussing a particular endpoint, "peer" refers to the endpoint
-              that is remote to the primary subject of discussion.
-            </t>
-            <t hangText="receiver:">
-              An endpoint that is receiving frames.
-            </t>
-            <t hangText="sender:">
-              An endpoint that is transmitting frames.
-            </t>
-            <t hangText="server:">
-              The endpoint which did not initiate the HTTP/2 connection.
-            </t>
-            <t hangText="stream:">
-              A bi-directional flow of frames across a virtual channel within the HTTP/2 connection.
-            </t>
-            <t hangText="stream error:">
-              An error on the individual HTTP/2 stream.
-            </t>
-          </list>
-        </t>
-        <t>
-          Finally, the terms "gateway", "intermediary", "proxy", and "tunnel" are defined
-          in <xref target="RFC7230" x:fmt="of" x:rel="#intermediaries"/>.
-        </t>
-      </section>
-    </section>
-
-    <section anchor="starting" title="Starting HTTP/2">
-      <t>
-        An HTTP/2 connection is an application layer protocol running on top of a TCP connection
-        (<xref target="TCP"/>). The client is the TCP connection initiator.
-      </t>
-      <t>
-        HTTP/2 uses the same "http" and "https" URI schemes used by HTTP/1.1. HTTP/2 shares the same
-        default port numbers: 80 for "http" URIs and 443 for "https" URIs.  As a result,
-        implementations processing requests for target resource URIs like <spanx
-        style="verb">http://example.org/foo</spanx> or <spanx
-        style="verb">https://example.com/bar</spanx> are required to first discover whether the
-        upstream server (the immediate peer to which the client wishes to establish a connection)
-        supports HTTP/2.
-      </t>
-
-      <t>
-        The means by which support for HTTP/2 is determined is different for "http" and "https"
-        URIs. Discovery for "http" URIs is described in <xref target="discover-http"/>.  Discovery
-        for "https" URIs is described in <xref target="discover-https"/>.
-      </t>
-
-      <section anchor="versioning" title="HTTP/2 Version Identification">
-        <t>
-          The protocol defined in this document has two identifiers.
-          <list style="symbols">
-            <x:lt>
-              <t>
-                The string "h2" identifies the protocol where HTTP/2 uses <xref
-                target="TLS12">TLS</xref>.  This identifier is used in the <xref
-                target="TLS-ALPN">TLS application layer protocol negotiation extension (ALPN)</xref>
-                field and any place that HTTP/2 over TLS is identified.
-              </t>
-              <t>
-                The "h2" string is serialized into an ALPN protocol identifier as the two octet
-                sequence: 0x68, 0x32.
-              </t>
-            </x:lt>
-            <x:lt>
-              <t>
-                The string "h2c" identifies the protocol where HTTP/2 is run over cleartext TCP.
-                This identifier is used in the HTTP/1.1 Upgrade header field and any place that
-                HTTP/2 over TCP is identified.
-              </t>
-            </x:lt>
-          </list>
-        </t>
-        <t>
-          Negotiating "h2" or "h2c" implies the use of the transport, security, framing and message
-          semantics described in this document.
-        </t>
-        <t>
-          <cref>RFC Editor's Note: please remove the remainder of this section prior to the
-          publication of a final version of this document.</cref>
-        </t>
-        <t>
-          Only implementations of the final, published RFC can identify themselves as "h2" or "h2c".
-          Until such an RFC exists, implementations MUST NOT identify themselves using these
-          strings.
-        </t>
-        <t>
-          Examples and text throughout the rest of this document use "h2" as a matter of
-          editorial convenience only.  Implementations of draft versions MUST NOT identify using
-          this string.
-        </t>
-        <t>
-          Implementations of draft versions of the protocol MUST add the string "-" and the
-          corresponding draft number to the identifier. For example, draft-ietf-httpbis-http2-11
-          over TLS is identified using the string "h2-11".
-        </t>
-        <t>
-          Non-compatible experiments that are based on these draft versions MUST append the string
-          "-" and an experiment name to the identifier.  For example, an experimental implementation
-          of packet mood-based encoding based on draft-ietf-httpbis-http2-09 might identify itself
-          as "h2-09-emo".  Note that any label MUST conform to the "token" syntax defined in
-          <xref target="RFC7230" x:fmt="of" x:rel="#field.components"/>.  Experimenters are
-          encouraged to coordinate their experiments on the ietf-http-wg@w3.org mailing list.
-        </t>
-      </section>
-
-      <section anchor="discover-http" title="Starting HTTP/2 for &quot;http&quot; URIs">
-        <t>
-          A client that makes a request for an "http" URI without prior knowledge about support for
-          HTTP/2 uses the HTTP Upgrade mechanism (<xref target="RFC7230" x:fmt="of"
-          x:rel="#header.upgrade"/>).  The client makes an HTTP/1.1 request that includes an Upgrade
-          header field identifying HTTP/2 with the "h2c" token.  The HTTP/1.1 request MUST include
-          exactly one <xref target="Http2SettingsHeader">HTTP2-Settings</xref> header field.
-        </t>
-        <figure>
-          <preamble>For example:</preamble>
-          <artwork type="message/http; msgtype=&#34;request&#34;" x:indent-with="  "><![CDATA[
-GET / HTTP/1.1
-Host: server.example.com
-Connection: Upgrade, HTTP2-Settings
-Upgrade: h2c
-HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
-
-]]></artwork>
-        </figure>
-        <t>
-          Requests that contain an entity body MUST be sent in their entirety before the client can
-          send HTTP/2 frames.  This means that a large request entity can block the use of the
-          connection until it is completely sent.
-        </t>
-        <t>
-          If concurrency of an initial request with subsequent requests is important, an OPTIONS
-          request can be used to perform the upgrade to HTTP/2, at the cost of an additional
-          round-trip.
-        </t>
-        <t>
-          A server that does not support HTTP/2 can respond to the request as though the Upgrade
-          header field were absent:
-        </t>
-        <figure>
-          <artwork type="message/http; msgtype=&#34;response&#34;" x:indent-with="  ">
-HTTP/1.1 200 OK
-Content-Length: 243
-Content-Type: text/html
-
-...
-</artwork>
-        </figure>
-        <t>
-          A server MUST ignore a "h2" token in an Upgrade header field.  Presence of a token with
-          "h2" implies HTTP/2 over TLS, which is instead negotiated as described in <xref
-          target="discover-https"/>.
-        </t>
-        <t>
-          A server that supports HTTP/2 can accept the upgrade with a 101 (Switching Protocols)
-          response.  After the empty line that terminates the 101 response, the server can begin
-          sending HTTP/2 frames.  These frames MUST include a response to the request that initiated
-          the Upgrade.
-        </t>
-
-        <figure>
-          <preamble>
-            For example:
-          </preamble>
-          <artwork type="message/http; msgtype=&#34;response&#34;" x:indent-with="  ">
-HTTP/1.1 101 Switching Protocols
-Connection: Upgrade
-Upgrade: h2c
-
-[ HTTP/2 connection ...
-</artwork>
-        </figure>
-        <t>
-          The first HTTP/2 frame sent by the server is a <x:ref>SETTINGS</x:ref> frame (<xref
-          target="SETTINGS"/>) as the server connection preface (<xref
-          target="ConnectionHeader"/>). Upon receiving the 101 response, the client sends a <xref
-          target="ConnectionHeader">connection preface</xref>, which includes a
-          <x:ref>SETTINGS</x:ref> frame.
-        </t>
-        <t>
-          The HTTP/1.1 request that is sent prior to upgrade is assigned stream identifier 1 and is
-          assigned <xref target="pri-default">default priority values</xref>.  Stream 1 is
-          implicitly half closed from the client toward the server, since the request is completed
-          as an HTTP/1.1 request.  After commencing the HTTP/2 connection, stream 1 is used for the
-          response.
-        </t>
-
-        <section anchor="Http2SettingsHeader" title="HTTP2-Settings Header Field">
-          <t>
-            A request that upgrades from HTTP/1.1 to HTTP/2 MUST include exactly one <spanx
-            style="verb">HTTP2-Settings</spanx> header field.  The <spanx
-            style="verb">HTTP2-Settings</spanx> header field is a connection-specific header field
-            that includes parameters that govern the HTTP/2 connection, provided in anticipation of
-            the server accepting the request to upgrade.
-          </t>
-          <figure>
-            <artwork type="abnf" x:indent-with="  "><![CDATA[
-HTTP2-Settings    = token68
-]]></artwork>
-          </figure>
-          <t>
-            A server MUST NOT upgrade the connection to HTTP/2 if this header field is not present,
-            or if more than one is present. A server MUST NOT send this header field.
-          </t>
-
-          <t>
-            The content of the <spanx style="verb">HTTP2-Settings</spanx> header field is the
-            payload of a <x:ref>SETTINGS</x:ref> frame (<xref target="SETTINGS"/>), encoded as a
-            base64url string (that is, the URL- and filename-safe Base64 encoding described in <xref
-            target="RFC4648" x:fmt="of" x:sec="5"/>, with any trailing '=' characters omitted).  The
-            <xref target="RFC5234">ABNF</xref> production for <spanx style="verb">token68</spanx> is
-            defined in <xref target="RFC7235" x:fmt="of" x:rel="#challenge.and.response"/>.
-          </t>
-          <t>
-            Since the upgrade is only intended to apply to the immediate connection, a client
-            sending <spanx style="verb">HTTP2-Settings</spanx> MUST also send <spanx
-            style="verb">HTTP2-Settings</spanx> as a connection option in the <spanx
-            style="verb">Connection</spanx> header field to prevent it from being forwarded
-            downstream.
-          </t>
-          <t>
-            A server decodes and interprets these values as it would any other
-            <x:ref>SETTINGS</x:ref> frame.  <xref target="SettingsSync">Acknowledgement of the
-            SETTINGS parameters</xref> is not necessary, since a 101 response serves as implicit
-            acknowledgment.  Providing these values in the Upgrade request gives a client an
-            opportunity to provide parameters prior to receiving any frames from the server.
-          </t>
-        </section>
-      </section>
-
-      <section anchor="discover-https" title="Starting HTTP/2 for &quot;https&quot; URIs">
-        <t>
-          A client that makes a request to an "https" URI uses <xref target="TLS12">TLS</xref>
-          with the <xref target="TLS-ALPN">application layer protocol negotiation extension</xref>.
-        </t>
-        <t>
-          HTTP/2 over TLS uses the "h2" application token.  The "h2c" token MUST NOT be sent by a
-          client or selected by a server.
-        </t>
-        <t>
-          Once TLS negotiation is complete, both the client and the server send a <xref
-          target="ConnectionHeader">connection preface</xref>.
-        </t>
-      </section>
-
-      <section anchor="known-http" title="Starting HTTP/2 with Prior Knowledge">
-        <t>
-          A client can learn that a particular server supports HTTP/2 by other means.  For example,
-          <xref target="ALT-SVC"/> describes a mechanism for advertising this capability.
-        </t>
-        <t>
-          A client MAY immediately send HTTP/2 frames to a server that is known to support HTTP/2,
-          after the <xref target="ConnectionHeader">connection preface</xref>; a server can
-          identify such a connection by the presence of the connection preface. This only affects
-          the establishment of HTTP/2 connections over cleartext TCP; implementations that support
-          HTTP/2 over TLS MUST use <xref target="TLS-ALPN">protocol negotiation in TLS</xref>.
-        </t>
-        <t>
-          Without additional information, prior support for HTTP/2 is not a strong signal that a
-          given server will support HTTP/2 for future connections. For example, it is possible for
-          server configurations to change, for configurations to differ between instances in
-          clustered servers, or for network conditions to change.
-        </t>
-      </section>
-
-      <section anchor="ConnectionHeader" title="HTTP/2 Connection Preface">
-        <t>
-          Upon establishment of a TCP connection and determination that HTTP/2 will be used by both
-          peers, each endpoint MUST send a connection preface as a final confirmation and to
-          establish the initial SETTINGS parameters for the HTTP/2 connection.  The client and
-          server each send a different connection preface.
-        </t>
-        <t>
-          The client connection preface starts with a sequence of 24 octets, which in hex notation
-          are:
-        </t>
-        <figure>
-          <artwork type="inline" x:indent-with="  "><![CDATA[
-0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
-]]></artwork>
-        </figure>
-        <t>
-          (the string <spanx style="verb">PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n</spanx>).  This sequence
-          is followed by a <x:ref>SETTINGS</x:ref> frame (<xref target="SETTINGS"/>).  The
-          <x:ref>SETTINGS</x:ref> frame MAY be empty.  The client sends the client connection
-          preface immediately upon receipt of a 101 Switching Protocols response (indicating a
-          successful upgrade), or as the first application data octets of a TLS connection. If
-          starting an HTTP/2 connection with prior knowledge of server support for the protocol, the
-          client connection preface is sent upon connection establishment.
-        </t>
-        <t>
-          <list>
-            <t>
-              The client connection preface is selected so that a large proportion of HTTP/1.1 or
-              HTTP/1.0 servers and intermediaries do not attempt to process further frames.  Note
-              that this does not address the concerns raised in <xref target="TALKING"/>.
-            </t>
-          </list>
-        </t>
-        <t>
-          The server connection preface consists of a potentially empty <x:ref>SETTINGS</x:ref>
-          frame (<xref target="SETTINGS"/>) that MUST be the first frame the server sends in the
-          HTTP/2 connection.
-        </t>
-        <t>
-          The <x:ref>SETTINGS</x:ref> frames received from a peer as part of the connection preface
-          MUST be acknowledged (see <xref target="SettingsSync"/>) after sending the connection
-          preface.
-        </t>
-        <t>
-          To avoid unnecessary latency, clients are permitted to send additional frames to the
-          server immediately after sending the client connection preface, without waiting to receive
-          the server connection preface.  It is important to note, however, that the server
-          connection preface <x:ref>SETTINGS</x:ref> frame might include parameters that necessarily
-          alter how a client is expected to communicate with the server. Upon receiving the
-          <x:ref>SETTINGS</x:ref> frame, the client is expected to honor any parameters established.
-          In some configurations, it is possible for the server to transmit <x:ref>SETTINGS</x:ref>
-          before the client sends additional frames, providing an opportunity to avoid this issue.
-        </t>
-        <t>
-          Clients and servers MUST treat an invalid connection preface as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.  A <x:ref>GOAWAY</x:ref> frame (<xref target="GOAWAY"/>)
-          MAY be omitted in this case, since an invalid preface indicates that the peer is not using
-          HTTP/2.
-        </t>
-      </section>
-    </section>
-
-    <section anchor="FramingLayer" title="HTTP Frames">
-      <t>
-        Once the HTTP/2 connection is established, endpoints can begin exchanging frames.
-      </t>
-
-      <section anchor="FrameHeader" title="Frame Format">
-        <t>
-          All frames begin with a fixed 9-octet header followed by a variable-length payload.
-        </t>
-        <figure title="Frame Layout">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |                 Length (24)                   |
- +---------------+---------------+---------------+
- |   Type (8)    |   Flags (8)   |
- +-+-+-----------+---------------+-------------------------------+
- |R|                 Stream Identifier (31)                      |
- +=+=============================================================+
- |                   Frame Payload (0...)                      ...
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-        <t>
-          The fields of the frame header are defined as:
-          <list style="hanging">
-            <x:lt hangText="Length:">
-              <t>
-                The length of the frame payload expressed as an unsigned 24-bit integer.  Values
-                greater than 2<x:sup>14</x:sup> (16,384) MUST NOT be sent unless the receiver has
-                set a larger value for <x:ref>SETTINGS_MAX_FRAME_SIZE</x:ref>.
-              </t>
-              <t>
-                The 9 octets of the frame header are not included in this value.
-              </t>
-            </x:lt>
-            <x:lt hangText="Type:">
-              <t>
-                The 8-bit type of the frame.  The frame type determines the format and semantics of
-                the frame.  Implementations MUST ignore and discard any frame that has a type that
-                is unknown.
-              </t>
-            </x:lt>
-            <x:lt hangText="Flags:">
-              <t>
-                An 8-bit field reserved for frame-type specific boolean flags.
-              </t>
-              <t>
-                Flags are assigned semantics specific to the indicated frame type.  Flags that have
-                no defined semantics for a particular frame type MUST be ignored, and MUST be left
-                unset (0) when sending.
-              </t>
-            </x:lt>
-            <x:lt hangText="R:">
-              <t>
-                A reserved 1-bit field.  The semantics of this bit are undefined and the bit MUST
-                remain unset (0) when sending and MUST be ignored when receiving.
-              </t>
-            </x:lt>
-            <x:lt hangText="Stream Identifier:">
-              <t>
-                A 31-bit stream identifier (see <xref target="StreamIdentifiers"/>).  The value 0 is
-                reserved for frames that are associated with the connection as a whole as opposed to
-                an individual stream.
-              </t>
-            </x:lt>
-          </list>
-        </t>
-        <t>
-          The structure and content of the frame payload is dependent entirely on the frame type.
-        </t>
-      </section>
-
-      <section anchor="FrameSize" title="Frame Size">
-        <t>
-          The size of a frame payload is limited by the maximum size that a receiver advertises in
-          the <x:ref>SETTINGS_MAX_FRAME_SIZE</x:ref> setting.  This setting can have any value
-          between 2<x:sup>14</x:sup> (16,384) and 2<x:sup>24</x:sup>-1 (16,777,215) octets,
-          inclusive.
-        </t>
-        <t>
-          All implementations MUST be capable of receiving and minimally processing frames up to
-          2<x:sup>14</x:sup> octets in length, plus the 9 octet <xref target="FrameHeader">frame
-          header</xref>.  The size of the frame header is not included when describing frame sizes.
-          <list style="hanging">
-            <t hangText="Note:">
-              Certain frame types, such as <xref target="PING">PING</xref>, impose additional limits
-              on the amount of payload data allowed.
-            </t>
-          </list>
-        </t>
-        <t>
-          If a frame size exceeds any defined limit, or is too small to contain mandatory frame
-          data, the endpoint MUST send a <x:ref>FRAME_SIZE_ERROR</x:ref> error. A frame size error
-          in a frame that could alter the state of the entire connection MUST be treated as a <xref
-          target="ConnectionErrorHandler">connection error</xref>; this includes any frame carrying
-          a <xref target="HeaderBlock">header block</xref> (that is, <x:ref>HEADERS</x:ref>,
-          <x:ref>PUSH_PROMISE</x:ref>, and <x:ref>CONTINUATION</x:ref>), <x:ref>SETTINGS</x:ref>,
-          and any <x:ref>WINDOW_UPDATE</x:ref> frame with a stream identifier of 0.
-        </t>
-        <t>
-          Endpoints are not obligated to use all available space in a frame. Responsiveness can be
-          improved by using frames that are smaller than the permitted maximum size. Sending large
-          frames can result in delays in sending time-sensitive frames (such
-          <x:ref>RST_STREAM</x:ref>, <x:ref>WINDOW_UPDATE</x:ref>, or <x:ref>PRIORITY</x:ref>)
-          which if blocked by the transmission of a large frame, could affect performance.
-        </t>
-      </section>
-
-      <section anchor="HeaderBlock" title="Header Compression and Decompression">
-        <t>
-          Just as in HTTP/1, a header field in HTTP/2 is a name with one or more associated values.
-          They are used within HTTP request and response messages as well as server push operations
-          (see <xref target="PushResources" />).
-        </t>
-        <t>
-          Header lists are collections of zero or more header fields.  When transmitted over a
-          connection, a header list is serialized into a header block using <xref
-          target="COMPRESSION">HTTP Header Compression</xref>.  The serialized header block is then
-          divided into one or more octet sequences, called header block fragments, and transmitted
-          within the payload of <xref target="HEADERS">HEADERS</xref>, <xref
-          target="PUSH_PROMISE">PUSH_PROMISE</xref> or <xref
-          target="CONTINUATION">CONTINUATION</xref> frames.
-        </t>
-        <t>
-          The <xref target="COOKIE">Cookie header field</xref> is treated specially by the HTTP
-          mapping (see <xref target="CompressCookie"/>).
-        </t>
-        <t>
-          A receiving endpoint reassembles the header block by concatenating its fragments, then
-          decompresses the block to reconstruct the header list.
-        </t>
-        <t>
-          A complete header block consists of either:
-          <list style="symbols">
-            <t>
-              a single <x:ref>HEADERS</x:ref> or <x:ref>PUSH_PROMISE</x:ref> frame,
-              with the END_HEADERS flag set, or
-            </t>
-            <t>
-              a <x:ref>HEADERS</x:ref> or <x:ref>PUSH_PROMISE</x:ref> frame with the END_HEADERS
-              flag cleared and one or more <x:ref>CONTINUATION</x:ref> frames,
-              where the last <x:ref>CONTINUATION</x:ref> frame has the END_HEADERS flag set.
-            </t>
-          </list>
-        </t>
-        <t>
-          Header compression is stateful.  One compression context and one decompression context is
-          used for the entire connection.  Each header block is processed as a discrete unit.
-          Header blocks MUST be transmitted as a contiguous sequence of frames, with no interleaved
-          frames of any other type or from any other stream.  The last frame in a sequence of
-          <x:ref>HEADERS</x:ref> or <x:ref>CONTINUATION</x:ref> frames MUST have the END_HEADERS
-          flag set.  The last frame in a sequence of <x:ref>PUSH_PROMISE</x:ref> or
-          <x:ref>CONTINUATION</x:ref> frames MUST have the END_HEADERS flag set.  This allows a
-          header block to be logically equivalent to a single frame.
-        </t>
-        <t>
-          Header block fragments can only be sent as the payload of <x:ref>HEADERS</x:ref>,
-          <x:ref>PUSH_PROMISE</x:ref> or <x:ref>CONTINUATION</x:ref> frames, because these frames
-          carry data that can modify the compression context maintained by a receiver.  An endpoint
-          receiving <x:ref>HEADERS</x:ref>, <x:ref>PUSH_PROMISE</x:ref> or
-          <x:ref>CONTINUATION</x:ref> frames MUST reassemble header blocks and perform decompression
-          even if the frames are to be discarded.  A receiver MUST terminate the connection with a
-          <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>COMPRESSION_ERROR</x:ref> if it does not decompress a header block.
-        </t>
-      </section>
-    </section>
-
-    <section anchor="StreamsLayer" title="Streams and Multiplexing">
-      <t>
-        A "stream" is an independent, bi-directional sequence of frames exchanged between the client
-        and server within an HTTP/2 connection.  Streams have several important characteristics:
-        <list style="symbols">
-          <t>
-            A single HTTP/2 connection can contain multiple concurrently open streams, with either
-            endpoint interleaving frames from multiple streams.
-          </t>
-          <t>
-            Streams can be established and used unilaterally or shared by either the client or
-            server.
-          </t>
-          <t>
-            Streams can be closed by either endpoint.
-          </t>
-          <t>
-            The order in which frames are sent on a stream is significant. Recipients process frames
-            in the order they are received.  In particular, the order of <x:ref>HEADERS</x:ref>,
-            and <x:ref>DATA</x:ref> frames is semantically significant.
-          </t>
-          <t>
-            Streams are identified by an integer.  Stream identifiers are assigned to streams by the
-            endpoint initiating the stream.
-          </t>
-        </list>
-      </t>
-
-      <section anchor="StreamStates" title="Stream States">
-        <t>
-          The lifecycle of a stream is shown in <xref target="StreamStatesFigure"/>.
-        </t>
-
-        <figure anchor="StreamStatesFigure" title="Stream States">
-          <artwork type="drawing">
-            <![CDATA[
-                           +--------+
-                     PP    |        |    PP
-                  ,--------|  idle  |--------.
-                 /         |        |         \
-                v          +--------+          v
-         +----------+          |           +----------+
-         |          |          | H         |          |
-     ,---| reserved |          |           | reserved |---.
-     |   | (local)  |          v           | (remote) |   |
-     |   +----------+      +--------+      +----------+   |
-     |      |          ES  |        |  ES          |      |
-     |      | H    ,-------|  open  |-------.      | H    |
-     |      |     /        |        |        \     |      |
-     |      v    v         +--------+         v    v      |
-     |   +----------+          |           +----------+   |
-     |   |   half   |          |           |   half   |   |
-     |   |  closed  |          | R         |  closed  |   |
-     |   | (remote) |          |           | (local)  |   |
-     |   +----------+          |           +----------+   |
-     |        |                v                 |        |
-     |        |  ES / R    +--------+  ES / R    |        |
-     |        `----------->|        |<-----------'        |
-     |  R                  | closed |                  R  |
-     `-------------------->|        |<--------------------'
-                           +--------+
-
-       H:  HEADERS frame (with implied CONTINUATIONs)
-       PP: PUSH_PROMISE frame (with implied CONTINUATIONs)
-       ES: END_STREAM flag
-       R:  RST_STREAM frame
-]]>
-          </artwork>
-        </figure>
-
-        <t>
-          Note that this diagram shows stream state transitions and the frames and flags that affect
-          those transitions only.  In this regard, <x:ref>CONTINUATION</x:ref> frames do not result
-          in state transitions; they are effectively part of the <x:ref>HEADERS</x:ref> or
-          <x:ref>PUSH_PROMISE</x:ref> that they follow.  For this purpose, the END_STREAM flag is
-          processed as a separate event to the frame that bears it; a <x:ref>HEADERS</x:ref> frame
-          with the END_STREAM flag set can cause two state transitions.
-        </t>
-        <t>
-          Both endpoints have a subjective view of the state of a stream that could be different
-          when frames are in transit.  Endpoints do not coordinate the creation of streams; they are
-          created unilaterally by either endpoint.  The negative consequences of a mismatch in
-          states are limited to the "closed" state after sending <x:ref>RST_STREAM</x:ref>, where
-          frames might be received for some time after closing.
-        </t>
-        <t>
-          Streams have the following states:
-          <list style="hanging">
-
-            <x:lt hangText="idle:">
-              <t>
-                <vspace blankLines="0"/>
-                All streams start in the "idle" state.  In this state, no frames have been
-                exchanged.
-              </t>
-              <t>
-                The following transitions are valid from this state:
-                <list style="symbols">
-                  <t>
-                    Sending or receiving a <x:ref>HEADERS</x:ref> frame causes the stream to become
-                    "open".  The stream identifier is selected as described in <xref
-                    target="StreamIdentifiers"/>.  The same <x:ref>HEADERS</x:ref> frame can also
-                    cause a stream to immediately become "half closed".
-                  </t>
-                  <t>
-                    Sending a <x:ref>PUSH_PROMISE</x:ref> frame marks the associated stream for
-                    later use.  The stream state for the reserved stream transitions to "reserved
-                    (local)".
-                  </t>
-                  <t>
-                    Receiving a <x:ref>PUSH_PROMISE</x:ref> frame marks the associated stream as
-                    reserved by the remote peer.  The state of the stream becomes "reserved
-                    (remote)".
-                  </t>
-                </list>
-              </t>
-              <t>
-                Receiving any frames other than <x:ref>HEADERS</x:ref> or
-                <x:ref>PUSH_PROMISE</x:ref> on a stream in this state MUST be treated as a <xref
-                target="ConnectionErrorHandler">connection error</xref> of type
-                <x:ref>PROTOCOL_ERROR</x:ref>.
-              </t>
-            </x:lt>
-
-            <x:lt hangText="reserved (local):">
-              <t>
-                <vspace blankLines="0"/>
-                A stream in the "reserved (local)" state is one that has been promised by sending a
-                <x:ref>PUSH_PROMISE</x:ref> frame.  A <x:ref>PUSH_PROMISE</x:ref> frame reserves an
-                idle stream by associating the stream with an open stream that was initiated by the
-                remote peer (see <xref target="PushResources"/>).
-              </t>
-              <t>
-                In this state, only the following transitions are possible:
-                <list style="symbols">
-                  <t>
-                    The endpoint can send a <x:ref>HEADERS</x:ref> frame.  This causes the stream to
-                    open in a "half closed (remote)" state.
-                  </t>
-                  <t>
-                    Either endpoint can send a <x:ref>RST_STREAM</x:ref> frame to cause the stream
-                    to become "closed".  This releases the stream reservation.
-                  </t>
-                </list>
-              </t>
-              <t>
-                An endpoint MUST NOT send any type of frame other than <x:ref>HEADERS</x:ref> or
-                <x:ref>RST_STREAM</x:ref> in this state.
-              </t>
-              <t>
-                A <x:ref>PRIORITY</x:ref> frame MAY be received in this state.  Receiving any type
-                of frame other than <x:ref>RST_STREAM</x:ref> or <x:ref>PRIORITY</x:ref> on a stream
-                in this state MUST be treated as a <xref target="ConnectionErrorHandler">connection
-                error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
-              </t>
-            </x:lt>
-
-            <x:lt hangText="reserved (remote):">
-              <t>
-                <vspace blankLines="0"/>
-                A stream in the "reserved (remote)" state has been reserved by a remote peer.
-              </t>
-              <t>
-                In this state, only the following transitions are possible:
-                <list style="symbols">
-                  <t>
-                    Receiving a <x:ref>HEADERS</x:ref> frame causes the stream to transition to
-                    "half closed (local)".
-                  </t>
-                  <t>
-                    Either endpoint can send a <x:ref>RST_STREAM</x:ref> frame to cause the stream
-                    to become "closed".  This releases the stream reservation.
-                  </t>
-                </list>
-              </t>
-              <t>
-                An endpoint MAY send a <x:ref>PRIORITY</x:ref> frame in this state to reprioritize
-                the reserved stream.  An endpoint MUST NOT send any type of frame other than
-                <x:ref>RST_STREAM</x:ref>, <x:ref>WINDOW_UPDATE</x:ref>, or <x:ref>PRIORITY</x:ref>
-                in this state.
-              </t>
-              <t>
-                Receiving any type of frame other than <x:ref>HEADERS</x:ref> or
-                <x:ref>RST_STREAM</x:ref> on a stream in this state MUST be treated as a <xref
-                target="ConnectionErrorHandler">connection error</xref> of type
-                <x:ref>PROTOCOL_ERROR</x:ref>.
-              </t>
-            </x:lt>
-
-            <x:lt hangText="open:">
-              <t>
-                <vspace blankLines="0"/>
-                A stream in the "open" state may be used by both peers to send frames of any type.
-                In this state, sending peers observe advertised <xref target="FlowControl">stream
-                level flow control limits</xref>.
-              </t>
-              <t>
-                From this state either endpoint can send a frame with an END_STREAM flag set, which
-                causes the stream to transition into one of the "half closed" states: an endpoint
-                sending an END_STREAM flag causes the stream state to become "half closed (local)";
-                an endpoint receiving an END_STREAM flag causes the stream state to become "half
-                closed (remote)".
-              </t>
-              <t>
-                Either endpoint can send a <x:ref>RST_STREAM</x:ref> frame from this state, causing
-                it to transition immediately to "closed".
-              </t>
-            </x:lt>
-
-            <x:lt hangText="half closed (local):">
-              <t>
-                <vspace blankLines="0"/>
-                A stream that is in the "half closed (local)" state cannot be used for sending
-                frames.  Only <x:ref>WINDOW_UPDATE</x:ref>, <x:ref>PRIORITY</x:ref> and
-                <x:ref>RST_STREAM</x:ref> frames can be sent in this state.
-              </t>
-              <t>
-                A stream transitions from this state to "closed" when a frame that contains an
-                END_STREAM flag is received, or when either peer sends a <x:ref>RST_STREAM</x:ref>
-                frame.
-              </t>
-              <t>
-                A receiver can ignore <x:ref>WINDOW_UPDATE</x:ref> frames in this state, which might
-                arrive for a short period after a frame bearing the END_STREAM flag is sent.
-              </t>
-              <t>
-                <x:ref>PRIORITY</x:ref> frames received in this state are used to reprioritize
-                streams that depend on the current stream.
-              </t>
-            </x:lt>
-
-            <x:lt hangText="half closed (remote):">
-              <t>
-                <vspace blankLines="0"/>
-                A stream that is "half closed (remote)" is no longer being used by the peer to send
-                frames.  In this state, an endpoint is no longer obligated to maintain a receiver
-                flow control window if it performs flow control.
-              </t>
-              <t>
-                If an endpoint receives additional frames for a stream that is in this state, other
-                than <x:ref>WINDOW_UPDATE</x:ref>, <x:ref>PRIORITY</x:ref> or
-                <x:ref>RST_STREAM</x:ref>, it MUST respond with a <xref
-                target="StreamErrorHandler">stream error</xref> of type
-                <x:ref>STREAM_CLOSED</x:ref>.
-              </t>
-              <t>
-                A stream that is "half closed (remote)" can be used by the endpoint to send frames
-                of any type. In this state, the endpoint continues to observe advertised <xref
-                target="FlowControl">stream level flow control limits</xref>.
-              </t>
-              <t>
-                A stream can transition from this state to "closed" by sending a frame that contains
-                an END_STREAM flag, or when either peer sends a <x:ref>RST_STREAM</x:ref> frame.
-              </t>
-            </x:lt>
-
-            <x:lt hangText="closed:">
-              <t>
-                <vspace blankLines="0"/>
-                The "closed" state is the terminal state.
-              </t>
-              <t>
-                An endpoint MUST NOT send frames other than <x:ref>PRIORITY</x:ref> on a closed
-                stream.  An endpoint that receives any frame other than <x:ref>PRIORITY</x:ref>
-                after receiving a <x:ref>RST_STREAM</x:ref> MUST treat that as a <xref
-                target="StreamErrorHandler">stream error</xref> of type
-                <x:ref>STREAM_CLOSED</x:ref>.  Similarly, an endpoint that receives any frames after
-                receiving a frame with the END_STREAM flag set MUST treat that as a <xref
-                target="ConnectionErrorHandler">connection error</xref> of type
-                <x:ref>STREAM_CLOSED</x:ref>, unless the frame is permitted as described below.
-              </t>
-              <t>
-                <x:ref>WINDOW_UPDATE</x:ref> or <x:ref>RST_STREAM</x:ref> frames can be received in
-                this state for a short period after a <x:ref>DATA</x:ref> or <x:ref>HEADERS</x:ref>
-                frame containing an END_STREAM flag is sent.  Until the remote peer receives and
-                processes <x:ref>RST_STREAM</x:ref> or the frame bearing the END_STREAM flag, it
-                might send frames of these types.  Endpoints MUST ignore
-                <x:ref>WINDOW_UPDATE</x:ref> or <x:ref>RST_STREAM</x:ref> frames received in this
-                state, though endpoints MAY choose to treat frames that arrive a significant time
-                after sending END_STREAM as a <xref target="ConnectionErrorHandler">connection
-                error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
-              </t>
-              <t>
-                <x:ref>PRIORITY</x:ref> frames can be sent on closed streams to prioritize streams
-                that are dependent on the closed stream.  Endpoints SHOULD process
-                <x:ref>PRIORITY</x:ref> frame, though they can be ignored if the stream has been
-                removed from the dependency tree (see <xref target="priority-gc"/>).
-              </t>
-              <t>
-                If this state is reached as a result of sending a <x:ref>RST_STREAM</x:ref> frame,
-                the peer that receives the <x:ref>RST_STREAM</x:ref> might have already sent - or
-                enqueued for sending - frames on the stream that cannot be withdrawn.  An endpoint
-                MUST ignore frames that it receives on closed streams after it has sent a
-                <x:ref>RST_STREAM</x:ref> frame.  An endpoint MAY choose to limit the period over
-                which it ignores frames and treat frames that arrive after this time as being in
-                error.
-              </t>
-              <t>
-                Flow controlled frames (i.e., <x:ref>DATA</x:ref>) received after sending
-                <x:ref>RST_STREAM</x:ref> are counted toward the connection flow control window.
-                Even though these frames might be ignored, because they are sent before the sender
-                receives the <x:ref>RST_STREAM</x:ref>, the sender will consider the frames to count
-                against the flow control window.
-              </t>
-              <t>
-                An endpoint might receive a <x:ref>PUSH_PROMISE</x:ref> frame after it sends
-                <x:ref>RST_STREAM</x:ref>.  <x:ref>PUSH_PROMISE</x:ref> causes a stream to become
-                "reserved" even if the associated stream has been reset.  Therefore, a
-                <x:ref>RST_STREAM</x:ref> is needed to close an unwanted promised stream.
-              </t>
-            </x:lt>
-          </list>
-        </t>
-        <t>
-          In the absence of more specific guidance elsewhere in this document, implementations
-          SHOULD treat the receipt of a frame that is not expressly permitted in the description of
-          a state as a <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.  Frame of unknown types are ignored.
-        </t>
-        <t>
-          An example of the state transitions for an HTTP request/response exchange can be found in
-          <xref target="HttpSequence"/>.  An example of the state transitions for server push can be
-          found in <xref target="PushRequests"/> and <xref target="PushResponses"/>.
-        </t>
-
-        <section anchor="StreamIdentifiers" title="Stream Identifiers">
-          <t>
-            Streams are identified with an unsigned 31-bit integer.  Streams initiated by a client
-            MUST use odd-numbered stream identifiers; those initiated by the server MUST use
-            even-numbered stream identifiers.  A stream identifier of zero (0x0) is used for
-            connection control messages; the stream identifier zero cannot be used to establish a
-            new stream.
-          </t>
-          <t>
-            HTTP/1.1 requests that are upgraded to HTTP/2 (see <xref target="discover-http"/>) are
-            responded to with a stream identifier of one (0x1).  After the upgrade
-            completes, stream 0x1 is "half closed (local)" to the client.  Therefore, stream 0x1
-            cannot be selected as a new stream identifier by a client that upgrades from HTTP/1.1.
-          </t>
-          <t>
-            The identifier of a newly established stream MUST be numerically greater than all
-            streams that the initiating endpoint has opened or reserved.  This governs streams that
-            are opened using a <x:ref>HEADERS</x:ref> frame and streams that are reserved using
-            <x:ref>PUSH_PROMISE</x:ref>.  An endpoint that receives an unexpected stream identifier
-            MUST respond with a <xref target="ConnectionErrorHandler">connection error</xref> of
-            type <x:ref>PROTOCOL_ERROR</x:ref>.
-          </t>
-          <t>
-            The first use of a new stream identifier implicitly closes all streams in the "idle"
-            state that might have been initiated by that peer with a lower-valued stream identifier.
-            For example, if a client sends a <x:ref>HEADERS</x:ref> frame on stream 7 without ever
-            sending a frame on stream 5, then stream 5 transitions to the "closed" state when the
-            first frame for stream 7 is sent or received.
-          </t>
-          <t>
-            Stream identifiers cannot be reused.  Long-lived connections can result in an endpoint
-            exhausting the available range of stream identifiers.  A client that is unable to
-            establish a new stream identifier can establish a new connection for new streams.  A
-            server that is unable to establish a new stream identifier can send a
-            <x:ref>GOAWAY</x:ref> frame so that the client is forced to open a new connection for
-            new streams.
-          </t>
-        </section>
-
-        <section title="Stream Concurrency">
-          <t>
-            A peer can limit the number of concurrently active streams using the
-            <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> parameter (see <xref
-            target="SettingValues"/>) within a <x:ref>SETTINGS</x:ref> frame. The maximum concurrent
-            streams setting is specific to each endpoint and applies only to the peer that receives
-            the setting. That is, clients specify the maximum number of concurrent streams the
-            server can initiate, and servers specify the maximum number of concurrent streams the
-            client can initiate.
-          </t>
-          <t>
-            Streams that are in the "open" state, or either of the "half closed" states count toward
-            the maximum number of streams that an endpoint is permitted to open.  Streams in any of
-            these three states count toward the limit advertised in the
-            <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> setting.  Streams in either of the
-            "reserved" states do not count toward the stream limit.
-          </t>
-          <t>
-            Endpoints MUST NOT exceed the limit set by their peer.  An endpoint that receives a
-            <x:ref>HEADERS</x:ref> frame that causes their advertised concurrent stream limit to be
-            exceeded MUST treat this as a <xref target="StreamErrorHandler">stream error</xref>.  An
-            endpoint that wishes to reduce the value of
-            <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> to a value that is below the current
-            number of open streams can either close streams that exceed the new value or allow
-            streams to complete.
-          </t>
-        </section>
-      </section>
-
-     <section anchor="FlowControl" title="Flow Control">
-        <t>
-          Using streams for multiplexing introduces contention over use of the TCP connection,
-          resulting in blocked streams.  A flow control scheme ensures that streams on the same
-          connection do not destructively interfere with each other.  Flow control is used for both
-          individual streams and for the connection as a whole.
-        </t>
-        <t>
-          HTTP/2 provides for flow control through use of the <xref
-          target="WINDOW_UPDATE">WINDOW_UPDATE frame</xref>.
-        </t>
-
-        <section anchor="fc-principles" title="Flow Control Principles">
-          <t>
-            HTTP/2 stream flow control aims to allow a variety of flow control algorithms to be
-            used without requiring protocol changes. Flow control in HTTP/2 has the following
-            characteristics:
-            <list style="numbers">
-              <t>
-                Flow control is specific to a connection; i.e., it is "hop-by-hop", not
-                "end-to-end".
-              </t>
-              <t>
-                Flow control is based on window update frames.  Receivers advertise how many octets
-                they are prepared to receive on a stream and for the entire connection.  This is a
-                credit-based scheme.
-              </t>
-              <t>
-                Flow control is directional with overall control provided by the receiver.  A
-                receiver MAY choose to set any window size that it desires for each stream and for
-                the entire connection.  A sender MUST respect flow control limits imposed by a
-                receiver.  Clients, servers and intermediaries all independently advertise their
-                flow control window as a receiver and abide by the flow control limits set by
-                their peer when sending.
-              </t>
-              <t>
-                The initial value for the flow control window is 65,535 octets for both new streams
-                and the overall connection.
-              </t>
-              <t>
-                The frame type determines whether flow control applies to a frame.  Of the frames
-                specified in this document, only <x:ref>DATA</x:ref> frames are subject to flow
-                control; all other frame types do not consume space in the advertised flow control
-                window.  This ensures that important control frames are not blocked by flow control.
-              </t>
-              <t>
-                Flow control cannot be disabled.
-              </t>
-              <t>
-                HTTP/2 defines only the format and semantics of the <x:ref>WINDOW_UPDATE</x:ref>
-                frame (<xref target="WINDOW_UPDATE"/>).  This document does not stipulate how a
-                receiver decides when to send this frame or the value that it sends, nor does it
-                specify how a sender chooses to send packets.  Implementations are able to select
-                any algorithm that suits their needs.
-              </t>
-            </list>
-          </t>
-          <t>
-            Implementations are also responsible for managing how requests and responses are sent
-            based on priority; choosing how to avoid head of line blocking for requests; and
-            managing the creation of new streams.  Algorithm choices for these could interact with
-            any flow control algorithm.
-          </t>
-        </section>
-
-        <section anchor="DisableFlowControl" title="Appropriate Use of Flow Control">
-          <t>
-            Flow control is defined to protect endpoints that are operating under resource
-            constraints.  For example, a proxy needs to share memory between many connections, and
-            also might have a slow upstream connection and a fast downstream one.  Flow control
-            addresses cases where the receiver is unable process data on one stream, yet wants to
-            continue to process other streams in the same connection.
-          </t>
-          <t>
-            Deployments that do not require this capability can advertise a flow control window of
-            the maximum size, incrementing the available space when new data is received.  This
-            effectively disables flow control for that receiver.  Conversely, a sender is always
-            subject to the flow control window advertised by the receiver.
-          </t>
-          <t>
-            Deployments with constrained resources (for example, memory) can employ flow control to
-            limit the amount of memory a peer can consume.  Note, however, that this can lead to
-            suboptimal use of available network resources if flow control is enabled without
-            knowledge of the bandwidth-delay product (see <xref target="RFC1323"/>).
-          </t>
-          <t>
-            Even with full awareness of the current bandwidth-delay product, implementation of flow
-            control can be difficult.  When using flow control, the receiver MUST read from the TCP
-            receive buffer in a timely fashion.  Failure to do so could lead to a deadlock when
-            critical frames, such as <x:ref>WINDOW_UPDATE</x:ref>, are not read and acted upon.
-          </t>
-        </section>
-      </section>
-
-      <section anchor="StreamPriority" title="Stream priority">
-        <t>
-          A client can assign a priority for a new stream by including prioritization information in
-          the <xref target="HEADERS">HEADERS frame</xref> that opens the stream.  For an existing
-          stream, the <xref target="PRIORITY">PRIORITY frame</xref> can be used to change the
-          priority.
-        </t>
-        <t>
-          The purpose of prioritization is to allow an endpoint to express how it would prefer its
-          peer allocate resources when managing concurrent streams.  Most importantly, priority can
-          be used to select streams for transmitting frames when there is limited capacity for
-          sending.
-        </t>
-        <t>
-          Streams can be prioritized by marking them as dependent on the completion of other streams
-          (<xref target="pri-depend"/>).  Each dependency is assigned a relative weight, a number
-          that is used to determine the relative proportion of available resources that are assigned
-          to streams dependent on the same stream.
-        </t>
-        <!--
-          Note that stream dependencies have not yet been validated in practice.  The theory
-          might be fairly sound, but there are no implementations currently sending these.  If it
-          turns out that they are not useful, or actively harmful, implementations will be requested
-          to avoid creating stream dependencies.
-        -->
-        <t>
-          Explicitly setting the priority for a stream is input to a prioritization process.  It
-          does not guarantee any particular processing or transmission order for the stream relative
-          to any other stream.  An endpoint cannot force a peer to process concurrent streams in a
-          particular order using priority.  Expressing priority is therefore only ever a suggestion.
-        </t>
-        <t>
-          Providing prioritization information is optional, so default values are used if no
-          explicit indicator is provided (<xref target="pri-default"/>).
-        </t>
-
-        <section title="Stream Dependencies" anchor="pri-depend">
-          <t>
-            Each stream can be given an explicit dependency on another stream.  Including a
-            dependency expresses a preference to allocate resources to the identified stream rather
-            than to the dependent stream.
-          </t>
-          <t>
-            A stream that is not dependent on any other stream is given a stream dependency of 0x0.
-            In other words, the non-existent stream 0 forms the root of the tree.
-          </t>
-          <t>
-            A stream that depends on another stream is a dependent stream. The stream upon which a
-            stream is dependent is a parent stream. A dependency on a stream that is not currently
-            in the tree - such as a stream in the "idle" state - results in that stream being given
-            a <xref target="pri-default">default priority</xref>.
-          </t>
-          <t>
-            When assigning a dependency on another stream, the stream is added as a new dependency
-            of the parent stream.  Dependent streams that share the same parent are not ordered with
-            respect to each other.  For example, if streams B and C are dependent on stream A, and
-            if stream D is created with a dependency on stream A, this results in a dependency order
-            of A followed by B, C, and D in any order.
-          </t>
-          <figure title="Example of Default Dependency Creation">
-            <artwork type="inline"><![CDATA[
-    A                 A
-   / \      ==>      /|\
-  B   C             B D C
-]]></artwork>
-          </figure>
-          <t>
-            An exclusive flag allows for the insertion of a new level of dependencies.  The
-            exclusive flag causes the stream to become the sole dependency of its parent stream,
-            causing other dependencies to become dependent on the exclusive stream.  In the
-            previous example, if stream D is created with an exclusive dependency on stream A, this
-            results in D becoming the dependency parent of B and C.
-          </t>
-          <figure title="Example of Exclusive Dependency Creation">
-            <artwork type="inline"><![CDATA[
-                      A
-    A                 |
-   / \      ==>       D
-  B   C              / \
-                    B   C
-]]></artwork>
-          </figure>
-          <t>
-            Inside the dependency tree, a dependent stream SHOULD only be allocated resources if all
-            of the streams that it depends on (the chain of parent streams up to 0x0) are either
-            closed, or it is not possible to make progress on them.
-          </t>
-          <t>
-            A stream cannot depend on itself.  An endpoint MUST treat this as a <xref
-            target="StreamErrorHandler">stream error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
-          </t>
-        </section>
-
-        <section title="Dependency Weighting">
-          <t>
-            All dependent streams are allocated an integer weight between 1 and 256 (inclusive).
-          </t>
-          <t>
-            Streams with the same parent SHOULD be allocated resources proportionally based on their
-            weight.  Thus, if stream B depends on stream A with weight 4, and C depends on stream A
-            with weight 12, and if no progress can be made on A, stream B ideally receives one third
-            of the resources allocated to stream C.
-          </t>
-        </section>
-
-        <section anchor="reprioritize" title="Reprioritization">
-          <t>
-            Stream priorities are changed using the <x:ref>PRIORITY</x:ref> frame.  Setting a
-            dependency causes a stream to become dependent on the identified parent stream.
-          </t>
-          <t>
-            Dependent streams move with their parent stream if the parent is reprioritized.  Setting
-            a dependency with the exclusive flag for a reprioritized stream moves all the
-            dependencies of the new parent stream to become dependent on the reprioritized stream.
-          </t>
-          <t>
-            If a stream is made dependent on one of its own dependencies, the formerly dependent
-            stream is first moved to be dependent on the reprioritized stream's previous parent.
-            The moved dependency retains its weight.
-          </t>
-          <figure title="Example of Dependency Reordering">
-            <preamble>
-              For example, consider an original dependency tree where B and C depend on A, D and E
-              depend on C, and F depends on D.  If A is made dependent on D, then D takes the place
-              of A.  All other dependency relationships stay the same, except for F, which becomes
-              dependent on A if the reprioritization is exclusive.
-            </preamble>
-            <artwork type="inline"><![CDATA[
-    ?                ?                ?                 ?
-    |               / \               |                 |
-    A              D   A              D                 D
-   / \            /   / \            / \                |
-  B   C     ==>  F   B   C   ==>    F   A       OR      A
-     / \                 |             / \             /|\
-    D   E                E            B   C           B C F
-    |                                     |             |
-    F                                     E             E
-               (intermediate)   (non-exclusive)    (exclusive)
-]]></artwork>
-          </figure>
-        </section>
-
-        <section anchor="priority-gc" title="Prioritization State Management">
-          <t>
-            When a stream is removed from the dependency tree, its dependencies can be moved to
-            become dependent on the parent of the closed stream.  The weights of new dependencies
-            are recalculated by distributing the weight of the dependency of the closed stream
-            proportionally based on the weights of its dependencies.
-          </t>
-          <t>
-            Streams that are removed from the dependency tree cause some prioritization information
-            to be lost.  Resources are shared between streams with the same parent stream, which
-            means that if a stream in that set closes or becomes blocked, any spare capacity
-            allocated to a stream is distributed to the immediate neighbors of the stream.  However,
-            if the common dependency is removed from the tree, those streams share resources with
-            streams at the next highest level.
-          </t>
-          <t>
-            For example, assume streams A and B share a parent, and streams C and D both depend on
-            stream A. Prior to the removal of stream A, if streams A and D are unable to proceed,
-            then stream C receives all the resources dedicated to stream A.  If stream A is removed
-            from the tree, the weight of stream A is divided between streams C and D.  If stream D
-            is still unable to proceed, this results in stream C receiving a reduced proportion of
-            resources.  For equal starting weights, C receives one third, rather than one half, of
-            available resources.
-          </t>
-          <t>
-            It is possible for a stream to become closed while prioritization information that
-            creates a dependency on that stream is in transit.  If a stream identified in a
-            dependency has no associated priority information, then the dependent stream is instead
-            assigned a <xref target="pri-default">default priority</xref>.  This potentially creates
-            suboptimal prioritization, since the stream could be given a priority that is different
-            to what is intended.
-          </t>
-          <t>
-            To avoid these problems, an endpoint SHOULD retain stream prioritization state for a
-            period after streams become closed.  The longer state is retained, the lower the chance
-            that streams are assigned incorrect or default priority values.
-          </t>
-          <t>
-            This could create a large state burden for an endpoint, so this state MAY be limited.
-            An endpoint MAY apply a fixed upper limit on the number of closed streams for which
-            prioritization state is tracked to limit state exposure.  The amount of additional state
-            an endpoint maintains could be dependent on load; under high load, prioritization state
-            can be discarded to limit resource commitments.  In extreme cases, an endpoint could
-            even discard prioritization state for active or reserved streams. If a fixed limit is
-            applied, endpoints SHOULD maintain state for at least as many streams as allowed by
-            their setting for <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref>.
-          </t>
-          <t>
-            An endpoint receiving a <x:ref>PRIORITY</x:ref> frame that changes the priority of a
-            closed stream SHOULD alter the dependencies of the streams that depend on it, if it has
-            retained enough state to do so.
-          </t>
-        </section>
-
-        <section title="Default Priorities" anchor="pri-default">
-          <t>
-            Providing priority information is optional.  Streams are assigned a non-exclusive
-            dependency on stream 0x0 by default.  <xref target="PushResources">Pushed streams</xref>
-            initially depend on their associated stream.  In both cases, streams are assigned a
-            default weight of 16.
-          </t>
-        </section>
-      </section>
-
-      <section title="Error Handling">
-        <t>
-          HTTP/2 framing permits two classes of error:
-          <list style="symbols">
-            <t>
-              An error condition that renders the entire connection unusable is a connection error.
-            </t>
-            <t>
-              An error in an individual stream is a stream error.
-            </t>
-          </list>
-        </t>
-        <t>
-          A list of error codes is included in <xref target="ErrorCodes"/>.
-        </t>
-
-        <section anchor="ConnectionErrorHandler" title="Connection Error Handling">
-          <t>
-            A connection error is any error which prevents further processing of the framing layer,
-            or which corrupts any connection state.
-          </t>
-          <t>
-            An endpoint that encounters a connection error SHOULD first send a <x:ref>GOAWAY</x:ref>
-            frame (<xref target="GOAWAY"/>) with the stream identifier of the last stream that it
-            successfully received from its peer.  The <x:ref>GOAWAY</x:ref> frame includes an error
-            code that indicates why the connection is terminating.  After sending the
-            <x:ref>GOAWAY</x:ref> frame, the endpoint MUST close the TCP connection.
-          </t>
-          <t>
-            It is possible that the <x:ref>GOAWAY</x:ref> will not be reliably received by the
-            receiving endpoint (see <xref target="RFC7230" x:fmt=","
-            x:rel="#persistent.tear-down"/>).  In the event of a connection error,
-            <x:ref>GOAWAY</x:ref> only provides a best effort attempt to communicate with the peer
-            about why the connection is being terminated.
-          </t>
-          <t>
-            An endpoint can end a connection at any time.  In particular, an endpoint MAY choose to
-            treat a stream error as a connection error.  Endpoints SHOULD send a
-            <x:ref>GOAWAY</x:ref> frame when ending a connection, providing that circumstances
-            permit it.
-          </t>
-        </section>
-
-        <section anchor="StreamErrorHandler" title="Stream Error Handling">
-          <t>
-            A stream error is an error related to a specific stream that does not affect processing
-            of other streams.
-          </t>
-          <t>
-            An endpoint that detects a stream error sends a <x:ref>RST_STREAM</x:ref> frame (<xref
-            target="RST_STREAM"/>) that contains the stream identifier of the stream where the error
-            occurred.  The <x:ref>RST_STREAM</x:ref> frame includes an error code that indicates the
-            type of error.
-          </t>
-          <t>
-            A <x:ref>RST_STREAM</x:ref> is the last frame that an endpoint can send on a stream.
-            The peer that sends the <x:ref>RST_STREAM</x:ref> frame MUST be prepared to receive any
-            frames that were sent or enqueued for sending by the remote peer.  These frames can be
-            ignored, except where they modify connection state (such as the state maintained for
-            <xref target="HeaderBlock">header compression</xref>, or flow control).
-          </t>
-          <t>
-            Normally, an endpoint SHOULD NOT send more than one <x:ref>RST_STREAM</x:ref> frame for
-            any stream. However, an endpoint MAY send additional <x:ref>RST_STREAM</x:ref> frames if
-            it receives frames on a closed stream after more than a round-trip time.  This behavior
-            is permitted to deal with misbehaving implementations.
-          </t>
-          <t>
-            An endpoint MUST NOT send a <x:ref>RST_STREAM</x:ref> in response to an
-            <x:ref>RST_STREAM</x:ref> frame, to avoid looping.
-          </t>
-        </section>
-
-        <section title="Connection Termination">
-          <t>
-            If the TCP connection is closed or reset while streams remain in open or half closed
-            states, then the endpoint MUST assume that those streams were abnormally interrupted and
-            could be incomplete.
-          </t>
-        </section>
-      </section>
-
-      <section anchor="extensibility" title="Extending HTTP/2">
-        <t>
-          HTTP/2 permits extension of the protocol.  Protocol extensions can be used to provide
-          additional services or alter any aspect of the protocol, within the limitations described
-          in this section.  Extensions are effective only within the scope of a single HTTP/2
-          connection.
-        </t>
-        <t>
-          Extensions are permitted to use new <xref target="FrameHeader">frame types</xref>, new
-          <xref target="SettingValues">settings</xref>, or new <xref target="ErrorCodes">error
-          codes</xref>.  Registries are established for managing these extension points: <xref
-          target="iana-frames">frame types</xref>, <xref target="iana-settings">settings</xref> and
-          <xref target="iana-errors">error codes</xref>.
-        </t>
-        <t>
-          Implementations MUST ignore unknown or unsupported values in all extensible protocol
-          elements.  Implementations MUST discard frames that have unknown or unsupported types.
-          This means that any of these extension points can be safely used by extensions without
-          prior arrangement or negotiation.  However, extension frames that appear in the middle of
-          a <xref target="HeaderBlock">header block</xref> are not permitted; these MUST be treated
-          as a <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          However, extensions that could change the semantics of existing protocol components MUST
-          be negotiated before being used.  For example, an extension that changes the layout of the
-          <x:ref>HEADERS</x:ref> frame cannot be used until the peer has given a positive signal
-          that this is acceptable.  In this case, it could also be necessary to coordinate when the
-          revised layout comes into effect.  Note that treating any frame other than
-          <x:ref>DATA</x:ref> frames as flow controlled is such a change in semantics, and can only
-          be done through negotiation.
-        </t>
-        <t>
-          This document doesn't mandate a specific method for negotiating the use of an extension,
-          but notes that a <xref target="SettingValues">setting</xref> could be used for that
-          purpose.  If both peers set a value that indicates willingness to use the extension, then
-          the extension can be used.  If a setting is used for extension negotiation, the initial
-          value MUST be defined so that the extension is initially disabled.
-        </t>
-      </section>
-    </section>
-
-    <section anchor="FrameTypes" title="Frame Definitions">
-      <t>
-        This specification defines a number of frame types, each identified by a unique 8-bit type
-        code. Each frame type serves a distinct purpose either in the establishment and management
-        of the connection as a whole, or of individual streams.
-      </t>
-      <t>
-        The transmission of specific frame types can alter the state of a connection. If endpoints
-        fail to maintain a synchronized view of the connection state, successful communication
-        within the connection will no longer be possible. Therefore, it is important that endpoints
-        have a shared comprehension of how the state is affected by the use any given frame.
-      </t>
-
-      <section anchor="DATA" title="DATA">
-        <t>
-          DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated
-          with a stream. One or more DATA frames are used, for instance, to carry HTTP request or
-          response payloads.
-        </t>
-        <t>
-          DATA frames MAY also contain arbitrary padding.  Padding can be added to DATA frames to
-          obscure the size of messages.
-        </t>
-        <figure title="DATA Frame Payload">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |Pad Length? (8)|
- +---------------+-----------------------------------------------+
- |                            Data (*)                         ...
- +---------------------------------------------------------------+
- |                           Padding (*)                       ...
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-        <t>
-          The DATA frame contains the following fields:
-          <list style="hanging">
-            <t hangText="Pad Length:">
-              An 8-bit field containing the length of the frame padding in units of octets.  This
-              field is optional and is only present if the PADDED flag is set.
-            </t>
-            <t hangText="Data:">
-              Application data.  The amount of data is the remainder of the frame payload after
-              subtracting the length of the other fields that are present.
-            </t>
-            <t hangText="Padding:">
-              Padding octets that contain no application semantic value.  Padding octets MUST be set
-              to zero when sending and ignored when receiving.
-            </t>
-          </list>
-        </t>
-
-        <t>
-          The DATA frame defines the following flags:
-          <list style="hanging">
-            <t hangText="END_STREAM (0x1):">
-              Bit 1 being set indicates that this frame is the last that the endpoint will send for
-              the identified stream.  Setting this flag causes the stream to enter one of <xref
-              target="StreamStates">the "half closed" states or the "closed" state</xref>.
-            </t>
-            <t hangText="PADDED (0x8):">
-              Bit 4 being set indicates that the Pad Length field and any padding that it describes
-              is present.
-            </t>
-          </list>
-        </t>
-        <t>
-          DATA frames MUST be associated with a stream. If a DATA frame is received whose stream
-          identifier field is 0x0, the recipient MUST respond with a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          DATA frames are subject to flow control and can only be sent when a stream is in the
-          "open" or "half closed (remote)" states. The entire DATA frame payload is included in flow
-          control, including Pad Length and Padding fields if present.  If a DATA frame is received
-          whose stream is not in "open" or "half closed (local)" state, the recipient MUST respond
-          with a <xref target="StreamErrorHandler">stream error</xref> of type
-          <x:ref>STREAM_CLOSED</x:ref>.
-        </t>
-        <t>
-          The total number of padding octets is determined by the value of the Pad Length field. If
-          the length of the padding is greater than the length of the frame payload, the recipient
-          MUST treat this as a <xref target="ConnectionErrorHandler">connection error</xref> of
-          type <x:ref>PROTOCOL_ERROR</x:ref>.
-          <list style="hanging">
-            <t hangText="Note:">
-              A frame can be increased in size by one octet by including a Pad Length field with a
-              value of zero.
-            </t>
-          </list>
-        </t>
-        <t>
-          Padding is a security feature; see <xref target="padding"/>.
-        </t>
-      </section>
-
-      <section anchor="HEADERS" title="HEADERS">
-        <t>
-          The HEADERS frame (type=0x1) is used to <xref target="StreamStates">open a stream</xref>,
-          and additionally carries a header block fragment. HEADERS frames can be sent on a stream
-          in the "open" or "half closed (remote)" states.
-        </t>
-        <figure title="HEADERS Frame Payload">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |Pad Length? (8)|
- +-+-------------+-----------------------------------------------+
- |E|                 Stream Dependency? (31)                     |
- +-+-------------+-----------------------------------------------+
- |  Weight? (8)  |
- +-+-------------+-----------------------------------------------+
- |                   Header Block Fragment (*)                 ...
- +---------------------------------------------------------------+
- |                           Padding (*)                       ...
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-        <t>
-          The HEADERS frame payload has the following fields:
-          <list style="hanging">
-            <t hangText="Pad Length:">
-              An 8-bit field containing the length of the frame padding in units of octets.  This
-              field is only present if the PADDED flag is set.
-            </t>
-            <t hangText="E:">
-              A single bit flag indicates that the stream dependency is exclusive, see <xref
-              target="StreamPriority"/>.  This field is only present if the PRIORITY flag is set.
-            </t>
-            <t hangText="Stream Dependency:">
-              A 31-bit stream identifier for the stream that this stream depends on, see <xref
-              target="StreamPriority"/>.  This field is only present if the PRIORITY flag is set.
-            </t>
-            <t hangText="Weight:">
-              An 8-bit weight for the stream, see <xref target="StreamPriority"/>.  Add one to the
-              value to obtain a weight between 1 and 256.  This field is only present if the
-              PRIORITY flag is set.
-            </t>
-            <t hangText="Header Block Fragment:">
-              A <xref target="HeaderBlock">header block fragment</xref>.
-            </t>
-            <t hangText="Padding:">
-              Padding octets that contain no application semantic value.  Padding octets MUST be set
-              to zero when sending and ignored when receiving.
-            </t>
-          </list>
-        </t>
-
-        <t>
-          The HEADERS frame defines the following flags:
-          <list style="hanging">
-            <x:lt hangText="END_STREAM (0x1):">
-              <t>
-                Bit 1 being set indicates that the <xref target="HeaderBlock">header block</xref> is
-                the last that the endpoint will send for the identified stream.  Setting this flag
-                causes the stream to enter one of <xref target="StreamStates">"half closed"
-                states</xref>.
-              </t>
-              <t>
-                A HEADERS frame carries the END_STREAM flag that signals the end of a stream.
-                However, a HEADERS frame with the END_STREAM flag set can be followed by
-                <x:ref>CONTINUATION</x:ref> frames on the same stream.  Logically, the
-                <x:ref>CONTINUATION</x:ref> frames are part of the HEADERS frame.
-              </t>
-            </x:lt>
-            <x:lt hangText="END_HEADERS (0x4):">
-              <t>
-                Bit 3 being set indicates that this frame contains an entire <xref
-                target="HeaderBlock">header block</xref> and is not followed by any
-                <x:ref>CONTINUATION</x:ref> frames.
-              </t>
-              <t>
-                A HEADERS frame without the END_HEADERS flag set MUST be followed by a
-                <x:ref>CONTINUATION</x:ref> frame for the same stream.  A receiver MUST treat the
-                receipt of any other type of frame or a frame on a different stream as a <xref
-                target="ConnectionErrorHandler">connection error</xref> of type
-                <x:ref>PROTOCOL_ERROR</x:ref>.
-              </t>
-            </x:lt>
-            <x:lt hangText="PADDED (0x8):">
-              <t>
-                Bit 4 being set indicates that the Pad Length field and any padding that it
-                describes is present.
-              </t>
-            </x:lt>
-            <x:lt hangText="PRIORITY (0x20):">
-              <t>
-                Bit 6 being set indicates that the Exclusive Flag (E), Stream Dependency, and Weight
-                fields are present; see <xref target="StreamPriority"/>.
-              </t>
-            </x:lt>
-          </list>
-        </t>
-
-        <t>
-          The payload of a HEADERS frame contains a <xref target="HeaderBlock">header block
-          fragment</xref>.  A header block that does not fit within a HEADERS frame is continued in
-          a <xref target="CONTINUATION">CONTINUATION frame</xref>.
-        </t>
-
-        <t>
-          HEADERS frames MUST be associated with a stream. If a HEADERS frame is received whose
-          stream identifier field is 0x0, the recipient MUST respond with a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-
-        <t>
-          The HEADERS frame changes the connection state as described in <xref
-          target="HeaderBlock"/>.
-        </t>
-
-        <t>
-          The HEADERS frame includes optional padding.  Padding fields and flags are identical to
-          those defined for <xref target="DATA">DATA frames</xref>.
-        </t>
-        <t>
-          Prioritization information in a HEADERS frame is logically equivalent to a separate
-          <x:ref>PRIORITY</x:ref> frame, but inclusion in HEADERS avoids the potential for churn in
-          stream prioritization when new streams are created.  Priorization fields in HEADERS frames
-          subsequent to the first on a stream <xref target="reprioritize">reprioritize the
-          stream</xref>.
-        </t>
-      </section>
-
-      <section anchor="PRIORITY" title="PRIORITY">
-        <t>
-          The PRIORITY frame (type=0x2) specifies the <xref target="StreamPriority">sender-advised
-          priority of a stream</xref>.  It can be sent at any time for an existing stream, including
-          closed streams.  This enables reprioritization of existing streams.
-        </t>
-        <figure title="PRIORITY Frame Payload">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |E|                  Stream Dependency (31)                     |
- +-+-------------+-----------------------------------------------+
- |   Weight (8)  |
- +-+-------------+
-]]></artwork>
-        </figure>
-        <t>
-          The payload of a PRIORITY frame contains the following fields:
-          <list style="hanging">
-            <t hangText="E:">
-              A single bit flag indicates that the stream dependency is exclusive, see <xref
-              target="StreamPriority"/>.
-            </t>
-            <t hangText="Stream Dependency:">
-              A 31-bit stream identifier for the stream that this stream depends on, see <xref
-              target="StreamPriority"/>.
-            </t>
-            <t hangText="Weight:">
-              An 8-bit weight for the identified stream dependency, see <xref
-              target="StreamPriority"/>.  Add one to the value to obtain a weight between 1 and 256.
-            </t>
-          </list>
-        </t>
-
-        <t>
-          The PRIORITY frame does not define any flags.
-        </t>
-
-        <t>
-          The PRIORITY frame is associated with an existing stream. If a PRIORITY frame is received
-          with a stream identifier of 0x0, the recipient MUST respond with a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          The PRIORITY frame can be sent on a stream in any of the "reserved (remote)", "open",
-          "half closed (local)", "half closed (remote)", or "closed" states, though it cannot be
-          sent between consecutive frames that comprise a single <xref target="HeaderBlock">header
-          block</xref>.  Note that this frame could arrive after processing or frame sending has
-          completed, which would cause it to have no effect on the current stream.  For a stream
-          that is in the "half closed (remote)" or "closed" - state, this frame can only affect
-          processing of the current stream and not frame transmission.
-        </t>
-        <t>
-          The PRIORITY frame is the only frame that can be sent for a stream in the "closed" state.
-          This allows for the reprioritization of a group of dependent streams by altering the
-          priority of a parent stream, which might be closed.  However, a PRIORITY frame sent on a
-          closed stream risks being ignored due to the peer having discarded priority state
-          information for that stream.
-        </t>
-      </section>
-
-      <section anchor="RST_STREAM" title="RST_STREAM">
-        <t>
-          The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream.  When sent by
-          the initiator of a stream, it indicates that they wish to cancel the stream or that an
-          error condition has occurred.  When sent by the receiver of a stream, it indicates that
-          either the receiver is rejecting the stream, requesting that the stream be cancelled, or
-          that an error condition has occurred.
-        </t>
-        <figure title="RST_STREAM Frame Payload">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |                        Error Code (32)                        |
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-
-        <t>
-          The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the <xref
-          target="ErrorCodes">error code</xref>.  The error code indicates why the stream is being
-          terminated.
-        </t>
-
-        <t>
-          The RST_STREAM frame does not define any flags.
-        </t>
-
-        <t>
-          The RST_STREAM frame fully terminates the referenced stream and causes it to enter the
-          closed state. After receiving a RST_STREAM on a stream, the receiver MUST NOT send
-          additional frames for that stream, with the exception of <x:ref>PRIORITY</x:ref>. However,
-          after sending the RST_STREAM, the sending endpoint MUST be prepared to receive and process
-          additional frames sent on the stream that might have been sent by the peer prior to the
-          arrival of the RST_STREAM.
-        </t>
-
-        <t>
-          RST_STREAM frames MUST be associated with a stream.  If a RST_STREAM frame is received
-          with a stream identifier of 0x0, the recipient MUST treat this as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-
-        <t>
-          RST_STREAM frames MUST NOT be sent for a stream in the "idle" state.  If a RST_STREAM
-          frame identifying an idle stream is received, the recipient MUST treat this as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-
-      </section>
-
-      <section anchor="SETTINGS" title="SETTINGS">
-        <t>
-          The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints
-          communicate, such as preferences and constraints on peer behavior.  The SETTINGS frame is
-          also used to acknowledge the receipt of those parameters.  Individually, a SETTINGS
-          parameter can also be referred to as a "setting".
-        </t>
-        <t>
-          SETTINGS parameters are not negotiated; they describe characteristics of the sending peer,
-          which are used by the receiving peer. Different values for the same parameter can be
-          advertised by each peer. For example, a client might set a high initial flow control
-          window, whereas a server might set a lower value to conserve resources.
-        </t>
-
-        <t>
-          A SETTINGS frame MUST be sent by both endpoints at the start of a connection, and MAY be
-          sent at any other time by either endpoint over the lifetime of the connection.
-          Implementations MUST support all of the parameters defined by this specification.
-        </t>
-
-        <t>
-          Each parameter in a SETTINGS frame replaces any existing value for that parameter.
-          Parameters are processed in the order in which they appear, and a receiver of a SETTINGS
-          frame does not need to maintain any state other than the current value of its
-          parameters. Therefore, the value of a SETTINGS parameter is the last value that is seen by
-          a receiver.
-        </t>
-        <t>
-          SETTINGS parameters are acknowledged by the receiving peer. To enable this, the SETTINGS
-          frame defines the following flag:
-          <list style="hanging">
-            <t hangText="ACK (0x1):">
-              Bit 1 being set indicates that this frame acknowledges receipt and application of the
-              peer's SETTINGS frame.  When this bit is set, the payload of the SETTINGS frame MUST
-              be empty.  Receipt of a SETTINGS frame with the ACK flag set and a length field value
-              other than 0 MUST be treated as a <xref target="ConnectionErrorHandler">connection
-              error</xref> of type <x:ref>FRAME_SIZE_ERROR</x:ref>.  For more info, see <xref
-              target="SettingsSync">Settings Synchronization</xref>.
-            </t>
-          </list>
-        </t>
-        <t>
-          SETTINGS frames always apply to a connection, never a single stream.  The stream
-          identifier for a SETTINGS frame MUST be zero (0x0). If an endpoint receives a SETTINGS
-          frame whose stream identifier field is anything other than 0x0, the endpoint MUST respond
-          with a <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          The SETTINGS frame affects connection state.  A badly formed or incomplete SETTINGS frame
-          MUST be treated as a <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-
-        <section title="SETTINGS Format" anchor="SettingFormat">
-          <t>
-            The payload of a SETTINGS frame consists of zero or more parameters, each consisting of
-            an unsigned 16-bit setting identifier and an unsigned 32-bit value.
-          </t>
-
-          <figure title="Setting Format">
-            <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |       Identifier (16)         |
- +-------------------------------+-------------------------------+
- |                        Value (32)                             |
- +---------------------------------------------------------------+
-]]></artwork>
-          </figure>
-        </section>
-
-        <section anchor="SettingValues" title="Defined SETTINGS Parameters">
-          <t>
-            The following parameters are defined:
-            <list style="hanging">
-              <x:lt hangText="SETTINGS_HEADER_TABLE_SIZE (0x1):"
-                    anchor="SETTINGS_HEADER_TABLE_SIZE">
-                <t>
-                  Allows the sender to inform the remote endpoint of the maximum size of the header
-                  compression table used to decode header blocks, in octets. The encoder can select
-                  any size equal to or less than this value by using signaling specific to the
-                  header compression format inside a header block. The initial value is 4,096
-                  octets.
-                </t>
-              </x:lt>
-              <x:lt hangText="SETTINGS_ENABLE_PUSH (0x2):"
-                    anchor="SETTINGS_ENABLE_PUSH">
-                <t>
-                  This setting can be use to disable <xref target="PushResources">server
-                  push</xref>. An endpoint MUST NOT send a <x:ref>PUSH_PROMISE</x:ref> frame if it
-                  receives this parameter set to a value of 0. An endpoint that has both set this
-                  parameter to 0 and had it acknowledged MUST treat the receipt of a
-                  <x:ref>PUSH_PROMISE</x:ref> frame as a <xref
-                  target="ConnectionErrorHandler">connection error</xref> of type
-                  <x:ref>PROTOCOL_ERROR</x:ref>.
-                </t>
-                <t>
-                  The initial value is 1, which indicates that server push is permitted.  Any value
-                  other than 0 or 1 MUST be treated as a <xref
-                  target="ConnectionErrorHandler">connection error</xref> of type
-                  <x:ref>PROTOCOL_ERROR</x:ref>.
-                </t>
-              </x:lt>
-              <x:lt hangText="SETTINGS_MAX_CONCURRENT_STREAMS (0x3):"
-                    anchor="SETTINGS_MAX_CONCURRENT_STREAMS">
-                <t>
-                  Indicates the maximum number of concurrent streams that the sender will allow.
-                  This limit is directional: it applies to the number of streams that the sender
-                  permits the receiver to create. Initially there is no limit to this value.  It is
-                  recommended that this value be no smaller than 100, so as to not unnecessarily
-                  limit parallelism.
-                </t>
-                <t>
-                  A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special
-                  by endpoints.  A zero value does prevent the creation of new streams, however this
-                  can also happen for any limit that is exhausted with active streams.  Servers
-                  SHOULD only set a zero value for short durations; if a server does not wish to
-                  accept requests, closing the connection could be preferable.
-                </t>
-              </x:lt>
-              <x:lt hangText="SETTINGS_INITIAL_WINDOW_SIZE (0x4):"
-                    anchor="SETTINGS_INITIAL_WINDOW_SIZE">
-                <t>
-                  Indicates the sender's initial window size (in octets) for stream level flow
-                  control.  The initial value is 2<x:sup>16</x:sup>-1 (65,535) octets.
-                </t>
-                <t>
-                  This setting affects the window size of all streams, including existing streams,
-                  see <xref target="InitialWindowSize"/>.
-                </t>
-                <t>
-                  Values above the maximum flow control window size of 2<x:sup>31</x:sup>-1 MUST
-                  be treated as a <xref target="ConnectionErrorHandler">connection error</xref> of
-                  type <x:ref>FLOW_CONTROL_ERROR</x:ref>.
-                </t>
-              </x:lt>
-              <x:lt hangText="SETTINGS_MAX_FRAME_SIZE (0x5):"
-                    anchor="SETTINGS_MAX_FRAME_SIZE">
-                <t>
-                  Indicates the size of the largest frame payload that the sender is willing to
-                  receive, in octets.
-                </t>
-                <t>
-                  The initial value is 2<x:sup>14</x:sup> (16,384) octets.  The value advertised by
-                  an endpoint MUST be between this initial value and the maximum allowed frame size
-                  (2<x:sup>24</x:sup>-1 or 16,777,215 octets), inclusive.  Values outside this range
-                  MUST be treated as a <xref target="ConnectionErrorHandler">connection error</xref>
-                  of type <x:ref>PROTOCOL_ERROR</x:ref>.
-                </t>
-              </x:lt>
-              <x:lt hangText="SETTINGS_MAX_HEADER_LIST_SIZE (0x6):"
-                    anchor="SETTINGS_MAX_HEADER_LIST_SIZE">
-                <t>
-                  This advisory setting informs a peer of the maximum size of header list that the
-                  sender is prepared to accept, in octets. The value is based on the uncompressed
-                  size of header fields, including the length of the name and value in octets plus
-                  an overhead of 32 octets for each header field.
-                </t>
-                <t>
-                  For any given request, a lower limit than what is advertised MAY be enforced.  The
-                  initial value of this setting is unlimited.
-                </t>
-              </x:lt>
-            </list>
-          </t>
-          <t>
-            An endpoint that receives a SETTINGS frame with any unknown or unsupported identifier
-            MUST ignore that setting.
-          </t>
-        </section>
-
-        <section anchor="SettingsSync" title="Settings Synchronization">
-          <t>
-            Most values in SETTINGS benefit from or require an understanding of when the peer has
-            received and applied the changed parameter values. In order to provide
-            such synchronization timepoints, the recipient of a SETTINGS frame in which the ACK flag
-            is not set MUST apply the updated parameters as soon as possible upon receipt.
-          </t>
-          <t>
-            The values in the SETTINGS frame MUST be processed in the order they appear, with no
-            other frame processing between values.  Unsupported parameters MUST be ignored.  Once
-            all values have been processed, the recipient MUST immediately emit a SETTINGS frame
-            with the ACK flag set. Upon receiving a SETTINGS frame with the ACK flag set, the sender
-            of the altered parameters can rely on the setting having been applied.
-          </t>
-          <t>
-            If the sender of a SETTINGS frame does not receive an acknowledgement within a
-            reasonable amount of time, it MAY issue a <xref
-            target="ConnectionErrorHandler">connection error</xref> of type
-            <x:ref>SETTINGS_TIMEOUT</x:ref>.
-          </t>
-        </section>
-      </section>
-
-      <section anchor="PUSH_PROMISE" title="PUSH_PROMISE">
-        <t>
-          The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of
-          streams the sender intends to initiate.  The PUSH_PROMISE frame includes the unsigned
-          31-bit identifier of the stream the endpoint plans to create along with a set of headers
-          that provide additional context for the stream.  <xref target="PushResources"/> contains a
-          thorough description of the use of PUSH_PROMISE frames.
-        </t>
-
-        <figure title="PUSH_PROMISE Payload Format">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |Pad Length? (8)|
- +-+-------------+-----------------------------------------------+
- |R|                  Promised Stream ID (31)                    |
- +-+-----------------------------+-------------------------------+
- |                   Header Block Fragment (*)                 ...
- +---------------------------------------------------------------+
- |                           Padding (*)                       ...
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-        <t>
-          The PUSH_PROMISE frame payload has the following fields:
-          <list style="hanging">
-            <t hangText="Pad Length:">
-              An 8-bit field containing the length of the frame padding in units of octets.  This
-              field is only present if the PADDED flag is set.
-            </t>
-            <t hangText="R:">
-              A single reserved bit.
-            </t>
-            <t hangText="Promised Stream ID:">
-              An unsigned 31-bit integer that identifies the stream that is reserved by the
-              PUSH_PROMISE.  The promised stream identifier MUST be a valid choice for the next
-              stream sent by the sender (see <xref target="StreamIdentifiers">new stream
-              identifier</xref>).
-            </t>
-            <t hangText="Header Block Fragment:">
-              A <xref target="HeaderBlock">header block fragment</xref> containing request header
-              fields.
-            </t>
-            <t hangText="Padding:">
-              Padding octets.
-            </t>
-          </list>
-        </t>
-
-        <t>
-          The PUSH_PROMISE frame defines the following flags:
-          <list style="hanging">
-            <x:lt hangText="END_HEADERS (0x4):">
-              <t>
-                Bit 3 being set indicates that this frame contains an entire <xref
-                target="HeaderBlock">header block</xref> and is not followed by any
-                <x:ref>CONTINUATION</x:ref> frames.
-              </t>
-              <t>
-                A PUSH_PROMISE frame without the END_HEADERS flag set MUST be followed by a
-                CONTINUATION frame for the same stream.  A receiver MUST treat the receipt of any
-                other type of frame or a frame on a different stream as a <xref
-                target="ConnectionErrorHandler">connection error</xref> of type
-                <x:ref>PROTOCOL_ERROR</x:ref>.
-              </t>
-            </x:lt>
-            <x:lt hangText="PADDED (0x8):">
-              <t>
-                Bit 4 being set indicates that the Pad Length field and any padding that it
-                describes is present.
-              </t>
-            </x:lt>
-          </list>
-        </t>
-
-        <t>
-          PUSH_PROMISE frames MUST be associated with an existing, peer-initiated stream. The stream
-          identifier of a PUSH_PROMISE frame indicates the stream it is associated with.  If the
-          stream identifier field specifies the value 0x0, a recipient MUST respond with a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-
-        <t>
-          Promised streams are not required to be used in the order they are promised.  The
-          PUSH_PROMISE only reserves stream identifiers for later use.
-        </t>
-
-        <t>
-          PUSH_PROMISE MUST NOT be sent if the <x:ref>SETTINGS_ENABLE_PUSH</x:ref> setting of the
-          peer endpoint is set to 0.  An endpoint that has set this setting and has received
-          acknowledgement MUST treat the receipt of a PUSH_PROMISE frame as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          Recipients of PUSH_PROMISE frames can choose to reject promised streams by returning a
-          <x:ref>RST_STREAM</x:ref> referencing the promised stream identifier back to the sender of
-          the PUSH_PROMISE.
-        </t>
-
-       <t>
-          A PUSH_PROMISE frame modifies the connection state in two ways.  The inclusion of a <xref
-          target="HeaderBlock">header block</xref> potentially modifies the state maintained for
-          header compression.  PUSH_PROMISE also reserves a stream for later use, causing the
-          promised stream to enter the "reserved" state.  A sender MUST NOT send a PUSH_PROMISE on a
-          stream unless that stream is either "open" or "half closed (remote)"; the sender MUST
-          ensure that the promised stream is a valid choice for a <xref
-          target="StreamIdentifiers">new stream identifier</xref> (that is, the promised stream MUST
-          be in the "idle" state).
-        </t>
-        <t>
-          Since PUSH_PROMISE reserves a stream, ignoring a PUSH_PROMISE frame causes the stream
-          state to become indeterminate.  A receiver MUST treat the receipt of a PUSH_PROMISE on a
-          stream that is neither "open" nor "half closed (local)" as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.  However, an endpoint that has sent
-          <x:ref>RST_STREAM</x:ref> on the associated stream MUST handle PUSH_PROMISE frames that
-          might have been created before the <x:ref>RST_STREAM</x:ref> frame is received and
-          processed.
-        </t>
-        <t>
-          A receiver MUST treat the receipt of a PUSH_PROMISE that promises an <xref
-          target="StreamIdentifiers">illegal stream identifier</xref> (that is, an identifier for a
-          stream that is not currently in the "idle" state) as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-
-        <t>
-          The PUSH_PROMISE frame includes optional padding.  Padding fields and flags are identical
-          to those defined for <xref target="DATA">DATA frames</xref>.
-        </t>
-      </section>
-
-      <section anchor="PING" title="PING">
-        <t>
-          The PING frame (type=0x6) is a mechanism for measuring a minimal round trip time from the
-          sender, as well as determining whether an idle connection is still functional.  PING
-          frames can be sent from any endpoint.
-        </t>
-        <figure title="PING Payload Format">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |                                                               |
- |                      Opaque Data (64)                         |
- |                                                               |
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-
-        <t>
-          In addition to the frame header, PING frames MUST contain 8 octets of data in the payload.
-          A sender can include any value it chooses and use those bytes in any fashion.
-        </t>
-        <t>
-          Receivers of a PING frame that does not include an ACK flag MUST send a PING frame with
-          the ACK flag set in response, with an identical payload.  PING responses SHOULD be given
-          higher priority than any other frame.
-        </t>
-
-        <t>
-          The PING frame defines the following flags:
-          <list style="hanging">
-            <t hangText="ACK (0x1):">
-              Bit 1 being set indicates that this PING frame is a PING response.  An endpoint MUST
-              set this flag in PING responses.  An endpoint MUST NOT respond to PING frames
-              containing this flag.
-            </t>
-          </list>
-        </t>
-        <t>
-          PING frames are not associated with any individual stream. If a PING frame is received
-          with a stream identifier field value other than 0x0, the recipient MUST respond with a
-          <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          Receipt of a PING frame with a length field value other than 8 MUST be treated as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>FRAME_SIZE_ERROR</x:ref>.
-        </t>
-
-      </section>
-
-      <section anchor="GOAWAY" title="GOAWAY">
-        <t>
-          The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this
-          connection.  GOAWAY can be sent by either the client or the server.  Once sent, the sender
-          will ignore frames sent on any new streams with identifiers higher than the included last
-          stream identifier.  Receivers of a GOAWAY frame MUST NOT open additional streams on the
-          connection, although a new connection can be established for new streams.
-        </t>
-        <t>
-          The purpose of this frame is to allow an endpoint to gracefully stop accepting new
-          streams, while still finishing processing of previously established streams.  This enables
-          administrative actions, like server maintainance.
-        </t>
-        <t>
-          There is an inherent race condition between an endpoint starting new streams and the
-          remote sending a GOAWAY frame.  To deal with this case, the GOAWAY contains the stream
-          identifier of the last peer-initiated stream which was or might be processed on the
-          sending endpoint in this connection.  For instance, if the server sends a GOAWAY frame,
-          the identified stream is the highest numbered stream initiated by the client.
-        </t>
-        <t>
-          If the receiver of the GOAWAY has sent data on streams with a higher stream identifier
-          than what is indicated in the GOAWAY frame, those streams are not or will not be
-          processed.  The receiver of the GOAWAY frame can treat the streams as though they had
-          never been created at all, thereby allowing those streams to be retried later on a new
-          connection.
-        </t>
-        <t>
-          Endpoints SHOULD always send a GOAWAY frame before closing a connection so that the remote
-          can know whether a stream has been partially processed or not.  For example, if an HTTP
-          client sends a POST at the same time that a server closes a connection, the client cannot
-          know if the server started to process that POST request if the server does not send a
-          GOAWAY frame to indicate what streams it might have acted on.
-        </t>
-        <t>
-          An endpoint might choose to close a connection without sending GOAWAY for misbehaving
-          peers.
-        </t>
-
-        <figure title="GOAWAY Payload Format">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |R|                  Last-Stream-ID (31)                        |
- +-+-------------------------------------------------------------+
- |                      Error Code (32)                          |
- +---------------------------------------------------------------+
- |                  Additional Debug Data (*)                    |
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-        <t>
-          The GOAWAY frame does not define any flags.
-        </t>
-        <t>
-          The GOAWAY frame applies to the connection, not a specific stream.  An endpoint MUST treat
-          a <x:ref>GOAWAY</x:ref> frame with a stream identifier other than 0x0 as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          The last stream identifier in the GOAWAY frame contains the highest numbered stream
-          identifier for which the sender of the GOAWAY frame might have taken some action on, or
-          might yet take action on.  All streams up to and including the identified stream might
-          have been processed in some way.  The last stream identifier can be set to 0 if no streams
-          were processed.
-          <list style="hanging">
-            <t hangText="Note:">
-              In this context, "processed" means that some data from the stream was passed to some
-              higher layer of software that might have taken some action as a result.
-            </t>
-          </list>
-          If a connection terminates without a GOAWAY frame, the last stream identifier is
-          effectively the highest possible stream identifier.
-        </t>
-        <t>
-          On streams with lower or equal numbered identifiers that were not closed completely prior
-          to the connection being closed, re-attempting requests, transactions, or any protocol
-          activity is not possible, with the exception of idempotent actions like HTTP GET, PUT, or
-          DELETE.  Any protocol activity that uses higher numbered streams can be safely retried
-          using a new connection.
-        </t>
-        <t>
-          Activity on streams numbered lower or equal to the last stream identifier might still
-          complete successfully.  The sender of a GOAWAY frame might gracefully shut down a
-          connection by sending a GOAWAY frame, maintaining the connection in an open state until
-          all in-progress streams complete.
-        </t>
-        <t>
-          An endpoint MAY send multiple GOAWAY frames if circumstances change.  For instance, an
-          endpoint that sends GOAWAY with <x:ref>NO_ERROR</x:ref> during graceful shutdown could
-          subsequently encounter an condition that requires immediate termination of the connection.
-          The last stream identifier from the last GOAWAY frame received indicates which streams
-          could have been acted upon.  Endpoints MUST NOT increase the value they send in the last
-          stream identifier, since the peers might already have retried unprocessed requests on
-          another connection.
-        </t>
-        <t>
-          A client that is unable to retry requests loses all requests that are in flight when the
-          server closes the connection.  This is especially true for intermediaries that might
-          not be serving clients using HTTP/2.  A server that is attempting to gracefully shut down
-          a connection SHOULD send an initial GOAWAY frame with the last stream identifier set to
-          2<x:sup>31</x:sup>-1 and a <x:ref>NO_ERROR</x:ref> code.  This signals to the client that
-          a shutdown is imminent and that no further requests can be initiated.  After waiting at
-          least one round trip time, the server can send another GOAWAY frame with an updated last
-          stream identifier.  This ensures that a connection can be cleanly shut down without losing
-          requests.
-        </t>
-
-        <t>
-          After sending a GOAWAY frame, the sender can discard frames for streams with identifiers
-          higher than the identified last stream.  However, any frames that alter connection state
-          cannot be completely ignored.  For instance, <x:ref>HEADERS</x:ref>,
-          <x:ref>PUSH_PROMISE</x:ref> and <x:ref>CONTINUATION</x:ref> frames MUST be minimally
-          processed to ensure the state maintained for header compression is consistent (see <xref
-          target="HeaderBlock"/>); similarly DATA frames MUST be counted toward the connection flow
-          control window.  Failure to process these frames can cause flow control or header
-          compression state to become unsynchronized.
-        </t>
-
-        <t>
-          The GOAWAY frame also contains a 32-bit <xref target="ErrorCodes">error code</xref> that
-          contains the reason for closing the connection.
-        </t>
-        <t>
-          Endpoints MAY append opaque data to the payload of any GOAWAY frame.  Additional debug
-          data is intended for diagnostic purposes only and carries no semantic value.  Debug
-          information could contain security- or privacy-sensitive data.  Logged or otherwise
-          persistently stored debug data MUST have adequate safeguards to prevent unauthorized
-          access.
-        </t>
-      </section>
-
-      <section anchor="WINDOW_UPDATE" title="WINDOW_UPDATE">
-        <t>
-          The WINDOW_UPDATE frame (type=0x8) is used to implement flow control; see <xref
-          target="FlowControl"/> for an overview.
-        </t>
-        <t>
-          Flow control operates at two levels: on each individual stream and on the entire
-          connection.
-        </t>
-        <t>
-          Both types of flow control are hop-by-hop; that is, only between the two endpoints.
-          Intermediaries do not forward WINDOW_UPDATE frames between dependent connections.
-          However, throttling of data transfer by any receiver can indirectly cause the propagation
-          of flow control information toward the original sender.
-        </t>
-        <t>
-          Flow control only applies to frames that are identified as being subject to flow control.
-          Of the frame types defined in this document, this includes only <x:ref>DATA</x:ref> frames.
-          Frames that are exempt from flow control MUST be accepted and processed, unless the
-          receiver is unable to assign resources to handling the frame.  A receiver MAY respond with
-          a <xref target="StreamErrorHandler">stream error</xref> or <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>FLOW_CONTROL_ERROR</x:ref> if it is unable to accept a frame.
-        </t>
-        <figure title="WINDOW_UPDATE Payload Format">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |R|              Window Size Increment (31)                     |
- +-+-------------------------------------------------------------+
-]]></artwork>
-        </figure>
-        <t>
-          The payload of a WINDOW_UPDATE frame is one reserved bit, plus an unsigned 31-bit integer
-          indicating the number of octets that the sender can transmit in addition to the existing
-          flow control window.  The legal range for the increment to the flow control window is 1 to
-          2<x:sup>31</x:sup>-1 (0x7fffffff) octets.
-        </t>
-        <t>
-          The WINDOW_UPDATE frame does not define any flags.
-        </t>
-        <t>
-          The WINDOW_UPDATE frame can be specific to a stream or to the entire connection.  In the
-          former case, the frame's stream identifier indicates the affected stream; in the latter,
-          the value "0" indicates that the entire connection is the subject of the frame.
-        </t>
-        <t>
-          A receiver MUST treat the receipt of a WINDOW_UPDATE frame with an flow control window
-          increment of 0 as a <xref target="StreamErrorHandler">stream error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>; errors on the connection flow control window MUST be
-          treated as a <xref target="ConnectionErrorHandler">connection error</xref>.
-        </t>
-        <t>
-          WINDOW_UPDATE can be sent by a peer that has sent a frame bearing the END_STREAM flag.
-          This means that a receiver could receive a WINDOW_UPDATE frame on a "half closed (remote)"
-          or "closed" stream.  A receiver MUST NOT treat this as an error, see <xref
-          target="StreamStates"/>.
-        </t>
-        <t>
-          A receiver that receives a flow controlled frame MUST always account for its contribution
-          against the connection flow control window, unless the receiver treats this as a <xref
-          target="ConnectionErrorHandler">connection error</xref>.  This is necessary even if the
-          frame is in error.  Since the sender counts the frame toward the flow control window, if
-          the receiver does not, the flow control window at sender and receiver can become
-          different.
-        </t>
-
-        <section title="The Flow Control Window">
-          <t>
-            Flow control in HTTP/2 is implemented using a window kept by each sender on every
-            stream. The flow control window is a simple integer value that indicates how many octets
-            of data the sender is permitted to transmit; as such, its size is a measure of the
-            buffering capacity of the receiver.
-          </t>
-          <t>
-            Two flow control windows are applicable: the stream flow control window and the
-            connection flow control window.  The sender MUST NOT send a flow controlled frame with a
-            length that exceeds the space available in either of the flow control windows advertised
-            by the receiver.  Frames with zero length with the END_STREAM flag set (that is, an
-            empty <x:ref>DATA</x:ref> frame) MAY be sent if there is no available space in either
-            flow control window.
-          </t>
-          <t>
-            For flow control calculations, the 9 octet frame header is not counted.
-          </t>
-          <t>
-            After sending a flow controlled frame, the sender reduces the space available in both
-            windows by the length of the transmitted frame.
-          </t>
-          <t>
-            The receiver of a frame sends a WINDOW_UPDATE frame as it consumes data and frees up
-            space in flow control windows.  Separate WINDOW_UPDATE frames are sent for the stream
-            and connection level flow control windows.
-          </t>
-          <t>
-            A sender that receives a WINDOW_UPDATE frame updates the corresponding window by the
-            amount specified in the frame.
-          </t>
-          <t>
-            A sender MUST NOT allow a flow control window to exceed 2<x:sup>31</x:sup>-1 octets.
-            If a sender receives a WINDOW_UPDATE that causes a flow control window to exceed this
-            maximum it MUST terminate either the stream or the connection, as appropriate.  For
-            streams, the sender sends a <x:ref>RST_STREAM</x:ref> with the error code of
-            <x:ref>FLOW_CONTROL_ERROR</x:ref> code; for the connection, a <x:ref>GOAWAY</x:ref>
-            frame with a <x:ref>FLOW_CONTROL_ERROR</x:ref> code.
-          </t>
-          <t>
-            Flow controlled frames from the sender and WINDOW_UPDATE frames from the receiver are
-            completely asynchronous with respect to each other. This property allows a receiver to
-            aggressively update the window size kept by the sender to prevent streams from stalling.
-          </t>
-        </section>
-
-        <section anchor="InitialWindowSize" title="Initial Flow Control Window Size">
-          <t>
-            When an HTTP/2 connection is first established, new streams are created with an initial
-            flow control window size of 65,535 octets. The connection flow control window is 65,535
-            octets. Both endpoints can adjust the initial window size for new streams by including
-            a value for <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> in the <x:ref>SETTINGS</x:ref>
-            frame that forms part of the connection preface. The connection flow control window can
-            only be changed using WINDOW_UPDATE frames.
-          </t>
-          <t>
-            Prior to receiving a <x:ref>SETTINGS</x:ref> frame that sets a value for
-            <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref>, an endpoint can only use the default
-            initial window size when sending flow controlled frames.  Similarly, the connection flow
-            control window is set to the default initial window size until a WINDOW_UPDATE frame is
-            received.
-          </t>
-          <t>
-            A <x:ref>SETTINGS</x:ref> frame can alter the initial flow control window size for all
-            current streams. When the value of <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> changes,
-            a receiver MUST adjust the size of all stream flow control windows that it maintains by
-            the difference between the new value and the old value.
-          </t>
-          <t>
-            A change to <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> can cause the available space in
-            a flow control window to become negative.  A sender MUST track the negative flow control
-            window, and MUST NOT send new flow controlled frames until it receives WINDOW_UPDATE
-            frames that cause the flow control window to become positive.
-          </t>
-          <t>
-            For example, if the client sends 60KB immediately on connection establishment, and the
-            server sets the initial window size to be 16KB, the client will recalculate the
-            available flow control window to be -44KB on receipt of the <x:ref>SETTINGS</x:ref>
-            frame.  The client retains a negative flow control window until WINDOW_UPDATE frames
-            restore the window to being positive, after which the client can resume sending.
-          </t>
-          <t>
-            A <x:ref>SETTINGS</x:ref> frame cannot alter the connection flow control window.
-          </t>
-          <t>
-            An endpoint MUST treat a change to <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> that
-            causes any flow control window to exceed the maximum size as a <xref
-            target="ConnectionErrorHandler">connection error</xref> of type
-            <x:ref>FLOW_CONTROL_ERROR</x:ref>.
-          </t>
-        </section>
-
-        <section title="Reducing the Stream Window Size">
-          <t>
-            A receiver that wishes to use a smaller flow control window than the current size can
-            send a new <x:ref>SETTINGS</x:ref> frame.  However, the receiver MUST be prepared to
-            receive data that exceeds this window size, since the sender might send data that
-            exceeds the lower limit prior to processing the <x:ref>SETTINGS</x:ref> frame.
-          </t>
-          <t>
-            After sending a SETTINGS frame that reduces the initial flow control window size, a
-            receiver has two options for handling streams that exceed flow control limits:
-            <list style="numbers">
-              <t>
-                The receiver can immediately send <x:ref>RST_STREAM</x:ref> with
-                <x:ref>FLOW_CONTROL_ERROR</x:ref> error code for the affected streams.
-              </t>
-              <t>
-                The receiver can accept the streams and tolerate the resulting head of line
-                blocking, sending WINDOW_UPDATE frames as it consumes data.
-              </t>
-            </list>
-          </t>
-        </section>
-      </section>
-
-      <section anchor="CONTINUATION" title="CONTINUATION">
-        <t>
-          The CONTINUATION frame (type=0x9) is used to continue a sequence of <xref
-          target="HeaderBlock">header block fragments</xref>.  Any number of CONTINUATION frames can
-          be sent on an existing stream, as long as the preceding frame is on the same stream and is
-          a <x:ref>HEADERS</x:ref>, <x:ref>PUSH_PROMISE</x:ref> or CONTINUATION frame without the
-          END_HEADERS flag set.
-        </t>
-
-        <figure title="CONTINUATION Frame Payload">
-          <artwork type="inline"><![CDATA[
-  0                   1                   2                   3
-  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |                   Header Block Fragment (*)                 ...
- +---------------------------------------------------------------+
-]]></artwork>
-        </figure>
-        <t>
-          The CONTINUATION frame payload contains a <xref target="HeaderBlock">header block
-          fragment</xref>.
-        </t>
-
-        <t>
-          The CONTINUATION frame defines the following flag:
-          <list style="hanging">
-            <x:lt hangText="END_HEADERS (0x4):">
-              <t>
-                Bit 3 being set indicates that this frame ends a <xref target="HeaderBlock">header
-                block</xref>.
-              </t>
-              <t>
-                If the END_HEADERS bit is not set, this frame MUST be followed by another
-                CONTINUATION frame.  A receiver MUST treat the receipt of any other type of frame or
-                a frame on a different stream as a <xref target="ConnectionErrorHandler">connection
-                error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
-              </t>
-            </x:lt>
-          </list>
-        </t>
-
-        <t>
-          The CONTINUATION frame changes the connection state as defined in <xref
-          target="HeaderBlock" />.
-        </t>
-
-        <t>
-          CONTINUATION frames MUST be associated with a stream. If a CONTINUATION frame is received
-          whose stream identifier field is 0x0, the recipient MUST respond with a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type PROTOCOL_ERROR.
-        </t>
-
-        <t>
-          A CONTINUATION frame MUST be preceded by a <x:ref>HEADERS</x:ref>,
-          <x:ref>PUSH_PROMISE</x:ref> or CONTINUATION frame without the END_HEADERS flag set.  A
-          recipient that observes violation of this rule MUST respond with a <xref
-          target="ConnectionErrorHandler"> connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-      </section>
-    </section>
-
-    <section anchor="ErrorCodes" title="Error Codes">
-      <t>
-        Error codes are 32-bit fields that are used in <x:ref>RST_STREAM</x:ref> and
-        <x:ref>GOAWAY</x:ref> frames to convey the reasons for the stream or connection error.
-      </t>
-
-      <t>
-        Error codes share a common code space.  Some error codes apply only to either streams or the
-        entire connection and have no defined semantics in the other context.
-      </t>
-
-      <t>
-        The following error codes are defined:
-        <list style="hanging">
-          <t hangText="NO_ERROR (0x0):" anchor="NO_ERROR">
-            The associated condition is not as a result of an error.  For example, a
-            <x:ref>GOAWAY</x:ref> might include this code to indicate graceful shutdown of a
-            connection.
-          </t>
-          <t hangText="PROTOCOL_ERROR (0x1):" anchor="PROTOCOL_ERROR">
-            The endpoint detected an unspecific protocol error.  This error is for use when a more
-            specific error code is not available.
-          </t>
-          <t hangText="INTERNAL_ERROR (0x2):" anchor="INTERNAL_ERROR">
-            The endpoint encountered an unexpected internal error.
-          </t>
-          <t hangText="FLOW_CONTROL_ERROR (0x3):" anchor="FLOW_CONTROL_ERROR">
-            The endpoint detected that its peer violated the flow control protocol.
-          </t>
-          <t hangText="SETTINGS_TIMEOUT (0x4):" anchor="SETTINGS_TIMEOUT">
-            The endpoint sent a <x:ref>SETTINGS</x:ref> frame, but did not receive a response in a
-            timely manner.  See <xref target="SettingsSync">Settings Synchronization</xref>.
-          </t>
-          <t hangText="STREAM_CLOSED (0x5):" anchor="STREAM_CLOSED">
-            The endpoint received a frame after a stream was half closed.
-          </t>
-          <t hangText="FRAME_SIZE_ERROR (0x6):" anchor="FRAME_SIZE_ERROR">
-            The endpoint received a frame with an invalid size.
-          </t>
-          <t hangText="REFUSED_STREAM (0x7):" anchor="REFUSED_STREAM">
-            The endpoint refuses the stream prior to performing any application processing, see
-            <xref target="Reliability"/> for details.
-          </t>
-          <t hangText="CANCEL (0x8):" anchor="CANCEL">
-            Used by the endpoint to indicate that the stream is no longer needed.
-          </t>
-          <t hangText="COMPRESSION_ERROR (0x9):" anchor="COMPRESSION_ERROR">
-            The endpoint is unable to maintain the header compression context for the connection.
-          </t>
-          <t hangText="CONNECT_ERROR (0xa):" anchor="CONNECT_ERROR">
-            The connection established in response to a <xref target="CONNECT">CONNECT
-            request</xref> was reset or abnormally closed.
-          </t>
-          <t hangText="ENHANCE_YOUR_CALM (0xb):" anchor="ENHANCE_YOUR_CALM">
-            The endpoint detected that its peer is exhibiting a behavior that might be generating
-            excessive load.
-          </t>
-          <t hangText="INADEQUATE_SECURITY (0xc):" anchor="INADEQUATE_SECURITY">
-            The underlying transport has properties that do not meet minimum security
-            requirements (see <xref target="TLSUsage"/>).
-          </t>
-        </list>
-      </t>
-      <t>
-        Unknown or unsupported error codes MUST NOT trigger any special behavior.  These MAY be
-        treated by an implementation as being equivalent to <x:ref>INTERNAL_ERROR</x:ref>.
-      </t>
-    </section>
-
-    <section anchor="HTTPLayer" title="HTTP Message Exchanges">
-      <t>
-        HTTP/2 is intended to be as compatible as possible with current uses of HTTP. This means
-        that, from the application perspective, the features of the protocol are largely
-        unchanged. To achieve this, all request and response semantics are preserved, although the
-        syntax of conveying those semantics has changed.
-      </t>
-      <t>
-        Thus, the specification and requirements of HTTP/1.1 Semantics and Content <xref
-        target="RFC7231"/>, Conditional Requests <xref target="RFC7232"/>, Range Requests <xref
-        target="RFC7233"/>, Caching <xref target="RFC7234"/> and Authentication <xref
-        target="RFC7235"/> are applicable to HTTP/2. Selected portions of HTTP/1.1 Message Syntax
-        and Routing <xref target="RFC7230"/>, such as the HTTP and HTTPS URI schemes, are also
-        applicable in HTTP/2, but the expression of those semantics for this protocol are defined
-        in the sections below.
-      </t>
-
-      <section anchor="HttpSequence" title="HTTP Request/Response Exchange">
-        <t>
-          A client sends an HTTP request on a new stream, using a previously unused <xref
-          target="StreamIdentifiers">stream identifier</xref>.  A server sends an HTTP response on
-          the same stream as the request.
-        </t>
-        <t>
-          An HTTP message (request or response) consists of:
-          <list style="numbers">
-            <t>
-              for a response only, zero or more <x:ref>HEADERS</x:ref> frames (each followed by zero
-              or more <x:ref>CONTINUATION</x:ref> frames) containing the message headers of
-              informational (1xx) HTTP responses (see <xref target="RFC7230" x:fmt=","
-              x:rel="#header.fields"/> and <xref target="RFC7231" x:fmt="," x:rel="#status.1xx"/>),
-              and
-            </t>
-            <t>
-              one <x:ref>HEADERS</x:ref> frame (followed by zero or more <x:ref>CONTINUATION</x:ref>
-              frames) containing the message headers (see <xref target="RFC7230" x:fmt=","
-              x:rel="#header.fields"/>), and
-            </t>
-            <t>
-              zero or more <x:ref>DATA</x:ref> frames containing the message payload (see <xref
-              target="RFC7230" x:fmt="," x:rel="#message.body"/>), and
-            </t>
-            <t>
-              optionally, one <x:ref>HEADERS</x:ref> frame, followed by zero or more
-              <x:ref>CONTINUATION</x:ref> frames containing the trailer-part, if present (see <xref
-              target="RFC7230" x:fmt="," x:rel="#chunked.trailer.part"/>).
-            </t>
-          </list>
-          The last frame in the sequence bears an END_STREAM flag, noting that a
-          <x:ref>HEADERS</x:ref> frame bearing the END_STREAM flag can be followed by
-          <x:ref>CONTINUATION</x:ref> frames that carry any remaining portions of the header block.
-        </t>
-        <t>
-          Other frames (from any stream) MUST NOT occur between either <x:ref>HEADERS</x:ref> frame
-          and any <x:ref>CONTINUATION</x:ref> frames that might follow.
-        </t>
-
-        <t>
-          Trailing header fields are carried in a header block that also terminates the stream.
-          That is, a sequence starting with a <x:ref>HEADERS</x:ref> frame, followed by zero or more
-          <x:ref>CONTINUATION</x:ref> frames, where the <x:ref>HEADERS</x:ref> frame bears an
-          END_STREAM flag.  Header blocks after the first that do not terminate the stream are not
-          part of an HTTP request or response.
-        </t>
-        <t>
-          A <x:ref>HEADERS</x:ref> frame (and associated <x:ref>CONTINUATION</x:ref> frames) can
-          only appear at the start or end of a stream.  An endpoint that receives a
-          <x:ref>HEADERS</x:ref> frame without the END_STREAM flag set after receiving a final
-          (non-informational) status code MUST treat the corresponding request or response as <xref
-          target="malformed">malformed</xref>.
-        </t>
-
-        <t>
-          An HTTP request/response exchange fully consumes a single stream.  A request starts with
-          the <x:ref>HEADERS</x:ref> frame that puts the stream into an "open" state. The request
-          ends with a frame bearing END_STREAM, which causes the stream to become "half closed
-          (local)" for the client and "half closed (remote)" for the server.  A response starts with
-          a <x:ref>HEADERS</x:ref> frame and ends with a frame bearing END_STREAM, which places the
-          stream in the "closed" state.
-          <!-- Yes, the response might be completed before the request does, but that's not a detail
-               we need to expand upon.  It's complicated enough explaining this as it is.  -->
-        </t>
-
-        <section anchor="informational-responses" title="Upgrading From HTTP/2">
-          <t>
-            HTTP/2 removes support for the 101 (Switching Protocols) informational status code
-            (<xref target="RFC7231" x:fmt="," x:rel="#status.101"/>).
-          </t>
-          <t>
-            The semantics of 101 (Switching Protocols) aren't applicable to a multiplexed protocol.
-            Alternative protocols are able to use the same mechanisms that HTTP/2 uses to negotiate
-            their use (see <xref target="starting"/>).
-          </t>
-        </section>
-
-        <section anchor="HttpHeaders" title="HTTP Header Fields">
-          <t>
-            HTTP header fields carry information as a series of key-value pairs. For a listing of
-            registered HTTP headers, see the Message Header Field Registry maintained at <eref
-            target="https://www.iana.org/assignments/message-headers"/>.
-          </t>
-
-          <section anchor="PseudoHeaderFields" title="Pseudo-Header Fields">
-            <t>
-              While HTTP/1.x used the message start-line (see <xref target="RFC7230" x:fmt=","
-              x:rel="#start.line"/>) to convey the target URI and method of the request, and the
-              status code for the response, HTTP/2 uses special pseudo-header fields beginning with
-              ':' character (ASCII 0x3a) for this purpose.
-            </t>
-            <t>
-              Pseudo-header fields are not HTTP header fields. Endpoints MUST NOT generate
-              pseudo-header fields other than those defined in this document.
-            </t>
-            <t>
-              Pseudo-header fields are only valid in the context in which they are defined.
-              Pseudo-header fields defined for requests MUST NOT appear in responses; pseudo-header
-              fields defined for responses MUST NOT appear in requests.  Pseudo-header fields MUST
-              NOT appear in trailers.  Endpoints MUST treat a request or response that contains
-              undefined or invalid pseudo-header fields as <xref
-              target="malformed">malformed</xref>.
-            </t>
-            <t>
-              Just as in HTTP/1.x, header field names are strings of ASCII characters that are
-              compared in a case-insensitive fashion. However, header field names MUST be converted
-              to lowercase prior to their encoding in HTTP/2. A request or response containing
-              uppercase header field names MUST be treated as <xref
-              target="malformed">malformed</xref>.
-            </t>
-            <t>
-              All pseudo-header fields MUST appear in the header block before regular header fields.
-              Any request or response that contains a pseudo-header field that appears in a header
-              block after a regular header field MUST be treated as <xref
-              target="malformed">malformed</xref>.
-            </t>
-          </section>
-
-          <section title="Connection-Specific Header Fields">
-            <t>
-              HTTP/2 does not use the <spanx style="verb">Connection</spanx> header field to
-              indicate connection-specific header fields; in this protocol, connection-specific
-              metadata is conveyed by other means.  An endpoint MUST NOT generate a HTTP/2 message
-              containing connection-specific header fields; any message containing
-              connection-specific header fields MUST be treated as <xref
-              target="malformed">malformed</xref>.
-            </t>
-            <t>
-              This means that an intermediary transforming an HTTP/1.x message to HTTP/2 will need
-              to remove any header fields nominated by the Connection header field, along with the
-              Connection header field itself. Such intermediaries SHOULD also remove other
-              connection-specific header fields, such as Keep-Alive, Proxy-Connection,
-              Transfer-Encoding and Upgrade, even if they are not nominated by Connection.
-            </t>
-            <t>
-              One exception to this is the TE header field, which MAY be present in an HTTP/2
-              request, but when it is MUST NOT contain any value other than "trailers".
-            </t>
-            <t>
-              <list style="hanging">
-                <t hangText="Note:">
-                  HTTP/2 purposefully does not support upgrade to another protocol.  The handshake
-                  methods described in <xref target="starting"/> are believed sufficient to
-                  negotiate the use of alternative protocols.
-                </t>
-              </list>
-            </t>
-          </section>
-
-          <section anchor="HttpRequest" title="Request Pseudo-Header Fields">
-            <t>
-              The following pseudo-header fields are defined for HTTP/2 requests:
-              <list style="symbols">
-                <x:lt>
-                  <t>
-                    The <spanx style="verb">:method</spanx> pseudo-header field includes the HTTP
-                    method (<xref target="RFC7231" x:fmt="," x:rel="#methods"/>).
-                  </t>
-                </x:lt>
-                <x:lt>
-                  <t>
-                    The <spanx style="verb">:scheme</spanx> pseudo-header field includes the scheme
-                    portion of the target URI (<xref target="RFC3986" x:fmt="," x:sec="3.1"/>).
-                  </t>
-                  <t>
-                    <spanx style="verb">:scheme</spanx> is not restricted to <spanx
-                    style="verb">http</spanx> and <spanx style="verb">https</spanx> schemed URIs.  A
-                    proxy or gateway can translate requests for non-HTTP schemes, enabling the use
-                    of HTTP to interact with non-HTTP services.
-                  </t>
-                </x:lt>
-                <x:lt>
-                  <t>
-                    The <spanx style="verb">:authority</spanx> pseudo-header field includes the
-                    authority portion of the target URI (<xref target="RFC3986" x:fmt=","
-                    x:sec="3.2"/>). The authority MUST NOT include the deprecated <spanx
-                    style="verb">userinfo</spanx> subcomponent for <spanx style="verb">http</spanx>
-                    or <spanx style="verb">https</spanx> schemed URIs.
-                  </t>
-                  <t>
-                    To ensure that the HTTP/1.1 request line can be reproduced accurately, this
-                    pseudo-header field MUST be omitted when translating from an HTTP/1.1 request
-                    that has a request target in origin or asterisk form (see <xref
-                    target="RFC7230" x:fmt="," x:rel="#request-target"/>). Clients that generate
-                    HTTP/2 requests directly SHOULD use the <spanx>:authority</spanx> pseudo-header
-                    field instead of the <spanx style="verb">Host</spanx> header field. An
-                    intermediary that converts an HTTP/2 request to HTTP/1.1 MUST create a <spanx
-                    style="verb">Host</spanx> header field if one is not present in a request by
-                    copying the value of the <spanx style="verb">:authority</spanx> pseudo-header
-                    field.
-                  </t>
-                </x:lt>
-                <x:lt>
-                  <t>
-                    The <spanx style="verb">:path</spanx> pseudo-header field includes the path and
-                    query parts of the target URI (the <spanx style="verb">path-absolute</spanx>
-                    production from <xref target="RFC3986"/> and optionally a '?' character
-                    followed by the <spanx style="verb">query</spanx> production, see <xref
-                    target="RFC3986" x:fmt="," x:sec="3.3"/> and <xref target="RFC3986" x:fmt=","
-                    x:sec="3.4"/>). A request in asterisk form includes the value '*' for the
-                    <spanx style="verb">:path</spanx> pseudo-header field.
-                  </t>
-                  <t>
-                    This pseudo-header field MUST NOT be empty for <spanx style="verb">http</spanx>
-                    or <spanx style="verb">https</spanx> URIs; <spanx style="verb">http</spanx> or
-                    <spanx style="verb">https</spanx> URIs that do not contain a path component
-                    MUST include a value of '/'. The exception to this rule is an OPTIONS request
-                    for an <spanx style="verb">http</spanx> or <spanx style="verb">https</spanx>
-                    URI that does not include a path component; these MUST include a <spanx
-                    style="verb">:path</spanx> pseudo-header field with a value of '*' (see <xref
-                    target="RFC7230" x:fmt="," x:rel="#asterisk-form"/>).
-                  </t>
-                </x:lt>
-              </list>
-            </t>
-            <t>
-              All HTTP/2 requests MUST include exactly one valid value for the <spanx
-              style="verb">:method</spanx>, <spanx style="verb">:scheme</spanx>, and <spanx
-              style="verb">:path</spanx> pseudo-header fields, unless it is a <xref
-              target="CONNECT">CONNECT request</xref>. An HTTP request that omits mandatory
-              pseudo-header fields is <xref target="malformed">malformed</xref>.
-            </t>
-            <t>
-              HTTP/2 does not define a way to carry the version identifier that is included in the
-              HTTP/1.1 request line.
-            </t>
-          </section>
-
-          <section anchor="HttpResponse" title="Response Pseudo-Header Fields">
-            <t>
-              For HTTP/2 responses, a single <spanx style="verb">:status</spanx> pseudo-header
-              field is defined that carries the HTTP status code field (see <xref target="RFC7231"
-              x:fmt="," x:rel="#status.codes"/>). This pseudo-header field MUST be included in all
-              responses, otherwise the response is <xref target="malformed">malformed</xref>.
-            </t>
-            <t>
-              HTTP/2 does not define a way to carry the version or reason phrase that is included in
-              an HTTP/1.1 status line.
-            </t>
-          </section>
-
-         <section anchor="CompressCookie" title="Compressing the Cookie Header Field">
-            <t>
-              The <xref target="COOKIE">Cookie header field</xref> can carry a significant amount of
-              redundant data.
-            </t>
-            <t>
-              The Cookie header field uses a semi-colon (";") to delimit cookie-pairs (or "crumbs").
-              This header field doesn't follow the list construction rules in HTTP (see <xref
-              target="RFC7230" x:fmt="," x:rel="#field.order"/>), which prevents cookie-pairs from
-              being separated into different name-value pairs.  This can significantly reduce
-              compression efficiency as individual cookie-pairs are updated.
-            </t>
-            <t>
-              To allow for better compression efficiency, the Cookie header field MAY be split into
-              separate header fields, each with one or more cookie-pairs.  If there are multiple
-              Cookie header fields after decompression, these MUST be concatenated into a single
-              octet string using the two octet delimiter of 0x3B, 0x20 (the ASCII string "; ")
-              before being passed into a non-HTTP/2 context, such as an HTTP/1.1 connection, or a
-              generic HTTP server application.
-            </t>
-            <figure>
-              <preamble>
-                Therefore, the following two lists of Cookie header fields are semantically
-                equivalent.
-              </preamble>
-              <artwork type="inline"><![CDATA[
-  cookie: a=b; c=d; e=f
-
-  cookie: a=b
-  cookie: c=d
-  cookie: e=f
-]]></artwork>
-            </figure>
-          </section>
-
-          <section anchor="malformed" title="Malformed Requests and Responses">
-            <t>
-              A malformed request or response is one that is an otherwise valid sequence of HTTP/2
-              frames, but is otherwise invalid due to the presence of extraneous frames, prohibited
-              header fields, the absence of mandatory header fields, or the inclusion of uppercase
-              header field names.
-            </t>
-            <t>
-              A request or response that includes an entity body can include a <spanx
-              style="verb">content-length</spanx> header field.  A request or response is also
-              malformed if the value of a <spanx style="verb">content-length</spanx> header field
-              does not equal the sum of the <x:ref>DATA</x:ref> frame payload lengths that form the
-              body.  A response that is defined to have no payload, as described in <xref
-              target="RFC7230" x:fmt="," x:rel="#header.content-length"/>, can have a non-zero
-              <spanx style="verb">content-length</spanx> header field, even though no content is
-              included in <x:ref>DATA</x:ref> frames.
-            </t>
-            <t>
-              Intermediaries that process HTTP requests or responses (i.e., any intermediary not
-              acting as a tunnel) MUST NOT forward a malformed request or response.  Malformed
-              requests or responses that are detected MUST be treated as a <xref
-              target="StreamErrorHandler">stream error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
-            </t>
-            <t>
-              For malformed requests, a server MAY send an HTTP response prior to closing or
-              resetting the stream.  Clients MUST NOT accept a malformed response. Note that these
-              requirements are intended to protect against several types of common attacks against
-              HTTP; they are deliberately strict, because being permissive can expose
-              implementations to these vulnerabilities.
-            </t>
-          </section>
-        </section>
-
-        <section title="Examples">
-          <t>
-            This section shows HTTP/1.1 requests and responses, with illustrations of equivalent
-            HTTP/2 requests and responses.
-          </t>
-          <t>
-            An HTTP GET request includes request header fields and no body and is therefore
-            transmitted as a single <x:ref>HEADERS</x:ref> frame, followed by zero or more
-            <x:ref>CONTINUATION</x:ref> frames containing the serialized block of request header
-            fields.  The <x:ref>HEADERS</x:ref> frame in the following has both the END_HEADERS and
-            END_STREAM flags set; no <x:ref>CONTINUATION</x:ref> frames are sent:
-          </t>
-
-          <figure>
-            <artwork type="inline"><![CDATA[
-  GET /resource HTTP/1.1           HEADERS
-  Host: example.org          ==>     + END_STREAM
-  Accept: image/jpeg                 + END_HEADERS
-                                       :method = GET
-                                       :scheme = https
-                                       :path = /resource
-                                       host = example.org
-                                       accept = image/jpeg
-]]></artwork>
-          </figure>
-
-          <t>
-            Similarly, a response that includes only response header fields is transmitted as a
-            <x:ref>HEADERS</x:ref> frame (again, followed by zero or more
-            <x:ref>CONTINUATION</x:ref> frames) containing the serialized block of response header
-            fields.
-          </t>
-
-          <figure>
-            <artwork type="inline"><![CDATA[
-  HTTP/1.1 304 Not Modified        HEADERS
-  ETag: "xyzzy"              ==>     + END_STREAM
-  Expires: Thu, 23 Jan ...           + END_HEADERS
-                                       :status = 304
-                                       etag = "xyzzy"
-                                       expires = Thu, 23 Jan ...
-]]></artwork>
-          </figure>
-
-          <t>
-            An HTTP POST request that includes request header fields and payload data is transmitted
-            as one <x:ref>HEADERS</x:ref> frame, followed by zero or more
-            <x:ref>CONTINUATION</x:ref> frames containing the request header fields, followed by one
-            or more <x:ref>DATA</x:ref> frames, with the last <x:ref>CONTINUATION</x:ref> (or
-            <x:ref>HEADERS</x:ref>) frame having the END_HEADERS flag set and the final
-            <x:ref>DATA</x:ref> frame having the END_STREAM flag set:
-          </t>
-
-          <figure>
-            <artwork type="inline"><![CDATA[
-  POST /resource HTTP/1.1          HEADERS
-  Host: example.org          ==>     - END_STREAM
-  Content-Type: image/jpeg           - END_HEADERS
-  Content-Length: 123                  :method = POST
-                                       :path = /resource
-  {binary data}                        :scheme = https
-
-                                   CONTINUATION
-                                     + END_HEADERS
-                                       content-type = image/jpeg
-                                       host = example.org
-                                       content-length = 123
-
-                                   DATA
-                                     + END_STREAM
-                                   {binary data}
-]]></artwork>
-            <postamble>
-              Note that data contributing to any given header field could be spread between header
-              block fragments.  The allocation of header fields to frames in this example is
-              illustrative only.
-            </postamble>
-          </figure>
-
-          <t>
-            A response that includes header fields and payload data is transmitted as a
-            <x:ref>HEADERS</x:ref> frame, followed by zero or more <x:ref>CONTINUATION</x:ref>
-            frames, followed by one or more <x:ref>DATA</x:ref> frames, with the last
-            <x:ref>DATA</x:ref> frame in the sequence having the END_STREAM flag set:
-          </t>
-
-          <figure>
-            <artwork type="inline"><![CDATA[
-  HTTP/1.1 200 OK                  HEADERS
-  Content-Type: image/jpeg   ==>     - END_STREAM
-  Content-Length: 123                + END_HEADERS
-                                       :status = 200
-  {binary data}                        content-type = image/jpeg
-                                       content-length = 123
-
-                                   DATA
-                                     + END_STREAM
-                                   {binary data}
-]]></artwork>
-          </figure>
-
-          <t>
-            Trailing header fields are sent as a header block after both the request or response
-            header block and all the <x:ref>DATA</x:ref> frames have been sent.  The
-            <x:ref>HEADERS</x:ref> frame starting the trailers header block has the END_STREAM flag
-            set.
-          </t>
-
-          <figure>
-            <artwork type="inline"><![CDATA[
-  HTTP/1.1 200 OK                  HEADERS
-  Content-Type: image/jpeg   ==>     - END_STREAM
-  Transfer-Encoding: chunked         + END_HEADERS
-  Trailer: Foo                         :status = 200
-                                       content-length = 123
-  123                                  content-type = image/jpeg
-  {binary data}                        trailer = Foo
-  0
-  Foo: bar                         DATA
-                                     - END_STREAM
-                                   {binary data}
-
-                                   HEADERS
-                                     + END_STREAM
-                                     + END_HEADERS
-                                       foo = bar
-]]></artwork>
-          </figure>
-
-
-          <figure>
-           <preamble>
-             An informational response using a 1xx status code other than 101 is transmitted as a
-             <x:ref>HEADERS</x:ref> frame, followed by zero or more <x:ref>CONTINUATION</x:ref>
-             frames:
-           </preamble>
-           <artwork type="inline"><![CDATA[
-  HTTP/1.1 103 BAR                 HEADERS
-  Extension-Field: bar       ==>     - END_STREAM
-                                     + END_HEADERS
-                                       :status = 103
-                                       extension-field = bar
-]]></artwork>
- </figure>
-        </section>
-
-        <section anchor="Reliability" title="Request Reliability Mechanisms in HTTP/2">
-          <t>
-            In HTTP/1.1, an HTTP client is unable to retry a non-idempotent request when an error
-            occurs, because there is no means to determine the nature of the error.  It is possible
-            that some server processing occurred prior to the error, which could result in
-            undesirable effects if the request were reattempted.
-          </t>
-          <t>
-            HTTP/2 provides two mechanisms for providing a guarantee to a client that a request has
-            not been processed:
-            <list style="symbols">
-              <t>
-                The <x:ref>GOAWAY</x:ref> frame indicates the highest stream number that might have
-                been processed.  Requests on streams with higher numbers are therefore guaranteed to
-                be safe to retry.
-              </t>
-              <t>
-                The <x:ref>REFUSED_STREAM</x:ref> error code can be included in a
-                <x:ref>RST_STREAM</x:ref> frame to indicate that the stream is being closed prior to
-                any processing having occurred.  Any request that was sent on the reset stream can
-                be safely retried.
-              </t>
-            </list>
-          </t>
-          <t>
-            Requests that have not been processed have not failed; clients MAY automatically retry
-            them, even those with non-idempotent methods.
-          </t>
-          <t>
-            A server MUST NOT indicate that a stream has not been processed unless it can guarantee
-            that fact.  If frames that are on a stream are passed to the application layer for any
-            stream, then <x:ref>REFUSED_STREAM</x:ref> MUST NOT be used for that stream, and a
-            <x:ref>GOAWAY</x:ref> frame MUST include a stream identifier that is greater than or
-            equal to the given stream identifier.
-          </t>
-          <t>
-            In addition to these mechanisms, the <x:ref>PING</x:ref> frame provides a way for a
-            client to easily test a connection.  Connections that remain idle can become broken as
-            some middleboxes (for instance, network address translators, or load balancers) silently
-            discard connection bindings.  The <x:ref>PING</x:ref> frame allows a client to safely
-            test whether a connection is still active without sending a request.
-          </t>
-        </section>
-      </section>
-
-      <section anchor="PushResources" title="Server Push">
-        <t>
-          HTTP/2 allows a server to pre-emptively send (or "push") responses (along with
-          corresponding "promised" requests) to a client in association with a previous
-          client-initiated request. This can be useful when the server knows the client will need
-          to have those responses available in order to fully process the response to the original
-          request.
-        </t>
-
-        <t>
-          Pushing additional message exchanges in this fashion is optional, and is negotiated
-          between individual endpoints. The <x:ref>SETTINGS_ENABLE_PUSH</x:ref> setting can be set
-          to 0 to indicate that server push is disabled.
-        </t>
-        <t>
-          Promised requests MUST be cacheable (see <xref target="RFC7231" x:fmt=","
-          x:rel="#cacheable.methods"/>), MUST be safe (see <xref target="RFC7231" x:fmt=","
-          x:rel="#safe.methods"/>) and MUST NOT include a request body. Clients that receive a
-          promised request that is not cacheable, unsafe or that includes a request body MUST
-          reset the stream with a <xref target="StreamErrorHandler">stream error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-        <t>
-          Pushed responses that are cacheable (see <xref target="RFC7234" x:fmt=","
-          x:rel="#response.cacheability"/>) can be stored by the client, if it implements a HTTP
-          cache.  Pushed responses are considered successfully validated on the origin server (e.g.,
-          if the "no-cache" cache response directive <xref target="RFC7234" x:fmt=","
-          x:rel="#cache-response-directive"/> is present) while the stream identified by the
-          promised stream ID is still open.
-        </t>
-        <t>
-          Pushed responses that are not cacheable MUST NOT be stored by any HTTP cache. They MAY
-          be made available to the application separately.
-        </t>
-        <t>
-          An intermediary can receive pushes from the server and choose not to forward them on to
-          the client. In other words, how to make use of the pushed information is up to that
-          intermediary. Equally, the intermediary might choose to make additional pushes to the
-          client, without any action taken by the server.
-        </t>
-        <t>
-          A client cannot push. Thus, servers MUST treat the receipt of a
-          <x:ref>PUSH_PROMISE</x:ref> frame as a <xref target="ConnectionErrorHandler">connection
-          error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>. Clients MUST reject any attempt to
-          change the <x:ref>SETTINGS_ENABLE_PUSH</x:ref> setting to a value other than 0 by treating
-          the message as a <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>PROTOCOL_ERROR</x:ref>.
-        </t>
-
-        <section anchor="PushRequests" title="Push Requests">
-          <t>
-            Server push is semantically equivalent to a server responding to a request; however, in
-            this case that request is also sent by the server, as a <x:ref>PUSH_PROMISE</x:ref>
-            frame.
-          </t>
-          <t>
-            The <x:ref>PUSH_PROMISE</x:ref> frame includes a header block that contains a complete
-            set of request header fields that the server attributes to the request. It is not
-            possible to push a response to a request that includes a request body.
-          </t>
-
-          <t>
-            Pushed responses are always associated with an explicit request from the client. The
-            <x:ref>PUSH_PROMISE</x:ref> frames sent by the server are sent on that explicit
-            request's stream. The <x:ref>PUSH_PROMISE</x:ref> frame also includes a promised stream
-            identifier, chosen from the stream identifiers available to the server (see <xref
-            target="StreamIdentifiers"/>).
-          </t>
-
-          <t>
-            The header fields in <x:ref>PUSH_PROMISE</x:ref> and any subsequent
-            <x:ref>CONTINUATION</x:ref> frames MUST be a valid and complete set of <xref
-            target="HttpRequest">request header fields</xref>.  The server MUST include a method in
-            the <spanx style="verb">:method</spanx> header field that is safe and cacheable.  If a
-            client receives a <x:ref>PUSH_PROMISE</x:ref> that does not include a complete and valid
-            set of header fields, or the <spanx style="verb">:method</spanx> header field identifies
-            a method that is not safe, it MUST respond with a <xref
-            target="StreamErrorHandler">stream error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
-          </t>
-
-          <t>
-            The server SHOULD send <x:ref>PUSH_PROMISE</x:ref> (<xref target="PUSH_PROMISE"/>)
-            frames prior to sending any frames that reference the promised responses. This avoids a
-            race where clients issue requests prior to receiving any <x:ref>PUSH_PROMISE</x:ref>
-            frames.
-          </t>
-          <t>
-            For example, if the server receives a request for a document containing embedded links
-            to multiple image files, and the server chooses to push those additional images to the
-            client, sending push promises before the <x:ref>DATA</x:ref> frames that contain the
-            image links ensures that the client is able to see the promises before discovering
-            embedded links. Similarly, if the server pushes responses referenced by the header block
-            (for instance, in Link header fields), sending the push promises before sending the
-            header block ensures that clients do not request them.
-          </t>
-
-          <t>
-            <x:ref>PUSH_PROMISE</x:ref> frames MUST NOT be sent by the client.
-          </t>
-          <t>
-            <x:ref>PUSH_PROMISE</x:ref> frames can be sent by the server in response to any
-            client-initiated stream, but the stream MUST be in either the "open" or "half closed
-            (remote)" state with respect to the server.  <x:ref>PUSH_PROMISE</x:ref> frames are
-            interspersed with the frames that comprise a response, though they cannot be
-            interspersed with <x:ref>HEADERS</x:ref> and <x:ref>CONTINUATION</x:ref> frames that
-            comprise a single header block.
-          </t>
-          <t>
-            Sending a <x:ref>PUSH_PROMISE</x:ref> frame creates a new stream and puts the stream
-            into the “reserved (local)” state for the server and the “reserved (remote)” state for
-            the client.
-          </t>
-        </section>
-
-        <section anchor="PushResponses" title="Push Responses">
-          <t>
-            After sending the <x:ref>PUSH_PROMISE</x:ref> frame, the server can begin delivering the
-            pushed response as a <xref target="HttpResponse">response</xref> on a server-initiated
-            stream that uses the promised stream identifier.  The server uses this stream to
-            transmit an HTTP response, using the same sequence of frames as defined in <xref
-            target="HttpSequence"/>.  This stream becomes <xref target="StreamStates">"half closed"
-            to the client</xref> after the initial <x:ref>HEADERS</x:ref> frame is sent.
-          </t>
-
-          <t>
-            Once a client receives a <x:ref>PUSH_PROMISE</x:ref> frame and chooses to accept the
-            pushed response, the client SHOULD NOT issue any requests for the promised response
-            until after the promised stream has closed.
-          </t>
-
-          <t>
-            If the client determines, for any reason, that it does not wish to receive the pushed
-            response from the server, or if the server takes too long to begin sending the promised
-            response, the client can send an <x:ref>RST_STREAM</x:ref> frame, using either the
-            <x:ref>CANCEL</x:ref> or <x:ref>REFUSED_STREAM</x:ref> codes, and referencing the pushed
-            stream's identifier.
-          </t>
-          <t>
-            A client can use the <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> setting to limit the
-            number of responses that can be concurrently pushed by a server.  Advertising a
-            <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> value of zero disables server push by
-            preventing the server from creating the necessary streams.  This does not prohibit a
-            server from sending <x:ref>PUSH_PROMISE</x:ref> frames; clients need to reset any
-            promised streams that are not wanted.
-          </t>
-
-          <t>
-            Clients receiving a pushed response MUST validate that either the server is
-            authoritative (see <xref target="authority"/>), or the proxy that provided the pushed
-            response is configured for the corresponding request. For example, a server that offers
-            a certificate for only the <spanx style="verb">example.com</spanx> DNS-ID or Common Name
-            is not permitted to push a response for <spanx
-            style="verb">https://www.example.org/doc</spanx>.
-          </t>
-          <t>
-            The response for a <x:ref>PUSH_PROMISE</x:ref> stream begins with a
-            <x:ref>HEADERS</x:ref> frame, which immediately puts the stream into the “half closed
-            (remote)” state for the server and “half closed (local)” state for the client, and ends
-            with a frame bearing END_STREAM, which places the stream in the "closed" state.
-            <list style="hanging">
-              <t hangText="Note:">
-                The client never sends a frame with the END_STREAM flag for a server push.
-              </t>
-            </list>
-          </t>
-        </section>
-
-      </section>
-
-      <section anchor="CONNECT" title="The CONNECT Method">
-        <t>
-          In HTTP/1.x, the pseudo-method CONNECT (<xref target="RFC7231" x:fmt=","
-          x:rel="#CONNECT"/>) is used to convert an HTTP connection into a tunnel to a remote host.
-          CONNECT is primarily used with HTTP proxies to establish a TLS session with an origin
-          server for the purposes of interacting with <spanx style="verb">https</spanx> resources.
-        </t>
-        <t>
-          In HTTP/2, the CONNECT method is used to establish a tunnel over a single HTTP/2 stream to
-          a remote host, for similar purposes. The HTTP header field mapping works as defined in
-          <xref target="HttpRequest">Request Header Fields</xref>, with a few
-          differences. Specifically:
-          <list style="symbols">
-            <t>
-              The <spanx style="verb">:method</spanx> header field is set to <spanx
-              style="verb">CONNECT</spanx>.
-            </t>
-            <t>
-              The <spanx style="verb">:scheme</spanx> and <spanx style="verb">:path</spanx> header
-              fields MUST be omitted.
-            </t>
-            <t>
-              The <spanx style="verb">:authority</spanx> header field contains the host and port to
-              connect to (equivalent to the authority-form of the request-target of CONNECT
-              requests, see <xref target="RFC7230" x:fmt="," x:rel="#request-target"/>).
-            </t>
-          </list>
-        </t>
-        <t>
-          A proxy that supports CONNECT establishes a <xref target="TCP">TCP connection</xref> to
-          the server identified in the <spanx style="verb">:authority</spanx> header field. Once
-          this connection is successfully established, the proxy sends a <x:ref>HEADERS</x:ref>
-          frame containing a 2xx series status code to the client, as defined in <xref
-          target="RFC7231" x:fmt="," x:rel="#CONNECT"/>.
-        </t>
-        <t>
-          After the initial <x:ref>HEADERS</x:ref> frame sent by each peer, all subsequent
-          <x:ref>DATA</x:ref> frames correspond to data sent on the TCP connection.  The payload of
-          any <x:ref>DATA</x:ref> frames sent by the client is transmitted by the proxy to the TCP
-          server; data received from the TCP server is assembled into <x:ref>DATA</x:ref> frames by
-          the proxy.  Frame types other than <x:ref>DATA</x:ref> or stream management frames
-          (<x:ref>RST_STREAM</x:ref>, <x:ref>WINDOW_UPDATE</x:ref>, and <x:ref>PRIORITY</x:ref>)
-          MUST NOT be sent on a connected stream, and MUST be treated as a <xref
-          target="StreamErrorHandler">stream error</xref> if received.
-        </t>
-        <t>
-          The TCP connection can be closed by either peer.  The END_STREAM flag on a
-          <x:ref>DATA</x:ref> frame is treated as being equivalent to the TCP FIN bit.  A client is
-          expected to send a <x:ref>DATA</x:ref> frame with the END_STREAM flag set after receiving
-          a frame bearing the END_STREAM flag.  A proxy that receives a <x:ref>DATA</x:ref> frame
-          with the END_STREAM flag set sends the attached data with the FIN bit set on the last TCP
-          segment.  A proxy that receives a TCP segment with the FIN bit set sends a
-          <x:ref>DATA</x:ref> frame with the END_STREAM flag set.  Note that the final TCP segment
-          or <x:ref>DATA</x:ref> frame could be empty.
-        </t>
-        <t>
-          A TCP connection error is signaled with <x:ref>RST_STREAM</x:ref>.  A proxy treats any
-          error in the TCP connection, which includes receiving a TCP segment with the RST bit set,
-          as a <xref target="StreamErrorHandler">stream error</xref> of type
-          <x:ref>CONNECT_ERROR</x:ref>.  Correspondingly, a proxy MUST send a TCP segment with the
-          RST bit set if it detects an error with the stream or the HTTP/2 connection.
-        </t>
-      </section>
-    </section>
-
-    <section anchor="HttpExtra" title="Additional HTTP Requirements/Considerations">
-      <t>
-        This section outlines attributes of the HTTP protocol that improve interoperability, reduce
-        exposure to known security vulnerabilities, or reduce the potential for implementation
-        variation.
-      </t>
-
-      <section title="Connection Management">
-        <t>
-          HTTP/2 connections are persistent.  For best performance, it is expected clients will not
-          close connections until it is determined that no further communication with a server is
-          necessary (for example, when a user navigates away from a particular web page), or until
-          the server closes the connection.
-        </t>
-        <t>
-          Clients SHOULD NOT open more than one HTTP/2 connection to a given host and port pair,
-          where host is derived from a URI, a selected <xref target="ALT-SVC">alternative
-          service</xref>, or a configured proxy.
-        </t>
-        <t>
-          A client can create additional connections as replacements, either to replace connections
-          that are near to exhausting the available <xref target="StreamIdentifiers">stream
-          identifier space</xref>, to refresh the keying material for a TLS connection, or to
-          replace connections that have encountered <xref
-          target="ConnectionErrorHandler">errors</xref>.
-        </t>
-        <t>
-          A client MAY open multiple connections to the same IP address and TCP port using different
-          <xref target="TLS-EXT">Server Name Indication</xref> values or to provide different TLS
-          client certificates, but SHOULD avoid creating multiple connections with the same
-          configuration.
-        </t>
-        <t>
-          Servers are encouraged to maintain open connections for as long as possible, but are
-          permitted to terminate idle connections if necessary.  When either endpoint chooses to
-          close the transport-layer TCP connection, the terminating endpoint SHOULD first send a
-          <x:ref>GOAWAY</x:ref> (<xref target="GOAWAY"/>) frame so that both endpoints can reliably
-          determine whether previously sent frames have been processed and gracefully complete or
-          terminate any necessary remaining tasks.
-        </t>
-
-        <section anchor="reuse" title="Connection Reuse">
-          <t>
-            Connections that are made to an origin servers, either directly or through a tunnel
-            created using the <xref target="CONNECT">CONNECT method</xref> MAY be reused for
-            requests with multiple different URI authority components.  A connection can be reused
-            as long as the origin server is <xref target="authority">authoritative</xref>.  For
-            <spanx style="verb">http</spanx> resources, this depends on the host having resolved to
-            the same IP address.
-          </t>
-          <t>
-            For <spanx style="verb">https</spanx> resources, connection reuse additionally depends
-            on having a certificate that is valid for the host in the URI.  An origin server might
-            offer a certificate with multiple <spanx style="verb">subjectAltName</spanx> attributes,
-            or names with wildcards, one of which is valid for the authority in the URI.  For
-            example, a certificate with a <spanx style="verb">subjectAltName</spanx> of <spanx
-            style="verb">*.example.com</spanx> might permit the use of the same connection for
-            requests to URIs starting with <spanx style="verb">https://a.example.com/</spanx> and
-            <spanx style="verb">https://b.example.com/</spanx>.
-          </t>
-          <t>
-            In some deployments, reusing a connection for multiple origins can result in requests
-            being directed to the wrong origin server.  For example, TLS termination might be
-            performed by a middlebox that uses the TLS <xref target="TLS-EXT">Server Name Indication
-            (SNI)</xref> extension to select an origin server.  This means that it is possible
-            for clients to send confidential information to servers that might not be the intended
-            target for the request, even though the server is otherwise authoritative.
-          </t>
-          <t>
-            A server that does not wish clients to reuse connections can indicate that it is not
-            authoritative for a request by sending a 421 (Misdirected Request) status code in response
-            to the request (see <xref target="MisdirectedRequest"/>).
-          </t>
-          <t>
-            A client that is configured to use a proxy over HTTP/2 directs requests to that proxy
-            through a single connection.  That is, all requests sent via a proxy reuse the
-            connection to the proxy.
-          </t>
-        </section>
-
-        <section anchor="MisdirectedRequest" title="The 421 (Misdirected Request) Status Code">
-          <t>
-            The 421 (Misdirected Request) status code indicates that the request was directed at a
-            server that is not able to produce a response.  This can be sent by a server that is not
-            configured to produce responses for the combination of scheme and authority that are
-            included in the request URI.
-          </t>
-          <t>
-            Clients receiving a 421 (Misdirected Request) response from a server MAY retry the
-            request - whether the request method is idempotent or not - over a different connection.
-            This is possible if a connection is reused (<xref target="reuse"/>) or if an alternative
-            service is selected (<xref target="ALT-SVC"/>).
-          </t>
-          <t>
-            This status code MUST NOT be generated by proxies.
-          </t>
-          <t>
-            A 421 response is cacheable by default; i.e., unless otherwise indicated by the method
-            definition or explicit cache controls (see <xref target="RFC7234"
-            x:rel="#heuristic.freshness" x:fmt="of"/>).
-          </t>
-        </section>
-      </section>
-
-      <section title="Use of TLS Features" anchor="TLSUsage">
-        <t>
-          Implementations of HTTP/2 MUST support <xref target="TLS12">TLS 1.2</xref> for HTTP/2 over
-          TLS.  The general TLS usage guidance in <xref target="TLSBCP"/> SHOULD be followed, with
-          some additional restrictions that are specific to HTTP/2.
-        </t>
-
-        <t>
-          An implementation of HTTP/2 over TLS MUST use TLS 1.2 or higher with the restrictions on
-          feature set and cipher suite described in this section.  Due to implementation
-          limitations, it might not be possible to fail TLS negotiation.  An endpoint MUST
-          immediately terminate an HTTP/2 connection that does not meet these minimum requirements
-          with a <xref target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>INADEQUATE_SECURITY</x:ref>.
-        </t>
-
-        <section anchor="TLSFeatures" title="TLS Features">
-          <t>
-            The TLS implementation MUST support the <xref target="TLS-EXT">Server Name Indication
-            (SNI)</xref> extension to TLS. HTTP/2 clients MUST indicate the target domain name when
-            negotiating TLS.
-          </t>
-          <t>
-            The TLS implementation MUST disable compression.  TLS compression can lead to the
-            exposure of information that would not otherwise be revealed <xref target="RFC3749"/>.
-            Generic compression is unnecessary since HTTP/2 provides compression features that are
-            more aware of context and therefore likely to be more appropriate for use for
-            performance, security or other reasons.
-          </t>
-          <t>
-            The TLS implementation MUST disable renegotiation.  An endpoint MUST treat a TLS
-            renegotiation as a <xref target="ConnectionErrorHandler">connection error</xref> of type
-            <x:ref>PROTOCOL_ERROR</x:ref>.  Note that disabling renegotiation can result in
-            long-lived connections becoming unusable due to limits on the number of messages the
-            underlying cipher suite can encipher.
-          </t>
-          <t>
-            A client MAY use renegotiation to provide confidentiality protection for client
-            credentials offered in the handshake, but any renegotiation MUST occur prior to sending
-            the connection preface.  A server SHOULD request a client certificate if it sees a
-            renegotiation request immediately after establishing a connection.
-          </t>
-          <t>
-            This effectively prevents the use of renegotiation in response to a request for a
-            specific protected resource.  A future specification might provide a way to support this
-            use case. <!-- <cref> We are tracking this in a non-blocking fashion in issue #496 and
-            with a new draft. -->
-          </t>
-        </section>
-
-        <section title="TLS Cipher Suites">
-          <t>
-            The set of TLS cipher suites that are permitted in HTTP/2 is restricted.  HTTP/2 MUST
-            only be used with cipher suites that have ephemeral key exchange, such as the <xref
-            target="TLS12">ephemeral Diffie-Hellman (DHE)</xref> or the <xref
-            target="RFC4492">elliptic curve variant (ECDHE)</xref>.  Ephemeral key exchange MUST
-            have a minimum size of 2048 bits for DHE or security level of 128 bits for ECDHE.
-            Clients MUST accept DHE sizes of up to 4096 bits.  HTTP MUST NOT be used with cipher
-            suites that use stream or block ciphers.  Authenticated Encryption with Additional Data
-            (AEAD) modes, such as the <xref target="RFC5288">Galois Counter Model (GCM) mode for
-            AES</xref> are acceptable.
-          </t>
-          <t>
-            The effect of these restrictions is that TLS 1.2 implementations could have
-            non-intersecting sets of available cipher suites, since these prevent the use of the
-            cipher suite that TLS 1.2 makes mandatory.  To avoid this problem, implementations of
-            HTTP/2 that use TLS 1.2 MUST support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 <xref
-            target="TLS-ECDHE"/> with P256 <xref target="FIPS186"/>.
-          </t>
-          <t>
-            Clients MAY advertise support of cipher suites that are prohibited by the above
-            restrictions in order to allow for connection to servers that do not support HTTP/2.
-            This enables a fallback to protocols without these constraints without the additional
-            latency imposed by using a separate connection for fallback.
-          </t>
-        </section>
-      </section>
-    </section>
-
-    <section anchor="security" title="Security Considerations">
-      <section title="Server Authority" anchor="authority">
-        <t>
-          HTTP/2 relies on the HTTP/1.1 definition of authority for determining whether a server is
-          authoritative in providing a given response, see <xref target="RFC7230" x:fmt=","
-          x:rel="#establishing.authority"/>.  This relies on local name resolution for the "http"
-          URI scheme, and the authenticated server identity for the "https" scheme (see <xref
-          target="RFC2818" x:fmt="," x:sec="3"/>).
-        </t>
-      </section>
-
-      <section title="Cross-Protocol Attacks">
-        <t>
-          In a cross-protocol attack, an attacker causes a client to initiate a transaction in one
-          protocol toward a server that understands a different protocol.  An attacker might be able
-          to cause the transaction to appear as valid transaction in the second protocol.  In
-          combination with the capabilities of the web context, this can be used to interact with
-          poorly protected servers in private networks.
-        </t>
-        <t>
-          Completing a TLS handshake with an ALPN identifier for HTTP/2 can be considered sufficient
-          protection against cross protocol attacks.  ALPN provides a positive indication that a
-          server is willing to proceed with HTTP/2, which prevents attacks on other TLS-based
-          protocols.
-        </t>
-        <t>
-          The encryption in TLS makes it difficult for attackers to control the data which could be
-          used in a cross-protocol attack on a cleartext protocol.
-        </t>
-        <t>
-          The cleartext version of HTTP/2 has minimal protection against cross-protocol attacks.
-          The <xref target="ConnectionHeader">connection preface</xref> contains a string that is
-          designed to confuse HTTP/1.1 servers, but no special protection is offered for other
-          protocols.  A server that is willing to ignore parts of an HTTP/1.1 request containing an
-          Upgrade header field in addition to the client connection preface could be exposed to a
-          cross-protocol attack.
-        </t>
-      </section>
-
-      <section title="Intermediary Encapsulation Attacks">
-        <t>
-          HTTP/2 header field names and values are encoded as sequences of octets with a length
-          prefix.  This enables HTTP/2 to carry any string of octets as the name or value of a
-          header field.  An intermediary that translates HTTP/2 requests or responses into HTTP/1.1
-          directly could permit the creation of corrupted HTTP/1.1 messages.  An attacker might
-          exploit this behavior to cause the intermediary to create HTTP/1.1 messages with illegal
-          header fields, extra header fields, or even new messages that are entirely falsified.
-        </t>
-        <t>
-          Header field names or values that contain characters not permitted by HTTP/1.1, including
-          carriage return (ASCII 0xd) or line feed (ASCII 0xa) MUST NOT be translated verbatim by an
-          intermediary, as stipulated in <xref target="RFC7230" x:rel="#field.parsing" x:fmt=","/>.
-        </t>
-        <t>
-          Translation from HTTP/1.x to HTTP/2 does not produce the same opportunity to an attacker.
-          Intermediaries that perform translation to HTTP/2 MUST remove any instances of the <spanx
-          style="verb">obs-fold</spanx> production from header field values.
-        </t>
-      </section>
-
-      <section title="Cacheability of Pushed Responses">
-        <t>
-          Pushed responses do not have an explicit request from the client; the request
-          is provided by the server in the <x:ref>PUSH_PROMISE</x:ref> frame.
-        </t>
-        <t>
-          Caching responses that are pushed is possible based on the guidance provided by the origin
-          server in the Cache-Control header field.  However, this can cause issues if a single
-          server hosts more than one tenant.  For example, a server might offer multiple users each
-          a small portion of its URI space.
-        </t>
-        <t>
-          Where multiple tenants share space on the same server, that server MUST ensure that
-          tenants are not able to push representations of resources that they do not have authority
-          over.  Failure to enforce this would allow a tenant to provide a representation that would
-          be served out of cache, overriding the actual representation that the authoritative tenant
-          provides.
-        </t>
-        <t>
-          Pushed responses for which an origin server is not authoritative (see
-          <xref target="authority"/>) are never cached or used.
-        </t>
-      </section>
-
-      <section anchor="dos" title="Denial of Service Considerations">
-        <t>
-          An HTTP/2 connection can demand a greater commitment of resources to operate than a
-          HTTP/1.1 connection.  The use of header compression and flow control depend on a
-          commitment of resources for storing a greater amount of state.  Settings for these
-          features ensure that memory commitments for these features are strictly bounded.
-        </t>
-        <t>
-          The number of <x:ref>PUSH_PROMISE</x:ref> frames is not constrained in the same fashion.
-          A client that accepts server push SHOULD limit the number of streams it allows to be in
-          the "reserved (remote)" state.  Excessive number of server push streams can be treated as
-          a <xref target="StreamErrorHandler">stream error</xref> of type
-          <x:ref>ENHANCE_YOUR_CALM</x:ref>.
-        </t>
-        <t>
-          Processing capacity cannot be guarded as effectively as state capacity.
-        </t>
-        <t>
-          The <x:ref>SETTINGS</x:ref> frame can be abused to cause a peer to expend additional
-          processing time. This might be done by pointlessly changing SETTINGS parameters, setting
-          multiple undefined parameters, or changing the same setting multiple times in the same
-          frame.  <x:ref>WINDOW_UPDATE</x:ref> or <x:ref>PRIORITY</x:ref> frames can be abused to
-          cause an unnecessary waste of resources.
-        </t>
-        <t>
-          Large numbers of small or empty frames can be abused to cause a peer to expend time
-          processing frame headers.  Note however that some uses are entirely legitimate, such as
-          the sending of an empty <x:ref>DATA</x:ref> frame to end a stream.
-        </t>
-        <t>
-          Header compression also offers some opportunities to waste processing resources; see <xref
-          target="COMPRESSION" x:fmt="of" x:rel="#Security"/> for more details on potential abuses.
-        </t>
-        <t>
-          Limits in <x:ref>SETTINGS</x:ref> parameters cannot be reduced instantaneously, which
-          leaves an endpoint exposed to behavior from a peer that could exceed the new limits. In
-          particular, immediately after establishing a connection, limits set by a server are not
-          known to clients and could be exceeded without being an obvious protocol violation.
-        </t>
-        <t>
-          All these features - i.e., <x:ref>SETTINGS</x:ref> changes, small frames, header
-          compression - have legitimate uses.  These features become a burden only when they are
-          used unnecessarily or to excess.
-        </t>
-        <t>
-          An endpoint that doesn't monitor this behavior exposes itself to a risk of denial of
-          service attack.  Implementations SHOULD track the use of these features and set limits on
-          their use.  An endpoint MAY treat activity that is suspicious as a <xref
-          target="ConnectionErrorHandler">connection error</xref> of type
-          <x:ref>ENHANCE_YOUR_CALM</x:ref>.
-        </t>
-
-        <section anchor="MaxHeaderBlock" title="Limits on Header Block Size">
-          <t>
-            A large <xref target="HeaderBlock">header block</xref> can cause an implementation to
-            commit a large amount of state.  Header fields that are critical for routing can appear
-            toward the end of a header block, which prevents streaming of header fields to their
-            ultimate destination. For this an other reasons, such as ensuring cache correctness,
-            means that an endpoint might need to buffer the entire header block.  Since there is no
-            hard limit to the size of a header block, some endpoints could be forced commit a large
-            amount of available memory for header fields.
-          </t>
-          <t>
-            An endpoint can use the <x:ref>SETTINGS_MAX_HEADER_LIST_SIZE</x:ref> to advise peers of
-            limits that might apply on the size of header blocks.  This setting is only advisory, so
-            endpoints MAY choose to send header blocks that exceed this limit and risk having the
-            request or response being treated as malformed.  This setting specific to a connection,
-            so any request or response could encounter a hop with a lower, unknown limit.  An
-            intermediary can attempt to avoid this problem by passing on values presented by
-            different peers, but they are not obligated to do so.
-          </t>
-          <t>
-            A server that receives a larger header block than it is willing to handle can send an
-            HTTP 431 (Request Header Fields Too Large) status code <xref target="RFC6585"/>.  A
-            client can discard responses that it cannot process.  The header block MUST be processed
-            to ensure a consistent connection state, unless the connection is closed.
-          </t>
-        </section>
-      </section>
-
-      <section title="Use of Compression">
-        <t>
-          HTTP/2 enables greater use of compression for both header fields (<xref
-          target="HeaderBlock"/>) and entity bodies.  Compression can allow an attacker to recover
-          secret data when it is compressed in the same context as data under attacker control.
-        </t>
-        <t>
-          There are demonstrable attacks on compression that exploit the characteristics of the web
-          (e.g., <xref target="BREACH"/>).  The attacker induces multiple requests containing
-          varying plaintext, observing the length of the resulting ciphertext in each, which
-          reveals a shorter length when a guess about the secret is correct.
-        </t>
-        <t>
-          Implementations communicating on a secure channel MUST NOT compress content that includes
-          both confidential and attacker-controlled data unless separate compression dictionaries
-          are used for each source of data.  Compression MUST NOT be used if the source of data
-          cannot be reliably determined.  Generic stream compression, such as that provided by TLS
-          MUST NOT be used with HTTP/2 (<xref target="TLSFeatures"/>).
-        </t>
-        <t>
-          Further considerations regarding the compression of header fields are described in <xref
-          target="COMPRESSION"/>.
-        </t>
-      </section>
-
-      <section title="Use of Padding" anchor="padding">
-        <t>
-          Padding within HTTP/2 is not intended as a replacement for general purpose padding, such
-          as might be provided by <xref target="TLS12">TLS</xref>.  Redundant padding could even be
-          counterproductive.  Correct application can depend on having specific knowledge of the
-          data that is being padded.
-        </t>
-        <t>
-          To mitigate attacks that rely on compression, disabling or limiting compression might be
-          preferable to padding as a countermeasure.
-        </t>
-        <t>
-          Padding can be used to obscure the exact size of frame content, and is provided to
-          mitigate specific attacks within HTTP.  For example, attacks where compressed content
-          includes both attacker-controlled plaintext and secret data (see for example, <xref
-          target="BREACH"/>).
-        </t>
-        <t>
-          Use of padding can result in less protection than might seem immediately obvious.  At
-          best, padding only makes it more difficult for an attacker to infer length information by
-          increasing the number of frames an attacker has to observe.  Incorrectly implemented
-          padding schemes can be easily defeated.  In particular, randomized padding with a
-          predictable distribution provides very little protection; similarly, padding payloads to a
-          fixed size exposes information as payload sizes cross the fixed size boundary, which could
-          be possible if an attacker can control plaintext.
-        </t>
-        <t>
-          Intermediaries SHOULD retain padding for <x:ref>DATA</x:ref> frames, but MAY drop padding
-          for <x:ref>HEADERS</x:ref> and <x:ref>PUSH_PROMISE</x:ref> frames.  A valid reason for an
-          intermediary to change the amount of padding of frames is to improve the protections that
-          padding provides.
-        </t>
-      </section>
-
-      <section title="Privacy Considerations">
-        <t>
-          Several characteristics of HTTP/2 provide an observer an opportunity to correlate actions
-          of a single client or server over time.  This includes the value of settings, the manner
-          in which flow control windows are managed, the way priorities are allocated to streams,
-          timing of reactions to stimulus, and handling of any optional features.
-        </t>
-        <t>
-          As far as this creates observable differences in behavior, they could be used as a basis
-          for fingerprinting a specific client, as defined in <xref target="HTML5" x:fmt="of"
-          x:sec="1.8" x:rel="introduction.html#fingerprint"/>.
-        </t>
-      </section>
-    </section>
-
-    <section anchor="iana" title="IANA Considerations">
-      <t>
-        A string for identifying HTTP/2 is entered into the "Application Layer Protocol Negotiation
-        (ALPN) Protocol IDs" registry established in <xref target="TLS-ALPN"/>.
-      </t>
-      <t>
-        This document establishes a registry for frame types, settings, and error codes.  These new
-        registries are entered into a new "Hypertext Transfer Protocol (HTTP) 2 Parameters" section.
-      </t>
-      <t>
-        This document registers the <spanx style="verb">HTTP2-Settings</spanx> header field for
-        use in HTTP; and the 421 (Misdirected Request) status code.
-      </t>
-      <t>
-        This document registers the <spanx style="verb">PRI</spanx> method for use in HTTP, to avoid
-        collisions with the <xref target="ConnectionHeader">connection preface</xref>.
-      </t>
-
-      <section anchor="iana-alpn" title="Registration of HTTP/2 Identification Strings">
-        <t>
-          This document creates two registrations for the identification of HTTP/2 in the
-          "Application Layer Protocol Negotiation (ALPN) Protocol IDs" registry established in <xref
-          target="TLS-ALPN"/>.
-        </t>
-        <t>
-          The "h2" string identifies HTTP/2 when used over TLS:
-          <list style="hanging">
-            <t hangText="Protocol:">HTTP/2 over TLS</t>
-            <t hangText="Identification Sequence:">0x68 0x32 ("h2")</t>
-            <t hangText="Specification:">This document</t>
-          </list>
-        </t>
-        <t>
-          The "h2c" string identifies HTTP/2 when used over cleartext TCP:
-          <list style="hanging">
-            <t hangText="Protocol:">HTTP/2 over TCP</t>
-            <t hangText="Identification Sequence:">0x68 0x32 0x63 ("h2c")</t>
-            <t hangText="Specification:">This document</t>
-          </list>
-        </t>
-      </section>
-
-      <section anchor="iana-frames" title="Frame Type Registry">
-        <t>
-          This document establishes a registry for HTTP/2 frame type codes.  The "HTTP/2 Frame
-          Type" registry manages an 8-bit space.  The "HTTP/2 Frame Type" registry operates under
-          either of the <xref target="RFC5226">"IETF Review" or "IESG Approval" policies</xref> for
-          values between 0x00 and 0xef, with values between 0xf0 and 0xff being reserved for
-          experimental use.
-        </t>
-        <t>
-          New entries in this registry require the following information:
-          <list style="hanging">
-            <t hangText="Frame Type:">
-              A name or label for the frame type.
-            </t>
-            <t hangText="Code:">
-              The 8-bit code assigned to the frame type.
-            </t>
-            <t hangText="Specification:">
-              A reference to a specification that includes a description of the frame layout,
-              it's semantics and flags that the frame type uses, including any parts of the frame
-              that are conditionally present based on the value of flags.
-            </t>
-          </list>
-        </t>
-        <t>
-          The entries in the following table are registered by this document.
-        </t>
-        <texttable align="left" suppress-title="true">
-          <ttcol>Frame Type</ttcol>
-          <ttcol>Code</ttcol>
-          <ttcol>Section</ttcol>
-          <c>DATA</c><c>0x0</c><c><xref target="DATA"/></c>
-          <c>HEADERS</c><c>0x1</c><c><xref target="HEADERS"/></c>
-          <c>PRIORITY</c><c>0x2</c><c><xref target="PRIORITY"/></c>
-          <c>RST_STREAM</c><c>0x3</c><c><xref target="RST_STREAM"/></c>
-          <c>SETTINGS</c><c>0x4</c><c><xref target="SETTINGS"/></c>
-          <c>PUSH_PROMISE</c><c>0x5</c><c><xref target="PUSH_PROMISE"/></c>
-          <c>PING</c><c>0x6</c><c><xref target="PING"/></c>
-          <c>GOAWAY</c><c>0x7</c><c><xref target="GOAWAY"/></c>
-          <c>WINDOW_UPDATE</c><c>0x8</c><c><xref target="WINDOW_UPDATE"/></c>
-          <c>CONTINUATION</c><c>0x9</c><c><xref target="CONTINUATION"/></c>
-        </texttable>
-      </section>
-
-      <section anchor="iana-settings" title="Settings Registry">
-        <t>
-          This document establishes a registry for HTTP/2 settings.  The "HTTP/2 Settings" registry
-          manages a 16-bit space.  The "HTTP/2 Settings" registry operates under the <xref
-          target="RFC5226">"Expert Review" policy</xref> for values in the range from 0x0000 to
-          0xefff, with values between and 0xf000 and 0xffff being reserved for experimental use.
-        </t>
-        <t>
-          New registrations are advised to provide the following information:
-          <list style="hanging">
-            <t hangText="Name:">
-              A symbolic name for the setting.  Specifying a setting name is optional.
-            </t>
-            <t hangText="Code:">
-              The 16-bit code assigned to the setting.
-            </t>
-            <t hangText="Initial Value:">
-              An initial value for the setting.
-            </t>
-            <t hangText="Specification:">
-              An optional reference to a specification that describes the use of the setting.
-            </t>
-          </list>
-        </t>
-        <t>
-          An initial set of setting registrations can be found in <xref target="SettingValues"/>.
-        </t>
-        <texttable align="left" suppress-title="true">
-          <ttcol>Name</ttcol>
-          <ttcol>Code</ttcol>
-          <ttcol>Initial Value</ttcol>
-          <ttcol>Specification</ttcol>
-          <c>HEADER_TABLE_SIZE</c>
-          <c>0x1</c><c>4096</c><c><xref target="SettingValues"/></c>
-          <c>ENABLE_PUSH</c>
-          <c>0x2</c><c>1</c><c><xref target="SettingValues"/></c>
-          <c>MAX_CONCURRENT_STREAMS</c>
-          <c>0x3</c><c>(infinite)</c><c><xref target="SettingValues"/></c>
-          <c>INITIAL_WINDOW_SIZE</c>
-          <c>0x4</c><c>65535</c><c><xref target="SettingValues"/></c>
-          <c>MAX_FRAME_SIZE</c>
-          <c>0x5</c><c>16384</c><c><xref target="SettingValues"/></c>
-          <c>MAX_HEADER_LIST_SIZE</c>
-          <c>0x6</c><c>(infinite)</c><c><xref target="SettingValues"/></c>
-        </texttable>
-
-      </section>
-
-      <section anchor="iana-errors" title="Error Code Registry">
-        <t>
-          This document establishes a registry for HTTP/2 error codes.  The "HTTP/2 Error Code"
-          registry manages a 32-bit space.  The "HTTP/2 Error Code" registry operates under the
-          <xref target="RFC5226">"Expert Review" policy</xref>.
-        </t>
-        <t>
-          Registrations for error codes are required to include a description of the error code.  An
-          expert reviewer is advised to examine new registrations for possible duplication with
-          existing error codes.  Use of existing registrations is to be encouraged, but not
-          mandated.
-        </t>
-        <t>
-          New registrations are advised to provide the following information:
-          <list style="hanging">
-            <t hangText="Name:">
-              A name for the error code.  Specifying an error code name is optional.
-            </t>
-            <t hangText="Code:">
-              The 32-bit error code value.
-            </t>
-            <t hangText="Description:">
-              A brief description of the error code semantics, longer if no detailed specification
-              is provided.
-            </t>
-            <t hangText="Specification:">
-              An optional reference for a specification that defines the error code.
-            </t>
-          </list>
-        </t>
-        <t>
-          The entries in the following table are registered by this document.
-        </t>
-        <texttable align="left" suppress-title="true">
-          <ttcol>Name</ttcol>
-          <ttcol>Code</ttcol>
-          <ttcol>Description</ttcol>
-          <ttcol>Specification</ttcol>
-          <c>NO_ERROR</c><c>0x0</c>
-          <c>Graceful shutdown</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>PROTOCOL_ERROR</c><c>0x1</c>
-          <c>Protocol error detected</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>INTERNAL_ERROR</c><c>0x2</c>
-          <c>Implementation fault</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>FLOW_CONTROL_ERROR</c><c>0x3</c>
-          <c>Flow control limits exceeded</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>SETTINGS_TIMEOUT</c><c>0x4</c>
-          <c>Settings not acknowledged</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>STREAM_CLOSED</c><c>0x5</c>
-          <c>Frame received for closed stream</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>FRAME_SIZE_ERROR</c><c>0x6</c>
-          <c>Frame size incorrect</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>REFUSED_STREAM</c><c>0x7</c>
-          <c>Stream not processed</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>CANCEL</c><c>0x8</c>
-          <c>Stream cancelled</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>COMPRESSION_ERROR</c><c>0x9</c>
-          <c>Compression state not updated</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>CONNECT_ERROR</c><c>0xa</c>
-          <c>TCP connection error for CONNECT method</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>ENHANCE_YOUR_CALM</c><c>0xb</c>
-          <c>Processing capacity exceeded</c>
-          <c><xref target="ErrorCodes"/></c>
-          <c>INADEQUATE_SECURITY</c><c>0xc</c>
-          <c>Negotiated TLS parameters not acceptable</c>
-          <c><xref target="ErrorCodes"/></c>
-        </texttable>
-
-      </section>
-
-      <section title="HTTP2-Settings Header Field Registration">
-        <t>
-          This section registers the <spanx style="verb">HTTP2-Settings</spanx> header field in the
-          <xref target="BCP90">Permanent Message Header Field Registry</xref>.
-          <list style="hanging">
-            <t hangText="Header field name:">
-              HTTP2-Settings
-            </t>
-            <t hangText="Applicable protocol:">
-              http
-            </t>
-            <t hangText="Status:">
-              standard
-            </t>
-            <t hangText="Author/Change controller:">
-              IETF
-            </t>
-            <t hangText="Specification document(s):">
-              <xref target="Http2SettingsHeader"/> of this document
-            </t>
-            <t hangText="Related information:">
-              This header field is only used by an HTTP/2 client for Upgrade-based negotiation.
-            </t>
-          </list>
-        </t>
-      </section>
-
-      <section title="PRI Method Registration">
-        <t>
-          This section registers the <spanx style="verb">PRI</spanx> method in the HTTP Method
-          Registry (<xref target="RFC7231" x:fmt="," x:rel="#method.registry"/>).
-          <list style="hanging">
-            <t hangText="Method Name:">
-              PRI
-            </t>
-            <t hangText="Safe">
-              No
-            </t>
-            <t hangText="Idempotent">
-              No
-            </t>
-            <t hangText="Specification document(s)">
-              <xref target="ConnectionHeader"/> of this document
-            </t>
-            <t hangText="Related information:">
-              This method is never used by an actual client. This method will appear to be used
-              when an HTTP/1.1 server or intermediary attempts to parse an HTTP/2 connection
-              preface.
-            </t>
-          </list>
-        </t>
-      </section>
-
-      <section title="The 421 (Misdirected Request) HTTP Status Code"
-               anchor="iana-MisdirectedRequest">
-        <t>
-          This document registers the 421 (Misdirected Request) HTTP Status code in the Hypertext
-          Transfer Protocol (HTTP) Status Code Registry (<xref target="RFC7231" x:fmt=","
-          x:rel="#status.code.registry"/>).
-        </t>
-        <t>
-          <list style="hanging">
-            <t hangText="Status Code:">
-              421
-            </t>
-            <t hangText="Short Description:">
-              Misdirected Request
-            </t>
-            <t hangText="Specification:">
-              <xref target="MisdirectedRequest"/> of this document
-            </t>
-          </list>
-        </t>
-      </section>
-
-    </section>
-
-    <section title="Acknowledgements">
-      <t>
-        This document includes substantial input from the following individuals:
-        <list style="symbols">
-          <t>
-            Adam Langley, Wan-Teh Chang, Jim Morrison, Mark Nottingham, Alyssa Wilk, Costin
-            Manolache, William Chan, Vitaliy Lvin, Joe Chan, Adam Barth, Ryan Hamilton, Gavin
-            Peters, Kent Alstad, Kevin Lindsay, Paul Amer, Fan Yang, Jonathan Leighton (SPDY
-            contributors).
-          </t>
-          <t>
-            Gabriel Montenegro and Willy Tarreau (Upgrade mechanism).
-          </t>
-          <t>
-            William Chan, Salvatore Loreto, Osama Mazahir, Gabriel Montenegro, Jitu Padhye, Roberto
-            Peon, Rob Trace (Flow control).
-          </t>
-          <t>
-            Mike Bishop (Extensibility).
-          </t>
-          <t>
-            Mark Nottingham, Julian Reschke, James Snell, Jeff Pinner, Mike Bishop, Herve Ruellan
-            (Substantial editorial contributions).
-          </t>
-          <t>
-            Kari Hurtta, Tatsuhiro Tsujikawa, Greg Wilkins, Poul-Henning Kamp.
-          </t>
-          <t>
-            Alexey Melnikov was an editor of this document during 2013.
-          </t>
-          <t>
-            A substantial proportion of Martin's contribution was supported by Microsoft during his
-            employment there.
-          </t>
-        </list>
-      </t>
-    </section>
-  </middle>
-
-  <back>
-    <references title="Normative References">
-      <reference anchor="COMPRESSION">
-        <front>
-          <title>HPACK - Header Compression for HTTP/2</title>
-          <author initials="H." surname="Ruellan" fullname="Herve Ruellan"/>
-          <author initials="R." surname="Peon" fullname="Roberto Peon"/>
-          <date month="July" year="2014" />
-        </front>
-        <seriesInfo name="Internet-Draft" value="draft-ietf-httpbis-header-compression-09" />
-        <x:source href="refs/draft-ietf-httpbis-header-compression-09.xml"/>
-      </reference>
-
-      <reference anchor="TCP">
-        <front>
-          <title abbrev="Transmission Control Protocol">
-            Transmission Control Protocol
-          </title>
-          <author initials="J." surname="Postel" fullname="Jon Postel">
-            <organization>University of Southern California (USC)/Information Sciences
-            Institute</organization>
-          </author>
-          <date year="1981" month="September" />
-        </front>
-        <seriesInfo name="STD" value="7" />
-        <seriesInfo name="RFC" value="793" />
-      </reference>
-
-      <reference anchor="RFC2119">
-        <front>
-          <title>
-            Key words for use in RFCs to Indicate Requirement Levels
-          </title>
-          <author initials="S." surname="Bradner" fullname="Scott Bradner">
-            <organization>Harvard University</organization>
-            <address><email>sob@harvard.edu</email></address>
-          </author>
-          <date month="March" year="1997"/>
-        </front>
-        <seriesInfo name="BCP" value="14"/>
-        <seriesInfo name="RFC" value="2119"/>
-      </reference>
-
-     <reference anchor="RFC2818">
-        <front>
-          <title>
-            HTTP Over TLS
-          </title>
-          <author initials="E." surname="Rescorla" fullname="Eric Rescorla"/>
-          <date month="May" year="2000"/>
-        </front>
-        <seriesInfo name="RFC" value="2818"/>
-      </reference>
-
-      <reference anchor="RFC3986">
-        <front>
-          <title abbrev="URI Generic Syntax">Uniform Resource Identifier (URI): Generic
-          Syntax</title>
-          <author initials="T." surname="Berners-Lee" fullname="Tim Berners-Lee"></author>
-          <author initials="R." surname="Fielding" fullname="Roy T. Fielding"></author>
-          <author initials="L." surname="Masinter" fullname="Larry Masinter"></author>
-          <date year="2005" month="January" />
-        </front>
-        <seriesInfo name="STD" value="66" />
-        <seriesInfo name="RFC" value="3986" />
-      </reference>
-
-      <reference anchor="RFC4648">
-        <front>
-          <title>The Base16, Base32, and Base64 Data Encodings</title>
-          <author fullname="S. Josefsson" initials="S." surname="Josefsson"/>
-          <date year="2006" month="October"/>
-        </front>
-        <seriesInfo value="4648" name="RFC"/>
-      </reference>
-
-      <reference anchor="RFC5226">
-        <front>
-          <title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
-          <author initials="T." surname="Narten" fullname="T. Narten"/>
-          <author initials="H." surname="Alvestrand" fullname="H. Alvestrand"/>
-          <date year="2008" month="May" />
-        </front>
-        <seriesInfo name="BCP" value="26" />
-        <seriesInfo name="RFC" value="5226" />
-      </reference>
-
-      <reference anchor="RFC5234">
-        <front>
-          <title>Augmented BNF for Syntax Specifications: ABNF</title>
-          <author initials="D." surname="Crocker" fullname="D. Crocker"/>
-          <author initials="P." surname="Overell" fullname="P. Overell"/>
-          <date year="2008" month="January" />
-        </front>
-        <seriesInfo name="STD" value="68" />
-        <seriesInfo name="RFC" value="5234" />
-      </reference>
-
-      <reference anchor="TLS12">
-        <front>
-          <title>The Transport Layer Security (TLS) Protocol Version 1.2</title>
-          <author initials="T." surname="Dierks" fullname="Tim Dierks"/>
-          <author initials="E." surname="Rescorla" fullname="Eric Rescorla"/>
-          <date year="2008" month="August" />
-        </front>
-        <seriesInfo name="RFC" value="5246" />
-      </reference>
-
-      <reference anchor="TLS-EXT">
-        <front>
-          <title>
-            Transport Layer Security (TLS) Extensions: Extension Definitions
-          </title>
-          <author initials="D." surname="Eastlake" fullname="D. Eastlake"/>
-          <date year="2011" month="January"/>
-        </front>
-        <seriesInfo name="RFC" value="6066"/>
-      </reference>
-
-      <reference anchor="TLS-ALPN">
-        <front>
-          <title>Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension</title>
-          <author initials="S." surname="Friedl" fullname="Stephan Friedl"></author>
-          <author initials="A." surname="Popov" fullname="Andrei Popov"></author>
-          <author initials="A." surname="Langley" fullname="Adam Langley"></author>
-          <author initials="E." surname="Stephan" fullname="Emile Stephan"></author>
-          <date month="July" year="2014" />
-        </front>
-        <seriesInfo name="RFC" value="7301" />
-      </reference>
-
-      <reference anchor="TLS-ECDHE">
-        <front>
-          <title>
-            TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois
-            Counter Mode (GCM)
-          </title>
-          <author initials="E." surname="Rescorla" fullname="E. Rescorla"/>
-          <date year="2008" month="August" />
-        </front>
-        <seriesInfo name="RFC" value="5289" />
-      </reference>
-
-      <reference anchor="FIPS186">
-        <front>
-          <title>
-            Digital Signature Standard (DSS)
-          </title>
-          <author><organization>NIST</organization></author>
-          <date year="2013" month="July" />
-        </front>
-        <seriesInfo name="FIPS" value="PUB 186-4" />
-      </reference>
-
-      <reference anchor="RFC7230">
-        <front>
-          <title>
-          Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing</title>
-          <author fullname="Roy T. Fielding" initials="R." role="editor" surname="Fielding">
-            <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
-            <address><email>fielding@gbiv.com</email></address>
-          </author>
-          <author fullname="Julian F. Reschke" initials="J. F." role="editor" surname="Reschke">
-            <organization abbrev="greenbytes">greenbytes GmbH</organization>
-            <address><email>julian.reschke@greenbytes.de</email></address>
-          </author>
-          <date month="June" year="2014" />
-        </front>
-        <seriesInfo name="RFC" value="7230" />
-        <x:source href="refs/rfc7230.xml"
-                  basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230"/>
-      </reference>
-      <reference anchor="RFC7231">
-        <front>
-          <title>
-          Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content</title>
-          <author fullname="Roy T. Fielding" initials="R." role="editor" surname="Fielding">
-            <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
-            <address><email>fielding@gbiv.com</email></address>
-          </author>
-          <author fullname="Julian F. Reschke" initials="J. F." role="editor" surname="Reschke">
-            <organization abbrev="greenbytes">greenbytes GmbH</organization>
-            <address><email>julian.reschke@greenbytes.de</email></address>
-          </author>
-          <date month="June" year="2014" />
-        </front>
-        <seriesInfo name="RFC" value="7231" />
-        <x:source href="refs/rfc7231.xml"
-                  basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231"/>
-      </reference>
-      <reference anchor="RFC7232">
-        <front>
-          <title>Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests</title>
-          <author fullname="Roy T. Fielding" initials="R." role="editor" surname="Fielding">
-            <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
-            <address><email>fielding@gbiv.com</email></address>
-          </author>
-          <author fullname="Julian F. Reschke" initials="J. F." role="editor" surname="Reschke">
-            <organization abbrev="greenbytes">greenbytes GmbH</organization>
-            <address><email>julian.reschke@greenbytes.de</email></address>
-          </author>
-          <date month="June" year="2014" />
-        </front>
-        <seriesInfo name="RFC" value="7232" />
-      </reference>
-      <reference anchor="RFC7233">
-        <front>
-          <title>Hypertext Transfer Protocol (HTTP/1.1): Range Requests</title>
-          <author initials="R." surname="Fielding" fullname="Roy T. Fielding" role="editor">
-            <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
-            <address><email>fielding@gbiv.com</email></address>
-          </author>
-          <author initials="Y." surname="Lafon" fullname="Yves Lafon" role="editor">
-            <organization abbrev="W3C">World Wide Web Consortium</organization>
-            <address><email>ylafon@w3.org</email></address>
-          </author>
-          <author initials="J. F." surname="Reschke" fullname="Julian F. Reschke" role="editor">
-            <organization abbrev="greenbytes">greenbytes GmbH</organization>
-            <address><email>julian.reschke@greenbytes.de</email></address>
-          </author>
-          <date month="June" year="2014" />
-        </front>
-        <seriesInfo name="RFC" value="7233" />
-      </reference>
-      <reference anchor="RFC7234">
-        <front>
-          <title>Hypertext Transfer Protocol (HTTP/1.1): Caching</title>
-          <author initials="R." surname="Fielding" fullname="Roy T. Fielding" role="editor">
-            <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
-            <address><email>fielding@gbiv.com</email></address>
-          </author>
-          <author fullname="Mark Nottingham" initials="M." role="editor" surname="Nottingham">
-            <organization>Akamai</organization>
-            <address><email>mnot@mnot.net</email></address>
-          </author>
-          <author initials="J. F." surname="Reschke" fullname="Julian F. Reschke" role="editor">
-            <organization abbrev="greenbytes">greenbytes GmbH</organization>
-            <address><email>julian.reschke@greenbytes.de</email></address>
-          </author>
-          <date month="June" year="2014" />
-        </front>
-        <seriesInfo name="RFC" value="7234"/>
-        <x:source href="refs/rfc7234.xml"
-                  basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7234"/>
-      </reference>
-      <reference anchor="RFC7235">
-        <front>
-          <title>Hypertext Transfer Protocol (HTTP/1.1): Authentication</title>
-          <author initials="R." surname="Fielding" fullname="Roy T. Fielding" role="editor">
-            <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
-            <address><email>fielding@gbiv.com</email></address>
-          </author>
-          <author initials="J. F." surname="Reschke" fullname="Julian F. Reschke" role="editor">
-            <organization abbrev="greenbytes">greenbytes GmbH</organization>
-            <address><email>julian.reschke@greenbytes.de</email></address>
-          </author>
-          <date month="June" year="2014" />
-        </front>
-        <seriesInfo name="RFC" value="7235"/>
-        <x:source href="refs/rfc7235.xml"
-                  basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7235"/>
-      </reference>
-
-      <reference anchor="COOKIE">
-        <front>
-          <title>HTTP State Management Mechanism</title>
-          <author initials="A." surname="Barth" fullname="A. Barth"/>
-          <date year="2011" month="April" />
-        </front>
-        <seriesInfo name="RFC" value="6265" />
-      </reference>
-    </references>
-
-    <references title="Informative References">
-      <reference anchor="RFC1323">
-        <front>
-          <title>
-            TCP Extensions for High Performance
-          </title>
-          <author initials="V." surname="Jacobson" fullname="Van Jacobson"></author>
-          <author initials="B." surname="Braden" fullname="Bob Braden"></author>
-          <author initials="D." surname="Borman" fullname="Dave Borman"></author>
-          <date year="1992" month="May" />
-        </front>
-        <seriesInfo name="RFC" value="1323" />
-      </reference>
-
-      <reference anchor="RFC3749">
-        <front>
-          <title>Transport Layer Security Protocol Compression Methods</title>
-          <author initials="S." surname="Hollenbeck" fullname="S. Hollenbeck"/>
-          <date year="2004" month="May" />
-        </front>
-        <seriesInfo name="RFC" value="3749" />
-      </reference>
-
-      <reference anchor="RFC6585">
-        <front>
-          <title>Additional HTTP Status Codes</title>
-          <author initials="M." surname="Nottingham" fullname="Mark Nottingham"/>
-          <author initials="R." surname="Fielding" fullname="Roy Fielding"/>
-          <date year="2012" month="April" />
-        </front>
-        <seriesInfo name="RFC" value="6585" />
-      </reference>
-
-      <reference anchor="RFC4492">
-        <front>
-          <title>
-            Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)
-          </title>
-          <author initials="S." surname="Blake-Wilson" fullname="S. Blake-Wilson"/>
-          <author initials="N." surname="Bolyard" fullname="N. Bolyard"/>
-          <author initials="V." surname="Gupta" fullname="V. Gupta"/>
-          <author initials="C." surname="Hawk" fullname="C. Hawk"/>
-          <author initials="B." surname="Moeller" fullname="B. Moeller"/>
-          <date year="2006" month="May" />
-        </front>
-        <seriesInfo name="RFC" value="4492" />
-      </reference>
-
-      <reference anchor="RFC5288">
-        <front>
-          <title>
-            AES Galois Counter Mode (GCM) Cipher Suites for TLS
-          </title>
-          <author initials="J." surname="Salowey" fullname="J. Salowey"/>
-          <author initials="A." surname="Choudhury" fullname="A. Choudhury"/>
-          <author initials="D." surname="McGrew" fullname="D. McGrew"/>
-          <date year="2008" month="August" />
-        </front>
-        <seriesInfo name="RFC" value="5288" />
-      </reference>
-
-      <reference anchor='HTML5'
-           target='http://www.w3.org/TR/2014/CR-html5-20140731/'>
-        <front>
-          <title>HTML5</title>
-          <author fullname='Robin Berjon' surname='Berjon' initials='R.'/>
-          <author fullname='Steve Faulkner' surname='Faulkner' initials='S.'/>
-          <author fullname='Travis Leithead' surname='Leithead' initials='T.'/>
-          <author fullname='Erika Doyle Navara' surname='Doyle Navara' initials='E.'/>
-          <author fullname='Edward O&apos;Connor' surname='O&apos;Connor' initials='E.'/>
-          <author fullname='Silvia Pfeiffer' surname='Pfeiffer' initials='S.'/>
-          <date year='2014' month='July' day='31'/>
-        </front>
-        <seriesInfo name='W3C Candidate Recommendation' value='CR-html5-20140731'/>
-        <annotation>
-          Latest version available at
-          <eref target='http://www.w3.org/TR/html5/'/>.
-        </annotation>
-      </reference>
-
-      <reference anchor="TALKING" target="http://w2spconf.com/2011/papers/websocket.pdf">
-        <front>
-          <title>
-            Talking to Yourself for Fun and Profit
-          </title>
-          <author initials="L-S." surname="Huang"/>
-          <author initials="E." surname="Chen"/>
-          <author initials="A." surname="Barth"/>
-          <author initials="E." surname="Rescorla"/>
-          <author initials="C." surname="Jackson"/>
-          <date year="2011" />
-        </front>
-      </reference>
-
-      <reference anchor="BREACH"
-                 target="http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf">
-        <front>
-          <title>
-            BREACH: Reviving the CRIME Attack
-          </title>
-          <author initials="Y." surname="Gluck"/>
-          <author initials="N." surname="Harris"/>
-          <author initials="A." surname="Prado"/>
-          <date year="2013" month="July" day="12"/>
-        </front>
-      </reference>
-
-      <reference anchor="BCP90">
-        <front>
-          <title>Registration Procedures for Message Header Fields</title>
-          <author initials="G." surname="Klyne" fullname="G. Klyne">
-            <organization>Nine by Nine</organization>
-            <address><email>GK-IETF@ninebynine.org</email></address>
-          </author>
-          <author initials="M." surname="Nottingham" fullname="M. Nottingham">
-            <organization>BEA Systems</organization>
-            <address><email>mnot@pobox.com</email></address>
-          </author>
-          <author initials="J." surname="Mogul" fullname="J. Mogul">
-            <organization>HP Labs</organization>
-            <address><email>JeffMogul@acm.org</email></address>
-          </author>
-          <date year="2004" month="September" />
-        </front>
-        <seriesInfo name="BCP" value="90" />
-        <seriesInfo name="RFC" value="3864" />
-      </reference>
-
-      <reference anchor="TLSBCP">
-        <front>
-          <title>Recommendations for Secure Use of TLS and DTLS</title>
-          <author initials="Y" surname="Sheffer" fullname="Yaron Sheffer">
-            <organization />
-          </author>
-          <author initials="R" surname="Holz" fullname="Ralph Holz">
-            <organization />
-          </author>
-          <author initials="P" surname="Saint-Andre" fullname="Peter Saint-Andre">
-            <organization />
-          </author>
-          <date month="June" day="23" year="2014" />
-        </front>
-        <seriesInfo name="Internet-Draft" value="draft-ietf-uta-tls-bcp-01" />
-      </reference>
-
-      <reference anchor="ALT-SVC">
-        <front>
-          <title>
-            HTTP Alternative Services
-          </title>
-          <author initials="M." surname="Nottingham" fullname="Mark Nottingham">
-            <organization>Akamai</organization>
-          </author>
-          <author initials="P." surname="McManus" fullname="Patrick McManus">
-            <organization>Mozilla</organization>
-          </author>
-          <author initials="J." surname="Reschke" fullname="Julian Reschke">
-            <organization>greenbytes</organization>
-          </author>
-          <date year="2014" month="April"/>
-        </front>
-        <seriesInfo name="Internet-Draft" value="draft-ietf-httpbis-alt-svc-02"/>
-        <x:source href="refs/draft-ietf-httpbis-alt-svc-02.xml"/>
-      </reference>
-    </references>
-
-    <section title="Change Log" anchor="change.log">
-      <t>
-        This section is to be removed by RFC Editor before publication.
-      </t>
-
-      <section title="Since draft-ietf-httpbis-http2-14" anchor="changes.since.draft-ietf-httpbis-http2-14">
-        <t>
-          Renamed Not Authoritative status code to Misdirected Request.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-13" anchor="changes.since.draft-ietf-httpbis-http2-13">
-        <t>
-          Pseudo-header fields are now required to appear strictly before regular ones.
-        </t>
-        <t>
-          Restored 1xx series status codes, except 101.
-        </t>
-        <t>
-          Changed frame length field 24-bits.  Expanded frame header to 9 octets.  Added a setting
-          to limit the damage.
-        </t>
-        <t>
-          Added a setting to advise peers of header set size limits.
-        </t>
-        <t>
-          Removed segments.
-        </t>
-        <t>
-          Made non-semantic-bearing <x:ref>HEADERS</x:ref> frames illegal in the HTTP mapping.
-        </t>
-      </section>
-
-       <section title="Since draft-ietf-httpbis-http2-12" anchor="changes.since.draft-ietf-httpbis-http2-12">
-         <t>
-           Restored extensibility options.
-         </t>
-         <t>
-           Restricting TLS cipher suites to AEAD only.
-         </t>
-         <t>
-           Removing Content-Encoding requirements.
-         </t>
-         <t>
-           Permitting the use of <x:ref>PRIORITY</x:ref> after stream close.
-         </t>
-         <t>
-           Removed ALTSVC frame.
-         </t>
-         <t>
-           Removed BLOCKED frame.
-         </t>
-         <t>
-           Reducing the maximum padding size to 256 octets; removing padding from
-           <x:ref>CONTINUATION</x:ref> frames.
-         </t>
-         <t>
-           Removed per-frame GZIP compression.
-         </t>
-       </section>
-
-       <section title="Since draft-ietf-httpbis-http2-11" anchor="changes.since.draft-ietf-httpbis-http2-11">
-         <t>
-           Added BLOCKED frame (at risk).
-         </t>
-         <t>
-           Simplified priority scheme.
-         </t>
-         <t>
-           Added <x:ref>DATA</x:ref> per-frame GZIP compression.
-         </t>
-       </section>
-
-       <section title="Since draft-ietf-httpbis-http2-10" anchor="changes.since.draft-ietf-httpbis-http2-10">
-        <t>
-          Changed "connection header" to "connection preface" to avoid confusion.
-        </t>
-        <t>
-          Added dependency-based stream prioritization.
-        </t>
-        <t>
-          Added "h2c" identifier to distinguish between cleartext and secured HTTP/2.
-        </t>
-        <t>
-          Adding missing padding to <x:ref>PUSH_PROMISE</x:ref>.
-        </t>
-        <t>
-          Integrate ALTSVC frame and supporting text.
-        </t>
-        <t>
-          Dropping requirement on "deflate" Content-Encoding.
-        </t>
-        <t>
-          Improving security considerations around use of compression.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-09" anchor="changes.since.draft-ietf-httpbis-http2-09">
-        <t>
-          Adding padding for data frames.
-        </t>
-        <t>
-          Renumbering frame types, error codes, and settings.
-        </t>
-        <t>
-          Adding INADEQUATE_SECURITY error code.
-        </t>
-        <t>
-          Updating TLS usage requirements to 1.2; forbidding TLS compression.
-        </t>
-        <t>
-          Removing extensibility for frames and settings.
-        </t>
-        <t>
-          Changing setting identifier size.
-        </t>
-        <t>
-          Removing the ability to disable flow control.
-        </t>
-        <t>
-          Changing the protocol identification token to "h2".
-        </t>
-        <t>
-          Changing the use of :authority to make it optional and to allow userinfo in non-HTTP
-          cases.
-        </t>
-        <t>
-          Allowing split on 0x0 for Cookie.
-        </t>
-        <t>
-          Reserved PRI method in HTTP/1.1 to avoid possible future collisions.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-08" anchor="changes.since.draft-ietf-httpbis-http2-08">
-        <t>
-          Added cookie crumbling for more efficient header compression.
-        </t>
-        <t>
-          Added header field ordering with the value-concatenation mechanism.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-07" anchor="changes.since.draft-ietf-httpbis-http2-07">
-        <t>
-          Marked draft for implementation.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-06" anchor="changes.since.draft-ietf-httpbis-http2-06">
-        <t>
-          Adding definition for CONNECT method.
-        </t>
-        <t>
-          Constraining the use of push to safe, cacheable methods with no request body.
-        </t>
-        <t>
-          Changing from :host to :authority to remove any potential confusion.
-        </t>
-        <t>
-          Adding setting for header compression table size.
-        </t>
-        <t>
-          Adding settings acknowledgement.
-        </t>
-        <t>
-          Removing unnecessary and potentially problematic flags from CONTINUATION.
-        </t>
-        <t>
-          Added denial of service considerations.
-        </t>
-      </section>
-      <section title="Since draft-ietf-httpbis-http2-05" anchor="changes.since.draft-ietf-httpbis-http2-05">
-        <t>
-          Marking the draft ready for implementation.
-        </t>
-        <t>
-          Renumbering END_PUSH_PROMISE flag.
-        </t>
-        <t>
-          Editorial clarifications and changes.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-04" anchor="changes.since.draft-ietf-httpbis-http2-04">
-        <t>
-          Added CONTINUATION frame for HEADERS and PUSH_PROMISE.
-        </t>
-        <t>
-          PUSH_PROMISE is no longer implicitly prohibited if SETTINGS_MAX_CONCURRENT_STREAMS is
-          zero.
-        </t>
-        <t>
-          Push expanded to allow all safe methods without a request body.
-        </t>
-        <t>
-          Clarified the use of HTTP header fields in requests and responses.  Prohibited HTTP/1.1
-          hop-by-hop header fields.
-        </t>
-        <t>
-          Requiring that intermediaries not forward requests with missing or illegal routing
-          :-headers.
-        </t>
-        <t>
-          Clarified requirements around handling different frames after stream close, stream reset
-          and <x:ref>GOAWAY</x:ref>.
-        </t>
-        <t>
-          Added more specific prohibitions for sending of different frame types in various stream
-          states.
-        </t>
-        <t>
-          Making the last received setting value the effective value.
-        </t>
-        <t>
-          Clarified requirements on TLS version, extension and ciphers.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-03" anchor="changes.since.draft-ietf-httpbis-http2-03">
-        <t>
-          Committed major restructuring atrocities.
-        </t>
-        <t>
-          Added reference to first header compression draft.
-        </t>
-        <t>
-          Added more formal description of frame lifecycle.
-        </t>
-        <t>
-          Moved END_STREAM (renamed from FINAL) back to <x:ref>HEADERS</x:ref>/<x:ref>DATA</x:ref>.
-        </t>
-        <t>
-          Removed HEADERS+PRIORITY, added optional priority to <x:ref>HEADERS</x:ref> frame.
-        </t>
-        <t>
-          Added <x:ref>PRIORITY</x:ref> frame.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-02" anchor="changes.since.draft-ietf-httpbis-http2-02">
-        <t>
-          Added continuations to frames carrying header blocks.
-        </t>
-        <t>
-          Replaced use of "session" with "connection" to avoid confusion with other HTTP stateful
-          concepts, like cookies.
-        </t>
-        <t>
-          Removed "message".
-        </t>
-        <t>
-          Switched to TLS ALPN from NPN.
-        </t>
-        <t>
-          Editorial changes.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-01" anchor="changes.since.draft-ietf-httpbis-http2-01">
-        <t>
-          Added IANA considerations section for frame types, error codes and settings.
-        </t>
-        <t>
-          Removed data frame compression.
-        </t>
-        <t>
-          Added <x:ref>PUSH_PROMISE</x:ref>.
-        </t>
-        <t>
-          Added globally applicable flags to framing.
-        </t>
-        <t>
-          Removed zlib-based header compression mechanism.
-        </t>
-        <t>
-          Updated references.
-        </t>
-        <t>
-          Clarified stream identifier reuse.
-        </t>
-        <t>
-          Removed CREDENTIALS frame and associated mechanisms.
-        </t>
-        <t>
-          Added advice against naive implementation of flow control.
-        </t>
-        <t>
-          Added session header section.
-        </t>
-        <t>
-          Restructured frame header.  Removed distinction between data and control frames.
-        </t>
-        <t>
-          Altered flow control properties to include session-level limits.
-        </t>
-        <t>
-          Added note on cacheability of pushed resources and multiple tenant servers.
-        </t>
-        <t>
-          Changed protocol label form based on discussions.
-        </t>
-      </section>
-
-      <section title="Since draft-ietf-httpbis-http2-00" anchor="changes.since.draft-ietf-httpbis-http2-00">
-        <t>
-          Changed title throughout.
-        </t>
-        <t>
-          Removed section on Incompatibilities with SPDY draft#2.
-        </t>
-        <t>
-          Changed <x:ref>INTERNAL_ERROR</x:ref> on <x:ref>GOAWAY</x:ref> to have a value of 2 <eref
-          target="https://groups.google.com/forum/?fromgroups#!topic/spdy-dev/cfUef2gL3iU"/>.
-        </t>
-        <t>
-          Replaced abstract and introduction.
-        </t>
-        <t>
-          Added section on starting HTTP/2.0, including upgrade mechanism.
-        </t>
-        <t>
-          Removed unused references.
-        </t>
-        <t>
-          Added <xref target="fc-principles">flow control principles</xref> based on <eref
-          target="https://tools.ietf.org/html/draft-montenegro-httpbis-http2-fc-principles-01"/>.
-        </t>
-      </section>
-
-      <section title="Since draft-mbelshe-httpbis-spdy-00" anchor="changes.since.draft-mbelshe-httpbis-spdy-00">
-        <t>
-          Adopted as base for draft-ietf-httpbis-http2.
-        </t>
-        <t>
-          Updated authors/editors list.
-        </t>
-        <t>
-          Added status note.
-        </t>
-      </section>
-    </section>
-
-  </back>
-</rfc>
-<!--
-  vim:et:tw=100:sw=2:
-  -->

+ 183 - 230
Godeps/_workspace/src/golang.org/x/net/http2/transport.go

@@ -187,8 +187,8 @@ type clientStream struct {
 	done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
 
 	// owned by clientConnReadLoop:
-	pastHeaders  bool // got HEADERS w/ END_HEADERS
-	pastTrailers bool // got second HEADERS frame w/ END_HEADERS
+	pastHeaders  bool // got first MetaHeadersFrame (actual headers)
+	pastTrailers bool // got optional second MetaHeadersFrame (trailers)
 
 	trailer    http.Header  // accumulated trailers
 	resTrailer *http.Header // client's Response.Trailer
@@ -333,8 +333,12 @@ func (t *Transport) newTLSConfig(host string) *tls.Config {
 	if t.TLSClientConfig != nil {
 		*cfg = *t.TLSClientConfig
 	}
-	cfg.NextProtos = []string{NextProtoTLS} // TODO: don't override if already in list
-	cfg.ServerName = host
+	if !strSliceContains(cfg.NextProtos, NextProtoTLS) {
+		cfg.NextProtos = append([]string{NextProtoTLS}, cfg.NextProtos...)
+	}
+	if cfg.ServerName == "" {
+		cfg.ServerName = host
+	}
 	return cfg
 }
 
@@ -401,14 +405,13 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
 	cc.bw = bufio.NewWriter(stickyErrWriter{c, &cc.werr})
 	cc.br = bufio.NewReader(c)
 	cc.fr = NewFramer(cc.bw, cc.br)
+	cc.fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
+	cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
 
 	// TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on
 	// henc in response to SETTINGS frames?
 	cc.henc = hpack.NewEncoder(&cc.hbuf)
 
-	type connectionStater interface {
-		ConnectionState() tls.ConnectionState
-	}
 	if cs, ok := c.(connectionStater); ok {
 		state := cs.ConnectionState()
 		cc.tlsState = &state
@@ -565,7 +568,27 @@ func (cc *ClientConn) responseHeaderTimeout() time.Duration {
 	return 0
 }
 
+// checkConnHeaders checks whether req has any invalid connection-level headers.
+// per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields.
+// Certain headers are special-cased as okay but not transmitted later.
+func checkConnHeaders(req *http.Request) error {
+	if v := req.Header.Get("Upgrade"); v != "" {
+		return errors.New("http2: invalid Upgrade request header")
+	}
+	if v := req.Header.Get("Transfer-Encoding"); (v != "" && v != "chunked") || len(req.Header["Transfer-Encoding"]) > 1 {
+		return errors.New("http2: invalid Transfer-Encoding request header")
+	}
+	if v := req.Header.Get("Connection"); (v != "" && v != "close" && v != "keep-alive") || len(req.Header["Connection"]) > 1 {
+		return errors.New("http2: invalid Connection request header")
+	}
+	return nil
+}
+
 func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
+	if err := checkConnHeaders(req); err != nil {
+		return nil, err
+	}
+
 	trailers, err := commaSeparatedTrailers(req)
 	if err != nil {
 		return nil, err
@@ -917,13 +940,24 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
 	var didUA bool
 	for k, vv := range req.Header {
 		lowKey := strings.ToLower(k)
-		if lowKey == "host" || lowKey == "content-length" {
+		switch lowKey {
+		case "host", "content-length":
+			// Host is :authority, already sent.
+			// Content-Length is automatic, set below.
 			continue
-		}
-		if lowKey == "user-agent" {
+		case "connection", "proxy-connection", "transfer-encoding", "upgrade":
+			// Per 8.1.2.2 Connection-Specific Header
+			// Fields, don't send connection-specific
+			// fields. We deal with these earlier in
+			// RoundTrip, deciding whether they're
+			// error-worthy, but we don't want to mutate
+			// the user's *Request so at this point, just
+			// skip over them at this point.
+			continue
+		case "user-agent":
 			// Match Go's http1 behavior: at most one
-			// User-Agent.  If set to nil or empty string,
-			// then omit it.  Otherwise if not mentioned,
+			// User-Agent. If set to nil or empty string,
+			// then omit it. Otherwise if not mentioned,
 			// include the default (below).
 			didUA = true
 			if len(vv) < 1 {
@@ -1033,17 +1067,9 @@ func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream {
 
 // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
 type clientConnReadLoop struct {
-	cc        *ClientConn
-	activeRes map[uint32]*clientStream // keyed by streamID
-
-	hdec *hpack.Decoder
-
-	// Fields reset on each HEADERS:
-	nextRes              *http.Response
-	sawRegHeader         bool  // saw non-pseudo header
-	reqMalformed         error // non-nil once known to be malformed
-	lastHeaderEndsStream bool
-	headerListSize       int64 // actually uint32, but easier math this way
+	cc            *ClientConn
+	activeRes     map[uint32]*clientStream // keyed by streamID
+	closeWhenIdle bool
 }
 
 // readLoop runs in its own goroutine and reads and dispatches frames.
@@ -1052,7 +1078,6 @@ func (cc *ClientConn) readLoop() {
 		cc:        cc,
 		activeRes: make(map[uint32]*clientStream),
 	}
-	rl.hdec = hpack.NewDecoder(initialHeaderTableSize, rl.onNewHeaderField)
 
 	defer rl.cleanup()
 	cc.readerErr = rl.run()
@@ -1094,7 +1119,7 @@ func (rl *clientConnReadLoop) cleanup() {
 
 func (rl *clientConnReadLoop) run() error {
 	cc := rl.cc
-	closeWhenIdle := cc.t.disableKeepAlives()
+	rl.closeWhenIdle = cc.t.disableKeepAlives()
 	gotReply := false // ever saw a reply
 	for {
 		f, err := cc.fr.ReadFrame()
@@ -1102,8 +1127,10 @@ func (rl *clientConnReadLoop) run() error {
 			cc.vlogf("Transport readFrame error: (%T) %v", err, err)
 		}
 		if se, ok := err.(StreamError); ok {
-			// TODO: deal with stream errors from the framer.
-			return se
+			if cs := cc.streamByID(se.StreamID, true /*ended; remove it*/); cs != nil {
+				rl.endStreamError(cs, cc.fr.errDetail)
+			}
+			continue
 		} else if err != nil {
 			return err
 		}
@@ -1113,13 +1140,10 @@ func (rl *clientConnReadLoop) run() error {
 		maybeIdle := false // whether frame might transition us to idle
 
 		switch f := f.(type) {
-		case *HeadersFrame:
+		case *MetaHeadersFrame:
 			err = rl.processHeaders(f)
 			maybeIdle = true
 			gotReply = true
-		case *ContinuationFrame:
-			err = rl.processContinuation(f)
-			maybeIdle = true
 		case *DataFrame:
 			err = rl.processData(f)
 			maybeIdle = true
@@ -1143,97 +1167,102 @@ func (rl *clientConnReadLoop) run() error {
 		if err != nil {
 			return err
 		}
-		if closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
+		if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
 			cc.closeIfIdle()
 		}
 	}
 }
 
-func (rl *clientConnReadLoop) processHeaders(f *HeadersFrame) error {
-	rl.sawRegHeader = false
-	rl.reqMalformed = nil
-	rl.lastHeaderEndsStream = f.StreamEnded()
-	rl.headerListSize = 0
-	rl.nextRes = &http.Response{
-		Proto:      "HTTP/2.0",
-		ProtoMajor: 2,
-		Header:     make(http.Header),
-	}
-	rl.hdec.SetEmitEnabled(true)
-	return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
-}
-
-func (rl *clientConnReadLoop) processContinuation(f *ContinuationFrame) error {
-	return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
-}
-
-func (rl *clientConnReadLoop) processHeaderBlockFragment(frag []byte, streamID uint32, finalFrag bool) error {
+func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error {
 	cc := rl.cc
-	streamEnded := rl.lastHeaderEndsStream
-	cs := cc.streamByID(streamID, streamEnded && finalFrag)
+	cs := cc.streamByID(f.StreamID, f.StreamEnded())
 	if cs == nil {
 		// We'd get here if we canceled a request while the
-		// server was mid-way through replying with its
-		// headers. (The case of a CONTINUATION arriving
-		// without HEADERS would be rejected earlier by the
-		// Framer). So if this was just something we canceled,
-		// ignore it.
+		// server had its response still in flight. So if this
+		// was just something we canceled, ignore it.
 		return nil
 	}
-	if cs.pastHeaders {
-		rl.hdec.SetEmitFunc(func(f hpack.HeaderField) { rl.onNewTrailerField(cs, f) })
+	if !cs.pastHeaders {
+		cs.pastHeaders = true
 	} else {
-		rl.hdec.SetEmitFunc(rl.onNewHeaderField)
+		return rl.processTrailers(cs, f)
 	}
-	_, err := rl.hdec.Write(frag)
+
+	res, err := rl.handleResponse(cs, f)
 	if err != nil {
-		return ConnectionError(ErrCodeCompression)
-	}
-	if finalFrag {
-		if err := rl.hdec.Close(); err != nil {
-			return ConnectionError(ErrCodeCompression)
+		if _, ok := err.(ConnectionError); ok {
+			return err
 		}
+		// Any other error type is a stream error.
+		cs.cc.writeStreamReset(f.StreamID, ErrCodeProtocol, err)
+		cs.resc <- resAndError{err: err}
+		return nil // return nil from process* funcs to keep conn alive
 	}
-
-	if !finalFrag {
+	if res == nil {
+		// (nil, nil) special case. See handleResponse docs.
 		return nil
 	}
-
-	if !cs.pastHeaders {
-		cs.pastHeaders = true
-	} else {
-		// We're dealing with trailers. (and specifically the
-		// final frame of headers)
-		if cs.pastTrailers {
-			// Too many HEADERS frames for this stream.
-			return ConnectionError(ErrCodeProtocol)
-		}
-		cs.pastTrailers = true
-		if !streamEnded {
-			// We expect that any header block fragment
-			// frame for trailers with END_HEADERS also
-			// has END_STREAM.
-			return ConnectionError(ErrCodeProtocol)
-		}
-		rl.endStream(cs)
-		return nil
+	if res.Body != noBody {
+		rl.activeRes[cs.ID] = cs
 	}
+	cs.resTrailer = &res.Trailer
+	cs.resc <- resAndError{res: res}
+	return nil
+}
 
-	if rl.reqMalformed != nil {
-		cs.resc <- resAndError{err: rl.reqMalformed}
-		rl.cc.writeStreamReset(cs.ID, ErrCodeProtocol, rl.reqMalformed)
-		return nil
+// may return error types nil, or ConnectionError. Any other error value
+// is a StreamError of type ErrCodeProtocol. The returned error in that case
+// is the detail.
+//
+// As a special case, handleResponse may return (nil, nil) to skip the
+// frame (currently only used for 100 expect continue). This special
+// case is going away after Issue 13851 is fixed.
+func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFrame) (*http.Response, error) {
+	if f.Truncated {
+		return nil, errResponseHeaderListSize
 	}
 
-	res := rl.nextRes
+	status := f.PseudoValue("status")
+	if status == "" {
+		return nil, errors.New("missing status pseudo header")
+	}
+	statusCode, err := strconv.Atoi(status)
+	if err != nil {
+		return nil, errors.New("malformed non-numeric status pseudo header")
+	}
 
-	if res.StatusCode == 100 {
+	if statusCode == 100 {
 		// Just skip 100-continue response headers for now.
 		// TODO: golang.org/issue/13851 for doing it properly.
 		cs.pastHeaders = false // do it all again
-		return nil
+		return nil, nil
+	}
+
+	header := make(http.Header)
+	res := &http.Response{
+		Proto:      "HTTP/2.0",
+		ProtoMajor: 2,
+		Header:     header,
+		StatusCode: statusCode,
+		Status:     status + " " + http.StatusText(statusCode),
+	}
+	for _, hf := range f.RegularFields() {
+		key := http.CanonicalHeaderKey(hf.Name)
+		if key == "Trailer" {
+			t := res.Trailer
+			if t == nil {
+				t = make(http.Header)
+				res.Trailer = t
+			}
+			foreachHeaderElement(hf.Value, func(v string) {
+				t[http.CanonicalHeaderKey(v)] = nil
+			})
+		} else {
+			header[key] = append(header[key], hf.Value)
+		}
 	}
 
+	streamEnded := f.StreamEnded()
 	if !streamEnded || cs.req.Method == "HEAD" {
 		res.ContentLength = -1
 		if clens := res.Header["Content-Length"]; len(clens) == 1 {
@@ -1251,25 +1280,49 @@ func (rl *clientConnReadLoop) processHeaderBlockFragment(frag []byte, streamID u
 
 	if streamEnded {
 		res.Body = noBody
-	} else {
-		buf := new(bytes.Buffer) // TODO(bradfitz): recycle this garbage
-		cs.bufPipe = pipe{b: buf}
-		cs.bytesRemain = res.ContentLength
-		res.Body = transportResponseBody{cs}
-		go cs.awaitRequestCancel(requestCancel(cs.req))
-
-		if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
-			res.Header.Del("Content-Encoding")
-			res.Header.Del("Content-Length")
-			res.ContentLength = -1
-			res.Body = &gzipReader{body: res.Body}
-		}
+		return res, nil
 	}
 
-	cs.resTrailer = &res.Trailer
-	rl.activeRes[cs.ID] = cs
-	cs.resc <- resAndError{res: res}
-	rl.nextRes = nil // unused now; will be reset next HEADERS frame
+	buf := new(bytes.Buffer) // TODO(bradfitz): recycle this garbage
+	cs.bufPipe = pipe{b: buf}
+	cs.bytesRemain = res.ContentLength
+	res.Body = transportResponseBody{cs}
+	go cs.awaitRequestCancel(requestCancel(cs.req))
+
+	if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
+		res.Header.Del("Content-Encoding")
+		res.Header.Del("Content-Length")
+		res.ContentLength = -1
+		res.Body = &gzipReader{body: res.Body}
+	}
+	return res, nil
+}
+
+func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFrame) error {
+	if cs.pastTrailers {
+		// Too many HEADERS frames for this stream.
+		return ConnectionError(ErrCodeProtocol)
+	}
+	cs.pastTrailers = true
+	if !f.StreamEnded() {
+		// We expect that any headers for trailers also
+		// has END_STREAM.
+		return ConnectionError(ErrCodeProtocol)
+	}
+	if len(f.PseudoFields()) > 0 {
+		// No pseudo header fields are defined for trailers.
+		// TODO: ConnectionError might be overly harsh? Check.
+		return ConnectionError(ErrCodeProtocol)
+	}
+
+	trailer := make(http.Header)
+	for _, hf := range f.RegularFields() {
+		key := http.CanonicalHeaderKey(hf.Name)
+		trailer[key] = append(trailer[key], hf.Value)
+	}
+	cs.trailer = trailer
+
+	rl.endStream(cs)
 	return nil
 }
 
@@ -1387,6 +1440,7 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error {
 		cc.mu.Unlock()
 
 		if _, err := cs.bufPipe.Write(data); err != nil {
+			rl.endStreamError(cs, err)
 			return err
 		}
 	}
@@ -1402,14 +1456,20 @@ var errInvalidTrailers = errors.New("http2: invalid trailers")
 func (rl *clientConnReadLoop) endStream(cs *clientStream) {
 	// TODO: check that any declared content-length matches, like
 	// server.go's (*stream).endStream method.
-	err := io.EOF
-	code := cs.copyTrailers
-	if rl.reqMalformed != nil {
-		err = rl.reqMalformed
-		code = nil
+	rl.endStreamError(cs, nil)
+}
+
+func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) {
+	var code func()
+	if err == nil {
+		err = io.EOF
+		code = cs.copyTrailers
 	}
 	cs.bufPipe.closeWithErrorAndCode(err, code)
 	delete(rl.activeRes, cs.ID)
+	if cs.req.Close || cs.req.Header.Get("Connection") == "close" {
+		rl.closeWhenIdle = true
+	}
 }
 
 func (cs *clientStream) copyTrailers() {
@@ -1542,118 +1602,6 @@ var (
 	errPseudoTrailers         = errors.New("http2: invalid pseudo header in trailers")
 )
 
-func (rl *clientConnReadLoop) checkHeaderField(f hpack.HeaderField) bool {
-	if rl.reqMalformed != nil {
-		return false
-	}
-
-	const headerFieldOverhead = 32 // per spec
-	rl.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
-	if max := rl.cc.t.maxHeaderListSize(); max != 0 && rl.headerListSize > int64(max) {
-		rl.hdec.SetEmitEnabled(false)
-		rl.reqMalformed = errResponseHeaderListSize
-		return false
-	}
-
-	if !validHeaderFieldValue(f.Value) {
-		rl.reqMalformed = errInvalidHeaderFieldValue
-		return false
-	}
-
-	isPseudo := strings.HasPrefix(f.Name, ":")
-	if isPseudo {
-		if rl.sawRegHeader {
-			rl.reqMalformed = errors.New("http2: invalid pseudo header after regular header")
-			return false
-		}
-	} else {
-		if !validHeaderFieldName(f.Name) {
-			rl.reqMalformed = errInvalidHeaderFieldName
-			return false
-		}
-		rl.sawRegHeader = true
-	}
-
-	return true
-}
-
-// onNewHeaderField runs on the readLoop goroutine whenever a new
-// hpack header field is decoded.
-func (rl *clientConnReadLoop) onNewHeaderField(f hpack.HeaderField) {
-	cc := rl.cc
-	if VerboseLogs {
-		cc.logf("http2: Transport decoded %v", f)
-	}
-
-	if !rl.checkHeaderField(f) {
-		return
-	}
-
-	isPseudo := strings.HasPrefix(f.Name, ":")
-	if isPseudo {
-		switch f.Name {
-		case ":status":
-			code, err := strconv.Atoi(f.Value)
-			if err != nil {
-				rl.reqMalformed = errors.New("http2: invalid :status")
-				return
-			}
-			rl.nextRes.Status = f.Value + " " + http.StatusText(code)
-			rl.nextRes.StatusCode = code
-		default:
-			// "Endpoints MUST NOT generate pseudo-header
-			// fields other than those defined in this
-			// document."
-			rl.reqMalformed = fmt.Errorf("http2: unknown response pseudo header %q", f.Name)
-		}
-		return
-	}
-
-	key := http.CanonicalHeaderKey(f.Name)
-	if key == "Trailer" {
-		t := rl.nextRes.Trailer
-		if t == nil {
-			t = make(http.Header)
-			rl.nextRes.Trailer = t
-		}
-		foreachHeaderElement(f.Value, func(v string) {
-			t[http.CanonicalHeaderKey(v)] = nil
-		})
-	} else {
-		rl.nextRes.Header.Add(key, f.Value)
-	}
-}
-
-func (rl *clientConnReadLoop) onNewTrailerField(cs *clientStream, f hpack.HeaderField) {
-	if VerboseLogs {
-		rl.cc.logf("http2: Transport decoded trailer %v", f)
-	}
-	if !rl.checkHeaderField(f) {
-		return
-	}
-	if strings.HasPrefix(f.Name, ":") {
-		// Pseudo-header fields MUST NOT appear in
-		// trailers. Endpoints MUST treat a request or
-		// response that contains undefined or invalid
-		// pseudo-header fields as malformed.
-		rl.reqMalformed = errPseudoTrailers
-		return
-	}
-
-	key := http.CanonicalHeaderKey(f.Name)
-
-	// The spec says one must predeclare their trailers but in practice
-	// popular users (which is to say the only user we found) do not so we
-	// violate the spec and accept all of them.
-	const acceptAllTrailers = true
-	if _, ok := (*cs.resTrailer)[key]; ok || acceptAllTrailers {
-		if cs.trailer == nil {
-			cs.trailer = make(http.Header)
-		}
-		cs.trailer[key] = append(cs.trailer[key], f.Value)
-	}
-}
-
 func (cc *ClientConn) logf(format string, args ...interface{}) {
 	cc.t.logf(format, args...)
 }
@@ -1691,13 +1639,18 @@ func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {
 // call gzip.NewReader on the first call to Read
 type gzipReader struct {
 	body io.ReadCloser // underlying Response.Body
-	zr   io.Reader     // lazily-initialized gzip reader
+	zr   *gzip.Reader  // lazily-initialized gzip reader
+	zerr error         // sticky error
 }
 
 func (gz *gzipReader) Read(p []byte) (n int, err error) {
+	if gz.zerr != nil {
+		return 0, gz.zerr
+	}
 	if gz.zr == nil {
 		gz.zr, err = gzip.NewReader(gz.body)
 		if err != nil {
+			gz.zerr = err
 			return 0, err
 		}
 	}

+ 0 - 1551
Godeps/_workspace/src/golang.org/x/net/http2/transport_test.go

@@ -1,1551 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"bufio"
-	"bytes"
-	"crypto/tls"
-	"errors"
-	"flag"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"math/rand"
-	"net"
-	"net/http"
-	"net/url"
-	"os"
-	"reflect"
-	"strconv"
-	"strings"
-	"sync"
-	"sync/atomic"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2/hpack"
-)
-
-var (
-	extNet        = flag.Bool("extnet", false, "do external network tests")
-	transportHost = flag.String("transporthost", "http2.golang.org", "hostname to use for TestTransport")
-	insecure      = flag.Bool("insecure", false, "insecure TLS dials") // TODO: dead code. remove?
-)
-
-var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true}
-
-func TestTransportExternal(t *testing.T) {
-	if !*extNet {
-		t.Skip("skipping external network test")
-	}
-	req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil)
-	rt := &Transport{TLSClientConfig: tlsConfigInsecure}
-	res, err := rt.RoundTrip(req)
-	if err != nil {
-		t.Fatalf("%v", err)
-	}
-	res.Write(os.Stdout)
-}
-
-func TestTransport(t *testing.T) {
-	const body = "sup"
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		io.WriteString(w, body)
-	}, optOnlyServer)
-	defer st.Close()
-
-	tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-	defer tr.CloseIdleConnections()
-
-	req, err := http.NewRequest("GET", st.ts.URL, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	res, err := tr.RoundTrip(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer res.Body.Close()
-
-	t.Logf("Got res: %+v", res)
-	if g, w := res.StatusCode, 200; g != w {
-		t.Errorf("StatusCode = %v; want %v", g, w)
-	}
-	if g, w := res.Status, "200 OK"; g != w {
-		t.Errorf("Status = %q; want %q", g, w)
-	}
-	wantHeader := http.Header{
-		"Content-Length": []string{"3"},
-		"Content-Type":   []string{"text/plain; charset=utf-8"},
-		"Date":           []string{"XXX"}, // see cleanDate
-	}
-	cleanDate(res)
-	if !reflect.DeepEqual(res.Header, wantHeader) {
-		t.Errorf("res Header = %v; want %v", res.Header, wantHeader)
-	}
-	if res.Request != req {
-		t.Errorf("Response.Request = %p; want %p", res.Request, req)
-	}
-	if res.TLS == nil {
-		t.Error("Response.TLS = nil; want non-nil")
-	}
-	slurp, err := ioutil.ReadAll(res.Body)
-	if err != nil {
-		t.Errorf("Body read: %v", err)
-	} else if string(slurp) != body {
-		t.Errorf("Body = %q; want %q", slurp, body)
-	}
-}
-
-func TestTransportReusesConns(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		io.WriteString(w, r.RemoteAddr)
-	}, optOnlyServer)
-	defer st.Close()
-	tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-	defer tr.CloseIdleConnections()
-	get := func() string {
-		req, err := http.NewRequest("GET", st.ts.URL, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		res, err := tr.RoundTrip(req)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer res.Body.Close()
-		slurp, err := ioutil.ReadAll(res.Body)
-		if err != nil {
-			t.Fatalf("Body read: %v", err)
-		}
-		addr := strings.TrimSpace(string(slurp))
-		if addr == "" {
-			t.Fatalf("didn't get an addr in response")
-		}
-		return addr
-	}
-	first := get()
-	second := get()
-	if first != second {
-		t.Errorf("first and second responses were on different connections: %q vs %q", first, second)
-	}
-}
-
-// Tests that the Transport only keeps one pending dial open per destination address.
-// https://golang.org/issue/13397
-func TestTransportGroupsPendingDials(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		io.WriteString(w, r.RemoteAddr)
-	}, optOnlyServer)
-	defer st.Close()
-	tr := &Transport{
-		TLSClientConfig: tlsConfigInsecure,
-	}
-	defer tr.CloseIdleConnections()
-	var (
-		mu    sync.Mutex
-		dials = map[string]int{}
-	)
-	var wg sync.WaitGroup
-	for i := 0; i < 10; i++ {
-		wg.Add(1)
-		go func() {
-			defer wg.Done()
-			req, err := http.NewRequest("GET", st.ts.URL, nil)
-			if err != nil {
-				t.Error(err)
-				return
-			}
-			res, err := tr.RoundTrip(req)
-			if err != nil {
-				t.Error(err)
-				return
-			}
-			defer res.Body.Close()
-			slurp, err := ioutil.ReadAll(res.Body)
-			if err != nil {
-				t.Errorf("Body read: %v", err)
-			}
-			addr := strings.TrimSpace(string(slurp))
-			if addr == "" {
-				t.Errorf("didn't get an addr in response")
-			}
-			mu.Lock()
-			dials[addr]++
-			mu.Unlock()
-		}()
-	}
-	wg.Wait()
-	if len(dials) != 1 {
-		t.Errorf("saw %d dials; want 1: %v", len(dials), dials)
-	}
-	tr.CloseIdleConnections()
-	if err := retry(50, 10*time.Millisecond, func() error {
-		cp, ok := tr.connPool().(*clientConnPool)
-		if !ok {
-			return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool())
-		}
-		cp.mu.Lock()
-		defer cp.mu.Unlock()
-		if len(cp.dialing) != 0 {
-			return fmt.Errorf("dialing map = %v; want empty", cp.dialing)
-		}
-		if len(cp.conns) != 0 {
-			return fmt.Errorf("conns = %v; want empty", cp.conns)
-		}
-		if len(cp.keys) != 0 {
-			return fmt.Errorf("keys = %v; want empty", cp.keys)
-		}
-		return nil
-	}); err != nil {
-		t.Errorf("State of pool after CloseIdleConnections: %v", err)
-	}
-}
-
-func retry(tries int, delay time.Duration, fn func() error) error {
-	var err error
-	for i := 0; i < tries; i++ {
-		err = fn()
-		if err == nil {
-			return nil
-		}
-		time.Sleep(delay)
-	}
-	return err
-}
-
-func TestTransportAbortClosesPipes(t *testing.T) {
-	shutdown := make(chan struct{})
-	st := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			w.(http.Flusher).Flush()
-			<-shutdown
-		},
-		optOnlyServer,
-	)
-	defer st.Close()
-	defer close(shutdown) // we must shutdown before st.Close() to avoid hanging
-
-	done := make(chan struct{})
-	requestMade := make(chan struct{})
-	go func() {
-		defer close(done)
-		tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-		req, err := http.NewRequest("GET", st.ts.URL, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		res, err := tr.RoundTrip(req)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer res.Body.Close()
-		close(requestMade)
-		_, err = ioutil.ReadAll(res.Body)
-		if err == nil {
-			t.Error("expected error from res.Body.Read")
-		}
-	}()
-
-	<-requestMade
-	// Now force the serve loop to end, via closing the connection.
-	st.closeConn()
-	// deadlock? that's a bug.
-	select {
-	case <-done:
-	case <-time.After(3 * time.Second):
-		t.Fatal("timeout")
-	}
-}
-
-// TODO: merge this with TestTransportBody to make TestTransportRequest? This
-// could be a table-driven test with extra goodies.
-func TestTransportPath(t *testing.T) {
-	gotc := make(chan *url.URL, 1)
-	st := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			gotc <- r.URL
-		},
-		optOnlyServer,
-	)
-	defer st.Close()
-
-	tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-	defer tr.CloseIdleConnections()
-	const (
-		path  = "/testpath"
-		query = "q=1"
-	)
-	surl := st.ts.URL + path + "?" + query
-	req, err := http.NewRequest("POST", surl, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	c := &http.Client{Transport: tr}
-	res, err := c.Do(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer res.Body.Close()
-	got := <-gotc
-	if got.Path != path {
-		t.Errorf("Read Path = %q; want %q", got.Path, path)
-	}
-	if got.RawQuery != query {
-		t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query)
-	}
-}
-
-func randString(n int) string {
-	rnd := rand.New(rand.NewSource(int64(n)))
-	b := make([]byte, n)
-	for i := range b {
-		b[i] = byte(rnd.Intn(256))
-	}
-	return string(b)
-}
-
-var bodyTests = []struct {
-	body         string
-	noContentLen bool
-}{
-	{body: "some message"},
-	{body: "some message", noContentLen: true},
-	{body: ""},
-	{body: "", noContentLen: true},
-	{body: strings.Repeat("a", 1<<20), noContentLen: true},
-	{body: strings.Repeat("a", 1<<20)},
-	{body: randString(16<<10 - 1)},
-	{body: randString(16 << 10)},
-	{body: randString(16<<10 + 1)},
-	{body: randString(512<<10 - 1)},
-	{body: randString(512 << 10)},
-	{body: randString(512<<10 + 1)},
-	{body: randString(1<<20 - 1)},
-	{body: randString(1 << 20)},
-	{body: randString(1<<20 + 2)},
-}
-
-func TestTransportBody(t *testing.T) {
-	type reqInfo struct {
-		req   *http.Request
-		slurp []byte
-		err   error
-	}
-	gotc := make(chan reqInfo, 1)
-	st := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			slurp, err := ioutil.ReadAll(r.Body)
-			if err != nil {
-				gotc <- reqInfo{err: err}
-			} else {
-				gotc <- reqInfo{req: r, slurp: slurp}
-			}
-		},
-		optOnlyServer,
-	)
-	defer st.Close()
-
-	for i, tt := range bodyTests {
-		tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-		defer tr.CloseIdleConnections()
-
-		var body io.Reader = strings.NewReader(tt.body)
-		if tt.noContentLen {
-			body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods
-		}
-		req, err := http.NewRequest("POST", st.ts.URL, body)
-		if err != nil {
-			t.Fatalf("#%d: %v", i, err)
-		}
-		c := &http.Client{Transport: tr}
-		res, err := c.Do(req)
-		if err != nil {
-			t.Fatalf("#%d: %v", i, err)
-		}
-		defer res.Body.Close()
-		ri := <-gotc
-		if ri.err != nil {
-			t.Errorf("%#d: read error: %v", i, ri.err)
-			continue
-		}
-		if got := string(ri.slurp); got != tt.body {
-			t.Errorf("#%d: Read body mismatch.\n got: %q (len %d)\nwant: %q (len %d)", i, shortString(got), len(got), shortString(tt.body), len(tt.body))
-		}
-		wantLen := int64(len(tt.body))
-		if tt.noContentLen && tt.body != "" {
-			wantLen = -1
-		}
-		if ri.req.ContentLength != wantLen {
-			t.Errorf("#%d. handler got ContentLength = %v; want %v", i, ri.req.ContentLength, wantLen)
-		}
-	}
-}
-
-func shortString(v string) string {
-	const maxLen = 100
-	if len(v) <= maxLen {
-		return v
-	}
-	return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:])
-}
-
-func TestTransportDialTLS(t *testing.T) {
-	var mu sync.Mutex // guards following
-	var gotReq, didDial bool
-
-	ts := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			mu.Lock()
-			gotReq = true
-			mu.Unlock()
-		},
-		optOnlyServer,
-	)
-	defer ts.Close()
-	tr := &Transport{
-		DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
-			mu.Lock()
-			didDial = true
-			mu.Unlock()
-			cfg.InsecureSkipVerify = true
-			c, err := tls.Dial(netw, addr, cfg)
-			if err != nil {
-				return nil, err
-			}
-			return c, c.Handshake()
-		},
-	}
-	defer tr.CloseIdleConnections()
-	client := &http.Client{Transport: tr}
-	res, err := client.Get(ts.ts.URL)
-	if err != nil {
-		t.Fatal(err)
-	}
-	res.Body.Close()
-	mu.Lock()
-	if !gotReq {
-		t.Error("didn't get request")
-	}
-	if !didDial {
-		t.Error("didn't use dial hook")
-	}
-}
-
-func TestConfigureTransport(t *testing.T) {
-	t1 := &http.Transport{}
-	err := ConfigureTransport(t1)
-	if err == errTransportVersion {
-		t.Skip(err)
-	}
-	if err != nil {
-		t.Fatal(err)
-	}
-	if got := fmt.Sprintf("%#v", *t1); !strings.Contains(got, `"h2"`) {
-		// Laziness, to avoid buildtags.
-		t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got)
-	}
-	wantNextProtos := []string{"h2", "http/1.1"}
-	if t1.TLSClientConfig == nil {
-		t.Errorf("nil t1.TLSClientConfig")
-	} else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, wantNextProtos) {
-		t.Errorf("TLSClientConfig.NextProtos = %q; want %q", t1.TLSClientConfig.NextProtos, wantNextProtos)
-	}
-	if err := ConfigureTransport(t1); err == nil {
-		t.Error("unexpected success on second call to ConfigureTransport")
-	}
-
-	// And does it work?
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		io.WriteString(w, r.Proto)
-	}, optOnlyServer)
-	defer st.Close()
-
-	t1.TLSClientConfig.InsecureSkipVerify = true
-	c := &http.Client{Transport: t1}
-	res, err := c.Get(st.ts.URL)
-	if err != nil {
-		t.Fatal(err)
-	}
-	slurp, err := ioutil.ReadAll(res.Body)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if got, want := string(slurp), "HTTP/2.0"; got != want {
-		t.Errorf("body = %q; want %q", got, want)
-	}
-}
-
-type capitalizeReader struct {
-	r io.Reader
-}
-
-func (cr capitalizeReader) Read(p []byte) (n int, err error) {
-	n, err = cr.r.Read(p)
-	for i, b := range p[:n] {
-		if b >= 'a' && b <= 'z' {
-			p[i] = b - ('a' - 'A')
-		}
-	}
-	return
-}
-
-type flushWriter struct {
-	w io.Writer
-}
-
-func (fw flushWriter) Write(p []byte) (n int, err error) {
-	n, err = fw.w.Write(p)
-	if f, ok := fw.w.(http.Flusher); ok {
-		f.Flush()
-	}
-	return
-}
-
-type clientTester struct {
-	t      *testing.T
-	tr     *Transport
-	sc, cc net.Conn // server and client conn
-	fr     *Framer  // server's framer
-	client func() error
-	server func() error
-}
-
-func newClientTester(t *testing.T) *clientTester {
-	var dialOnce struct {
-		sync.Mutex
-		dialed bool
-	}
-	ct := &clientTester{
-		t: t,
-	}
-	ct.tr = &Transport{
-		TLSClientConfig: tlsConfigInsecure,
-		DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
-			dialOnce.Lock()
-			defer dialOnce.Unlock()
-			if dialOnce.dialed {
-				return nil, errors.New("only one dial allowed in test mode")
-			}
-			dialOnce.dialed = true
-			return ct.cc, nil
-		},
-	}
-
-	ln := newLocalListener(t)
-	cc, err := net.Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatal(err)
-
-	}
-	sc, err := ln.Accept()
-	if err != nil {
-		t.Fatal(err)
-	}
-	ln.Close()
-	ct.cc = cc
-	ct.sc = sc
-	ct.fr = NewFramer(sc, sc)
-	return ct
-}
-
-func newLocalListener(t *testing.T) net.Listener {
-	ln, err := net.Listen("tcp4", "127.0.0.1:0")
-	if err == nil {
-		return ln
-	}
-	ln, err = net.Listen("tcp6", "[::1]:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	return ln
-}
-
-func (ct *clientTester) greet() {
-	buf := make([]byte, len(ClientPreface))
-	_, err := io.ReadFull(ct.sc, buf)
-	if err != nil {
-		ct.t.Fatalf("reading client preface: %v", err)
-	}
-	f, err := ct.fr.ReadFrame()
-	if err != nil {
-		ct.t.Fatalf("Reading client settings frame: %v", err)
-	}
-	if sf, ok := f.(*SettingsFrame); !ok {
-		ct.t.Fatalf("Wanted client settings frame; got %v", f)
-		_ = sf // stash it away?
-	}
-	if err := ct.fr.WriteSettings(); err != nil {
-		ct.t.Fatal(err)
-	}
-	if err := ct.fr.WriteSettingsAck(); err != nil {
-		ct.t.Fatal(err)
-	}
-}
-
-func (ct *clientTester) cleanup() {
-	ct.tr.CloseIdleConnections()
-}
-
-func (ct *clientTester) run() {
-	errc := make(chan error, 2)
-	ct.start("client", errc, ct.client)
-	ct.start("server", errc, ct.server)
-	defer ct.cleanup()
-	for i := 0; i < 2; i++ {
-		if err := <-errc; err != nil {
-			ct.t.Error(err)
-			return
-		}
-	}
-}
-
-func (ct *clientTester) start(which string, errc chan<- error, fn func() error) {
-	go func() {
-		finished := false
-		var err error
-		defer func() {
-			if !finished {
-				err = fmt.Errorf("%s goroutine didn't finish.", which)
-			} else if err != nil {
-				err = fmt.Errorf("%s: %v", which, err)
-			}
-			errc <- err
-		}()
-		err = fn()
-		finished = true
-	}()
-}
-
-type countingReader struct {
-	n *int64
-}
-
-func (r countingReader) Read(p []byte) (n int, err error) {
-	for i := range p {
-		p[i] = byte(i)
-	}
-	atomic.AddInt64(r.n, int64(len(p)))
-	return len(p), err
-}
-
-func TestTransportReqBodyAfterResponse_200(t *testing.T) { testTransportReqBodyAfterResponse(t, 200) }
-func TestTransportReqBodyAfterResponse_403(t *testing.T) { testTransportReqBodyAfterResponse(t, 403) }
-
-func testTransportReqBodyAfterResponse(t *testing.T, status int) {
-	const bodySize = 10 << 20
-	ct := newClientTester(t)
-	ct.client = func() error {
-		var n int64 // atomic
-		req, err := http.NewRequest("PUT", "https://dummy.tld/", io.LimitReader(countingReader{&n}, bodySize))
-		if err != nil {
-			return err
-		}
-		res, err := ct.tr.RoundTrip(req)
-		if err != nil {
-			return fmt.Errorf("RoundTrip: %v", err)
-		}
-		defer res.Body.Close()
-		if res.StatusCode != status {
-			return fmt.Errorf("status code = %v; want %v", res.StatusCode, status)
-		}
-		slurp, err := ioutil.ReadAll(res.Body)
-		if err != nil {
-			return fmt.Errorf("Slurp: %v", err)
-		}
-		if len(slurp) > 0 {
-			return fmt.Errorf("unexpected body: %q", slurp)
-		}
-		if status == 200 {
-			if got := atomic.LoadInt64(&n); got != bodySize {
-				return fmt.Errorf("For 200 response, Transport wrote %d bytes; want %d", got, bodySize)
-			}
-		} else {
-			if got := atomic.LoadInt64(&n); got == 0 || got >= bodySize {
-				return fmt.Errorf("For %d response, Transport wrote %d bytes; want (0,%d) exclusive", status, got, bodySize)
-			}
-		}
-		return nil
-	}
-	ct.server = func() error {
-		ct.greet()
-		var buf bytes.Buffer
-		enc := hpack.NewEncoder(&buf)
-		var dataRecv int64
-		var closed bool
-		for {
-			f, err := ct.fr.ReadFrame()
-			if err != nil {
-				return err
-			}
-			//println(fmt.Sprintf("server got frame: %v", f))
-			switch f := f.(type) {
-			case *WindowUpdateFrame, *SettingsFrame:
-			case *HeadersFrame:
-				if !f.HeadersEnded() {
-					return fmt.Errorf("headers should have END_HEADERS be ended: %v", f)
-				}
-				if f.StreamEnded() {
-					return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f)
-				}
-				time.Sleep(50 * time.Millisecond) // let client send body
-				enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
-				ct.fr.WriteHeaders(HeadersFrameParam{
-					StreamID:      f.StreamID,
-					EndHeaders:    true,
-					EndStream:     false,
-					BlockFragment: buf.Bytes(),
-				})
-			case *DataFrame:
-				dataLen := len(f.Data())
-				dataRecv += int64(dataLen)
-				if dataLen > 0 {
-					if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
-						return err
-					}
-					if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
-						return err
-					}
-				}
-				if !closed && ((status != 200 && dataRecv > 0) ||
-					(status == 200 && dataRecv == bodySize)) {
-					closed = true
-					if err := ct.fr.WriteData(f.StreamID, true, nil); err != nil {
-						return err
-					}
-					return nil
-				}
-			default:
-				return fmt.Errorf("Unexpected client frame %v", f)
-			}
-		}
-		return nil
-	}
-	ct.run()
-}
-
-// See golang.org/issue/13444
-func TestTransportFullDuplex(t *testing.T) {
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		w.WriteHeader(200) // redundant but for clarity
-		w.(http.Flusher).Flush()
-		io.Copy(flushWriter{w}, capitalizeReader{r.Body})
-		fmt.Fprintf(w, "bye.\n")
-	}, optOnlyServer)
-	defer st.Close()
-
-	tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-	defer tr.CloseIdleConnections()
-	c := &http.Client{Transport: tr}
-
-	pr, pw := io.Pipe()
-	req, err := http.NewRequest("PUT", st.ts.URL, ioutil.NopCloser(pr))
-	if err != nil {
-		log.Fatal(err)
-	}
-	req.ContentLength = -1
-	res, err := c.Do(req)
-	if err != nil {
-		log.Fatal(err)
-	}
-	defer res.Body.Close()
-	if res.StatusCode != 200 {
-		t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200)
-	}
-	bs := bufio.NewScanner(res.Body)
-	want := func(v string) {
-		if !bs.Scan() {
-			t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err())
-		}
-	}
-	write := func(v string) {
-		_, err := io.WriteString(pw, v)
-		if err != nil {
-			t.Fatalf("pipe write: %v", err)
-		}
-	}
-	write("foo\n")
-	want("FOO")
-	write("bar\n")
-	want("BAR")
-	pw.Close()
-	want("bye.")
-	if err := bs.Err(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestTransportConnectRequest(t *testing.T) {
-	gotc := make(chan *http.Request, 1)
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		gotc <- r
-	}, optOnlyServer)
-	defer st.Close()
-
-	u, err := url.Parse(st.ts.URL)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-	defer tr.CloseIdleConnections()
-	c := &http.Client{Transport: tr}
-
-	tests := []struct {
-		req  *http.Request
-		want string
-	}{
-		{
-			req: &http.Request{
-				Method: "CONNECT",
-				Header: http.Header{},
-				URL:    u,
-			},
-			want: u.Host,
-		},
-		{
-			req: &http.Request{
-				Method: "CONNECT",
-				Header: http.Header{},
-				URL:    u,
-				Host:   "example.com:123",
-			},
-			want: "example.com:123",
-		},
-	}
-
-	for i, tt := range tests {
-		res, err := c.Do(tt.req)
-		if err != nil {
-			t.Errorf("%d. RoundTrip = %v", i, err)
-			continue
-		}
-		res.Body.Close()
-		req := <-gotc
-		if req.Method != "CONNECT" {
-			t.Errorf("method = %q; want CONNECT", req.Method)
-		}
-		if req.Host != tt.want {
-			t.Errorf("Host = %q; want %q", req.Host, tt.want)
-		}
-		if req.URL.Host != tt.want {
-			t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want)
-		}
-	}
-}
-
-type headerType int
-
-const (
-	noHeader headerType = iota // omitted
-	oneHeader
-	splitHeader // broken into continuation on purpose
-)
-
-const (
-	f0 = noHeader
-	f1 = oneHeader
-	f2 = splitHeader
-	d0 = false
-	d1 = true
-)
-
-// Test all 36 combinations of response frame orders:
-//    (3 ways of 100-continue) * (2 ways of headers) * (2 ways of data) * (3 ways of trailers):func TestTransportResponsePattern_00f0(t *testing.T) { testTransportResponsePattern(h0, h1, false, h0) }
-// Generated by http://play.golang.org/p/SScqYKJYXd
-func TestTransportResPattern_c0h1d0t0(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f0) }
-func TestTransportResPattern_c0h1d0t1(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f1) }
-func TestTransportResPattern_c0h1d0t2(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f2) }
-func TestTransportResPattern_c0h1d1t0(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f0) }
-func TestTransportResPattern_c0h1d1t1(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f1) }
-func TestTransportResPattern_c0h1d1t2(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f2) }
-func TestTransportResPattern_c0h2d0t0(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f0) }
-func TestTransportResPattern_c0h2d0t1(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f1) }
-func TestTransportResPattern_c0h2d0t2(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f2) }
-func TestTransportResPattern_c0h2d1t0(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f0) }
-func TestTransportResPattern_c0h2d1t1(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f1) }
-func TestTransportResPattern_c0h2d1t2(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f2) }
-func TestTransportResPattern_c1h1d0t0(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f0) }
-func TestTransportResPattern_c1h1d0t1(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f1) }
-func TestTransportResPattern_c1h1d0t2(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f2) }
-func TestTransportResPattern_c1h1d1t0(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f0) }
-func TestTransportResPattern_c1h1d1t1(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f1) }
-func TestTransportResPattern_c1h1d1t2(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f2) }
-func TestTransportResPattern_c1h2d0t0(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f0) }
-func TestTransportResPattern_c1h2d0t1(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f1) }
-func TestTransportResPattern_c1h2d0t2(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f2) }
-func TestTransportResPattern_c1h2d1t0(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f0) }
-func TestTransportResPattern_c1h2d1t1(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f1) }
-func TestTransportResPattern_c1h2d1t2(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f2) }
-func TestTransportResPattern_c2h1d0t0(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f0) }
-func TestTransportResPattern_c2h1d0t1(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f1) }
-func TestTransportResPattern_c2h1d0t2(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f2) }
-func TestTransportResPattern_c2h1d1t0(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f0) }
-func TestTransportResPattern_c2h1d1t1(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f1) }
-func TestTransportResPattern_c2h1d1t2(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f2) }
-func TestTransportResPattern_c2h2d0t0(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f0) }
-func TestTransportResPattern_c2h2d0t1(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f1) }
-func TestTransportResPattern_c2h2d0t2(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f2) }
-func TestTransportResPattern_c2h2d1t0(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f0) }
-func TestTransportResPattern_c2h2d1t1(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f1) }
-func TestTransportResPattern_c2h2d1t2(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f2) }
-
-func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) {
-	const reqBody = "some request body"
-	const resBody = "some response body"
-
-	if resHeader == noHeader {
-		// TODO: test 100-continue followed by immediate
-		// server stream reset, without headers in the middle?
-		panic("invalid combination")
-	}
-
-	ct := newClientTester(t)
-	ct.client = func() error {
-		req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(reqBody))
-		if expect100Continue != noHeader {
-			req.Header.Set("Expect", "100-continue")
-		}
-		res, err := ct.tr.RoundTrip(req)
-		if err != nil {
-			return fmt.Errorf("RoundTrip: %v", err)
-		}
-		defer res.Body.Close()
-		if res.StatusCode != 200 {
-			return fmt.Errorf("status code = %v; want 200", res.StatusCode)
-		}
-		slurp, err := ioutil.ReadAll(res.Body)
-		if err != nil {
-			return fmt.Errorf("Slurp: %v", err)
-		}
-		wantBody := resBody
-		if !withData {
-			wantBody = ""
-		}
-		if string(slurp) != wantBody {
-			return fmt.Errorf("body = %q; want %q", slurp, wantBody)
-		}
-		if trailers == noHeader {
-			if len(res.Trailer) > 0 {
-				t.Errorf("Trailer = %v; want none", res.Trailer)
-			}
-		} else {
-			want := http.Header{"Some-Trailer": {"some-value"}}
-			if !reflect.DeepEqual(res.Trailer, want) {
-				t.Errorf("Trailer = %v; want %v", res.Trailer, want)
-			}
-		}
-		return nil
-	}
-	ct.server = func() error {
-		ct.greet()
-		var buf bytes.Buffer
-		enc := hpack.NewEncoder(&buf)
-
-		for {
-			f, err := ct.fr.ReadFrame()
-			if err != nil {
-				return err
-			}
-			switch f := f.(type) {
-			case *WindowUpdateFrame, *SettingsFrame:
-			case *DataFrame:
-				// ignore for now.
-			case *HeadersFrame:
-				endStream := false
-				send := func(mode headerType) {
-					hbf := buf.Bytes()
-					switch mode {
-					case oneHeader:
-						ct.fr.WriteHeaders(HeadersFrameParam{
-							StreamID:      f.StreamID,
-							EndHeaders:    true,
-							EndStream:     endStream,
-							BlockFragment: hbf,
-						})
-					case splitHeader:
-						if len(hbf) < 2 {
-							panic("too small")
-						}
-						ct.fr.WriteHeaders(HeadersFrameParam{
-							StreamID:      f.StreamID,
-							EndHeaders:    false,
-							EndStream:     endStream,
-							BlockFragment: hbf[:1],
-						})
-						ct.fr.WriteContinuation(f.StreamID, true, hbf[1:])
-					default:
-						panic("bogus mode")
-					}
-				}
-				if expect100Continue != noHeader {
-					buf.Reset()
-					enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
-					send(expect100Continue)
-				}
-				// Response headers (1+ frames; 1 or 2 in this test, but never 0)
-				{
-					buf.Reset()
-					enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
-					enc.WriteField(hpack.HeaderField{Name: "x-foo", Value: "blah"})
-					enc.WriteField(hpack.HeaderField{Name: "x-bar", Value: "more"})
-					if trailers != noHeader {
-						enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "some-trailer"})
-					}
-					endStream = withData == false && trailers == noHeader
-					send(resHeader)
-				}
-				if withData {
-					endStream = trailers == noHeader
-					ct.fr.WriteData(f.StreamID, endStream, []byte(resBody))
-				}
-				if trailers != noHeader {
-					endStream = true
-					buf.Reset()
-					enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "some-value"})
-					send(trailers)
-				}
-				return nil
-			}
-		}
-	}
-	ct.run()
-}
-
-func TestTransportReceiveUndeclaredTrailer(t *testing.T) {
-	ct := newClientTester(t)
-	ct.client = func() error {
-		req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
-		res, err := ct.tr.RoundTrip(req)
-		if err != nil {
-			return fmt.Errorf("RoundTrip: %v", err)
-		}
-		defer res.Body.Close()
-		if res.StatusCode != 200 {
-			return fmt.Errorf("status code = %v; want 200", res.StatusCode)
-		}
-		slurp, err := ioutil.ReadAll(res.Body)
-		if err != nil {
-			return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, nil)
-		}
-		if len(slurp) > 0 {
-			return fmt.Errorf("body = %q; want nothing", slurp)
-		}
-		if _, ok := res.Trailer["Some-Trailer"]; !ok {
-			return fmt.Errorf("expected Some-Trailer")
-		}
-		return nil
-	}
-	ct.server = func() error {
-		ct.greet()
-
-		var n int
-		var hf *HeadersFrame
-		for hf == nil && n < 10 {
-			f, err := ct.fr.ReadFrame()
-			if err != nil {
-				return err
-			}
-			hf, _ = f.(*HeadersFrame)
-			n++
-		}
-
-		var buf bytes.Buffer
-		enc := hpack.NewEncoder(&buf)
-
-		// send headers without Trailer header
-		enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
-		ct.fr.WriteHeaders(HeadersFrameParam{
-			StreamID:      hf.StreamID,
-			EndHeaders:    true,
-			EndStream:     false,
-			BlockFragment: buf.Bytes(),
-		})
-
-		// send trailers
-		buf.Reset()
-		enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "I'm an undeclared Trailer!"})
-		ct.fr.WriteHeaders(HeadersFrameParam{
-			StreamID:      hf.StreamID,
-			EndHeaders:    true,
-			EndStream:     true,
-			BlockFragment: buf.Bytes(),
-		})
-		return nil
-	}
-	ct.run()
-}
-
-func TestTransportInvalidTrailer_Pseudo1(t *testing.T) {
-	testTransportInvalidTrailer_Pseudo(t, oneHeader)
-}
-func TestTransportInvalidTrailer_Pseudo2(t *testing.T) {
-	testTransportInvalidTrailer_Pseudo(t, splitHeader)
-}
-func testTransportInvalidTrailer_Pseudo(t *testing.T, trailers headerType) {
-	testInvalidTrailer(t, trailers, errPseudoTrailers, func(enc *hpack.Encoder) {
-		enc.WriteField(hpack.HeaderField{Name: ":colon", Value: "foo"})
-		enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
-	})
-}
-
-func TestTransportInvalidTrailer_Capital1(t *testing.T) {
-	testTransportInvalidTrailer_Capital(t, oneHeader)
-}
-func TestTransportInvalidTrailer_Capital2(t *testing.T) {
-	testTransportInvalidTrailer_Capital(t, splitHeader)
-}
-func testTransportInvalidTrailer_Capital(t *testing.T, trailers headerType) {
-	testInvalidTrailer(t, trailers, errInvalidHeaderFieldName, func(enc *hpack.Encoder) {
-		enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
-		enc.WriteField(hpack.HeaderField{Name: "Capital", Value: "bad"})
-	})
-}
-func TestTransportInvalidTrailer_EmptyFieldName(t *testing.T) {
-	testInvalidTrailer(t, oneHeader, errInvalidHeaderFieldName, func(enc *hpack.Encoder) {
-		enc.WriteField(hpack.HeaderField{Name: "", Value: "bad"})
-	})
-}
-func TestTransportInvalidTrailer_BinaryFieldValue(t *testing.T) {
-	testInvalidTrailer(t, oneHeader, errInvalidHeaderFieldValue, func(enc *hpack.Encoder) {
-		enc.WriteField(hpack.HeaderField{Name: "", Value: "has\nnewline"})
-	})
-}
-
-func testInvalidTrailer(t *testing.T, trailers headerType, wantErr error, writeTrailer func(*hpack.Encoder)) {
-	ct := newClientTester(t)
-	ct.client = func() error {
-		req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
-		res, err := ct.tr.RoundTrip(req)
-		if err != nil {
-			return fmt.Errorf("RoundTrip: %v", err)
-		}
-		defer res.Body.Close()
-		if res.StatusCode != 200 {
-			return fmt.Errorf("status code = %v; want 200", res.StatusCode)
-		}
-		slurp, err := ioutil.ReadAll(res.Body)
-		if err != wantErr {
-			return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, wantErr)
-		}
-		if len(slurp) > 0 {
-			return fmt.Errorf("body = %q; want nothing", slurp)
-		}
-		return nil
-	}
-	ct.server = func() error {
-		ct.greet()
-		var buf bytes.Buffer
-		enc := hpack.NewEncoder(&buf)
-
-		for {
-			f, err := ct.fr.ReadFrame()
-			if err != nil {
-				return err
-			}
-			switch f := f.(type) {
-			case *HeadersFrame:
-				var endStream bool
-				send := func(mode headerType) {
-					hbf := buf.Bytes()
-					switch mode {
-					case oneHeader:
-						ct.fr.WriteHeaders(HeadersFrameParam{
-							StreamID:      f.StreamID,
-							EndHeaders:    true,
-							EndStream:     endStream,
-							BlockFragment: hbf,
-						})
-					case splitHeader:
-						if len(hbf) < 2 {
-							panic("too small")
-						}
-						ct.fr.WriteHeaders(HeadersFrameParam{
-							StreamID:      f.StreamID,
-							EndHeaders:    false,
-							EndStream:     endStream,
-							BlockFragment: hbf[:1],
-						})
-						ct.fr.WriteContinuation(f.StreamID, true, hbf[1:])
-					default:
-						panic("bogus mode")
-					}
-				}
-				// Response headers (1+ frames; 1 or 2 in this test, but never 0)
-				{
-					buf.Reset()
-					enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
-					enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "declared"})
-					endStream = false
-					send(oneHeader)
-				}
-				// Trailers:
-				{
-					endStream = true
-					buf.Reset()
-					writeTrailer(enc)
-					send(trailers)
-				}
-				return nil
-			}
-		}
-	}
-	ct.run()
-}
-
-func TestTransportChecksResponseHeaderListSize(t *testing.T) {
-	ct := newClientTester(t)
-	ct.client = func() error {
-		req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
-		res, err := ct.tr.RoundTrip(req)
-		if err != errResponseHeaderListSize {
-			if res != nil {
-				res.Body.Close()
-			}
-			size := int64(0)
-			for k, vv := range res.Header {
-				for _, v := range vv {
-					size += int64(len(k)) + int64(len(v)) + 32
-				}
-			}
-			return fmt.Errorf("RoundTrip Error = %v (and %d bytes of response headers); want errResponseHeaderListSize", err, size)
-		}
-		return nil
-	}
-	ct.server = func() error {
-		ct.greet()
-		var buf bytes.Buffer
-		enc := hpack.NewEncoder(&buf)
-
-		for {
-			f, err := ct.fr.ReadFrame()
-			if err != nil {
-				return err
-			}
-			switch f := f.(type) {
-			case *HeadersFrame:
-				enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
-				large := strings.Repeat("a", 1<<10)
-				for i := 0; i < 5042; i++ {
-					enc.WriteField(hpack.HeaderField{Name: large, Value: large})
-				}
-				if size, want := buf.Len(), 6329; size != want {
-					// Note: this number might change if
-					// our hpack implementation
-					// changes. That's fine. This is
-					// just a sanity check that our
-					// response can fit in a single
-					// header block fragment frame.
-					return fmt.Errorf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want)
-				}
-				ct.fr.WriteHeaders(HeadersFrameParam{
-					StreamID:      f.StreamID,
-					EndHeaders:    true,
-					EndStream:     true,
-					BlockFragment: buf.Bytes(),
-				})
-				return nil
-			}
-		}
-	}
-	ct.run()
-}
-
-// Test that the the Transport returns a typed error from Response.Body.Read calls
-// when the server sends an error. (here we use a panic, since that should generate
-// a stream error, but others like cancel should be similar)
-func TestTransportBodyReadErrorType(t *testing.T) {
-	doPanic := make(chan bool, 1)
-	st := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			w.(http.Flusher).Flush() // force headers out
-			<-doPanic
-			panic("boom")
-		},
-		optOnlyServer,
-		optQuiet,
-	)
-	defer st.Close()
-
-	tr := &Transport{TLSClientConfig: tlsConfigInsecure}
-	defer tr.CloseIdleConnections()
-	c := &http.Client{Transport: tr}
-
-	res, err := c.Get(st.ts.URL)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer res.Body.Close()
-	doPanic <- true
-	buf := make([]byte, 100)
-	n, err := res.Body.Read(buf)
-	want := StreamError{StreamID: 0x1, Code: 0x2}
-	if !reflect.DeepEqual(want, err) {
-		t.Errorf("Read = %v, %#v; want error %#v", n, err, want)
-	}
-}
-
-// golang.org/issue/13924
-// This used to fail after many iterations, especially with -race:
-// go test -v -run=TestTransportDoubleCloseOnWriteError -count=500 -race
-func TestTransportDoubleCloseOnWriteError(t *testing.T) {
-	var (
-		mu   sync.Mutex
-		conn net.Conn // to close if set
-	)
-
-	st := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			mu.Lock()
-			defer mu.Unlock()
-			if conn != nil {
-				conn.Close()
-			}
-		},
-		optOnlyServer,
-	)
-	defer st.Close()
-
-	tr := &Transport{
-		TLSClientConfig: tlsConfigInsecure,
-		DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
-			tc, err := tls.Dial(network, addr, cfg)
-			if err != nil {
-				return nil, err
-			}
-			mu.Lock()
-			defer mu.Unlock()
-			conn = tc
-			return tc, nil
-		},
-	}
-	defer tr.CloseIdleConnections()
-	c := &http.Client{Transport: tr}
-	c.Get(st.ts.URL)
-}
-
-// Test that the http1 Transport.DisableKeepAlives option is respected
-// and connections are closed as soon as idle.
-// See golang.org/issue/14008
-func TestTransportDisableKeepAlives(t *testing.T) {
-	st := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			io.WriteString(w, "hi")
-		},
-		optOnlyServer,
-	)
-	defer st.Close()
-
-	connClosed := make(chan struct{}) // closed on tls.Conn.Close
-	tr := &Transport{
-		t1: &http.Transport{
-			DisableKeepAlives: true,
-		},
-		TLSClientConfig: tlsConfigInsecure,
-		DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
-			tc, err := tls.Dial(network, addr, cfg)
-			if err != nil {
-				return nil, err
-			}
-			return &noteCloseConn{Conn: tc, closefn: func() { close(connClosed) }}, nil
-		},
-	}
-	c := &http.Client{Transport: tr}
-	res, err := c.Get(st.ts.URL)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if _, err := ioutil.ReadAll(res.Body); err != nil {
-		t.Fatal(err)
-	}
-	defer res.Body.Close()
-
-	select {
-	case <-connClosed:
-	case <-time.After(1 * time.Second):
-		t.Errorf("timeout")
-	}
-
-}
-
-// Test concurrent requests with Transport.DisableKeepAlives. We can share connections,
-// but when things are totally idle, it still needs to close.
-func TestTransportDisableKeepAlives_Concurrency(t *testing.T) {
-	const D = 25 * time.Millisecond
-	st := newServerTester(t,
-		func(w http.ResponseWriter, r *http.Request) {
-			time.Sleep(D)
-			io.WriteString(w, "hi")
-		},
-		optOnlyServer,
-	)
-	defer st.Close()
-
-	var dials int32
-	var conns sync.WaitGroup
-	tr := &Transport{
-		t1: &http.Transport{
-			DisableKeepAlives: true,
-		},
-		TLSClientConfig: tlsConfigInsecure,
-		DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
-			tc, err := tls.Dial(network, addr, cfg)
-			if err != nil {
-				return nil, err
-			}
-			atomic.AddInt32(&dials, 1)
-			conns.Add(1)
-			return &noteCloseConn{Conn: tc, closefn: func() { conns.Done() }}, nil
-		},
-	}
-	c := &http.Client{Transport: tr}
-	var reqs sync.WaitGroup
-	const N = 20
-	for i := 0; i < N; i++ {
-		reqs.Add(1)
-		if i == N-1 {
-			// For the final request, try to make all the
-			// others close. This isn't verified in the
-			// count, other than the Log statement, since
-			// it's so timing dependent. This test is
-			// really to make sure we don't interrupt a
-			// valid request.
-			time.Sleep(D * 2)
-		}
-		go func() {
-			defer reqs.Done()
-			res, err := c.Get(st.ts.URL)
-			if err != nil {
-				t.Error(err)
-				return
-			}
-			if _, err := ioutil.ReadAll(res.Body); err != nil {
-				t.Error(err)
-				return
-			}
-			res.Body.Close()
-		}()
-	}
-	reqs.Wait()
-	conns.Wait()
-	t.Logf("did %d dials, %d requests", atomic.LoadInt32(&dials), N)
-}
-
-type noteCloseConn struct {
-	net.Conn
-	onceClose sync.Once
-	closefn   func()
-}
-
-func (c *noteCloseConn) Close() error {
-	c.onceClose.Do(c.closefn)
-	return c.Conn.Close()
-}
-
-func isTimeout(err error) bool {
-	switch err := err.(type) {
-	case nil:
-		return false
-	case *url.Error:
-		return isTimeout(err.Err)
-	case net.Error:
-		return err.Timeout()
-	}
-	return false
-}
-
-// Test that the http1 Transport.ResponseHeaderTimeout option and cancel is sent.
-func TestTransportResponseHeaderTimeout_NoBody(t *testing.T) {
-	testTransportResponseHeaderTimeout(t, false)
-}
-func TestTransportResponseHeaderTimeout_Body(t *testing.T) {
-	testTransportResponseHeaderTimeout(t, true)
-}
-
-func testTransportResponseHeaderTimeout(t *testing.T, body bool) {
-	ct := newClientTester(t)
-	ct.tr.t1 = &http.Transport{
-		ResponseHeaderTimeout: 5 * time.Millisecond,
-	}
-	ct.client = func() error {
-		c := &http.Client{Transport: ct.tr}
-		var err error
-		var n int64
-		const bodySize = 4 << 20
-		if body {
-			_, err = c.Post("https://dummy.tld/", "text/foo", io.LimitReader(countingReader{&n}, bodySize))
-		} else {
-			_, err = c.Get("https://dummy.tld/")
-		}
-		if !isTimeout(err) {
-			t.Errorf("client expected timeout error; got %#v", err)
-		}
-		if body && n != bodySize {
-			t.Errorf("only read %d bytes of body; want %d", n, bodySize)
-		}
-		return nil
-	}
-	ct.server = func() error {
-		ct.greet()
-		for {
-			f, err := ct.fr.ReadFrame()
-			if err != nil {
-				t.Logf("ReadFrame: %v", err)
-				return nil
-			}
-			switch f := f.(type) {
-			case *DataFrame:
-				dataLen := len(f.Data())
-				if dataLen > 0 {
-					if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
-						return err
-					}
-					if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
-						return err
-					}
-				}
-			case *RSTStreamFrame:
-				if f.StreamID == 1 && f.ErrCode == ErrCodeCancel {
-					return nil
-				}
-			}
-		}
-		return nil
-	}
-	ct.run()
-}
-
-func TestTransportDisableCompression(t *testing.T) {
-	const body = "sup"
-	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		want := http.Header{
-			"User-Agent": []string{"Go-http-client/2.0"},
-		}
-		if !reflect.DeepEqual(r.Header, want) {
-			t.Errorf("request headers = %v; want %v", r.Header, want)
-		}
-	}, optOnlyServer)
-	defer st.Close()
-
-	tr := &Transport{
-		TLSClientConfig: tlsConfigInsecure,
-		t1: &http.Transport{
-			DisableCompression: true,
-		},
-	}
-	defer tr.CloseIdleConnections()
-
-	req, err := http.NewRequest("GET", st.ts.URL, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	res, err := tr.RoundTrip(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer res.Body.Close()
-}

+ 10 - 0
Godeps/_workspace/src/golang.org/x/net/http2/write.go

@@ -241,8 +241,18 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
 	for _, k := range keys {
 		vv := h[k]
 		k = lowerHeader(k)
+		if !validHeaderFieldName(k) {
+			// TODO: return an error? golang.org/issue/14048
+			// For now just omit it.
+			continue
+		}
 		isTE := k == "transfer-encoding"
 		for _, v := range vv {
+			if !validHeaderFieldValue(v) {
+				// TODO: return an error? golang.org/issue/14048
+				// For now just omit it.
+				continue
+			}
 			// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
 			if isTE && v != "trailers" {
 				continue

+ 0 - 356
Godeps/_workspace/src/golang.org/x/net/http2/z_spec_test.go

@@ -1,356 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package http2
-
-import (
-	"bytes"
-	"encoding/xml"
-	"flag"
-	"fmt"
-	"io"
-	"os"
-	"reflect"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-	"sync"
-	"testing"
-)
-
-var coverSpec = flag.Bool("coverspec", false, "Run spec coverage tests")
-
-// The global map of sentence coverage for the http2 spec.
-var defaultSpecCoverage specCoverage
-
-var loadSpecOnce sync.Once
-
-func loadSpec() {
-	if f, err := os.Open("testdata/draft-ietf-httpbis-http2.xml"); err != nil {
-		panic(err)
-	} else {
-		defaultSpecCoverage = readSpecCov(f)
-		f.Close()
-	}
-}
-
-// covers marks all sentences for section sec in defaultSpecCoverage. Sentences not
-// "covered" will be included in report outputed by TestSpecCoverage.
-func covers(sec, sentences string) {
-	loadSpecOnce.Do(loadSpec)
-	defaultSpecCoverage.cover(sec, sentences)
-}
-
-type specPart struct {
-	section  string
-	sentence string
-}
-
-func (ss specPart) Less(oo specPart) bool {
-	atoi := func(s string) int {
-		n, err := strconv.Atoi(s)
-		if err != nil {
-			panic(err)
-		}
-		return n
-	}
-	a := strings.Split(ss.section, ".")
-	b := strings.Split(oo.section, ".")
-	for len(a) > 0 {
-		if len(b) == 0 {
-			return false
-		}
-		x, y := atoi(a[0]), atoi(b[0])
-		if x == y {
-			a, b = a[1:], b[1:]
-			continue
-		}
-		return x < y
-	}
-	if len(b) > 0 {
-		return true
-	}
-	return false
-}
-
-type bySpecSection []specPart
-
-func (a bySpecSection) Len() int           { return len(a) }
-func (a bySpecSection) Less(i, j int) bool { return a[i].Less(a[j]) }
-func (a bySpecSection) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
-
-type specCoverage struct {
-	coverage map[specPart]bool
-	d        *xml.Decoder
-}
-
-func joinSection(sec []int) string {
-	s := fmt.Sprintf("%d", sec[0])
-	for _, n := range sec[1:] {
-		s = fmt.Sprintf("%s.%d", s, n)
-	}
-	return s
-}
-
-func (sc specCoverage) readSection(sec []int) {
-	var (
-		buf = new(bytes.Buffer)
-		sub = 0
-	)
-	for {
-		tk, err := sc.d.Token()
-		if err != nil {
-			if err == io.EOF {
-				return
-			}
-			panic(err)
-		}
-		switch v := tk.(type) {
-		case xml.StartElement:
-			if skipElement(v) {
-				if err := sc.d.Skip(); err != nil {
-					panic(err)
-				}
-				if v.Name.Local == "section" {
-					sub++
-				}
-				break
-			}
-			switch v.Name.Local {
-			case "section":
-				sub++
-				sc.readSection(append(sec, sub))
-			case "xref":
-				buf.Write(sc.readXRef(v))
-			}
-		case xml.CharData:
-			if len(sec) == 0 {
-				break
-			}
-			buf.Write(v)
-		case xml.EndElement:
-			if v.Name.Local == "section" {
-				sc.addSentences(joinSection(sec), buf.String())
-				return
-			}
-		}
-	}
-}
-
-func (sc specCoverage) readXRef(se xml.StartElement) []byte {
-	var b []byte
-	for {
-		tk, err := sc.d.Token()
-		if err != nil {
-			panic(err)
-		}
-		switch v := tk.(type) {
-		case xml.CharData:
-			if b != nil {
-				panic("unexpected CharData")
-			}
-			b = []byte(string(v))
-		case xml.EndElement:
-			if v.Name.Local != "xref" {
-				panic("expected </xref>")
-			}
-			if b != nil {
-				return b
-			}
-			sig := attrSig(se)
-			switch sig {
-			case "target":
-				return []byte(fmt.Sprintf("[%s]", attrValue(se, "target")))
-			case "fmt-of,rel,target", "fmt-,,rel,target":
-				return []byte(fmt.Sprintf("[%s, %s]", attrValue(se, "target"), attrValue(se, "rel")))
-			case "fmt-of,sec,target", "fmt-,,sec,target":
-				return []byte(fmt.Sprintf("[section %s of %s]", attrValue(se, "sec"), attrValue(se, "target")))
-			case "fmt-of,rel,sec,target":
-				return []byte(fmt.Sprintf("[section %s of %s, %s]", attrValue(se, "sec"), attrValue(se, "target"), attrValue(se, "rel")))
-			default:
-				panic(fmt.Sprintf("unknown attribute signature %q in %#v", sig, fmt.Sprintf("%#v", se)))
-			}
-		default:
-			panic(fmt.Sprintf("unexpected tag %q", v))
-		}
-	}
-}
-
-var skipAnchor = map[string]bool{
-	"intro":    true,
-	"Overview": true,
-}
-
-var skipTitle = map[string]bool{
-	"Acknowledgements":            true,
-	"Change Log":                  true,
-	"Document Organization":       true,
-	"Conventions and Terminology": true,
-}
-
-func skipElement(s xml.StartElement) bool {
-	switch s.Name.Local {
-	case "artwork":
-		return true
-	case "section":
-		for _, attr := range s.Attr {
-			switch attr.Name.Local {
-			case "anchor":
-				if skipAnchor[attr.Value] || strings.HasPrefix(attr.Value, "changes.since.") {
-					return true
-				}
-			case "title":
-				if skipTitle[attr.Value] {
-					return true
-				}
-			}
-		}
-	}
-	return false
-}
-
-func readSpecCov(r io.Reader) specCoverage {
-	sc := specCoverage{
-		coverage: map[specPart]bool{},
-		d:        xml.NewDecoder(r)}
-	sc.readSection(nil)
-	return sc
-}
-
-func (sc specCoverage) addSentences(sec string, sentence string) {
-	for _, s := range parseSentences(sentence) {
-		sc.coverage[specPart{sec, s}] = false
-	}
-}
-
-func (sc specCoverage) cover(sec string, sentence string) {
-	for _, s := range parseSentences(sentence) {
-		p := specPart{sec, s}
-		if _, ok := sc.coverage[p]; !ok {
-			panic(fmt.Sprintf("Not found in spec: %q, %q", sec, s))
-		}
-		sc.coverage[specPart{sec, s}] = true
-	}
-
-}
-
-var whitespaceRx = regexp.MustCompile(`\s+`)
-
-func parseSentences(sens string) []string {
-	sens = strings.TrimSpace(sens)
-	if sens == "" {
-		return nil
-	}
-	ss := strings.Split(whitespaceRx.ReplaceAllString(sens, " "), ". ")
-	for i, s := range ss {
-		s = strings.TrimSpace(s)
-		if !strings.HasSuffix(s, ".") {
-			s += "."
-		}
-		ss[i] = s
-	}
-	return ss
-}
-
-func TestSpecParseSentences(t *testing.T) {
-	tests := []struct {
-		ss   string
-		want []string
-	}{
-		{"Sentence 1. Sentence 2.",
-			[]string{
-				"Sentence 1.",
-				"Sentence 2.",
-			}},
-		{"Sentence 1.  \nSentence 2.\tSentence 3.",
-			[]string{
-				"Sentence 1.",
-				"Sentence 2.",
-				"Sentence 3.",
-			}},
-	}
-
-	for i, tt := range tests {
-		got := parseSentences(tt.ss)
-		if !reflect.DeepEqual(got, tt.want) {
-			t.Errorf("%d: got = %q, want %q", i, got, tt.want)
-		}
-	}
-}
-
-func TestSpecCoverage(t *testing.T) {
-	if !*coverSpec {
-		t.Skip()
-	}
-
-	loadSpecOnce.Do(loadSpec)
-
-	var (
-		list     []specPart
-		cv       = defaultSpecCoverage.coverage
-		total    = len(cv)
-		complete = 0
-	)
-
-	for sp, touched := range defaultSpecCoverage.coverage {
-		if touched {
-			complete++
-		} else {
-			list = append(list, sp)
-		}
-	}
-	sort.Stable(bySpecSection(list))
-
-	if testing.Short() && len(list) > 5 {
-		list = list[:5]
-	}
-
-	for _, p := range list {
-		t.Errorf("\tSECTION %s: %s", p.section, p.sentence)
-	}
-
-	t.Logf("%d/%d (%d%%) sentances covered", complete, total, (complete/total)*100)
-}
-
-func attrSig(se xml.StartElement) string {
-	var names []string
-	for _, attr := range se.Attr {
-		if attr.Name.Local == "fmt" {
-			names = append(names, "fmt-"+attr.Value)
-		} else {
-			names = append(names, attr.Name.Local)
-		}
-	}
-	sort.Strings(names)
-	return strings.Join(names, ",")
-}
-
-func attrValue(se xml.StartElement, attr string) string {
-	for _, a := range se.Attr {
-		if a.Name.Local == attr {
-			return a.Value
-		}
-	}
-	panic("unknown attribute " + attr)
-}
-
-func TestSpecPartLess(t *testing.T) {
-	tests := []struct {
-		sec1, sec2 string
-		want       bool
-	}{
-		{"6.2.1", "6.2", false},
-		{"6.2", "6.2.1", true},
-		{"6.10", "6.10.1", true},
-		{"6.10", "6.1.1", false}, // 10, not 1
-		{"6.1", "6.1", false},    // equal, so not less
-	}
-	for _, tt := range tests {
-		got := (specPart{tt.sec1, "foo"}).Less(specPart{tt.sec2, "foo"})
-		if got != tt.want {
-			t.Errorf("Less(%q, %q) = %v; want %v", tt.sec1, tt.sec2, got, tt.want)
-		}
-	}
-}

+ 0 - 170
Godeps/_workspace/src/golang.org/x/net/internal/timeseries/timeseries_test.go

@@ -1,170 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package timeseries
-
-import (
-	"math"
-	"testing"
-	"time"
-)
-
-func isNear(x *Float, y float64, tolerance float64) bool {
-	return math.Abs(x.Value()-y) < tolerance
-}
-
-func isApproximate(x *Float, y float64) bool {
-	return isNear(x, y, 1e-2)
-}
-
-func checkApproximate(t *testing.T, o Observable, y float64) {
-	x := o.(*Float)
-	if !isApproximate(x, y) {
-		t.Errorf("Wanted %g, got %g", y, x.Value())
-	}
-}
-
-func checkNear(t *testing.T, o Observable, y, tolerance float64) {
-	x := o.(*Float)
-	if !isNear(x, y, tolerance) {
-		t.Errorf("Wanted %g +- %g, got %g", y, tolerance, x.Value())
-	}
-}
-
-var baseTime = time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC)
-
-func tu(s int64) time.Time {
-	return baseTime.Add(time.Duration(s) * time.Second)
-}
-
-func tu2(s int64, ns int64) time.Time {
-	return baseTime.Add(time.Duration(s)*time.Second + time.Duration(ns)*time.Nanosecond)
-}
-
-func TestBasicTimeSeries(t *testing.T) {
-	ts := NewTimeSeries(NewFloat)
-	fo := new(Float)
-	*fo = Float(10)
-	ts.AddWithTime(fo, tu(1))
-	ts.AddWithTime(fo, tu(1))
-	ts.AddWithTime(fo, tu(1))
-	ts.AddWithTime(fo, tu(1))
-	checkApproximate(t, ts.Range(tu(0), tu(1)), 40)
-	checkApproximate(t, ts.Total(), 40)
-	ts.AddWithTime(fo, tu(3))
-	ts.AddWithTime(fo, tu(3))
-	ts.AddWithTime(fo, tu(3))
-	checkApproximate(t, ts.Range(tu(0), tu(2)), 40)
-	checkApproximate(t, ts.Range(tu(2), tu(4)), 30)
-	checkApproximate(t, ts.Total(), 70)
-	ts.AddWithTime(fo, tu(1))
-	ts.AddWithTime(fo, tu(1))
-	checkApproximate(t, ts.Range(tu(0), tu(2)), 60)
-	checkApproximate(t, ts.Range(tu(2), tu(4)), 30)
-	checkApproximate(t, ts.Total(), 90)
-	*fo = Float(100)
-	ts.AddWithTime(fo, tu(100))
-	checkApproximate(t, ts.Range(tu(99), tu(100)), 100)
-	checkApproximate(t, ts.Range(tu(0), tu(4)), 36)
-	checkApproximate(t, ts.Total(), 190)
-	*fo = Float(10)
-	ts.AddWithTime(fo, tu(1))
-	ts.AddWithTime(fo, tu(1))
-	checkApproximate(t, ts.Range(tu(0), tu(4)), 44)
-	checkApproximate(t, ts.Range(tu(37), tu2(100, 100e6)), 100)
-	checkApproximate(t, ts.Range(tu(50), tu2(100, 100e6)), 100)
-	checkApproximate(t, ts.Range(tu(99), tu2(100, 100e6)), 100)
-	checkApproximate(t, ts.Total(), 210)
-
-	for i, l := range ts.ComputeRange(tu(36), tu(100), 64) {
-		if i == 63 {
-			checkApproximate(t, l, 100)
-		} else {
-			checkApproximate(t, l, 0)
-		}
-	}
-
-	checkApproximate(t, ts.Range(tu(0), tu(100)), 210)
-	checkApproximate(t, ts.Range(tu(10), tu(100)), 100)
-
-	for i, l := range ts.ComputeRange(tu(0), tu(100), 100) {
-		if i < 10 {
-			checkApproximate(t, l, 11)
-		} else if i >= 90 {
-			checkApproximate(t, l, 10)
-		} else {
-			checkApproximate(t, l, 0)
-		}
-	}
-}
-
-func TestFloat(t *testing.T) {
-	f := Float(1)
-	if g, w := f.String(), "1"; g != w {
-		t.Errorf("Float(1).String = %q; want %q", g, w)
-	}
-	f2 := Float(2)
-	var o Observable = &f2
-	f.Add(o)
-	if g, w := f.Value(), 3.0; g != w {
-		t.Errorf("Float post-add = %v; want %v", g, w)
-	}
-	f.Multiply(2)
-	if g, w := f.Value(), 6.0; g != w {
-		t.Errorf("Float post-multiply = %v; want %v", g, w)
-	}
-	f.Clear()
-	if g, w := f.Value(), 0.0; g != w {
-		t.Errorf("Float post-clear = %v; want %v", g, w)
-	}
-	f.CopyFrom(&f2)
-	if g, w := f.Value(), 2.0; g != w {
-		t.Errorf("Float post-CopyFrom = %v; want %v", g, w)
-	}
-}
-
-type mockClock struct {
-	time time.Time
-}
-
-func (m *mockClock) Time() time.Time { return m.time }
-func (m *mockClock) Set(t time.Time) { m.time = t }
-
-const buckets = 6
-
-var testResolutions = []time.Duration{
-	10 * time.Second,  // level holds one minute of observations
-	100 * time.Second, // level holds ten minutes of observations
-	10 * time.Minute,  // level holds one hour of observations
-}
-
-// TestTimeSeries uses a small number of buckets to force a higher
-// error rate on approximations from the timeseries.
-type TestTimeSeries struct {
-	timeSeries
-}
-
-func TestExpectedErrorRate(t *testing.T) {
-	ts := new(TestTimeSeries)
-	fake := new(mockClock)
-	fake.Set(time.Now())
-	ts.timeSeries.init(testResolutions, NewFloat, buckets, fake)
-	for i := 1; i <= 61*61; i++ {
-		fake.Set(fake.Time().Add(1 * time.Second))
-		ob := Float(1)
-		ts.AddWithTime(&ob, fake.Time())
-
-		// The results should be accurate within one missing bucket (1/6) of the observations recorded.
-		checkNear(t, ts.Latest(0, buckets), min(float64(i), 60), 10)
-		checkNear(t, ts.Latest(1, buckets), min(float64(i), 600), 100)
-		checkNear(t, ts.Latest(2, buckets), min(float64(i), 3600), 600)
-	}
-}
-
-func min(a, b float64) float64 {
-	if a < b {
-		return a
-	}
-	return b
-}

+ 0 - 325
Godeps/_workspace/src/golang.org/x/net/trace/histogram_test.go

@@ -1,325 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package trace
-
-import (
-	"math"
-	"testing"
-)
-
-type sumTest struct {
-	value        int64
-	sum          int64
-	sumOfSquares float64
-	total        int64
-}
-
-var sumTests = []sumTest{
-	{100, 100, 10000, 1},
-	{50, 150, 12500, 2},
-	{50, 200, 15000, 3},
-	{50, 250, 17500, 4},
-}
-
-type bucketingTest struct {
-	in     int64
-	log    int
-	bucket int
-}
-
-var bucketingTests = []bucketingTest{
-	{0, 0, 0},
-	{1, 1, 0},
-	{2, 2, 1},
-	{3, 2, 1},
-	{4, 3, 2},
-	{1000, 10, 9},
-	{1023, 10, 9},
-	{1024, 11, 10},
-	{1000000, 20, 19},
-}
-
-type multiplyTest struct {
-	in                   int64
-	ratio                float64
-	expectedSum          int64
-	expectedTotal        int64
-	expectedSumOfSquares float64
-}
-
-var multiplyTests = []multiplyTest{
-	{15, 2.5, 37, 2, 562.5},
-	{128, 4.6, 758, 13, 77953.9},
-}
-
-type percentileTest struct {
-	fraction float64
-	expected int64
-}
-
-var percentileTests = []percentileTest{
-	{0.25, 48},
-	{0.5, 96},
-	{0.6, 109},
-	{0.75, 128},
-	{0.90, 205},
-	{0.95, 230},
-	{0.99, 256},
-}
-
-func TestSum(t *testing.T) {
-	var h histogram
-
-	for _, test := range sumTests {
-		h.addMeasurement(test.value)
-		sum := h.sum
-		if sum != test.sum {
-			t.Errorf("h.Sum = %v WANT: %v", sum, test.sum)
-		}
-
-		sumOfSquares := h.sumOfSquares
-		if sumOfSquares != test.sumOfSquares {
-			t.Errorf("h.SumOfSquares = %v WANT: %v", sumOfSquares, test.sumOfSquares)
-		}
-
-		total := h.total()
-		if total != test.total {
-			t.Errorf("h.Total = %v WANT: %v", total, test.total)
-		}
-	}
-}
-
-func TestMultiply(t *testing.T) {
-	var h histogram
-	for i, test := range multiplyTests {
-		h.addMeasurement(test.in)
-		h.Multiply(test.ratio)
-		if h.sum != test.expectedSum {
-			t.Errorf("#%v: h.sum = %v WANT: %v", i, h.sum, test.expectedSum)
-		}
-		if h.total() != test.expectedTotal {
-			t.Errorf("#%v: h.total = %v WANT: %v", i, h.total(), test.expectedTotal)
-		}
-		if h.sumOfSquares != test.expectedSumOfSquares {
-			t.Errorf("#%v: h.SumOfSquares = %v WANT: %v", i, test.expectedSumOfSquares, h.sumOfSquares)
-		}
-	}
-}
-
-func TestBucketingFunctions(t *testing.T) {
-	for _, test := range bucketingTests {
-		log := log2(test.in)
-		if log != test.log {
-			t.Errorf("log2 = %v WANT: %v", log, test.log)
-		}
-
-		bucket := getBucket(test.in)
-		if bucket != test.bucket {
-			t.Errorf("getBucket = %v WANT: %v", bucket, test.bucket)
-		}
-	}
-}
-
-func TestAverage(t *testing.T) {
-	a := new(histogram)
-	average := a.average()
-	if average != 0 {
-		t.Errorf("Average of empty histogram was %v WANT: 0", average)
-	}
-
-	a.addMeasurement(1)
-	a.addMeasurement(1)
-	a.addMeasurement(3)
-	const expected = float64(5) / float64(3)
-	average = a.average()
-
-	if !isApproximate(average, expected) {
-		t.Errorf("Average = %g WANT: %v", average, expected)
-	}
-}
-
-func TestStandardDeviation(t *testing.T) {
-	a := new(histogram)
-	add(a, 10, 1<<4)
-	add(a, 10, 1<<5)
-	add(a, 10, 1<<6)
-	stdDev := a.standardDeviation()
-	const expected = 19.95
-
-	if !isApproximate(stdDev, expected) {
-		t.Errorf("StandardDeviation = %v WANT: %v", stdDev, expected)
-	}
-
-	// No values
-	a = new(histogram)
-	stdDev = a.standardDeviation()
-
-	if !isApproximate(stdDev, 0) {
-		t.Errorf("StandardDeviation = %v WANT: 0", stdDev)
-	}
-
-	add(a, 1, 1<<4)
-	if !isApproximate(stdDev, 0) {
-		t.Errorf("StandardDeviation = %v WANT: 0", stdDev)
-	}
-
-	add(a, 10, 1<<4)
-	if !isApproximate(stdDev, 0) {
-		t.Errorf("StandardDeviation = %v WANT: 0", stdDev)
-	}
-}
-
-func TestPercentileBoundary(t *testing.T) {
-	a := new(histogram)
-	add(a, 5, 1<<4)
-	add(a, 10, 1<<6)
-	add(a, 5, 1<<7)
-
-	for _, test := range percentileTests {
-		percentile := a.percentileBoundary(test.fraction)
-		if percentile != test.expected {
-			t.Errorf("h.PercentileBoundary (fraction=%v) = %v WANT: %v", test.fraction, percentile, test.expected)
-		}
-	}
-}
-
-func TestCopyFrom(t *testing.T) {
-	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
-	b := histogram{6, 36, []int64{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
-		20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, 5, -1}
-
-	a.CopyFrom(&b)
-
-	if a.String() != b.String() {
-		t.Errorf("a.String = %s WANT: %s", a.String(), b.String())
-	}
-}
-
-func TestClear(t *testing.T) {
-	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
-
-	a.Clear()
-
-	expected := "0, 0.000000, 0, 0, []"
-	if a.String() != expected {
-		t.Errorf("a.String = %s WANT %s", a.String(), expected)
-	}
-}
-
-func TestNew(t *testing.T) {
-	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
-	b := a.New()
-
-	expected := "0, 0.000000, 0, 0, []"
-	if b.(*histogram).String() != expected {
-		t.Errorf("b.(*histogram).String = %s WANT: %s", b.(*histogram).String(), expected)
-	}
-}
-
-func TestAdd(t *testing.T) {
-	// The tests here depend on the associativity of addMeasurement and Add.
-	// Add empty observation
-	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
-	b := a.New()
-
-	expected := a.String()
-	a.Add(b)
-	if a.String() != expected {
-		t.Errorf("a.String = %s WANT: %s", a.String(), expected)
-	}
-
-	// Add same bucketed value, no new buckets
-	c := new(histogram)
-	d := new(histogram)
-	e := new(histogram)
-	c.addMeasurement(12)
-	d.addMeasurement(11)
-	e.addMeasurement(12)
-	e.addMeasurement(11)
-	c.Add(d)
-	if c.String() != e.String() {
-		t.Errorf("c.String = %s WANT: %s", c.String(), e.String())
-	}
-
-	// Add bucketed values
-	f := new(histogram)
-	g := new(histogram)
-	h := new(histogram)
-	f.addMeasurement(4)
-	f.addMeasurement(12)
-	f.addMeasurement(100)
-	g.addMeasurement(18)
-	g.addMeasurement(36)
-	g.addMeasurement(255)
-	h.addMeasurement(4)
-	h.addMeasurement(12)
-	h.addMeasurement(100)
-	h.addMeasurement(18)
-	h.addMeasurement(36)
-	h.addMeasurement(255)
-	f.Add(g)
-	if f.String() != h.String() {
-		t.Errorf("f.String = %q WANT: %q", f.String(), h.String())
-	}
-
-	// add buckets to no buckets
-	i := new(histogram)
-	j := new(histogram)
-	k := new(histogram)
-	j.addMeasurement(18)
-	j.addMeasurement(36)
-	j.addMeasurement(255)
-	k.addMeasurement(18)
-	k.addMeasurement(36)
-	k.addMeasurement(255)
-	i.Add(j)
-	if i.String() != k.String() {
-		t.Errorf("i.String = %q WANT: %q", i.String(), k.String())
-	}
-
-	// add buckets to single value (no overlap)
-	l := new(histogram)
-	m := new(histogram)
-	n := new(histogram)
-	l.addMeasurement(0)
-	m.addMeasurement(18)
-	m.addMeasurement(36)
-	m.addMeasurement(255)
-	n.addMeasurement(0)
-	n.addMeasurement(18)
-	n.addMeasurement(36)
-	n.addMeasurement(255)
-	l.Add(m)
-	if l.String() != n.String() {
-		t.Errorf("l.String = %q WANT: %q", l.String(), n.String())
-	}
-
-	// mixed order
-	o := new(histogram)
-	p := new(histogram)
-	o.addMeasurement(0)
-	o.addMeasurement(2)
-	o.addMeasurement(0)
-	p.addMeasurement(0)
-	p.addMeasurement(0)
-	p.addMeasurement(2)
-	if o.String() != p.String() {
-		t.Errorf("o.String = %q WANT: %q", o.String(), p.String())
-	}
-}
-
-func add(h *histogram, times int, val int64) {
-	for i := 0; i < times; i++ {
-		h.addMeasurement(val)
-	}
-}
-
-func isApproximate(x, y float64) bool {
-	return math.Abs(x-y) < 1e-2
-}

+ 0 - 46
Godeps/_workspace/src/golang.org/x/net/trace/trace_test.go

@@ -1,46 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package trace
-
-import (
-	"reflect"
-	"testing"
-)
-
-type s struct{}
-
-func (s) String() string { return "lazy string" }
-
-// TestReset checks whether all the fields are zeroed after reset.
-func TestReset(t *testing.T) {
-	tr := New("foo", "bar")
-	tr.LazyLog(s{}, false)
-	tr.LazyPrintf("%d", 1)
-	tr.SetRecycler(func(_ interface{}) {})
-	tr.SetTraceInfo(3, 4)
-	tr.SetMaxEvents(100)
-	tr.SetError()
-	tr.Finish()
-
-	tr.(*trace).reset()
-
-	if !reflect.DeepEqual(tr, new(trace)) {
-		t.Errorf("reset didn't clear all fields: %+v", tr)
-	}
-}
-
-// TestResetLog checks whether all the fields are zeroed after reset.
-func TestResetLog(t *testing.T) {
-	el := NewEventLog("foo", "bar")
-	el.Printf("message")
-	el.Errorf("error")
-	el.Finish()
-
-	el.(*eventLog).reset()
-
-	if !reflect.DeepEqual(el, new(eventLog)) {
-		t.Errorf("reset didn't clear all fields: %+v", el)
-	}
-}

+ 0 - 1
Godeps/_workspace/src/google.golang.org/grpc/.travis.yml

@@ -11,4 +11,3 @@ install:
 
 script:
   - make test testrace
-  - make coverage

+ 0 - 197
Godeps/_workspace/src/google.golang.org/grpc/benchmark/benchmark_test.go

@@ -1,197 +0,0 @@
-package benchmark
-
-import (
-	"os"
-	"sync"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
-	testpb "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/benchmark/grpc_testing"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/benchmark/stats"
-)
-
-func runUnary(b *testing.B, maxConcurrentCalls int) {
-	s := stats.AddStats(b, 38)
-	b.StopTimer()
-	target, stopper := StartServer("localhost:0")
-	defer stopper()
-	conn := NewClientConn(target)
-	tc := testpb.NewTestServiceClient(conn)
-
-	// Warm up connection.
-	for i := 0; i < 10; i++ {
-		unaryCaller(tc)
-	}
-	ch := make(chan int, maxConcurrentCalls*4)
-	var (
-		mu sync.Mutex
-		wg sync.WaitGroup
-	)
-	wg.Add(maxConcurrentCalls)
-
-	// Distribute the b.N calls over maxConcurrentCalls workers.
-	for i := 0; i < maxConcurrentCalls; i++ {
-		go func() {
-			for range ch {
-				start := time.Now()
-				unaryCaller(tc)
-				elapse := time.Since(start)
-				mu.Lock()
-				s.Add(elapse)
-				mu.Unlock()
-			}
-			wg.Done()
-		}()
-	}
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		ch <- i
-	}
-	b.StopTimer()
-	close(ch)
-	wg.Wait()
-	conn.Close()
-}
-
-func runStream(b *testing.B, maxConcurrentCalls int) {
-	s := stats.AddStats(b, 38)
-	b.StopTimer()
-	target, stopper := StartServer("localhost:0")
-	defer stopper()
-	conn := NewClientConn(target)
-	tc := testpb.NewTestServiceClient(conn)
-
-	// Warm up connection.
-	stream, err := tc.StreamingCall(context.Background())
-	if err != nil {
-		b.Fatalf("%v.StreamingCall(_) = _, %v", tc, err)
-	}
-	for i := 0; i < 10; i++ {
-		streamCaller(tc, stream)
-	}
-
-	ch := make(chan int, maxConcurrentCalls*4)
-	var (
-		mu sync.Mutex
-		wg sync.WaitGroup
-	)
-	wg.Add(maxConcurrentCalls)
-
-	// Distribute the b.N calls over maxConcurrentCalls workers.
-	for i := 0; i < maxConcurrentCalls; i++ {
-		go func() {
-			stream, err := tc.StreamingCall(context.Background())
-			if err != nil {
-				b.Fatalf("%v.StreamingCall(_) = _, %v", tc, err)
-			}
-			for range ch {
-				start := time.Now()
-				streamCaller(tc, stream)
-				elapse := time.Since(start)
-				mu.Lock()
-				s.Add(elapse)
-				mu.Unlock()
-			}
-			wg.Done()
-		}()
-	}
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		ch <- i
-	}
-	b.StopTimer()
-	close(ch)
-	wg.Wait()
-	conn.Close()
-}
-func unaryCaller(client testpb.TestServiceClient) {
-	DoUnaryCall(client, 1, 1)
-}
-
-func streamCaller(client testpb.TestServiceClient, stream testpb.TestService_StreamingCallClient) {
-	DoStreamingRoundTrip(client, stream, 1, 1)
-}
-
-func BenchmarkClientStreamc1(b *testing.B) {
-	grpc.EnableTracing = true
-	runStream(b, 1)
-}
-
-func BenchmarkClientStreamc8(b *testing.B) {
-	grpc.EnableTracing = true
-	runStream(b, 8)
-}
-
-func BenchmarkClientStreamc64(b *testing.B) {
-	grpc.EnableTracing = true
-	runStream(b, 64)
-}
-
-func BenchmarkClientStreamc512(b *testing.B) {
-	grpc.EnableTracing = true
-	runStream(b, 512)
-}
-func BenchmarkClientUnaryc1(b *testing.B) {
-	grpc.EnableTracing = true
-	runUnary(b, 1)
-}
-
-func BenchmarkClientUnaryc8(b *testing.B) {
-	grpc.EnableTracing = true
-	runUnary(b, 8)
-}
-
-func BenchmarkClientUnaryc64(b *testing.B) {
-	grpc.EnableTracing = true
-	runUnary(b, 64)
-}
-
-func BenchmarkClientUnaryc512(b *testing.B) {
-	grpc.EnableTracing = true
-	runUnary(b, 512)
-}
-
-func BenchmarkClientStreamNoTracec1(b *testing.B) {
-	grpc.EnableTracing = false
-	runStream(b, 1)
-}
-
-func BenchmarkClientStreamNoTracec8(b *testing.B) {
-	grpc.EnableTracing = false
-	runStream(b, 8)
-}
-
-func BenchmarkClientStreamNoTracec64(b *testing.B) {
-	grpc.EnableTracing = false
-	runStream(b, 64)
-}
-
-func BenchmarkClientStreamNoTracec512(b *testing.B) {
-	grpc.EnableTracing = false
-	runStream(b, 512)
-}
-func BenchmarkClientUnaryNoTracec1(b *testing.B) {
-	grpc.EnableTracing = false
-	runUnary(b, 1)
-}
-
-func BenchmarkClientUnaryNoTracec8(b *testing.B) {
-	grpc.EnableTracing = false
-	runUnary(b, 8)
-}
-
-func BenchmarkClientUnaryNoTracec64(b *testing.B) {
-	grpc.EnableTracing = false
-	runUnary(b, 64)
-}
-
-func BenchmarkClientUnaryNoTracec512(b *testing.B) {
-	grpc.EnableTracing = false
-	runUnary(b, 512)
-}
-
-func TestMain(m *testing.M) {
-	os.Exit(stats.RunTestMain(m))
-}

+ 358 - 58
Godeps/_workspace/src/google.golang.org/grpc/benchmark/grpc_testing/test.pb.go

@@ -27,18 +27,22 @@ It has these top-level messages:
 package grpc_testing
 
 import proto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
 
 import (
 	context "github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
 	grpc "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
 )
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConn
-
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.ProtoPackageIsVersion1
 
 type PayloadType int32
 
@@ -65,6 +69,7 @@ var PayloadType_value = map[string]int32{
 func (x PayloadType) String() string {
 	return proto.EnumName(PayloadType_name, int32(x))
 }
+func (PayloadType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 type ClientType int32
 
@@ -85,6 +90,7 @@ var ClientType_value = map[string]int32{
 func (x ClientType) String() string {
 	return proto.EnumName(ClientType_name, int32(x))
 }
+func (ClientType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 type ServerType int32
 
@@ -105,6 +111,7 @@ var ServerType_value = map[string]int32{
 func (x ServerType) String() string {
 	return proto.EnumName(ServerType_name, int32(x))
 }
+func (ServerType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
 
 type RpcType int32
 
@@ -125,15 +132,17 @@ var RpcType_value = map[string]int32{
 func (x RpcType) String() string {
 	return proto.EnumName(RpcType_name, int32(x))
 }
+func (RpcType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
 
 type StatsRequest struct {
 	// run number
 	TestNum int32 `protobuf:"varint,1,opt,name=test_num" json:"test_num,omitempty"`
 }
 
-func (m *StatsRequest) Reset()         { *m = StatsRequest{} }
-func (m *StatsRequest) String() string { return proto.CompactTextString(m) }
-func (*StatsRequest) ProtoMessage()    {}
+func (m *StatsRequest) Reset()                    { *m = StatsRequest{} }
+func (m *StatsRequest) String() string            { return proto.CompactTextString(m) }
+func (*StatsRequest) ProtoMessage()               {}
+func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 type ServerStats struct {
 	// wall clock time
@@ -144,9 +153,10 @@ type ServerStats struct {
 	TimeSystem float64 `protobuf:"fixed64,3,opt,name=time_system" json:"time_system,omitempty"`
 }
 
-func (m *ServerStats) Reset()         { *m = ServerStats{} }
-func (m *ServerStats) String() string { return proto.CompactTextString(m) }
-func (*ServerStats) ProtoMessage()    {}
+func (m *ServerStats) Reset()                    { *m = ServerStats{} }
+func (m *ServerStats) String() string            { return proto.CompactTextString(m) }
+func (*ServerStats) ProtoMessage()               {}
+func (*ServerStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 type Payload struct {
 	// The type of data in body.
@@ -155,9 +165,10 @@ type Payload struct {
 	Body []byte `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
 }
 
-func (m *Payload) Reset()         { *m = Payload{} }
-func (m *Payload) String() string { return proto.CompactTextString(m) }
-func (*Payload) ProtoMessage()    {}
+func (m *Payload) Reset()                    { *m = Payload{} }
+func (m *Payload) String() string            { return proto.CompactTextString(m) }
+func (*Payload) ProtoMessage()               {}
+func (*Payload) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
 
 type HistogramData struct {
 	Bucket       []uint32 `protobuf:"varint,1,rep,name=bucket" json:"bucket,omitempty"`
@@ -168,9 +179,10 @@ type HistogramData struct {
 	Count        float64  `protobuf:"fixed64,6,opt,name=count" json:"count,omitempty"`
 }
 
-func (m *HistogramData) Reset()         { *m = HistogramData{} }
-func (m *HistogramData) String() string { return proto.CompactTextString(m) }
-func (*HistogramData) ProtoMessage()    {}
+func (m *HistogramData) Reset()                    { *m = HistogramData{} }
+func (m *HistogramData) String() string            { return proto.CompactTextString(m) }
+func (*HistogramData) ProtoMessage()               {}
+func (*HistogramData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
 
 type ClientConfig struct {
 	ServerTargets             []string   `protobuf:"bytes,1,rep,name=server_targets" json:"server_targets,omitempty"`
@@ -184,41 +196,141 @@ type ClientConfig struct {
 	RpcType            RpcType `protobuf:"varint,8,opt,name=rpc_type,enum=grpc.testing.RpcType" json:"rpc_type,omitempty"`
 }
 
-func (m *ClientConfig) Reset()         { *m = ClientConfig{} }
-func (m *ClientConfig) String() string { return proto.CompactTextString(m) }
-func (*ClientConfig) ProtoMessage()    {}
+func (m *ClientConfig) Reset()                    { *m = ClientConfig{} }
+func (m *ClientConfig) String() string            { return proto.CompactTextString(m) }
+func (*ClientConfig) ProtoMessage()               {}
+func (*ClientConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
 
 // Request current stats
 type Mark struct {
 }
 
-func (m *Mark) Reset()         { *m = Mark{} }
-func (m *Mark) String() string { return proto.CompactTextString(m) }
-func (*Mark) ProtoMessage()    {}
+func (m *Mark) Reset()                    { *m = Mark{} }
+func (m *Mark) String() string            { return proto.CompactTextString(m) }
+func (*Mark) ProtoMessage()               {}
+func (*Mark) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
 
 type ClientArgs struct {
-	Setup *ClientConfig `protobuf:"bytes,1,opt,name=setup" json:"setup,omitempty"`
-	Mark  *Mark         `protobuf:"bytes,2,opt,name=mark" json:"mark,omitempty"`
+	// Types that are valid to be assigned to Argtype:
+	//	*ClientArgs_Setup
+	//	*ClientArgs_Mark
+	Argtype isClientArgs_Argtype `protobuf_oneof:"argtype"`
 }
 
-func (m *ClientArgs) Reset()         { *m = ClientArgs{} }
-func (m *ClientArgs) String() string { return proto.CompactTextString(m) }
-func (*ClientArgs) ProtoMessage()    {}
+func (m *ClientArgs) Reset()                    { *m = ClientArgs{} }
+func (m *ClientArgs) String() string            { return proto.CompactTextString(m) }
+func (*ClientArgs) ProtoMessage()               {}
+func (*ClientArgs) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
 
-func (m *ClientArgs) GetSetup() *ClientConfig {
+type isClientArgs_Argtype interface {
+	isClientArgs_Argtype()
+}
+
+type ClientArgs_Setup struct {
+	Setup *ClientConfig `protobuf:"bytes,1,opt,name=setup,oneof"`
+}
+type ClientArgs_Mark struct {
+	Mark *Mark `protobuf:"bytes,2,opt,name=mark,oneof"`
+}
+
+func (*ClientArgs_Setup) isClientArgs_Argtype() {}
+func (*ClientArgs_Mark) isClientArgs_Argtype()  {}
+
+func (m *ClientArgs) GetArgtype() isClientArgs_Argtype {
 	if m != nil {
-		return m.Setup
+		return m.Argtype
+	}
+	return nil
+}
+
+func (m *ClientArgs) GetSetup() *ClientConfig {
+	if x, ok := m.GetArgtype().(*ClientArgs_Setup); ok {
+		return x.Setup
 	}
 	return nil
 }
 
 func (m *ClientArgs) GetMark() *Mark {
-	if m != nil {
-		return m.Mark
+	if x, ok := m.GetArgtype().(*ClientArgs_Mark); ok {
+		return x.Mark
+	}
+	return nil
+}
+
+// XXX_OneofFuncs is for the internal use of the proto package.
+func (*ClientArgs) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
+	return _ClientArgs_OneofMarshaler, _ClientArgs_OneofUnmarshaler, _ClientArgs_OneofSizer, []interface{}{
+		(*ClientArgs_Setup)(nil),
+		(*ClientArgs_Mark)(nil),
+	}
+}
+
+func _ClientArgs_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
+	m := msg.(*ClientArgs)
+	// argtype
+	switch x := m.Argtype.(type) {
+	case *ClientArgs_Setup:
+		b.EncodeVarint(1<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Setup); err != nil {
+			return err
+		}
+	case *ClientArgs_Mark:
+		b.EncodeVarint(2<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Mark); err != nil {
+			return err
+		}
+	case nil:
+	default:
+		return fmt.Errorf("ClientArgs.Argtype has unexpected type %T", x)
 	}
 	return nil
 }
 
+func _ClientArgs_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
+	m := msg.(*ClientArgs)
+	switch tag {
+	case 1: // argtype.setup
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(ClientConfig)
+		err := b.DecodeMessage(msg)
+		m.Argtype = &ClientArgs_Setup{msg}
+		return true, err
+	case 2: // argtype.mark
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(Mark)
+		err := b.DecodeMessage(msg)
+		m.Argtype = &ClientArgs_Mark{msg}
+		return true, err
+	default:
+		return false, nil
+	}
+}
+
+func _ClientArgs_OneofSizer(msg proto.Message) (n int) {
+	m := msg.(*ClientArgs)
+	// argtype
+	switch x := m.Argtype.(type) {
+	case *ClientArgs_Setup:
+		s := proto.Size(x.Setup)
+		n += proto.SizeVarint(1<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(s))
+		n += s
+	case *ClientArgs_Mark:
+		s := proto.Size(x.Mark)
+		n += proto.SizeVarint(2<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(s))
+		n += s
+	case nil:
+	default:
+		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
+	}
+	return n
+}
+
 type ClientStats struct {
 	Latencies   *HistogramData `protobuf:"bytes,1,opt,name=latencies" json:"latencies,omitempty"`
 	TimeElapsed float64        `protobuf:"fixed64,3,opt,name=time_elapsed" json:"time_elapsed,omitempty"`
@@ -226,9 +338,10 @@ type ClientStats struct {
 	TimeSystem  float64        `protobuf:"fixed64,5,opt,name=time_system" json:"time_system,omitempty"`
 }
 
-func (m *ClientStats) Reset()         { *m = ClientStats{} }
-func (m *ClientStats) String() string { return proto.CompactTextString(m) }
-func (*ClientStats) ProtoMessage()    {}
+func (m *ClientStats) Reset()                    { *m = ClientStats{} }
+func (m *ClientStats) String() string            { return proto.CompactTextString(m) }
+func (*ClientStats) ProtoMessage()               {}
+func (*ClientStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
 
 func (m *ClientStats) GetLatencies() *HistogramData {
 	if m != nil {
@@ -241,9 +354,10 @@ type ClientStatus struct {
 	Stats *ClientStats `protobuf:"bytes,1,opt,name=stats" json:"stats,omitempty"`
 }
 
-func (m *ClientStatus) Reset()         { *m = ClientStatus{} }
-func (m *ClientStatus) String() string { return proto.CompactTextString(m) }
-func (*ClientStatus) ProtoMessage()    {}
+func (m *ClientStatus) Reset()                    { *m = ClientStatus{} }
+func (m *ClientStatus) String() string            { return proto.CompactTextString(m) }
+func (*ClientStatus) ProtoMessage()               {}
+func (*ClientStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
 
 func (m *ClientStatus) GetStats() *ClientStats {
 	if m != nil {
@@ -258,41 +372,141 @@ type ServerConfig struct {
 	EnableSsl  bool       `protobuf:"varint,3,opt,name=enable_ssl" json:"enable_ssl,omitempty"`
 }
 
-func (m *ServerConfig) Reset()         { *m = ServerConfig{} }
-func (m *ServerConfig) String() string { return proto.CompactTextString(m) }
-func (*ServerConfig) ProtoMessage()    {}
+func (m *ServerConfig) Reset()                    { *m = ServerConfig{} }
+func (m *ServerConfig) String() string            { return proto.CompactTextString(m) }
+func (*ServerConfig) ProtoMessage()               {}
+func (*ServerConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
 
 type ServerArgs struct {
-	Setup *ServerConfig `protobuf:"bytes,1,opt,name=setup" json:"setup,omitempty"`
-	Mark  *Mark         `protobuf:"bytes,2,opt,name=mark" json:"mark,omitempty"`
+	// Types that are valid to be assigned to Argtype:
+	//	*ServerArgs_Setup
+	//	*ServerArgs_Mark
+	Argtype isServerArgs_Argtype `protobuf_oneof:"argtype"`
 }
 
-func (m *ServerArgs) Reset()         { *m = ServerArgs{} }
-func (m *ServerArgs) String() string { return proto.CompactTextString(m) }
-func (*ServerArgs) ProtoMessage()    {}
+func (m *ServerArgs) Reset()                    { *m = ServerArgs{} }
+func (m *ServerArgs) String() string            { return proto.CompactTextString(m) }
+func (*ServerArgs) ProtoMessage()               {}
+func (*ServerArgs) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
 
-func (m *ServerArgs) GetSetup() *ServerConfig {
+type isServerArgs_Argtype interface {
+	isServerArgs_Argtype()
+}
+
+type ServerArgs_Setup struct {
+	Setup *ServerConfig `protobuf:"bytes,1,opt,name=setup,oneof"`
+}
+type ServerArgs_Mark struct {
+	Mark *Mark `protobuf:"bytes,2,opt,name=mark,oneof"`
+}
+
+func (*ServerArgs_Setup) isServerArgs_Argtype() {}
+func (*ServerArgs_Mark) isServerArgs_Argtype()  {}
+
+func (m *ServerArgs) GetArgtype() isServerArgs_Argtype {
 	if m != nil {
-		return m.Setup
+		return m.Argtype
+	}
+	return nil
+}
+
+func (m *ServerArgs) GetSetup() *ServerConfig {
+	if x, ok := m.GetArgtype().(*ServerArgs_Setup); ok {
+		return x.Setup
 	}
 	return nil
 }
 
 func (m *ServerArgs) GetMark() *Mark {
-	if m != nil {
-		return m.Mark
+	if x, ok := m.GetArgtype().(*ServerArgs_Mark); ok {
+		return x.Mark
 	}
 	return nil
 }
 
+// XXX_OneofFuncs is for the internal use of the proto package.
+func (*ServerArgs) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
+	return _ServerArgs_OneofMarshaler, _ServerArgs_OneofUnmarshaler, _ServerArgs_OneofSizer, []interface{}{
+		(*ServerArgs_Setup)(nil),
+		(*ServerArgs_Mark)(nil),
+	}
+}
+
+func _ServerArgs_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
+	m := msg.(*ServerArgs)
+	// argtype
+	switch x := m.Argtype.(type) {
+	case *ServerArgs_Setup:
+		b.EncodeVarint(1<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Setup); err != nil {
+			return err
+		}
+	case *ServerArgs_Mark:
+		b.EncodeVarint(2<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Mark); err != nil {
+			return err
+		}
+	case nil:
+	default:
+		return fmt.Errorf("ServerArgs.Argtype has unexpected type %T", x)
+	}
+	return nil
+}
+
+func _ServerArgs_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
+	m := msg.(*ServerArgs)
+	switch tag {
+	case 1: // argtype.setup
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(ServerConfig)
+		err := b.DecodeMessage(msg)
+		m.Argtype = &ServerArgs_Setup{msg}
+		return true, err
+	case 2: // argtype.mark
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(Mark)
+		err := b.DecodeMessage(msg)
+		m.Argtype = &ServerArgs_Mark{msg}
+		return true, err
+	default:
+		return false, nil
+	}
+}
+
+func _ServerArgs_OneofSizer(msg proto.Message) (n int) {
+	m := msg.(*ServerArgs)
+	// argtype
+	switch x := m.Argtype.(type) {
+	case *ServerArgs_Setup:
+		s := proto.Size(x.Setup)
+		n += proto.SizeVarint(1<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(s))
+		n += s
+	case *ServerArgs_Mark:
+		s := proto.Size(x.Mark)
+		n += proto.SizeVarint(2<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(s))
+		n += s
+	case nil:
+	default:
+		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
+	}
+	return n
+}
+
 type ServerStatus struct {
 	Stats *ServerStats `protobuf:"bytes,1,opt,name=stats" json:"stats,omitempty"`
 	Port  int32        `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
 }
 
-func (m *ServerStatus) Reset()         { *m = ServerStatus{} }
-func (m *ServerStatus) String() string { return proto.CompactTextString(m) }
-func (*ServerStatus) ProtoMessage()    {}
+func (m *ServerStatus) Reset()                    { *m = ServerStatus{} }
+func (m *ServerStatus) String() string            { return proto.CompactTextString(m) }
+func (*ServerStatus) ProtoMessage()               {}
+func (*ServerStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
 
 func (m *ServerStatus) GetStats() *ServerStats {
 	if m != nil {
@@ -312,9 +526,10 @@ type SimpleRequest struct {
 	Payload *Payload `protobuf:"bytes,3,opt,name=payload" json:"payload,omitempty"`
 }
 
-func (m *SimpleRequest) Reset()         { *m = SimpleRequest{} }
-func (m *SimpleRequest) String() string { return proto.CompactTextString(m) }
-func (*SimpleRequest) ProtoMessage()    {}
+func (m *SimpleRequest) Reset()                    { *m = SimpleRequest{} }
+func (m *SimpleRequest) String() string            { return proto.CompactTextString(m) }
+func (*SimpleRequest) ProtoMessage()               {}
+func (*SimpleRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
 
 func (m *SimpleRequest) GetPayload() *Payload {
 	if m != nil {
@@ -327,9 +542,10 @@ type SimpleResponse struct {
 	Payload *Payload `protobuf:"bytes,1,opt,name=payload" json:"payload,omitempty"`
 }
 
-func (m *SimpleResponse) Reset()         { *m = SimpleResponse{} }
-func (m *SimpleResponse) String() string { return proto.CompactTextString(m) }
-func (*SimpleResponse) ProtoMessage()    {}
+func (m *SimpleResponse) Reset()                    { *m = SimpleResponse{} }
+func (m *SimpleResponse) String() string            { return proto.CompactTextString(m) }
+func (*SimpleResponse) ProtoMessage()               {}
+func (*SimpleResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
 
 func (m *SimpleResponse) GetPayload() *Payload {
 	if m != nil {
@@ -339,12 +555,30 @@ func (m *SimpleResponse) GetPayload() *Payload {
 }
 
 func init() {
+	proto.RegisterType((*StatsRequest)(nil), "grpc.testing.StatsRequest")
+	proto.RegisterType((*ServerStats)(nil), "grpc.testing.ServerStats")
+	proto.RegisterType((*Payload)(nil), "grpc.testing.Payload")
+	proto.RegisterType((*HistogramData)(nil), "grpc.testing.HistogramData")
+	proto.RegisterType((*ClientConfig)(nil), "grpc.testing.ClientConfig")
+	proto.RegisterType((*Mark)(nil), "grpc.testing.Mark")
+	proto.RegisterType((*ClientArgs)(nil), "grpc.testing.ClientArgs")
+	proto.RegisterType((*ClientStats)(nil), "grpc.testing.ClientStats")
+	proto.RegisterType((*ClientStatus)(nil), "grpc.testing.ClientStatus")
+	proto.RegisterType((*ServerConfig)(nil), "grpc.testing.ServerConfig")
+	proto.RegisterType((*ServerArgs)(nil), "grpc.testing.ServerArgs")
+	proto.RegisterType((*ServerStatus)(nil), "grpc.testing.ServerStatus")
+	proto.RegisterType((*SimpleRequest)(nil), "grpc.testing.SimpleRequest")
+	proto.RegisterType((*SimpleResponse)(nil), "grpc.testing.SimpleResponse")
 	proto.RegisterEnum("grpc.testing.PayloadType", PayloadType_name, PayloadType_value)
 	proto.RegisterEnum("grpc.testing.ClientType", ClientType_name, ClientType_value)
 	proto.RegisterEnum("grpc.testing.ServerType", ServerType_name, ServerType_value)
 	proto.RegisterEnum("grpc.testing.RpcType", RpcType_name, RpcType_value)
 }
 
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
 // Client API for TestService service
 
 type TestServiceClient interface {
@@ -639,3 +873,69 @@ var _Worker_serviceDesc = grpc.ServiceDesc{
 		},
 	},
 }
+
+var fileDescriptor0 = []byte{
+	// 988 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x56, 0x5f, 0x6f, 0x1b, 0x45,
+	0x10, 0xef, 0xc5, 0xff, 0xe2, 0x39, 0x27, 0x44, 0xab, 0x52, 0x39, 0x69, 0x11, 0x70, 0x05, 0x11,
+	0x22, 0x91, 0x56, 0x46, 0x42, 0xea, 0x0b, 0x91, 0xeb, 0x1a, 0x52, 0x29, 0x71, 0xa2, 0xbd, 0x04,
+	0xd4, 0xa7, 0xd3, 0xc6, 0xde, 0xb8, 0xa7, 0x9c, 0xef, 0xae, 0xb7, 0x7b, 0xa8, 0xe6, 0x09, 0xf1,
+	0x19, 0xf8, 0x0a, 0x3c, 0x20, 0xbe, 0x24, 0xb3, 0xb3, 0x7b, 0x89, 0x9d, 0x9a, 0x36, 0x52, 0x9f,
+	0x72, 0x3b, 0xf3, 0x9b, 0xdf, 0xce, 0xfe, 0xe6, 0x8f, 0x03, 0xa0, 0xa5, 0xd2, 0xfb, 0x79, 0x91,
+	0xe9, 0x8c, 0x75, 0xa6, 0x45, 0x3e, 0xde, 0x37, 0x86, 0x38, 0x9d, 0x06, 0xdf, 0x42, 0x27, 0xd4,
+	0x42, 0x2b, 0x2e, 0xdf, 0x94, 0x68, 0x62, 0xdb, 0xb0, 0x6e, 0x5c, 0x51, 0x5a, 0xce, 0xba, 0xde,
+	0x17, 0xde, 0x6e, 0x83, 0xb7, 0xcc, 0x79, 0x54, 0xce, 0x82, 0x14, 0xfc, 0x50, 0x16, 0xbf, 0xc9,
+	0x82, 0x02, 0xd8, 0x97, 0xd0, 0xd1, 0xf1, 0x4c, 0x46, 0x32, 0x11, 0xb9, 0x92, 0x13, 0x42, 0x7b,
+	0xdc, 0x37, 0xb6, 0xa1, 0x35, 0xb1, 0x87, 0xd0, 0x26, 0x48, 0xa9, 0x64, 0xd1, 0x5d, 0x23, 0xff,
+	0xba, 0x31, 0x9c, 0xe3, 0x99, 0x7d, 0x0e, 0x84, 0x8d, 0xd4, 0x5c, 0x69, 0x39, 0xeb, 0xd6, 0xc8,
+	0x0d, 0xc6, 0x14, 0x92, 0x25, 0x38, 0x82, 0xd6, 0xa9, 0x98, 0x27, 0x99, 0x98, 0xb0, 0xef, 0xa0,
+	0xae, 0xe7, 0xb9, 0xa4, 0x3b, 0x36, 0x7b, 0xdb, 0xfb, 0x8b, 0x4f, 0xd8, 0x77, 0xa0, 0x33, 0x04,
+	0x70, 0x82, 0x31, 0x06, 0xf5, 0x8b, 0x6c, 0x32, 0xa7, 0x2b, 0x3b, 0x9c, 0xbe, 0x83, 0x7f, 0x3d,
+	0xd8, 0x38, 0x8c, 0x95, 0xce, 0xa6, 0x85, 0x98, 0xbd, 0x10, 0x5a, 0xb0, 0x07, 0xd0, 0xbc, 0x28,
+	0xc7, 0x57, 0x52, 0x23, 0x6d, 0x6d, 0x77, 0x83, 0xbb, 0x93, 0x91, 0x60, 0x16, 0xa7, 0x91, 0x92,
+	0x32, 0x75, 0x49, 0xb7, 0xf0, 0x1c, 0xe2, 0x91, 0x5c, 0xe2, 0xad, 0x75, 0xd5, 0x9c, 0x4b, 0xbc,
+	0x25, 0xd7, 0x16, 0xd4, 0x14, 0x6a, 0x56, 0x27, 0xab, 0xf9, 0x64, 0x5f, 0xc1, 0x26, 0xfe, 0x89,
+	0xb2, 0xcb, 0x48, 0xbd, 0x29, 0x45, 0x21, 0x55, 0xb7, 0x41, 0xce, 0x0e, 0x5a, 0x4f, 0x2e, 0x43,
+	0x6b, 0x63, 0xf7, 0xa1, 0x31, 0xce, 0xca, 0x54, 0x77, 0x9b, 0xe4, 0xb4, 0x87, 0xe0, 0x8f, 0x1a,
+	0x74, 0x06, 0x49, 0x2c, 0x53, 0x3d, 0xc8, 0xd2, 0xcb, 0x78, 0xca, 0xbe, 0x46, 0x32, 0x12, 0x3f,
+	0xd2, 0xa2, 0x98, 0x4a, 0xad, 0x28, 0xe9, 0x36, 0xdf, 0xb0, 0xd6, 0x33, 0x6b, 0x64, 0xcf, 0xc0,
+	0x1f, 0x53, 0x58, 0x44, 0x7a, 0xad, 0x91, 0x5e, 0xdd, 0x65, 0xbd, 0x2c, 0x2f, 0xc9, 0x05, 0xe3,
+	0xeb, 0x6f, 0xf6, 0x19, 0x80, 0x4c, 0xc5, 0x45, 0x82, 0x15, 0x51, 0x09, 0xbd, 0x6e, 0x9d, 0xb7,
+	0xad, 0x25, 0x54, 0x09, 0x3b, 0x80, 0x47, 0x59, 0xa9, 0x95, 0x16, 0xe9, 0x04, 0x49, 0x22, 0x24,
+	0x54, 0x51, 0x8e, 0xe9, 0x8c, 0x5f, 0x8b, 0x34, 0x95, 0x09, 0x3d, 0xbc, 0xc1, 0xb7, 0x17, 0x30,
+	0x1c, 0x21, 0xa7, 0xb2, 0x18, 0x58, 0x00, 0xfb, 0x06, 0x3e, 0x71, 0xa9, 0xb9, 0x10, 0xab, 0x47,
+	0x83, 0x6f, 0x5a, 0xb3, 0xc3, 0x51, 0x63, 0xe5, 0xb6, 0xa4, 0x91, 0x8a, 0x7f, 0x97, 0x24, 0x4c,
+	0x83, 0xfb, 0xce, 0x16, 0xa2, 0x89, 0x3d, 0x85, 0xfb, 0x42, 0xcd, 0xd3, 0x71, 0x54, 0x3d, 0xf6,
+	0x75, 0x21, 0xc5, 0x44, 0x75, 0x5b, 0x04, 0x65, 0xe4, 0x73, 0xcf, 0xb4, 0x1e, 0x8c, 0x58, 0xc7,
+	0x94, 0xad, 0x2a, 0xeb, 0xa4, 0xca, 0xa7, 0xcb, 0xaa, 0x60, 0xb6, 0x24, 0x49, 0xab, 0xb0, 0x1f,
+	0x41, 0x13, 0xea, 0xc7, 0xa2, 0xb8, 0x0a, 0x4a, 0x00, 0x4b, 0xd5, 0x2f, 0xa6, 0x8a, 0xf5, 0xa0,
+	0xa1, 0xa4, 0x2e, 0x73, 0x6a, 0x45, 0xbf, 0xb7, 0xb3, 0x4a, 0x5a, 0x5b, 0xb2, 0xc3, 0x7b, 0xdc,
+	0x42, 0xd9, 0x2e, 0xd4, 0x67, 0xc8, 0x44, 0xd5, 0xf0, 0x7b, 0x6c, 0x39, 0xc4, 0xdc, 0x81, 0x50,
+	0x42, 0x3c, 0x6f, 0x43, 0x0b, 0x0b, 0x69, 0x92, 0x0c, 0xfe, 0xf1, 0xc0, 0xb7, 0x74, 0x76, 0xdc,
+	0x9e, 0x41, 0x3b, 0x11, 0x5a, 0xa6, 0xe3, 0x58, 0x2a, 0x77, 0xf9, 0xc3, 0x65, 0xa6, 0xa5, 0xee,
+	0xe6, 0x37, 0xe8, 0x77, 0x26, 0xb5, 0xf6, 0x81, 0x49, 0xad, 0xbf, 0x7f, 0x52, 0x1b, 0xef, 0x4c,
+	0xea, 0x41, 0xd5, 0xac, 0x26, 0xd5, 0x52, 0xb1, 0x27, 0x28, 0x92, 0x49, 0xda, 0xe5, 0xb9, 0xbd,
+	0x4a, 0x24, 0xbb, 0x75, 0x2c, 0x2e, 0xf8, 0xd3, 0xc3, 0x35, 0x44, 0x8d, 0xec, 0xda, 0x1d, 0xfb,
+	0xb8, 0x6a, 0xf7, 0x9b, 0xb9, 0xbf, 0xd5, 0xc7, 0x36, 0xc0, 0xf6, 0xb1, 0xba, 0xfe, 0x66, 0x5d,
+	0x68, 0x55, 0xed, 0xb0, 0xe6, 0x16, 0x98, 0xeb, 0x81, 0xf7, 0x77, 0xb8, 0x29, 0xb4, 0xa5, 0xbc,
+	0x43, 0xa1, 0x17, 0x93, 0xfd, 0xc8, 0x42, 0x87, 0xd5, 0xd3, 0xef, 0x24, 0xde, 0xc2, 0x06, 0x76,
+	0xe2, 0x99, 0x6d, 0x97, 0x67, 0x85, 0x76, 0xaf, 0xa5, 0xef, 0xe0, 0x6f, 0xdc, 0x76, 0x61, 0x3c,
+	0xcb, 0x13, 0x59, 0x2d, 0xf6, 0x1f, 0x61, 0x03, 0xd7, 0x4d, 0x9e, 0xa5, 0x4a, 0x46, 0x77, 0xdb,
+	0xa5, 0x9d, 0x0a, 0x4f, 0xb2, 0x3e, 0x5e, 0x88, 0xa7, 0xb1, 0xb4, 0xd7, 0x5d, 0x83, 0x68, 0x2e,
+	0x9f, 0x40, 0xcb, 0x8d, 0x29, 0xc9, 0xeb, 0xdf, 0x1e, 0x32, 0x47, 0xcf, 0x2b, 0x54, 0xd0, 0x87,
+	0xcd, 0x2a, 0x4d, 0x4b, 0xb3, 0x48, 0xe1, 0xdd, 0x85, 0x62, 0xef, 0x00, 0xfc, 0x85, 0xac, 0x71,
+	0x0f, 0x77, 0x06, 0x27, 0xc7, 0xa7, 0x7c, 0x18, 0x86, 0xfd, 0xe7, 0x47, 0xc3, 0xad, 0x7b, 0xa8,
+	0xcf, 0xe6, 0xf9, 0x68, 0xc9, 0xe6, 0x31, 0x80, 0x26, 0xef, 0x8f, 0x5e, 0x9c, 0x1c, 0x6f, 0xad,
+	0xed, 0xfd, 0x50, 0x0d, 0x38, 0xc5, 0x3f, 0x00, 0x16, 0xbe, 0x1a, 0x0d, 0x0e, 0xf9, 0xc9, 0xe8,
+	0xe4, 0x3c, 0x8c, 0x06, 0x47, 0x2f, 0x87, 0xa3, 0x33, 0x64, 0x41, 0xde, 0xbe, 0x71, 0x54, 0x16,
+	0xcf, 0xc4, 0xdd, 0xb4, 0xe0, 0xed, 0xb8, 0x70, 0xc8, 0x7f, 0x19, 0xf2, 0xc5, 0x38, 0x67, 0xf1,
+	0xf6, 0x1e, 0x43, 0xcb, 0x2d, 0x1b, 0xd6, 0x86, 0xc6, 0xf9, 0xa8, 0xcf, 0x5f, 0x21, 0x6e, 0x03,
+	0xda, 0xe1, 0x19, 0x1f, 0xf6, 0x8f, 0x5f, 0x8e, 0x7e, 0xde, 0xf2, 0x7a, 0x58, 0x40, 0xff, 0x0c,
+	0x9f, 0x6c, 0x6e, 0x88, 0xc7, 0x92, 0xfd, 0x04, 0xed, 0xf3, 0x54, 0x14, 0xf3, 0x81, 0x48, 0x12,
+	0x76, 0x6b, 0xf0, 0x97, 0x0a, 0xbd, 0xf3, 0x68, 0xb5, 0xd3, 0xc9, 0x3b, 0xc2, 0xbe, 0xd0, 0x38,
+	0x0e, 0xf8, 0x8b, 0x36, 0xfd, 0x48, 0xae, 0x5d, 0xef, 0xa9, 0xd7, 0xfb, 0xcb, 0x83, 0xe6, 0xaf,
+	0x59, 0x71, 0x85, 0x6b, 0x62, 0x80, 0xef, 0x2a, 0x53, 0x93, 0x34, 0x5b, 0xf9, 0x8b, 0x63, 0xc6,
+	0x6a, 0x67, 0xe7, 0xff, 0x76, 0x41, 0xa9, 0x0c, 0x1f, 0x1b, 0x42, 0x1b, 0x49, 0xac, 0xae, 0x6c,
+	0xe5, 0xc0, 0xaf, 0xa2, 0x59, 0x1c, 0x20, 0x43, 0x73, 0xd1, 0xa4, 0xff, 0x75, 0xbe, 0xff, 0x2f,
+	0x00, 0x00, 0xff, 0xff, 0xe3, 0xb1, 0x00, 0x4d, 0xf9, 0x08, 0x00, 0x00,
+}

+ 1 - 1
Godeps/_workspace/src/google.golang.org/grpc/benchmark/grpc_testing/test.proto

@@ -17,7 +17,7 @@ enum PayloadType {
 
 message StatsRequest {
     // run number
-    optional int32 test_num = 1;
+    int32 test_num = 1;
 }
 
 message ServerStats {

+ 5 - 9
Godeps/_workspace/src/google.golang.org/grpc/call.go

@@ -55,9 +55,9 @@ func recvResponse(dopts dialOptions, t transport.ClientTransport, c *callInfo, s
 	if err != nil {
 		return err
 	}
-	p := &parser{s: stream}
+	p := &parser{r: stream}
 	for {
-		if err = recv(p, dopts.codec, stream, dopts.dg, reply); err != nil {
+		if err = recv(p, dopts.codec, stream, dopts.dc, reply); err != nil {
 			if err == io.EOF {
 				break
 			}
@@ -133,11 +133,7 @@ func Invoke(ctx context.Context, method string, args, reply interface{}, cc *Cli
 	}
 	var (
 		lastErr error // record the error that happened
-		cp      Compressor
 	)
-	if cc.dopts.cg != nil {
-		cp = cc.dopts.cg()
-	}
 	for {
 		var (
 			err    error
@@ -152,8 +148,8 @@ func Invoke(ctx context.Context, method string, args, reply interface{}, cc *Cli
 			Host:   cc.authority,
 			Method: method,
 		}
-		if cp != nil {
-			callHdr.SendCompress = cp.Type()
+		if cc.dopts.cp != nil {
+			callHdr.SendCompress = cc.dopts.cp.Type()
 		}
 		t, err = cc.dopts.picker.Pick(ctx)
 		if err != nil {
@@ -166,7 +162,7 @@ func Invoke(ctx context.Context, method string, args, reply interface{}, cc *Cli
 		if c.traceInfo.tr != nil {
 			c.traceInfo.tr.LazyLog(&payload{sent: true, msg: args}, true)
 		}
-		stream, err = sendRequest(ctx, cc.dopts.codec, cp, callHdr, t, args, topts)
+		stream, err = sendRequest(ctx, cc.dopts.codec, cc.dopts.cp, callHdr, t, args, topts)
 		if err != nil {
 			if _, ok := err.(transport.ConnectionError); ok {
 				lastErr = err

+ 0 - 215
Godeps/_workspace/src/google.golang.org/grpc/call_test.go

@@ -1,215 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package grpc
-
-import (
-	"io"
-	"math"
-	"net"
-	"strconv"
-	"sync"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/codes"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/transport"
-)
-
-var (
-	expectedRequest  = "ping"
-	expectedResponse = "pong"
-	sizeLargeErr     = 1024 * 1024
-)
-
-type testCodec struct {
-}
-
-func (testCodec) Marshal(v interface{}) ([]byte, error) {
-	return []byte(*(v.(*string))), nil
-}
-
-func (testCodec) Unmarshal(data []byte, v interface{}) error {
-	*(v.(*string)) = string(data)
-	return nil
-}
-
-func (testCodec) String() string {
-	return "test"
-}
-
-type testStreamHandler struct {
-	t transport.ServerTransport
-}
-
-func (h *testStreamHandler) handleStream(t *testing.T, s *transport.Stream) {
-	p := &parser{s: s}
-	for {
-		pf, req, err := p.recvMsg()
-		if err == io.EOF {
-			break
-		}
-		if err != nil {
-			return
-		}
-		if pf != compressionNone {
-			t.Errorf("Received the mistaken message format %d, want %d", pf, compressionNone)
-			return
-		}
-		var v string
-		codec := testCodec{}
-		if err := codec.Unmarshal(req, &v); err != nil {
-			t.Fatalf("Failed to unmarshal the received message %v", err)
-		}
-		if v != expectedRequest {
-			h.t.WriteStatus(s, codes.Internal, string(make([]byte, sizeLargeErr)))
-			return
-		}
-	}
-	// send a response back to end the stream.
-	reply, err := encode(testCodec{}, &expectedResponse, nil, nil)
-	if err != nil {
-		t.Fatalf("Failed to encode the response: %v", err)
-	}
-	h.t.Write(s, reply, &transport.Options{})
-	h.t.WriteStatus(s, codes.OK, "")
-}
-
-type server struct {
-	lis  net.Listener
-	port string
-	// channel to signal server is ready to serve.
-	readyChan chan bool
-	mu        sync.Mutex
-	conns     map[transport.ServerTransport]bool
-}
-
-// start starts server. Other goroutines should block on s.readyChan for futher operations.
-func (s *server) start(t *testing.T, port int, maxStreams uint32) {
-	var err error
-	if port == 0 {
-		s.lis, err = net.Listen("tcp", ":0")
-	} else {
-		s.lis, err = net.Listen("tcp", ":"+strconv.Itoa(port))
-	}
-	if err != nil {
-		t.Fatalf("failed to listen: %v", err)
-	}
-	_, p, err := net.SplitHostPort(s.lis.Addr().String())
-	if err != nil {
-		t.Fatalf("failed to parse listener address: %v", err)
-	}
-	s.port = p
-	s.conns = make(map[transport.ServerTransport]bool)
-	if s.readyChan != nil {
-		close(s.readyChan)
-	}
-	for {
-		conn, err := s.lis.Accept()
-		if err != nil {
-			return
-		}
-		st, err := transport.NewServerTransport("http2", conn, maxStreams, nil)
-		if err != nil {
-			return
-		}
-		s.mu.Lock()
-		if s.conns == nil {
-			s.mu.Unlock()
-			st.Close()
-			return
-		}
-		s.conns[st] = true
-		s.mu.Unlock()
-		h := &testStreamHandler{st}
-		go st.HandleStreams(func(s *transport.Stream) {
-			go h.handleStream(t, s)
-		})
-	}
-}
-
-func (s *server) wait(t *testing.T, timeout time.Duration) {
-	select {
-	case <-s.readyChan:
-	case <-time.After(timeout):
-		t.Fatalf("Timed out after %v waiting for server to be ready", timeout)
-	}
-}
-
-func (s *server) stop() {
-	s.lis.Close()
-	s.mu.Lock()
-	for c := range s.conns {
-		c.Close()
-	}
-	s.conns = nil
-	s.mu.Unlock()
-}
-
-func setUp(t *testing.T, port int, maxStreams uint32) (*server, *ClientConn) {
-	server := &server{readyChan: make(chan bool)}
-	go server.start(t, port, maxStreams)
-	server.wait(t, 2*time.Second)
-	addr := "localhost:" + server.port
-	cc, err := Dial(addr, WithBlock(), WithInsecure(), WithCodec(testCodec{}))
-	if err != nil {
-		t.Fatalf("Failed to create ClientConn: %v", err)
-	}
-	return server, cc
-}
-
-func TestInvoke(t *testing.T) {
-	server, cc := setUp(t, 0, math.MaxUint32)
-	var reply string
-	if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
-		t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
-	}
-	cc.Close()
-	server.stop()
-}
-
-func TestInvokeLargeErr(t *testing.T) {
-	server, cc := setUp(t, 0, math.MaxUint32)
-	var reply string
-	req := "hello"
-	err := Invoke(context.Background(), "/foo/bar", &req, &reply, cc)
-	if _, ok := err.(rpcError); !ok {
-		t.Fatalf("grpc.Invoke(_, _, _, _, _) receives non rpc error.")
-	}
-	if Code(err) != codes.Internal || len(ErrorDesc(err)) != sizeLargeErr {
-		t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want an error of code %d and desc size %d", err, codes.Internal, sizeLargeErr)
-	}
-	cc.Close()
-	server.stop()
-}

+ 8 - 7
Godeps/_workspace/src/google.golang.org/grpc/clientconn.go

@@ -73,8 +73,8 @@ var (
 // values passed to Dial.
 type dialOptions struct {
 	codec    Codec
-	cg       CompressorGenerator
-	dg       DecompressorGenerator
+	cp       Compressor
+	dc       Decompressor
 	picker   Picker
 	block    bool
 	insecure bool
@@ -93,17 +93,17 @@ func WithCodec(c Codec) DialOption {
 
 // WithCompressor returns a DialOption which sets a CompressorGenerator for generating message
 // compressor.
-func WithCompressor(f CompressorGenerator) DialOption {
+func WithCompressor(cp Compressor) DialOption {
 	return func(o *dialOptions) {
-		o.cg = f
+		o.cp = cp
 	}
 }
 
 // WithDecompressor returns a DialOption which sets a DecompressorGenerator for generating
 // message decompressor.
-func WithDecompressor(f DecompressorGenerator) DialOption {
+func WithDecompressor(dc Decompressor) DialOption {
 	return func(o *dialOptions) {
-		o.dg = f
+		o.dc = dc
 	}
 }
 
@@ -539,8 +539,9 @@ func (cc *Conn) Wait(ctx context.Context) (transport.ClientTransport, error) {
 			cc.mu.Unlock()
 			return nil, ErrClientConnClosing
 		case cc.state == Ready:
+			ct := cc.transport
 			cc.mu.Unlock()
-			return cc.transport, nil
+			return ct, nil
 		default:
 			ready := cc.ready
 			if ready == nil {

+ 0 - 82
Godeps/_workspace/src/google.golang.org/grpc/clientconn_test.go

@@ -1,82 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package grpc
-
-import (
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/credentials"
-)
-
-const tlsDir = "testdata/"
-
-func TestDialTimeout(t *testing.T) {
-	conn, err := Dial("Non-Existent.Server:80", WithTimeout(time.Millisecond), WithBlock(), WithInsecure())
-	if err == nil {
-		conn.Close()
-	}
-	if err != ErrClientConnTimeout {
-		t.Fatalf("Dial(_, _) = %v, %v, want %v", conn, err, ErrClientConnTimeout)
-	}
-}
-
-func TestTLSDialTimeout(t *testing.T) {
-	creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
-	if err != nil {
-		t.Fatalf("Failed to create credentials %v", err)
-	}
-	conn, err := Dial("Non-Existent.Server:80", WithTransportCredentials(creds), WithTimeout(time.Millisecond), WithBlock())
-	if err == nil {
-		conn.Close()
-	}
-	if err != ErrClientConnTimeout {
-		t.Fatalf("grpc.Dial(_, _) = %v, %v, want %v", conn, err, ErrClientConnTimeout)
-	}
-}
-
-func TestCredentialsMisuse(t *testing.T) {
-	creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
-	if err != nil {
-		t.Fatalf("Failed to create credentials %v", err)
-	}
-	// Two conflicting credential configurations
-	if _, err := Dial("Non-Existent.Server:80", WithTransportCredentials(creds), WithTimeout(time.Millisecond), WithBlock(), WithInsecure()); err != ErrCredentialsMisuse {
-		t.Fatalf("Dial(_, _) = _, %v, want _, %v", err, ErrCredentialsMisuse)
-	}
-	// security info on insecure connection
-	if _, err := Dial("Non-Existent.Server:80", WithPerRPCCredentials(creds), WithTimeout(time.Millisecond), WithBlock(), WithInsecure()); err != ErrCredentialsMisuse {
-		t.Fatalf("Dial(_, _) = _, %v, want _, %v", err, ErrCredentialsMisuse)
-	}
-}

+ 1 - 1
Godeps/_workspace/src/google.golang.org/grpc/doc.go

@@ -1,6 +1,6 @@
 /*
 Package grpc implements an RPC system called gRPC.
 
-See https://github.com/grpc/grpc for more information about gRPC.
+See www.grpc.io for more information about gRPC.
 */
 package grpc

+ 38 - 10
Godeps/_workspace/src/google.golang.org/grpc/examples/helloworld/helloworld/helloworld.pb.go

@@ -15,40 +15,52 @@ It has these top-level messages:
 package helloworld
 
 import proto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
 
 import (
 	context "github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
 	grpc "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
 )
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConn
-
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.ProtoPackageIsVersion1
 
 // The request message containing the user's name.
 type HelloRequest struct {
 	Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
 }
 
-func (m *HelloRequest) Reset()         { *m = HelloRequest{} }
-func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
-func (*HelloRequest) ProtoMessage()    {}
+func (m *HelloRequest) Reset()                    { *m = HelloRequest{} }
+func (m *HelloRequest) String() string            { return proto.CompactTextString(m) }
+func (*HelloRequest) ProtoMessage()               {}
+func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 // The response message containing the greetings
 type HelloReply struct {
 	Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"`
 }
 
-func (m *HelloReply) Reset()         { *m = HelloReply{} }
-func (m *HelloReply) String() string { return proto.CompactTextString(m) }
-func (*HelloReply) ProtoMessage()    {}
+func (m *HelloReply) Reset()                    { *m = HelloReply{} }
+func (m *HelloReply) String() string            { return proto.CompactTextString(m) }
+func (*HelloReply) ProtoMessage()               {}
+func (*HelloReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 func init() {
+	proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest")
+	proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply")
 }
 
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
 // Client API for Greeter service
 
 type GreeterClient interface {
@@ -107,3 +119,19 @@ var _Greeter_serviceDesc = grpc.ServiceDesc{
 	},
 	Streams: []grpc.StreamDesc{},
 }
+
+var fileDescriptor0 = []byte{
+	// 181 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9,
+	0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88,
+	0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42,
+	0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92,
+	0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71,
+	0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a,
+	0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64,
+	0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x00, 0xad, 0x50, 0x62, 0x70, 0x32, 0xe3, 0x92, 0xce, 0xcc, 0xd7,
+	0x4b, 0x2f, 0x2a, 0x48, 0xd6, 0x4b, 0xad, 0x48, 0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0x46, 0x52, 0xeb,
+	0xc4, 0x0f, 0x56, 0x1c, 0x0e, 0x62, 0x07, 0x80, 0xbc, 0x14, 0xc0, 0xb8, 0x88, 0x89, 0xd9, 0xc3,
+	0x27, 0x3c, 0x89, 0x0d, 0xec, 0x43, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x0a, 0xdc,
+	0xe8, 0xf5, 0x00, 0x00, 0x00,
+}

+ 3 - 1
Godeps/_workspace/src/google.golang.org/grpc/examples/helloworld/helloworld/helloworld.proto

@@ -29,7 +29,9 @@
 
 syntax = "proto3";
 
-option java_package = "io.grpc.examples";
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.helloworld";
+option java_outer_classname = "HelloWorldProto";
 option objc_class_prefix = "HLW";
 
 package helloworld;

+ 68 - 21
Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/routeguide/route_guide.pb.go

@@ -1,12 +1,12 @@
 // Code generated by protoc-gen-go.
-// source: google.golang.org/grpc/examples/route_guide/routeguide/route_guide.proto
+// source: route_guide.proto
 // DO NOT EDIT!
 
 /*
 Package routeguide is a generated protocol buffer package.
 
 It is generated from these files:
-	google.golang.org/grpc/examples/route_guide/routeguide/route_guide.proto
+	route_guide.proto
 
 It has these top-level messages:
 	Point
@@ -31,6 +31,10 @@ var _ = proto.Marshal
 var _ = fmt.Errorf
 var _ = math.Inf
 
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.ProtoPackageIsVersion1
+
 // Points are represented as latitude-longitude pairs in the E7 representation
 // (degrees multiplied by 10**7 and rounded to the nearest integer).
 // Latitudes should be in the range +/- 90 degrees and longitude should be in
@@ -40,9 +44,10 @@ type Point struct {
 	Longitude int32 `protobuf:"varint,2,opt,name=longitude" json:"longitude,omitempty"`
 }
 
-func (m *Point) Reset()         { *m = Point{} }
-func (m *Point) String() string { return proto.CompactTextString(m) }
-func (*Point) ProtoMessage()    {}
+func (m *Point) Reset()                    { *m = Point{} }
+func (m *Point) String() string            { return proto.CompactTextString(m) }
+func (*Point) ProtoMessage()               {}
+func (*Point) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 // A latitude-longitude rectangle, represented as two diagonally opposite
 // points "lo" and "hi".
@@ -53,9 +58,10 @@ type Rectangle struct {
 	Hi *Point `protobuf:"bytes,2,opt,name=hi" json:"hi,omitempty"`
 }
 
-func (m *Rectangle) Reset()         { *m = Rectangle{} }
-func (m *Rectangle) String() string { return proto.CompactTextString(m) }
-func (*Rectangle) ProtoMessage()    {}
+func (m *Rectangle) Reset()                    { *m = Rectangle{} }
+func (m *Rectangle) String() string            { return proto.CompactTextString(m) }
+func (*Rectangle) ProtoMessage()               {}
+func (*Rectangle) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 func (m *Rectangle) GetLo() *Point {
 	if m != nil {
@@ -81,9 +87,10 @@ type Feature struct {
 	Location *Point `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
 }
 
-func (m *Feature) Reset()         { *m = Feature{} }
-func (m *Feature) String() string { return proto.CompactTextString(m) }
-func (*Feature) ProtoMessage()    {}
+func (m *Feature) Reset()                    { *m = Feature{} }
+func (m *Feature) String() string            { return proto.CompactTextString(m) }
+func (*Feature) ProtoMessage()               {}
+func (*Feature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
 
 func (m *Feature) GetLocation() *Point {
 	if m != nil {
@@ -100,9 +107,10 @@ type RouteNote struct {
 	Message string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
 }
 
-func (m *RouteNote) Reset()         { *m = RouteNote{} }
-func (m *RouteNote) String() string { return proto.CompactTextString(m) }
-func (*RouteNote) ProtoMessage()    {}
+func (m *RouteNote) Reset()                    { *m = RouteNote{} }
+func (m *RouteNote) String() string            { return proto.CompactTextString(m) }
+func (*RouteNote) ProtoMessage()               {}
+func (*RouteNote) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
 
 func (m *RouteNote) GetLocation() *Point {
 	if m != nil {
@@ -127,9 +135,18 @@ type RouteSummary struct {
 	ElapsedTime int32 `protobuf:"varint,4,opt,name=elapsed_time" json:"elapsed_time,omitempty"`
 }
 
-func (m *RouteSummary) Reset()         { *m = RouteSummary{} }
-func (m *RouteSummary) String() string { return proto.CompactTextString(m) }
-func (*RouteSummary) ProtoMessage()    {}
+func (m *RouteSummary) Reset()                    { *m = RouteSummary{} }
+func (m *RouteSummary) String() string            { return proto.CompactTextString(m) }
+func (*RouteSummary) ProtoMessage()               {}
+func (*RouteSummary) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+
+func init() {
+	proto.RegisterType((*Point)(nil), "routeguide.Point")
+	proto.RegisterType((*Rectangle)(nil), "routeguide.Rectangle")
+	proto.RegisterType((*Feature)(nil), "routeguide.Feature")
+	proto.RegisterType((*RouteNote)(nil), "routeguide.RouteNote")
+	proto.RegisterType((*RouteSummary)(nil), "routeguide.RouteSummary")
+}
 
 // Reference imports to suppress errors if they are not otherwise used.
 var _ context.Context
@@ -142,8 +159,8 @@ type RouteGuideClient interface {
 	//
 	// Obtains the feature at a given position.
 	//
-	// If no feature is found for the given point, a feature with an empty name
-	// should be returned.
+	// A feature with an empty name is returned if there's no feature at the given
+	// position.
 	GetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (*Feature, error)
 	// A server-to-client streaming RPC.
 	//
@@ -285,8 +302,8 @@ type RouteGuideServer interface {
 	//
 	// Obtains the feature at a given position.
 	//
-	// If no feature is found for the given point, a feature with an empty name
-	// should be returned.
+	// A feature with an empty name is returned if there's no feature at the given
+	// position.
 	GetFeature(context.Context, *Point) (*Feature, error)
 	// A server-to-client streaming RPC.
 	//
@@ -424,3 +441,33 @@ var _RouteGuide_serviceDesc = grpc.ServiceDesc{
 		},
 	},
 }
+
+var fileDescriptor0 = []byte{
+	// 412 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x53, 0xd1, 0x6a, 0xa3, 0x40,
+	0x14, 0xcd, 0x98, 0x64, 0xb3, 0x5e, 0x5d, 0x96, 0xcc, 0xb2, 0x20, 0xd9, 0x85, 0xb6, 0xf6, 0x25,
+	0x2f, 0x95, 0x90, 0x42, 0x1e, 0x5b, 0x9a, 0x40, 0xf3, 0x12, 0x4a, 0x6a, 0xf3, 0x1e, 0xa6, 0x3a,
+	0x35, 0x03, 0xea, 0x88, 0x8e, 0xd0, 0x7e, 0x40, 0xbf, 0xa0, 0x7f, 0xd0, 0x2f, 0xed, 0x38, 0x6a,
+	0x62, 0xda, 0x84, 0xbe, 0x39, 0xe7, 0x9e, 0x73, 0xef, 0xb9, 0xe7, 0x22, 0xf4, 0x53, 0x9e, 0x0b,
+	0xba, 0x0e, 0x72, 0xe6, 0x53, 0x27, 0x49, 0xb9, 0xe0, 0x18, 0x14, 0xa4, 0x10, 0xfb, 0x06, 0xba,
+	0x4b, 0xce, 0x62, 0x81, 0x07, 0xf0, 0x33, 0x24, 0x82, 0x89, 0xdc, 0xa7, 0x16, 0x3a, 0x45, 0xc3,
+	0xae, 0xbb, 0x7d, 0xe3, 0xff, 0xa0, 0x87, 0x3c, 0x0e, 0xca, 0xa2, 0xa6, 0x8a, 0x3b, 0xc0, 0xbe,
+	0x07, 0xdd, 0xa5, 0x9e, 0x20, 0x71, 0x10, 0x52, 0x7c, 0x06, 0x5a, 0xc8, 0x55, 0x03, 0x63, 0xdc,
+	0x77, 0x76, 0x83, 0x1c, 0x35, 0xc5, 0x95, 0xc5, 0x82, 0xb2, 0x61, 0xaa, 0xcd, 0x61, 0xca, 0x86,
+	0xd9, 0x0b, 0xe8, 0xdd, 0x52, 0x22, 0xf2, 0x94, 0x62, 0x0c, 0x9d, 0x98, 0x44, 0xa5, 0x27, 0xdd,
+	0x55, 0xdf, 0xf8, 0x42, 0x7a, 0xe5, 0x9e, 0x74, 0xc7, 0xe3, 0xe3, 0x7d, 0xb6, 0x14, 0x7b, 0x25,
+	0x0d, 0x16, 0xd5, 0x3b, 0x2e, 0xf6, 0xb5, 0xe8, 0x5b, 0x2d, 0xb6, 0xa0, 0x17, 0xd1, 0x2c, 0x23,
+	0x41, 0xb9, 0xb8, 0xee, 0xd6, 0x4f, 0xfb, 0x0d, 0x81, 0xa9, 0xda, 0x3e, 0xe4, 0x51, 0x44, 0xd2,
+	0x17, 0x7c, 0x02, 0x46, 0x52, 0xa8, 0xd7, 0x1e, 0xcf, 0x63, 0x51, 0x85, 0x08, 0x0a, 0x9a, 0x15,
+	0x08, 0x3e, 0x87, 0x5f, 0x4f, 0xe5, 0x56, 0x15, 0xa5, 0x8c, 0xd2, 0xac, 0xc0, 0x92, 0x24, 0xef,
+	0xe0, 0xb3, 0x4c, 0xa6, 0xe9, 0x51, 0xab, 0x5d, 0xde, 0xa1, 0x7e, 0xcb, 0xe4, 0x4c, 0x1a, 0x92,
+	0x24, 0xa3, 0xfe, 0x5a, 0x30, 0x99, 0x49, 0x47, 0xd5, 0x8d, 0x0a, 0x5b, 0x49, 0x68, 0xfc, 0xaa,
+	0x01, 0x28, 0x57, 0xf3, 0x62, 0x1d, 0x3c, 0x01, 0x98, 0x53, 0x51, 0x67, 0xf9, 0x75, 0xd3, 0xc1,
+	0x9f, 0x26, 0x54, 0xf1, 0xec, 0x16, 0xbe, 0x02, 0x73, 0x21, 0xa7, 0x56, 0x40, 0x86, 0xff, 0x36,
+	0x69, 0xdb, 0x6b, 0x1f, 0x51, 0x8f, 0x90, 0xd4, 0x1b, 0x92, 0xc5, 0x53, 0x5f, 0x79, 0x39, 0x34,
+	0xd8, 0xda, 0xeb, 0xd8, 0xc8, 0xd1, 0x6e, 0x0d, 0x11, 0xbe, 0xae, 0x4e, 0x36, 0xdb, 0x10, 0xf1,
+	0x69, 0x78, 0x7d, 0xc9, 0xc1, 0x61, 0xb8, 0x90, 0x8f, 0xd0, 0x74, 0x02, 0xff, 0x18, 0x77, 0x82,
+	0x34, 0xf1, 0x1c, 0xfa, 0x4c, 0xa2, 0x24, 0xa4, 0x59, 0x83, 0x3e, 0xfd, 0xbd, 0xcb, 0x68, 0x59,
+	0xfc, 0x13, 0x4b, 0xf4, 0xae, 0xb5, 0xdd, 0xd5, 0xfc, 0xf1, 0x87, 0xfa, 0x45, 0x2e, 0x3f, 0x02,
+	0x00, 0x00, 0xff, 0xff, 0xf3, 0xe2, 0x76, 0x5e, 0x37, 0x03, 0x00, 0x00,
+}

+ 7 - 2
Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/routeguide/route_guide.proto

@@ -29,6 +29,11 @@
 
 syntax = "proto3";
 
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.routeguide";
+option java_outer_classname = "RouteGuideProto";
+option objc_class_prefix = "RTG";
+
 package routeguide;
 
 // Interface exported by the server.
@@ -37,8 +42,8 @@ service RouteGuide {
   //
   // Obtains the feature at a given position.
   //
-  // If no feature is found for the given point, a feature with an empty name
-  // should be returned.
+  // A feature with an empty name is returned if there's no feature at the given
+  // position.
   rpc GetFeature(Point) returns (Feature) {}
 
   // A server-to-client streaming RPC.

+ 0 - 15
Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/ca.pem

@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
-Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
-YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
-BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
-+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
-g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
-Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
-sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
-oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
-Dfcog5wrJytaQ6UA0wE=
------END CERTIFICATE-----

+ 0 - 601
Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/route_guide_db.json

@@ -1,601 +0,0 @@
-[{
-    "location": {
-        "latitude": 407838351,
-        "longitude": -746143763
-    },
-    "name": "Patriots Path, Mendham, NJ 07945, USA"
-}, {
-    "location": {
-        "latitude": 408122808,
-        "longitude": -743999179
-    },
-    "name": "101 New Jersey 10, Whippany, NJ 07981, USA"
-}, {
-    "location": {
-        "latitude": 413628156,
-        "longitude": -749015468
-    },
-    "name": "U.S. 6, Shohola, PA 18458, USA"
-}, {
-    "location": {
-        "latitude": 419999544,
-        "longitude": -740371136
-    },
-    "name": "5 Conners Road, Kingston, NY 12401, USA"
-}, {
-    "location": {
-        "latitude": 414008389,
-        "longitude": -743951297
-    },
-    "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
-}, {
-    "location": {
-        "latitude": 419611318,
-        "longitude": -746524769
-    },
-    "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
-}, {
-    "location": {
-        "latitude": 406109563,
-        "longitude": -742186778
-    },
-    "name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
-}, {
-    "location": {
-        "latitude": 416802456,
-        "longitude": -742370183
-    },
-    "name": "352 South Mountain Road, Wallkill, NY 12589, USA"
-}, {
-    "location": {
-        "latitude": 412950425,
-        "longitude": -741077389
-    },
-    "name": "Bailey Turn Road, Harriman, NY 10926, USA"
-}, {
-    "location": {
-        "latitude": 412144655,
-        "longitude": -743949739
-    },
-    "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
-}, {
-    "location": {
-        "latitude": 415736605,
-        "longitude": -742847522
-    },
-    "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
-}, {
-    "location": {
-        "latitude": 413843930,
-        "longitude": -740501726
-    },
-    "name": "162 Merrill Road, Highland Mills, NY 10930, USA"
-}, {
-    "location": {
-        "latitude": 410873075,
-        "longitude": -744459023
-    },
-    "name": "Clinton Road, West Milford, NJ 07480, USA"
-}, {
-    "location": {
-        "latitude": 412346009,
-        "longitude": -744026814
-    },
-    "name": "16 Old Brook Lane, Warwick, NY 10990, USA"
-}, {
-    "location": {
-        "latitude": 402948455,
-        "longitude": -747903913
-    },
-    "name": "3 Drake Lane, Pennington, NJ 08534, USA"
-}, {
-    "location": {
-        "latitude": 406337092,
-        "longitude": -740122226
-    },
-    "name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
-}, {
-    "location": {
-        "latitude": 406421967,
-        "longitude": -747727624
-    },
-    "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
-}, {
-    "location": {
-        "latitude": 416318082,
-        "longitude": -749677716
-    },
-    "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
-}, {
-    "location": {
-        "latitude": 415301720,
-        "longitude": -748416257
-    },
-    "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
-}, {
-    "location": {
-        "latitude": 402647019,
-        "longitude": -747071791
-    },
-    "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
-}, {
-    "location": {
-        "latitude": 412567807,
-        "longitude": -741058078
-    },
-    "name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
-}, {
-    "location": {
-        "latitude": 416855156,
-        "longitude": -744420597
-    },
-    "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
-}, {
-    "location": {
-        "latitude": 404663628,
-        "longitude": -744820157
-    },
-    "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
-}, {
-    "location": {
-        "latitude": 407113723,
-        "longitude": -749746483
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 402133926,
-        "longitude": -743613249
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 400273442,
-        "longitude": -741220915
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 411236786,
-        "longitude": -744070769
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 411633782,
-        "longitude": -746784970
-    },
-    "name": "211-225 Plains Road, Augusta, NJ 07822, USA"
-}, {
-    "location": {
-        "latitude": 415830701,
-        "longitude": -742952812
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 413447164,
-        "longitude": -748712898
-    },
-    "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
-}, {
-    "location": {
-        "latitude": 405047245,
-        "longitude": -749800722
-    },
-    "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
-}, {
-    "location": {
-        "latitude": 418858923,
-        "longitude": -746156790
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 417951888,
-        "longitude": -748484944
-    },
-    "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
-}, {
-    "location": {
-        "latitude": 407033786,
-        "longitude": -743977337
-    },
-    "name": "26 East 3rd Street, New Providence, NJ 07974, USA"
-}, {
-    "location": {
-        "latitude": 417548014,
-        "longitude": -740075041
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 410395868,
-        "longitude": -744972325
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 404615353,
-        "longitude": -745129803
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 406589790,
-        "longitude": -743560121
-    },
-    "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
-}, {
-    "location": {
-        "latitude": 414653148,
-        "longitude": -740477477
-    },
-    "name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
-}, {
-    "location": {
-        "latitude": 405957808,
-        "longitude": -743255336
-    },
-    "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
-}, {
-    "location": {
-        "latitude": 411733589,
-        "longitude": -741648093
-    },
-    "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
-}, {
-    "location": {
-        "latitude": 412676291,
-        "longitude": -742606606
-    },
-    "name": "1270 Lakes Road, Monroe, NY 10950, USA"
-}, {
-    "location": {
-        "latitude": 409224445,
-        "longitude": -748286738
-    },
-    "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
-}, {
-    "location": {
-        "latitude": 406523420,
-        "longitude": -742135517
-    },
-    "name": "652 Garden Street, Elizabeth, NJ 07202, USA"
-}, {
-    "location": {
-        "latitude": 401827388,
-        "longitude": -740294537
-    },
-    "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
-}, {
-    "location": {
-        "latitude": 410564152,
-        "longitude": -743685054
-    },
-    "name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
-}, {
-    "location": {
-        "latitude": 408472324,
-        "longitude": -740726046
-    },
-    "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
-}, {
-    "location": {
-        "latitude": 412452168,
-        "longitude": -740214052
-    },
-    "name": "5 White Oak Lane, Stony Point, NY 10980, USA"
-}, {
-    "location": {
-        "latitude": 409146138,
-        "longitude": -746188906
-    },
-    "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
-}, {
-    "location": {
-        "latitude": 404701380,
-        "longitude": -744781745
-    },
-    "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
-}, {
-    "location": {
-        "latitude": 409642566,
-        "longitude": -746017679
-    },
-    "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
-}, {
-    "location": {
-        "latitude": 408031728,
-        "longitude": -748645385
-    },
-    "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
-}, {
-    "location": {
-        "latitude": 413700272,
-        "longitude": -742135189
-    },
-    "name": "367 Prospect Road, Chester, NY 10918, USA"
-}, {
-    "location": {
-        "latitude": 404310607,
-        "longitude": -740282632
-    },
-    "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
-}, {
-    "location": {
-        "latitude": 409319800,
-        "longitude": -746201391
-    },
-    "name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
-}, {
-    "location": {
-        "latitude": 406685311,
-        "longitude": -742108603
-    },
-    "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
-}, {
-    "location": {
-        "latitude": 419018117,
-        "longitude": -749142781
-    },
-    "name": "43 Dreher Road, Roscoe, NY 12776, USA"
-}, {
-    "location": {
-        "latitude": 412856162,
-        "longitude": -745148837
-    },
-    "name": "Swan Street, Pine Island, NY 10969, USA"
-}, {
-    "location": {
-        "latitude": 416560744,
-        "longitude": -746721964
-    },
-    "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
-}, {
-    "location": {
-        "latitude": 405314270,
-        "longitude": -749836354
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 414219548,
-        "longitude": -743327440
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 415534177,
-        "longitude": -742900616
-    },
-    "name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
-}, {
-    "location": {
-        "latitude": 406898530,
-        "longitude": -749127080
-    },
-    "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
-}, {
-    "location": {
-        "latitude": 407586880,
-        "longitude": -741670168
-    },
-    "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
-}, {
-    "location": {
-        "latitude": 400106455,
-        "longitude": -742870190
-    },
-    "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
-}, {
-    "location": {
-        "latitude": 400066188,
-        "longitude": -746793294
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 418803880,
-        "longitude": -744102673
-    },
-    "name": "40 Mountain Road, Napanoch, NY 12458, USA"
-}, {
-    "location": {
-        "latitude": 414204288,
-        "longitude": -747895140
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 414777405,
-        "longitude": -740615601
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 415464475,
-        "longitude": -747175374
-    },
-    "name": "48 North Road, Forestburgh, NY 12777, USA"
-}, {
-    "location": {
-        "latitude": 404062378,
-        "longitude": -746376177
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 405688272,
-        "longitude": -749285130
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 400342070,
-        "longitude": -748788996
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 401809022,
-        "longitude": -744157964
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 404226644,
-        "longitude": -740517141
-    },
-    "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
-}, {
-    "location": {
-        "latitude": 410322033,
-        "longitude": -747871659
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 407100674,
-        "longitude": -747742727
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 418811433,
-        "longitude": -741718005
-    },
-    "name": "213 Bush Road, Stone Ridge, NY 12484, USA"
-}, {
-    "location": {
-        "latitude": 415034302,
-        "longitude": -743850945
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 411349992,
-        "longitude": -743694161
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 404839914,
-        "longitude": -744759616
-    },
-    "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
-}, {
-    "location": {
-        "latitude": 414638017,
-        "longitude": -745957854
-    },
-    "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
-}, {
-    "location": {
-        "latitude": 412127800,
-        "longitude": -740173578
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 401263460,
-        "longitude": -747964303
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 412843391,
-        "longitude": -749086026
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 418512773,
-        "longitude": -743067823
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 404318328,
-        "longitude": -740835638
-    },
-    "name": "42-102 Main Street, Belford, NJ 07718, USA"
-}, {
-    "location": {
-        "latitude": 419020746,
-        "longitude": -741172328
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 404080723,
-        "longitude": -746119569
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 401012643,
-        "longitude": -744035134
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 404306372,
-        "longitude": -741079661
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 403966326,
-        "longitude": -748519297
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 405002031,
-        "longitude": -748407866
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 409532885,
-        "longitude": -742200683
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 416851321,
-        "longitude": -742674555
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 406411633,
-        "longitude": -741722051
-    },
-    "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
-}, {
-    "location": {
-        "latitude": 413069058,
-        "longitude": -744597778
-    },
-    "name": "261 Van Sickle Road, Goshen, NY 10924, USA"
-}, {
-    "location": {
-        "latitude": 418465462,
-        "longitude": -746859398
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 411733222,
-        "longitude": -744228360
-    },
-    "name": ""
-}, {
-    "location": {
-        "latitude": 410248224,
-        "longitude": -747127767
-    },
-    "name": "3 Hasta Way, Newton, NJ 07860, USA"
-}]

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/server1.key

@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
-M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
-3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
-AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
-V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
-tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
-dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
-K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
-81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
-DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
-aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
-ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
-XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
-F98XJ7tIFfJq
------END PRIVATE KEY-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/examples/route_guide/testdata/server1.pem

@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
-MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
-ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
-LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
-zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
-9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
-CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
-em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
-CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
-hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
-y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
------END CERTIFICATE-----

+ 4 - 1
Godeps/_workspace/src/google.golang.org/grpc/grpclog/logger.go

@@ -42,6 +42,8 @@ import (
 )
 
 // Use golang's standard logger by default.
+// Access is not mutex-protected: do not modify except in init()
+// functions.
 var logger Logger = log.New(os.Stderr, "", log.LstdFlags)
 
 // Logger mimics golang's standard Logger as an interface.
@@ -54,7 +56,8 @@ type Logger interface {
 	Println(args ...interface{})
 }
 
-// SetLogger sets the logger that is used in grpc.
+// SetLogger sets the logger that is used in grpc. Call only from
+// init() functions.
 func SetLogger(l Logger) {
 	logger = l
 }

+ 41 - 12
Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1alpha/health.pb.go → Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1/health.pb.go

@@ -3,7 +3,7 @@
 // DO NOT EDIT!
 
 /*
-Package grpc_health_v1alpha is a generated protocol buffer package.
+Package grpc_health_v1 is a generated protocol buffer package.
 
 It is generated from these files:
 	health.proto
@@ -12,7 +12,7 @@ It has these top-level messages:
 	HealthCheckRequest
 	HealthCheckResponse
 */
-package grpc_health_v1alpha
+package grpc_health_v1
 
 import proto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
 import fmt "fmt"
@@ -28,6 +28,10 @@ var _ = proto.Marshal
 var _ = fmt.Errorf
 var _ = math.Inf
 
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.ProtoPackageIsVersion1
+
 type HealthCheckResponse_ServingStatus int32
 
 const (
@@ -50,25 +54,32 @@ var HealthCheckResponse_ServingStatus_value = map[string]int32{
 func (x HealthCheckResponse_ServingStatus) String() string {
 	return proto.EnumName(HealthCheckResponse_ServingStatus_name, int32(x))
 }
+func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{1, 0}
+}
 
 type HealthCheckRequest struct {
 	Service string `protobuf:"bytes,1,opt,name=service" json:"service,omitempty"`
 }
 
-func (m *HealthCheckRequest) Reset()         { *m = HealthCheckRequest{} }
-func (m *HealthCheckRequest) String() string { return proto.CompactTextString(m) }
-func (*HealthCheckRequest) ProtoMessage()    {}
+func (m *HealthCheckRequest) Reset()                    { *m = HealthCheckRequest{} }
+func (m *HealthCheckRequest) String() string            { return proto.CompactTextString(m) }
+func (*HealthCheckRequest) ProtoMessage()               {}
+func (*HealthCheckRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 type HealthCheckResponse struct {
-	Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,enum=grpc.health.v1alpha.HealthCheckResponse_ServingStatus" json:"status,omitempty"`
+	Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,enum=grpc.health.v1.HealthCheckResponse_ServingStatus" json:"status,omitempty"`
 }
 
-func (m *HealthCheckResponse) Reset()         { *m = HealthCheckResponse{} }
-func (m *HealthCheckResponse) String() string { return proto.CompactTextString(m) }
-func (*HealthCheckResponse) ProtoMessage()    {}
+func (m *HealthCheckResponse) Reset()                    { *m = HealthCheckResponse{} }
+func (m *HealthCheckResponse) String() string            { return proto.CompactTextString(m) }
+func (*HealthCheckResponse) ProtoMessage()               {}
+func (*HealthCheckResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 func init() {
-	proto.RegisterEnum("grpc.health.v1alpha.HealthCheckResponse_ServingStatus", HealthCheckResponse_ServingStatus_name, HealthCheckResponse_ServingStatus_value)
+	proto.RegisterType((*HealthCheckRequest)(nil), "grpc.health.v1.HealthCheckRequest")
+	proto.RegisterType((*HealthCheckResponse)(nil), "grpc.health.v1.HealthCheckResponse")
+	proto.RegisterEnum("grpc.health.v1.HealthCheckResponse_ServingStatus", HealthCheckResponse_ServingStatus_name, HealthCheckResponse_ServingStatus_value)
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -91,7 +102,7 @@ func NewHealthClient(cc *grpc.ClientConn) HealthClient {
 
 func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
 	out := new(HealthCheckResponse)
-	err := grpc.Invoke(ctx, "/grpc.health.v1alpha.Health/Check", in, out, c.cc, opts...)
+	err := grpc.Invoke(ctx, "/grpc.health.v1.Health/Check", in, out, c.cc, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -121,7 +132,7 @@ func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interf
 }
 
 var _Health_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "grpc.health.v1alpha.Health",
+	ServiceName: "grpc.health.v1.Health",
 	HandlerType: (*HealthServer)(nil),
 	Methods: []grpc.MethodDesc{
 		{
@@ -131,3 +142,21 @@ var _Health_serviceDesc = grpc.ServiceDesc{
 	},
 	Streams: []grpc.StreamDesc{},
 }
+
+var fileDescriptor0 = []byte{
+	// 209 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xc9, 0x48, 0x4d, 0xcc,
+	0x29, 0xc9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4e, 0x2f, 0x2a, 0x48, 0xd6, 0x83,
+	0x0a, 0x95, 0x19, 0x26, 0xe6, 0x14, 0x64, 0x24, 0x2a, 0xe9, 0x71, 0x09, 0x79, 0x80, 0x45, 0x9c,
+	0x33, 0x52, 0x93, 0xb3, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x24, 0xb8, 0xd8, 0x8b,
+	0x53, 0x8b, 0xca, 0x32, 0x93, 0x53, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x60, 0x5c, 0xa5,
+	0x85, 0x8c, 0x5c, 0xc2, 0x28, 0x1a, 0x8a, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0xfc, 0xb8, 0xd8,
+	0x8a, 0x4b, 0x12, 0x4b, 0x4a, 0x8b, 0xc1, 0x1a, 0xf8, 0x8c, 0xcc, 0xf4, 0xb0, 0xd8, 0xa6, 0x87,
+	0x45, 0xa7, 0x5e, 0x30, 0xc8, 0xe4, 0xbc, 0xf4, 0x60, 0xb0, 0xee, 0x20, 0xa8, 0x29, 0x4a, 0x56,
+	0x5c, 0xbc, 0x28, 0x12, 0x42, 0xdc, 0x5c, 0xec, 0xa1, 0x7e, 0xde, 0x7e, 0xfe, 0xe1, 0x7e, 0x02,
+	0x0c, 0x20, 0x4e, 0xb0, 0x6b, 0x50, 0x98, 0xa7, 0x9f, 0xbb, 0x00, 0xa3, 0x10, 0x3f, 0x17, 0xb7,
+	0x9f, 0x7f, 0x48, 0x3c, 0x4c, 0x80, 0xc9, 0x28, 0x85, 0x8b, 0x0d, 0x62, 0x91, 0x50, 0x14, 0x17,
+	0x2b, 0xd8, 0x32, 0x21, 0x75, 0xc2, 0xce, 0x01, 0xfb, 0x5c, 0x4a, 0x83, 0x58, 0x77, 0x27, 0xb1,
+	0x81, 0x43, 0xd5, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xe1, 0x3f, 0xd0, 0xe1, 0x65, 0x01, 0x00,
+	0x00,
+}

+ 1 - 1
Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1alpha/health.proto → Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1/health.proto

@@ -1,6 +1,6 @@
 syntax = "proto3";
 
-package grpc.health.v1alpha;
+package grpc.health.v1;
 
 message HealthCheckRequest {
   string service = 1;

+ 1 - 1
Godeps/_workspace/src/google.golang.org/grpc/health/health.go

@@ -8,7 +8,7 @@ import (
 	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
 	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
 	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/codes"
-	healthpb "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1alpha"
+	healthpb "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1"
 )
 
 type HealthServer struct {

+ 0 - 15
Godeps/_workspace/src/google.golang.org/grpc/interop/client/testdata/ca.pem

@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
-Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
-YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
-BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
-+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
-g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
-Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
-sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
-oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
-Dfcog5wrJytaQ6UA0wE=
------END CERTIFICATE-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/interop/client/testdata/server1.key

@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
-M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
-3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
-AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
-V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
-tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
-dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
-K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
-81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
-DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
-aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
-ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
-XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
-F98XJ7tIFfJq
------END PRIVATE KEY-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/interop/client/testdata/server1.pem

@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
-MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
-ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
-LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
-zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
-9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
-CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
-em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
-CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
-hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
-y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
------END CERTIFICATE-----

+ 96 - 31
Godeps/_workspace/src/google.golang.org/grpc/interop/grpc_testing/test.pb.go

@@ -22,6 +22,7 @@ It has these top-level messages:
 package grpc_testing
 
 import proto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
+import fmt "fmt"
 import math "math"
 
 import (
@@ -29,14 +30,15 @@ import (
 	grpc "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
 )
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConn
-
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
+var _ = fmt.Errorf
 var _ = math.Inf
 
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.ProtoPackageIsVersion1
+
 // The type of payload that should be returned.
 type PayloadType int32
 
@@ -76,14 +78,16 @@ func (x *PayloadType) UnmarshalJSON(data []byte) error {
 	*x = PayloadType(value)
 	return nil
 }
+func (PayloadType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 type Empty struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *Empty) Reset()         { *m = Empty{} }
-func (m *Empty) String() string { return proto.CompactTextString(m) }
-func (*Empty) ProtoMessage()    {}
+func (m *Empty) Reset()                    { *m = Empty{} }
+func (m *Empty) String() string            { return proto.CompactTextString(m) }
+func (*Empty) ProtoMessage()               {}
+func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 // A block of data, to simply increase gRPC message size.
 type Payload struct {
@@ -94,9 +98,10 @@ type Payload struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *Payload) Reset()         { *m = Payload{} }
-func (m *Payload) String() string { return proto.CompactTextString(m) }
-func (*Payload) ProtoMessage()    {}
+func (m *Payload) Reset()                    { *m = Payload{} }
+func (m *Payload) String() string            { return proto.CompactTextString(m) }
+func (*Payload) ProtoMessage()               {}
+func (*Payload) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 func (m *Payload) GetType() PayloadType {
 	if m != nil && m.Type != nil {
@@ -129,9 +134,10 @@ type SimpleRequest struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *SimpleRequest) Reset()         { *m = SimpleRequest{} }
-func (m *SimpleRequest) String() string { return proto.CompactTextString(m) }
-func (*SimpleRequest) ProtoMessage()    {}
+func (m *SimpleRequest) Reset()                    { *m = SimpleRequest{} }
+func (m *SimpleRequest) String() string            { return proto.CompactTextString(m) }
+func (*SimpleRequest) ProtoMessage()               {}
+func (*SimpleRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
 
 func (m *SimpleRequest) GetResponseType() PayloadType {
 	if m != nil && m.ResponseType != nil {
@@ -180,9 +186,10 @@ type SimpleResponse struct {
 	XXX_unrecognized []byte  `json:"-"`
 }
 
-func (m *SimpleResponse) Reset()         { *m = SimpleResponse{} }
-func (m *SimpleResponse) String() string { return proto.CompactTextString(m) }
-func (*SimpleResponse) ProtoMessage()    {}
+func (m *SimpleResponse) Reset()                    { *m = SimpleResponse{} }
+func (m *SimpleResponse) String() string            { return proto.CompactTextString(m) }
+func (*SimpleResponse) ProtoMessage()               {}
+func (*SimpleResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
 
 func (m *SimpleResponse) GetPayload() *Payload {
 	if m != nil {
@@ -212,9 +219,10 @@ type StreamingInputCallRequest struct {
 	XXX_unrecognized []byte   `json:"-"`
 }
 
-func (m *StreamingInputCallRequest) Reset()         { *m = StreamingInputCallRequest{} }
-func (m *StreamingInputCallRequest) String() string { return proto.CompactTextString(m) }
-func (*StreamingInputCallRequest) ProtoMessage()    {}
+func (m *StreamingInputCallRequest) Reset()                    { *m = StreamingInputCallRequest{} }
+func (m *StreamingInputCallRequest) String() string            { return proto.CompactTextString(m) }
+func (*StreamingInputCallRequest) ProtoMessage()               {}
+func (*StreamingInputCallRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
 
 func (m *StreamingInputCallRequest) GetPayload() *Payload {
 	if m != nil {
@@ -230,9 +238,10 @@ type StreamingInputCallResponse struct {
 	XXX_unrecognized      []byte `json:"-"`
 }
 
-func (m *StreamingInputCallResponse) Reset()         { *m = StreamingInputCallResponse{} }
-func (m *StreamingInputCallResponse) String() string { return proto.CompactTextString(m) }
-func (*StreamingInputCallResponse) ProtoMessage()    {}
+func (m *StreamingInputCallResponse) Reset()                    { *m = StreamingInputCallResponse{} }
+func (m *StreamingInputCallResponse) String() string            { return proto.CompactTextString(m) }
+func (*StreamingInputCallResponse) ProtoMessage()               {}
+func (*StreamingInputCallResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
 
 func (m *StreamingInputCallResponse) GetAggregatedPayloadSize() int32 {
 	if m != nil && m.AggregatedPayloadSize != nil {
@@ -252,9 +261,10 @@ type ResponseParameters struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *ResponseParameters) Reset()         { *m = ResponseParameters{} }
-func (m *ResponseParameters) String() string { return proto.CompactTextString(m) }
-func (*ResponseParameters) ProtoMessage()    {}
+func (m *ResponseParameters) Reset()                    { *m = ResponseParameters{} }
+func (m *ResponseParameters) String() string            { return proto.CompactTextString(m) }
+func (*ResponseParameters) ProtoMessage()               {}
+func (*ResponseParameters) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
 
 func (m *ResponseParameters) GetSize() int32 {
 	if m != nil && m.Size != nil {
@@ -284,9 +294,10 @@ type StreamingOutputCallRequest struct {
 	XXX_unrecognized []byte   `json:"-"`
 }
 
-func (m *StreamingOutputCallRequest) Reset()         { *m = StreamingOutputCallRequest{} }
-func (m *StreamingOutputCallRequest) String() string { return proto.CompactTextString(m) }
-func (*StreamingOutputCallRequest) ProtoMessage()    {}
+func (m *StreamingOutputCallRequest) Reset()                    { *m = StreamingOutputCallRequest{} }
+func (m *StreamingOutputCallRequest) String() string            { return proto.CompactTextString(m) }
+func (*StreamingOutputCallRequest) ProtoMessage()               {}
+func (*StreamingOutputCallRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
 
 func (m *StreamingOutputCallRequest) GetResponseType() PayloadType {
 	if m != nil && m.ResponseType != nil {
@@ -316,9 +327,10 @@ type StreamingOutputCallResponse struct {
 	XXX_unrecognized []byte   `json:"-"`
 }
 
-func (m *StreamingOutputCallResponse) Reset()         { *m = StreamingOutputCallResponse{} }
-func (m *StreamingOutputCallResponse) String() string { return proto.CompactTextString(m) }
-func (*StreamingOutputCallResponse) ProtoMessage()    {}
+func (m *StreamingOutputCallResponse) Reset()                    { *m = StreamingOutputCallResponse{} }
+func (m *StreamingOutputCallResponse) String() string            { return proto.CompactTextString(m) }
+func (*StreamingOutputCallResponse) ProtoMessage()               {}
+func (*StreamingOutputCallResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
 
 func (m *StreamingOutputCallResponse) GetPayload() *Payload {
 	if m != nil {
@@ -328,9 +340,22 @@ func (m *StreamingOutputCallResponse) GetPayload() *Payload {
 }
 
 func init() {
+	proto.RegisterType((*Empty)(nil), "grpc.testing.Empty")
+	proto.RegisterType((*Payload)(nil), "grpc.testing.Payload")
+	proto.RegisterType((*SimpleRequest)(nil), "grpc.testing.SimpleRequest")
+	proto.RegisterType((*SimpleResponse)(nil), "grpc.testing.SimpleResponse")
+	proto.RegisterType((*StreamingInputCallRequest)(nil), "grpc.testing.StreamingInputCallRequest")
+	proto.RegisterType((*StreamingInputCallResponse)(nil), "grpc.testing.StreamingInputCallResponse")
+	proto.RegisterType((*ResponseParameters)(nil), "grpc.testing.ResponseParameters")
+	proto.RegisterType((*StreamingOutputCallRequest)(nil), "grpc.testing.StreamingOutputCallRequest")
+	proto.RegisterType((*StreamingOutputCallResponse)(nil), "grpc.testing.StreamingOutputCallResponse")
 	proto.RegisterEnum("grpc.testing.PayloadType", PayloadType_name, PayloadType_value)
 }
 
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
 // Client API for TestService service
 
 type TestServiceClient interface {
@@ -700,3 +725,43 @@ var _TestService_serviceDesc = grpc.ServiceDesc{
 		},
 	},
 }
+
+var fileDescriptor0 = []byte{
+	// 567 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x54, 0x51, 0x6f, 0xd2, 0x50,
+	0x14, 0xb6, 0x03, 0x64, 0x1c, 0x58, 0x43, 0x0e, 0x59, 0x64, 0x9d, 0x89, 0x4b, 0x7d, 0xb0, 0x9a,
+	0x88, 0x86, 0x44, 0x1f, 0x35, 0x73, 0x63, 0x71, 0x09, 0x03, 0x6c, 0xe1, 0x99, 0x5c, 0xe1, 0x0e,
+	0x9b, 0x94, 0xb6, 0xb6, 0xb7, 0x46, 0x7c, 0xf0, 0x8f, 0xf9, 0x67, 0xfc, 0x11, 0xfe, 0x00, 0xef,
+	0xbd, 0x6d, 0xa1, 0x40, 0x17, 0x99, 0xc6, 0xbd, 0xb5, 0xdf, 0xf9, 0xce, 0x77, 0xbe, 0xef, 0x9e,
+	0xdb, 0x02, 0x30, 0x1a, 0xb2, 0x96, 0x1f, 0x78, 0xcc, 0xc3, 0xda, 0x2c, 0xf0, 0x27, 0x2d, 0x01,
+	0xd8, 0xee, 0x4c, 0x2f, 0x43, 0xa9, 0x33, 0xf7, 0xd9, 0x42, 0xef, 0x42, 0x79, 0x40, 0x16, 0x8e,
+	0x47, 0xa6, 0xf8, 0x1c, 0x8a, 0x6c, 0xe1, 0xd3, 0xa6, 0x72, 0xa2, 0x18, 0x6a, 0xfb, 0xa8, 0x95,
+	0x6d, 0x68, 0x25, 0xa4, 0x21, 0x27, 0x98, 0x92, 0x86, 0x08, 0xc5, 0x8f, 0xde, 0x74, 0xd1, 0xdc,
+	0xe3, 0xf4, 0x9a, 0x29, 0x9f, 0xf5, 0x5f, 0x0a, 0x1c, 0x58, 0xf6, 0xdc, 0x77, 0xa8, 0x49, 0x3f,
+	0x47, 0xbc, 0x15, 0xdf, 0xc0, 0x41, 0x40, 0x43, 0xdf, 0x73, 0x43, 0x3a, 0xde, 0x4d, 0xbd, 0x96,
+	0xf2, 0xc5, 0x1b, 0x3e, 0xce, 0xf4, 0x87, 0xf6, 0x37, 0x2a, 0xc7, 0x95, 0x56, 0x24, 0x8b, 0x63,
+	0xf8, 0x02, 0xca, 0x7e, 0xac, 0xd0, 0x2c, 0xf0, 0x72, 0xb5, 0x7d, 0x98, 0x2b, 0x6f, 0xa6, 0x2c,
+	0xa1, 0x7a, 0x6d, 0x3b, 0xce, 0x38, 0x0a, 0x69, 0xe0, 0x92, 0x39, 0x6d, 0x16, 0x79, 0xdb, 0xbe,
+	0x59, 0x13, 0xe0, 0x28, 0xc1, 0xd0, 0x80, 0xba, 0x24, 0x79, 0x24, 0x62, 0x9f, 0xc6, 0xe1, 0xc4,
+	0xe3, 0xee, 0x4b, 0x92, 0xa7, 0x0a, 0xbc, 0x2f, 0x60, 0x4b, 0xa0, 0xfa, 0x77, 0x50, 0xd3, 0xd4,
+	0xb1, 0xab, 0xac, 0x23, 0x65, 0x27, 0x47, 0x1a, 0xec, 0x2f, 0xcd, 0x88, 0x88, 0x15, 0x73, 0xf9,
+	0x8e, 0x8f, 0xa0, 0x9a, 0xf5, 0x50, 0x90, 0x65, 0xf0, 0x56, 0xf3, 0xbb, 0x70, 0x64, 0xb1, 0x80,
+	0x92, 0x39, 0x97, 0xbe, 0x74, 0xfd, 0x88, 0x9d, 0x11, 0xc7, 0x49, 0x37, 0x70, 0x5b, 0x2b, 0xfa,
+	0x10, 0xb4, 0x3c, 0xb5, 0x24, 0xd9, 0x6b, 0x78, 0x40, 0x66, 0xb3, 0x80, 0xce, 0x08, 0xa3, 0xd3,
+	0x71, 0xd2, 0x13, 0xaf, 0x46, 0x91, 0xab, 0x39, 0x5c, 0x95, 0x13, 0x69, 0xb1, 0x23, 0xfd, 0x12,
+	0x30, 0xd5, 0x18, 0x90, 0x80, 0xc7, 0x62, 0x34, 0x08, 0xc5, 0x25, 0xca, 0xb4, 0xca, 0x67, 0x11,
+	0xd7, 0x76, 0x79, 0xf5, 0x0b, 0x11, 0x0b, 0x4a, 0x16, 0x0e, 0x29, 0x34, 0x0a, 0xf5, 0x9f, 0x4a,
+	0xc6, 0x61, 0x3f, 0x62, 0x1b, 0x81, 0xff, 0xf5, 0xca, 0x7d, 0x80, 0xc6, 0xb2, 0xdf, 0x5f, 0x5a,
+	0xe5, 0x3e, 0x0a, 0xfc, 0xf0, 0x4e, 0xd6, 0x55, 0xb6, 0x23, 0x99, 0x18, 0x6c, 0xc7, 0xbc, 0xed,
+	0x05, 0xd5, 0x7b, 0x70, 0x9c, 0x9b, 0xf0, 0x2f, 0xaf, 0xd7, 0xb3, 0xb7, 0x50, 0xcd, 0x04, 0xc6,
+	0x3a, 0xd4, 0xce, 0xfa, 0x57, 0x03, 0xb3, 0x63, 0x59, 0xa7, 0xef, 0xba, 0x9d, 0xfa, 0x3d, 0xbe,
+	0x08, 0x75, 0xd4, 0x5b, 0xc3, 0x14, 0x04, 0xb8, 0x6f, 0x9e, 0xf6, 0xce, 0xfb, 0x57, 0xf5, 0xbd,
+	0xf6, 0x8f, 0x22, 0x54, 0x87, 0x5c, 0xdd, 0xe2, 0x4b, 0xb0, 0x27, 0x14, 0x5f, 0x41, 0x45, 0xfe,
+	0x40, 0x84, 0x2d, 0x6c, 0xac, 0x4f, 0x97, 0x05, 0x2d, 0x0f, 0xc4, 0x0b, 0xa8, 0x8c, 0x5c, 0x12,
+	0xc4, 0x6d, 0xc7, 0xeb, 0x8c, 0xb5, 0x1f, 0x87, 0xf6, 0x30, 0xbf, 0x98, 0x1c, 0x80, 0x03, 0x8d,
+	0x9c, 0xf3, 0x41, 0x63, 0xa3, 0xe9, 0xc6, 0x4b, 0xa2, 0x3d, 0xdd, 0x81, 0x19, 0xcf, 0x7a, 0xa9,
+	0xa0, 0x0d, 0xb8, 0xfd, 0x45, 0xe0, 0x93, 0x1b, 0x24, 0x36, 0xbf, 0x40, 0xcd, 0xf8, 0x33, 0x31,
+	0x1e, 0x65, 0x88, 0x51, 0xea, 0x45, 0xe4, 0x38, 0xe7, 0x11, 0x4f, 0xfb, 0xf5, 0xbf, 0x65, 0x32,
+	0x14, 0x99, 0x4a, 0x7d, 0x4f, 0x9c, 0xeb, 0x3b, 0x18, 0xf5, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x4c,
+	0x41, 0xfe, 0xb6, 0x89, 0x06, 0x00, 0x00,
+}

+ 0 - 15
Godeps/_workspace/src/google.golang.org/grpc/interop/server/testdata/ca.pem

@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
-Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
-YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
-BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
-+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
-g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
-Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
-sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
-oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
-Dfcog5wrJytaQ6UA0wE=
------END CERTIFICATE-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/interop/server/testdata/server1.key

@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
-M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
-3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
-AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
-V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
-tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
-dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
-K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
-81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
-DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
-aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
-ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
-XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
-F98XJ7tIFfJq
------END PRIVATE KEY-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/interop/server/testdata/server1.pem

@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
-MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
-ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
-LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
-zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
-9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
-CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
-em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
-CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
-hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
-y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
------END CERTIFICATE-----

+ 0 - 107
Godeps/_workspace/src/google.golang.org/grpc/metadata/metadata_test.go

@@ -1,107 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package metadata
-
-import (
-	"reflect"
-	"testing"
-)
-
-const binaryValue = string(128)
-
-func TestEncodeKeyValue(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		kin string
-		vin string
-		// output
-		kout string
-		vout string
-	}{
-		{"key", "abc", "key", "abc"},
-		{"KEY", "abc", "key", "abc"},
-		{"key-bin", "abc", "key-bin", "YWJj"},
-		{"key-bin", binaryValue, "key-bin", "woA="},
-	} {
-		k, v := encodeKeyValue(test.kin, test.vin)
-		if k != test.kout || !reflect.DeepEqual(v, test.vout) {
-			t.Fatalf("encodeKeyValue(%q, %q) = %q, %q, want %q, %q", test.kin, test.vin, k, v, test.kout, test.vout)
-		}
-	}
-}
-
-func TestDecodeKeyValue(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		kin string
-		vin string
-		// output
-		kout string
-		vout string
-		err  error
-	}{
-		{"a", "abc", "a", "abc", nil},
-		{"key-bin", "Zm9vAGJhcg==", "key-bin", "foo\x00bar", nil},
-		{"key-bin", "woA=", "key-bin", binaryValue, nil},
-	} {
-		k, v, err := DecodeKeyValue(test.kin, test.vin)
-		if k != test.kout || !reflect.DeepEqual(v, test.vout) || !reflect.DeepEqual(err, test.err) {
-			t.Fatalf("DecodeKeyValue(%q, %q) = %q, %q, %v, want %q, %q, %v", test.kin, test.vin, k, v, err, test.kout, test.vout, test.err)
-		}
-	}
-}
-
-func TestPairsMD(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		kv []string
-		// output
-		md   MD
-		size int
-	}{
-		{[]string{}, MD{}, 0},
-		{[]string{"k1", "v1", "k2-bin", binaryValue}, New(map[string]string{
-			"k1":     "v1",
-			"k2-bin": binaryValue,
-		}), 2},
-	} {
-		md := Pairs(test.kv...)
-		if !reflect.DeepEqual(md, test.md) {
-			t.Fatalf("Pairs(%v) = %v, want %v", test.kv, md, test.md)
-		}
-		if md.Len() != test.size {
-			t.Fatalf("Pairs(%v) generates md of size %d, want %d", test.kv, md.Len(), test.size)
-		}
-	}
-}

+ 0 - 188
Godeps/_workspace/src/google.golang.org/grpc/picker_test.go

@@ -1,188 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package grpc
-
-import (
-	"fmt"
-	"math"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/naming"
-)
-
-type testWatcher struct {
-	// the channel to receives name resolution updates
-	update chan *naming.Update
-	// the side channel to get to know how many updates in a batch
-	side chan int
-	// the channel to notifiy update injector that the update reading is done
-	readDone chan int
-}
-
-func (w *testWatcher) Next() (updates []*naming.Update, err error) {
-	n := <-w.side
-	if n == 0 {
-		return nil, fmt.Errorf("w.side is closed")
-	}
-	for i := 0; i < n; i++ {
-		u := <-w.update
-		if u != nil {
-			updates = append(updates, u)
-		}
-	}
-	w.readDone <- 0
-	return
-}
-
-func (w *testWatcher) Close() {
-}
-
-func (w *testWatcher) inject(updates []*naming.Update) {
-	w.side <- len(updates)
-	for _, u := range updates {
-		w.update <- u
-	}
-	<-w.readDone
-}
-
-type testNameResolver struct {
-	w    *testWatcher
-	addr string
-}
-
-func (r *testNameResolver) Resolve(target string) (naming.Watcher, error) {
-	r.w = &testWatcher{
-		update:   make(chan *naming.Update, 1),
-		side:     make(chan int, 1),
-		readDone: make(chan int),
-	}
-	r.w.side <- 1
-	r.w.update <- &naming.Update{
-		Op:   naming.Add,
-		Addr: r.addr,
-	}
-	go func() {
-		<-r.w.readDone
-	}()
-	return r.w, nil
-}
-
-func startServers(t *testing.T, numServers, port int, maxStreams uint32) ([]*server, *testNameResolver) {
-	var servers []*server
-	for i := 0; i < numServers; i++ {
-		s := &server{readyChan: make(chan bool)}
-		servers = append(servers, s)
-		go s.start(t, port, maxStreams)
-		s.wait(t, 2*time.Second)
-	}
-	// Point to server1
-	addr := "127.0.0.1:" + servers[0].port
-	return servers, &testNameResolver{
-		addr: addr,
-	}
-}
-
-func TestNameDiscovery(t *testing.T) {
-	// Start 3 servers on 3 ports.
-	servers, r := startServers(t, 3, 0, math.MaxUint32)
-	cc, err := Dial("foo.bar.com", WithPicker(NewUnicastNamingPicker(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
-	if err != nil {
-		t.Fatalf("Failed to create ClientConn: %v", err)
-	}
-	var reply string
-	if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
-		t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
-	}
-	// Inject name resolution change to point to the second server now.
-	var updates []*naming.Update
-	updates = append(updates, &naming.Update{
-		Op:   naming.Delete,
-		Addr: "127.0.0.1:" + servers[0].port,
-	})
-	updates = append(updates, &naming.Update{
-		Op:   naming.Add,
-		Addr: "127.0.0.1:" + servers[1].port,
-	})
-	r.w.inject(updates)
-	servers[0].stop()
-	if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
-		t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
-	}
-	// Add another server address (server#3) to name resolution
-	updates = nil
-	updates = append(updates, &naming.Update{
-		Op:   naming.Add,
-		Addr: "127.0.0.1:" + servers[2].port,
-	})
-	r.w.inject(updates)
-	// Stop server#2. The library should direct to server#3 automatically.
-	servers[1].stop()
-	if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
-		t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
-	}
-	cc.Close()
-	servers[2].stop()
-}
-
-func TestEmptyAddrs(t *testing.T) {
-	servers, r := startServers(t, 1, 0, math.MaxUint32)
-	cc, err := Dial("foo.bar.com", WithPicker(NewUnicastNamingPicker(r)), WithBlock(), WithInsecure(), WithCodec(testCodec{}))
-	if err != nil {
-		t.Fatalf("Failed to create ClientConn: %v", err)
-	}
-	var reply string
-	if err := Invoke(context.Background(), "/foo/bar", &expectedRequest, &reply, cc); err != nil || reply != expectedResponse {
-		t.Fatalf("grpc.Invoke(_, _, _, _, _) = %v, want <nil>", err)
-	}
-	// Inject name resolution change to remove the server address so that there is no address
-	// available after that.
-	var updates []*naming.Update
-	updates = append(updates, &naming.Update{
-		Op:   naming.Delete,
-		Addr: "127.0.0.1:" + servers[0].port,
-	})
-	r.w.inject(updates)
-	// Loop until the above updates apply.
-	for {
-		time.Sleep(10 * time.Millisecond)
-		ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
-		if err := Invoke(ctx, "/foo/bar", &expectedRequest, &reply, cc); err != nil {
-			break
-		}
-	}
-	cc.Close()
-	servers[0].stop()
-}

+ 28 - 24
Godeps/_workspace/src/google.golang.org/grpc/rpc_util.go

@@ -135,12 +135,6 @@ func (d *gzipDecompressor) Type() string {
 	return "gzip"
 }
 
-// CompressorGenerator defines the function generating a Compressor.
-type CompressorGenerator func() Compressor
-
-// DecompressorGenerator defines the function generating a Decompressor.
-type DecompressorGenerator func() Decompressor
-
 // callInfo contains all related configuration and information about an RPC.
 type callInfo struct {
 	failFast  bool
@@ -197,30 +191,44 @@ const (
 
 // parser reads complelete gRPC messages from the underlying reader.
 type parser struct {
-	s io.Reader
-}
+	// r is the underlying reader.
+	// See the comment on recvMsg for the permissible
+	// error types.
+	r io.Reader
 
-// recvMsg is to read a complete gRPC message from the stream. It is blocking if
-// the message has not been complete yet. It returns the message and its type,
-// EOF is returned with nil msg and 0 pf if the entire stream is done. Other
-// non-nil error is returned if something is wrong on reading.
-func (p *parser) recvMsg() (pf payloadFormat, msg []byte, err error) {
 	// The header of a gRPC message. Find more detail
 	// at http://www.grpc.io/docs/guides/wire.html.
-	var buf [5]byte
+	header [5]byte
+}
 
-	if _, err := io.ReadFull(p.s, buf[:]); err != nil {
+// recvMsg reads a complete gRPC message from the stream.
+//
+// It returns the message and its payload (compression/encoding)
+// format. The caller owns the returned msg memory.
+//
+// If there is an error, possible values are:
+//   * io.EOF, when no messages remain
+//   * io.ErrUnexpectedEOF
+//   * of type transport.ConnectionError
+//   * of type transport.StreamError
+// No other error values or types must be returned, which also means
+// that the underlying io.Reader must not return an incompatible
+// error.
+func (p *parser) recvMsg() (pf payloadFormat, msg []byte, err error) {
+	if _, err := io.ReadFull(p.r, p.header[:]); err != nil {
 		return 0, nil, err
 	}
 
-	pf = payloadFormat(buf[0])
-	length := binary.BigEndian.Uint32(buf[1:])
+	pf = payloadFormat(p.header[0])
+	length := binary.BigEndian.Uint32(p.header[1:])
 
 	if length == 0 {
 		return pf, nil, nil
 	}
+	// TODO(bradfitz,zhaoq): garbage. reuse buffer after proto decoding instead
+	// of making it for each message:
 	msg = make([]byte, int(length))
-	if _, err := io.ReadFull(p.s, msg); err != nil {
+	if _, err := io.ReadFull(p.r, msg); err != nil {
 		if err == io.EOF {
 			err = io.ErrUnexpectedEOF
 		}
@@ -279,7 +287,7 @@ func checkRecvPayload(pf payloadFormat, recvCompress string, dc Decompressor) er
 	case compressionNone:
 	case compressionMade:
 		if recvCompress == "" {
-			return transport.StreamErrorf(codes.InvalidArgument, "grpc: received unexpected payload format %d", pf)
+			return transport.StreamErrorf(codes.InvalidArgument, "grpc: invalid grpc-encoding %q with compression enabled", recvCompress)
 		}
 		if dc == nil || recvCompress != dc.Type() {
 			return transport.StreamErrorf(codes.InvalidArgument, "grpc: Decompressor is not installed for grpc-encoding %q", recvCompress)
@@ -290,15 +298,11 @@ func checkRecvPayload(pf payloadFormat, recvCompress string, dc Decompressor) er
 	return nil
 }
 
-func recv(p *parser, c Codec, s *transport.Stream, dg DecompressorGenerator, m interface{}) error {
+func recv(p *parser, c Codec, s *transport.Stream, dc Decompressor, m interface{}) error {
 	pf, d, err := p.recvMsg()
 	if err != nil {
 		return err
 	}
-	var dc Decompressor
-	if pf == compressionMade && dg != nil {
-		dc = dg()
-	}
 	if err := checkRecvPayload(pf, s.RecvCompress(), dc); err != nil {
 		return err
 	}

+ 0 - 217
Godeps/_workspace/src/google.golang.org/grpc/rpc_util_test.go

@@ -1,217 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package grpc
-
-import (
-	"bytes"
-	"io"
-	"reflect"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/codes"
-	perfpb "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/test/codec_perf"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/transport"
-)
-
-func TestSimpleParsing(t *testing.T) {
-	bigMsg := bytes.Repeat([]byte{'x'}, 1<<24)
-	for _, test := range []struct {
-		// input
-		p []byte
-		// outputs
-		err error
-		b   []byte
-		pt  payloadFormat
-	}{
-		{nil, io.EOF, nil, compressionNone},
-		{[]byte{0, 0, 0, 0, 0}, nil, nil, compressionNone},
-		{[]byte{0, 0, 0, 0, 1, 'a'}, nil, []byte{'a'}, compressionNone},
-		{[]byte{1, 0}, io.ErrUnexpectedEOF, nil, compressionNone},
-		{[]byte{0, 0, 0, 0, 10, 'a'}, io.ErrUnexpectedEOF, nil, compressionNone},
-		// Check that messages with length >= 2^24 are parsed.
-		{append([]byte{0, 1, 0, 0, 0}, bigMsg...), nil, bigMsg, compressionNone},
-	} {
-		buf := bytes.NewReader(test.p)
-		parser := &parser{buf}
-		pt, b, err := parser.recvMsg()
-		if err != test.err || !bytes.Equal(b, test.b) || pt != test.pt {
-			t.Fatalf("parser{%v}.recvMsg() = %v, %v, %v\nwant %v, %v, %v", test.p, pt, b, err, test.pt, test.b, test.err)
-		}
-	}
-}
-
-func TestMultipleParsing(t *testing.T) {
-	// Set a byte stream consists of 3 messages with their headers.
-	p := []byte{0, 0, 0, 0, 1, 'a', 0, 0, 0, 0, 2, 'b', 'c', 0, 0, 0, 0, 1, 'd'}
-	b := bytes.NewReader(p)
-	parser := &parser{b}
-
-	wantRecvs := []struct {
-		pt   payloadFormat
-		data []byte
-	}{
-		{compressionNone, []byte("a")},
-		{compressionNone, []byte("bc")},
-		{compressionNone, []byte("d")},
-	}
-	for i, want := range wantRecvs {
-		pt, data, err := parser.recvMsg()
-		if err != nil || pt != want.pt || !reflect.DeepEqual(data, want.data) {
-			t.Fatalf("after %d calls, parser{%v}.recvMsg() = %v, %v, %v\nwant %v, %v, <nil>",
-				i, p, pt, data, err, want.pt, want.data)
-		}
-	}
-
-	pt, data, err := parser.recvMsg()
-	if err != io.EOF {
-		t.Fatalf("after %d recvMsgs calls, parser{%v}.recvMsg() = %v, %v, %v\nwant _, _, %v",
-			len(wantRecvs), p, pt, data, err, io.EOF)
-	}
-}
-
-func TestEncode(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		msg proto.Message
-		cp  Compressor
-		// outputs
-		b   []byte
-		err error
-	}{
-		{nil, nil, []byte{0, 0, 0, 0, 0}, nil},
-	} {
-		b, err := encode(protoCodec{}, test.msg, nil, nil)
-		if err != test.err || !bytes.Equal(b, test.b) {
-			t.Fatalf("encode(_, _, %v, _) = %v, %v\nwant %v, %v", test.cp, b, err, test.b, test.err)
-		}
-	}
-}
-
-func TestCompress(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		data []byte
-		cp   Compressor
-		dc   Decompressor
-		// outputs
-		err error
-	}{
-		{make([]byte, 1024), &gzipCompressor{}, &gzipDecompressor{}, nil},
-	} {
-		b := new(bytes.Buffer)
-		if err := test.cp.Do(b, test.data); err != test.err {
-			t.Fatalf("Compressor.Do(_, %v) = %v, want %v", test.data, err, test.err)
-		}
-		if b.Len() >= len(test.data) {
-			t.Fatalf("The compressor fails to compress data.")
-		}
-		if p, err := test.dc.Do(b); err != nil || !bytes.Equal(test.data, p) {
-			t.Fatalf("Decompressor.Do(%v) = %v, %v, want %v, <nil>", b, p, err, test.data)
-		}
-	}
-}
-
-func TestToRPCErr(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		errIn error
-		// outputs
-		errOut error
-	}{
-		{transport.StreamErrorf(codes.Unknown, ""), Errorf(codes.Unknown, "")},
-		{transport.ErrConnClosing, Errorf(codes.Internal, transport.ErrConnClosing.Desc)},
-	} {
-		err := toRPCErr(test.errIn)
-		if err != test.errOut {
-			t.Fatalf("toRPCErr{%v} = %v \nwant %v", test.errIn, err, test.errOut)
-		}
-	}
-}
-
-func TestContextErr(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		errIn error
-		// outputs
-		errOut transport.StreamError
-	}{
-		{context.DeadlineExceeded, transport.StreamErrorf(codes.DeadlineExceeded, "%v", context.DeadlineExceeded)},
-		{context.Canceled, transport.StreamErrorf(codes.Canceled, "%v", context.Canceled)},
-	} {
-		err := transport.ContextErr(test.errIn)
-		if err != test.errOut {
-			t.Fatalf("ContextErr{%v} = %v \nwant %v", test.errIn, err, test.errOut)
-		}
-	}
-}
-
-// bmEncode benchmarks encoding a Protocol Buffer message containing mSize
-// bytes.
-func bmEncode(b *testing.B, mSize int) {
-	msg := &perfpb.Buffer{Body: make([]byte, mSize)}
-	encoded, _ := encode(protoCodec{}, msg, nil, nil)
-	encodedSz := int64(len(encoded))
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		encode(protoCodec{}, msg, nil, nil)
-	}
-	b.SetBytes(encodedSz)
-}
-
-func BenchmarkEncode1B(b *testing.B) {
-	bmEncode(b, 1)
-}
-
-func BenchmarkEncode1KiB(b *testing.B) {
-	bmEncode(b, 1024)
-}
-
-func BenchmarkEncode8KiB(b *testing.B) {
-	bmEncode(b, 8*1024)
-}
-
-func BenchmarkEncode64KiB(b *testing.B) {
-	bmEncode(b, 64*1024)
-}
-
-func BenchmarkEncode512KiB(b *testing.B) {
-	bmEncode(b, 512*1024)
-}
-
-func BenchmarkEncode1MiB(b *testing.B) {
-	bmEncode(b, 1024*1024)
-}

+ 235 - 89
Godeps/_workspace/src/google.golang.org/grpc/server.go

@@ -39,6 +39,7 @@ import (
 	"fmt"
 	"io"
 	"net"
+	"net/http"
 	"reflect"
 	"runtime"
 	"strings"
@@ -46,6 +47,7 @@ import (
 	"time"
 
 	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2"
 	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/trace"
 	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/codes"
 	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/credentials"
@@ -82,10 +84,11 @@ type service struct {
 
 // Server is a gRPC server to serve RPC requests.
 type Server struct {
-	opts   options
-	mu     sync.Mutex
+	opts options
+
+	mu     sync.Mutex // guards following
 	lis    map[net.Listener]bool
-	conns  map[transport.ServerTransport]bool
+	conns  map[io.Closer]bool
 	m      map[string]*service // service name -> service info
 	events trace.EventLog
 }
@@ -93,9 +96,10 @@ type Server struct {
 type options struct {
 	creds                credentials.Credentials
 	codec                Codec
-	cg                   CompressorGenerator
-	dg                   DecompressorGenerator
+	cp                   Compressor
+	dc                   Decompressor
 	maxConcurrentStreams uint32
+	useHandlerImpl       bool // use http.Handler-based server
 }
 
 // A ServerOption sets options.
@@ -108,15 +112,15 @@ func CustomCodec(codec Codec) ServerOption {
 	}
 }
 
-func CompressON(f CompressorGenerator) ServerOption {
+func RPCCompressor(cp Compressor) ServerOption {
 	return func(o *options) {
-		o.cg = f
+		o.cp = cp
 	}
 }
 
-func DecompressON(f DecompressorGenerator) ServerOption {
+func RPCDecompressor(dc Decompressor) ServerOption {
 	return func(o *options) {
-		o.dg = f
+		o.dc = dc
 	}
 }
 
@@ -149,7 +153,7 @@ func NewServer(opt ...ServerOption) *Server {
 	s := &Server{
 		lis:   make(map[net.Listener]bool),
 		opts:  opts,
-		conns: make(map[transport.ServerTransport]bool),
+		conns: make(map[io.Closer]bool),
 		m:     make(map[string]*service),
 	}
 	if EnableTracing {
@@ -216,9 +220,17 @@ var (
 	ErrServerStopped = errors.New("grpc: the server has been stopped")
 )
 
+func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
+	creds, ok := s.opts.creds.(credentials.TransportAuthenticator)
+	if !ok {
+		return rawConn, nil, nil
+	}
+	return creds.ServerHandshake(rawConn)
+}
+
 // Serve accepts incoming connections on the listener lis, creating a new
 // ServerTransport and service goroutine for each. The service goroutines
-// read gRPC request and then call the registered handlers to reply to them.
+// read gRPC requests and then call the registered handlers to reply to them.
 // Service returns when lis.Accept fails.
 func (s *Server) Serve(lis net.Listener) error {
 	s.mu.Lock()
@@ -235,70 +247,171 @@ func (s *Server) Serve(lis net.Listener) error {
 		delete(s.lis, lis)
 		s.mu.Unlock()
 	}()
+	listenerAddr := lis.Addr()
 	for {
-		c, err := lis.Accept()
+		rawConn, err := lis.Accept()
 		if err != nil {
 			s.mu.Lock()
 			s.printf("done serving; Accept = %v", err)
 			s.mu.Unlock()
 			return err
 		}
-		var authInfo credentials.AuthInfo
-		if creds, ok := s.opts.creds.(credentials.TransportAuthenticator); ok {
-			var conn net.Conn
-			conn, authInfo, err = creds.ServerHandshake(c)
-			if err != nil {
-				s.mu.Lock()
-				s.errorf("ServerHandshake(%q) failed: %v", c.RemoteAddr(), err)
-				s.mu.Unlock()
-				grpclog.Println("grpc: Server.Serve failed to complete security handshake.")
-				continue
-			}
-			c = conn
-		}
+		// Start a new goroutine to deal with rawConn
+		// so we don't stall this Accept loop goroutine.
+		go s.handleRawConn(listenerAddr, rawConn)
+	}
+}
+
+// handleRawConn is run in its own goroutine and handles a just-accepted
+// connection that has not had any I/O performed on it yet.
+func (s *Server) handleRawConn(listenerAddr net.Addr, rawConn net.Conn) {
+	conn, authInfo, err := s.useTransportAuthenticator(rawConn)
+	if err != nil {
 		s.mu.Lock()
-		if s.conns == nil {
-			s.mu.Unlock()
-			c.Close()
-			return nil
-		}
-		st, err := transport.NewServerTransport("http2", c, s.opts.maxConcurrentStreams, authInfo)
-		if err != nil {
-			s.errorf("NewServerTransport(%q) failed: %v", c.RemoteAddr(), err)
-			s.mu.Unlock()
-			c.Close()
-			grpclog.Println("grpc: Server.Serve failed to create ServerTransport: ", err)
-			continue
-		}
-		s.conns[st] = true
+		s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err)
+		s.mu.Unlock()
+		grpclog.Printf("grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err)
+		rawConn.Close()
+		return
+	}
+
+	s.mu.Lock()
+	if s.conns == nil {
 		s.mu.Unlock()
+		conn.Close()
+		return
+	}
+	s.mu.Unlock()
+
+	if s.opts.useHandlerImpl {
+		s.serveUsingHandler(listenerAddr, conn)
+	} else {
+		s.serveNewHTTP2Transport(conn, authInfo)
+	}
+}
+
+// serveNewHTTP2Transport sets up a new http/2 transport (using the
+// gRPC http2 server transport in transport/http2_server.go) and
+// serves streams on it.
+// This is run in its own goroutine (it does network I/O in
+// transport.NewServerTransport).
+func (s *Server) serveNewHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) {
+	st, err := transport.NewServerTransport("http2", c, s.opts.maxConcurrentStreams, authInfo)
+	if err != nil {
+		s.mu.Lock()
+		s.errorf("NewServerTransport(%q) failed: %v", c.RemoteAddr(), err)
+		s.mu.Unlock()
+		c.Close()
+		grpclog.Println("grpc: Server.Serve failed to create ServerTransport: ", err)
+		return
+	}
+	if !s.addConn(st) {
+		st.Close()
+		return
+	}
+	s.serveStreams(st)
+}
 
+func (s *Server) serveStreams(st transport.ServerTransport) {
+	defer s.removeConn(st)
+	defer st.Close()
+	var wg sync.WaitGroup
+	st.HandleStreams(func(stream *transport.Stream) {
+		wg.Add(1)
 		go func() {
-			var wg sync.WaitGroup
-			st.HandleStreams(func(stream *transport.Stream) {
-				var trInfo *traceInfo
-				if EnableTracing {
-					trInfo = &traceInfo{
-						tr: trace.New("grpc.Recv."+methodFamily(stream.Method()), stream.Method()),
-					}
-					trInfo.firstLine.client = false
-					trInfo.firstLine.remoteAddr = st.RemoteAddr()
-					stream.TraceContext(trInfo.tr)
-					if dl, ok := stream.Context().Deadline(); ok {
-						trInfo.firstLine.deadline = dl.Sub(time.Now())
-					}
-				}
-				wg.Add(1)
-				go func() {
-					s.handleStream(st, stream, trInfo)
-					wg.Done()
-				}()
-			})
-			wg.Wait()
-			s.mu.Lock()
-			delete(s.conns, st)
-			s.mu.Unlock()
+			defer wg.Done()
+			s.handleStream(st, stream, s.traceInfo(st, stream))
 		}()
+	})
+	wg.Wait()
+}
+
+var _ http.Handler = (*Server)(nil)
+
+// serveUsingHandler is called from handleRawConn when s is configured
+// to handle requests via the http.Handler interface. It sets up a
+// net/http.Server to handle the just-accepted conn. The http.Server
+// is configured to route all incoming requests (all HTTP/2 streams)
+// to ServeHTTP, which creates a new ServerTransport for each stream.
+// serveUsingHandler blocks until conn closes.
+//
+// This codepath is only used when Server.TestingUseHandlerImpl has
+// been configured. This lets the end2end tests exercise the ServeHTTP
+// method as one of the environment types.
+//
+// conn is the *tls.Conn that's already been authenticated.
+func (s *Server) serveUsingHandler(listenerAddr net.Addr, conn net.Conn) {
+	if !s.addConn(conn) {
+		conn.Close()
+		return
+	}
+	defer s.removeConn(conn)
+	connDone := make(chan struct{})
+	hs := &http.Server{
+		Handler: s,
+		ConnState: func(c net.Conn, cs http.ConnState) {
+			if cs == http.StateClosed {
+				close(connDone)
+			}
+		},
+	}
+	if err := http2.ConfigureServer(hs, &http2.Server{
+		MaxConcurrentStreams: s.opts.maxConcurrentStreams,
+	}); err != nil {
+		grpclog.Fatalf("grpc: http2.ConfigureServer: %v", err)
+		return
+	}
+	hs.Serve(&singleConnListener{addr: listenerAddr, conn: conn})
+	<-connDone
+}
+
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	st, err := transport.NewServerHandlerTransport(w, r)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	if !s.addConn(st) {
+		st.Close()
+		return
+	}
+	defer s.removeConn(st)
+	s.serveStreams(st)
+}
+
+// traceInfo returns a traceInfo and associates it with stream, if tracing is enabled.
+// If tracing is not enabled, it returns nil.
+func (s *Server) traceInfo(st transport.ServerTransport, stream *transport.Stream) (trInfo *traceInfo) {
+	if !EnableTracing {
+		return nil
+	}
+	trInfo = &traceInfo{
+		tr: trace.New("grpc.Recv."+methodFamily(stream.Method()), stream.Method()),
+	}
+	trInfo.firstLine.client = false
+	trInfo.firstLine.remoteAddr = st.RemoteAddr()
+	stream.TraceContext(trInfo.tr)
+	if dl, ok := stream.Context().Deadline(); ok {
+		trInfo.firstLine.deadline = dl.Sub(time.Now())
+	}
+	return trInfo
+}
+
+func (s *Server) addConn(c io.Closer) bool {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	if s.conns == nil {
+		return false
+	}
+	s.conns[c] = true
+	return true
+}
+
+func (s *Server) removeConn(c io.Closer) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	if s.conns != nil {
+		delete(s.conns, c)
 	}
 }
 
@@ -333,13 +446,16 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
 			}
 		}()
 	}
-	p := &parser{s: stream}
+	p := &parser{r: stream}
 	for {
 		pf, req, err := p.recvMsg()
 		if err == io.EOF {
 			// The entire stream is done (for unary RPC only).
 			return err
 		}
+		if err == io.ErrUnexpectedEOF {
+			err = transport.StreamError{Code: codes.Internal, Desc: "io.ErrUnexpectedEOF"}
+		}
 		if err != nil {
 			switch err := err.(type) {
 			case transport.ConnectionError:
@@ -354,11 +470,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
 			return err
 		}
 
-		var dc Decompressor
-		if pf == compressionMade && s.opts.dg != nil {
-			dc = s.opts.dg()
-		}
-		if err := checkRecvPayload(pf, stream.RecvCompress(), dc); err != nil {
+		if err := checkRecvPayload(pf, stream.RecvCompress(), s.opts.dc); err != nil {
 			switch err := err.(type) {
 			case transport.StreamError:
 				if err := t.WriteStatus(stream, err.Code, err.Desc); err != nil {
@@ -377,9 +489,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
 		df := func(v interface{}) error {
 			if pf == compressionMade {
 				var err error
-				req, err = dc.Do(bytes.NewReader(req))
-				//req, err = ioutil.ReadAll(dc)
-				//defer dc.Close()
+				req, err = s.opts.dc.Do(bytes.NewReader(req))
 				if err != nil {
 					if err := t.WriteStatus(stream, codes.Internal, err.Error()); err != nil {
 						grpclog.Printf("grpc: Server.processUnaryRPC failed to write status %v", err)
@@ -421,12 +531,10 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
 			Last:  true,
 			Delay: false,
 		}
-		var cp Compressor
-		if s.opts.cg != nil {
-			cp = s.opts.cg()
-			stream.SetSendCompress(cp.Type())
+		if s.opts.cp != nil {
+			stream.SetSendCompress(s.opts.cp.Type())
 		}
-		if err := s.sendResponse(t, stream, reply, cp, opts); err != nil {
+		if err := s.sendResponse(t, stream, reply, s.opts.cp, opts); err != nil {
 			switch err := err.(type) {
 			case transport.ConnectionError:
 				// Nothing to do here.
@@ -447,21 +555,19 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
 }
 
 func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, sd *StreamDesc, trInfo *traceInfo) (err error) {
-	var cp Compressor
-	if s.opts.cg != nil {
-		cp = s.opts.cg()
-		stream.SetSendCompress(cp.Type())
+	if s.opts.cp != nil {
+		stream.SetSendCompress(s.opts.cp.Type())
 	}
 	ss := &serverStream{
 		t:      t,
 		s:      stream,
-		p:      &parser{s: stream},
+		p:      &parser{r: stream},
 		codec:  s.opts.codec,
-		cp:     cp,
-		dg:     s.opts.dg,
+		cp:     s.opts.cp,
+		dc:     s.opts.dc,
 		trInfo: trInfo,
 	}
-	if cp != nil {
+	if ss.cp != nil {
 		ss.cbuf = new(bytes.Buffer)
 	}
 	if trInfo != nil {
@@ -571,8 +677,11 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str
 	}
 }
 
-// Stop stops the gRPC server. Once Stop returns, the server stops accepting
-// connection requests and closes all the connected connections.
+// Stop stops the gRPC server. It immediately closes all open
+// connections and listeners.
+// It cancels all active RPCs on the server side and the corresponding
+// pending RPCs on the client side will get notified by connection
+// errors.
 func (s *Server) Stop() {
 	s.mu.Lock()
 	listeners := s.lis
@@ -580,12 +689,14 @@ func (s *Server) Stop() {
 	cs := s.conns
 	s.conns = nil
 	s.mu.Unlock()
+
 	for lis := range listeners {
 		lis.Close()
 	}
 	for c := range cs {
 		c.Close()
 	}
+
 	s.mu.Lock()
 	if s.events != nil {
 		s.events.Finish()
@@ -595,16 +706,24 @@ func (s *Server) Stop() {
 }
 
 // TestingCloseConns closes all exiting transports but keeps s.lis accepting new
-// connections. This is for test only now.
+// connections.
+// This is only for tests and is subject to removal.
 func (s *Server) TestingCloseConns() {
 	s.mu.Lock()
 	for c := range s.conns {
 		c.Close()
+		delete(s.conns, c)
 	}
-	s.conns = make(map[transport.ServerTransport]bool)
 	s.mu.Unlock()
 }
 
+// TestingUseHandlerImpl enables the http.Handler-based server implementation.
+// It must be called before Serve and requires TLS credentials.
+// This is only for tests and is subject to removal.
+func (s *Server) TestingUseHandlerImpl() {
+	s.opts.useHandlerImpl = true
+}
+
 // SendHeader sends header metadata. It may be called at most once from a unary
 // RPC handler. The ctx is the RPC handler's Context or one derived from it.
 func SendHeader(ctx context.Context, md metadata.MD) error {
@@ -635,3 +754,30 @@ func SetTrailer(ctx context.Context, md metadata.MD) error {
 	}
 	return stream.SetTrailer(md)
 }
+
+// singleConnListener is a net.Listener that yields a single conn.
+type singleConnListener struct {
+	mu   sync.Mutex
+	addr net.Addr
+	conn net.Conn // nil if done
+}
+
+func (ln *singleConnListener) Addr() net.Addr { return ln.addr }
+
+func (ln *singleConnListener) Close() error {
+	ln.mu.Lock()
+	defer ln.mu.Unlock()
+	ln.conn = nil
+	return nil
+}
+
+func (ln *singleConnListener) Accept() (net.Conn, error) {
+	ln.mu.Lock()
+	defer ln.mu.Unlock()
+	c := ln.conn
+	if c == nil {
+		return nil, io.EOF
+	}
+	ln.conn = nil
+	return c, nil
+}

+ 23 - 17
Godeps/_workspace/src/google.golang.org/grpc/stream.go

@@ -71,7 +71,7 @@ type Stream interface {
 	SendMsg(m interface{}) error
 	// RecvMsg blocks until it receives a message or the stream is
 	// done. On client side, it returns io.EOF when the stream is done. On
-	// any other error, it aborts the streama nd returns an RPC status. On
+	// any other error, it aborts the stream and returns an RPC status. On
 	// server side, it simply returns the error to the caller.
 	RecvMsg(m interface{}) error
 }
@@ -105,27 +105,24 @@ func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
 	if err != nil {
 		return nil, toRPCErr(err)
 	}
-	var cp Compressor
-	if cc.dopts.cg != nil {
-		cp = cc.dopts.cg()
-	}
 	// TODO(zhaoq): CallOption is omitted. Add support when it is needed.
 	callHdr := &transport.CallHdr{
 		Host:   cc.authority,
 		Method: method,
+		Flush:  desc.ServerStreams && desc.ClientStreams,
 	}
-	if cp != nil {
-		callHdr.SendCompress = cp.Type()
+	if cc.dopts.cp != nil {
+		callHdr.SendCompress = cc.dopts.cp.Type()
 	}
 	cs := &clientStream{
 		desc:    desc,
 		codec:   cc.dopts.codec,
-		cp:      cp,
-		dg:      cc.dopts.dg,
+		cp:      cc.dopts.cp,
+		dc:      cc.dopts.dc,
 		tracing: EnableTracing,
 	}
-	if cp != nil {
-		callHdr.SendCompress = cp.Type()
+	if cc.dopts.cp != nil {
+		callHdr.SendCompress = cc.dopts.cp.Type()
 		cs.cbuf = new(bytes.Buffer)
 	}
 	if cs.tracing {
@@ -144,7 +141,7 @@ func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
 	}
 	cs.t = t
 	cs.s = s
-	cs.p = &parser{s: s}
+	cs.p = &parser{r: s}
 	// Listen on ctx.Done() to detect cancellation when there is no pending
 	// I/O operations on this stream.
 	go func() {
@@ -169,7 +166,7 @@ type clientStream struct {
 	codec Codec
 	cp    Compressor
 	cbuf  *bytes.Buffer
-	dg    DecompressorGenerator
+	dc    Decompressor
 
 	tracing bool // set to EnableTracing when the clientStream is created.
 
@@ -207,6 +204,9 @@ func (cs *clientStream) SendMsg(m interface{}) (err error) {
 		cs.mu.Unlock()
 	}
 	defer func() {
+		if err != nil {
+			cs.finish(err)
+		}
 		if err == nil || err == io.EOF {
 			return
 		}
@@ -228,7 +228,7 @@ func (cs *clientStream) SendMsg(m interface{}) (err error) {
 }
 
 func (cs *clientStream) RecvMsg(m interface{}) (err error) {
-	err = recv(cs.p, cs.codec, cs.s, cs.dg, m)
+	err = recv(cs.p, cs.codec, cs.s, cs.dc, m)
 	defer func() {
 		// err != nil indicates the termination of the stream.
 		if err != nil {
@@ -247,13 +247,14 @@ func (cs *clientStream) RecvMsg(m interface{}) (err error) {
 			return
 		}
 		// Special handling for client streaming rpc.
-		err = recv(cs.p, cs.codec, cs.s, cs.dg, m)
+		err = recv(cs.p, cs.codec, cs.s, cs.dc, m)
 		cs.closeTransportStream(err)
 		if err == nil {
 			return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>"))
 		}
 		if err == io.EOF {
 			if cs.s.StatusCode() == codes.OK {
+				cs.finish(err)
 				return nil
 			}
 			return Errorf(cs.s.StatusCode(), cs.s.StatusDesc())
@@ -275,6 +276,11 @@ func (cs *clientStream) RecvMsg(m interface{}) (err error) {
 
 func (cs *clientStream) CloseSend() (err error) {
 	err = cs.t.Write(cs.s, nil, &transport.Options{Last: true})
+	defer func() {
+		if err != nil {
+			cs.finish(err)
+		}
+	}()
 	if err == nil || err == io.EOF {
 		return
 	}
@@ -333,7 +339,7 @@ type serverStream struct {
 	p          *parser
 	codec      Codec
 	cp         Compressor
-	dg         DecompressorGenerator
+	dc         Decompressor
 	cbuf       *bytes.Buffer
 	statusCode codes.Code
 	statusDesc string
@@ -401,5 +407,5 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) {
 			ss.mu.Unlock()
 		}
 	}()
-	return recv(ss.p, ss.codec, ss.s, ss.dg, m)
+	return recv(ss.p, ss.codec, ss.s, ss.dc, m)
 }

+ 20 - 3
Godeps/_workspace/src/google.golang.org/grpc/test/codec_perf/perf.pb.go

@@ -14,12 +14,18 @@ It has these top-level messages:
 package codec_perf
 
 import proto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
+import fmt "fmt"
 import math "math"
 
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
+var _ = fmt.Errorf
 var _ = math.Inf
 
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.ProtoPackageIsVersion1
+
 // Buffer is a message that contains a body of bytes that is used to exercise
 // encoding and decoding overheads.
 type Buffer struct {
@@ -27,9 +33,10 @@ type Buffer struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *Buffer) Reset()         { *m = Buffer{} }
-func (m *Buffer) String() string { return proto.CompactTextString(m) }
-func (*Buffer) ProtoMessage()    {}
+func (m *Buffer) Reset()                    { *m = Buffer{} }
+func (m *Buffer) String() string            { return proto.CompactTextString(m) }
+func (*Buffer) ProtoMessage()               {}
+func (*Buffer) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 func (m *Buffer) GetBody() []byte {
 	if m != nil {
@@ -39,4 +46,14 @@ func (m *Buffer) GetBody() []byte {
 }
 
 func init() {
+	proto.RegisterType((*Buffer)(nil), "codec.perf.Buffer")
+}
+
+var fileDescriptor0 = []byte{
+	// 73 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x48, 0x2d, 0x4a,
+	0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4a, 0xce, 0x4f, 0x49, 0x4d, 0xd6, 0x03, 0x89,
+	0x28, 0xc9, 0x70, 0xb1, 0x39, 0x95, 0xa6, 0xa5, 0xa5, 0x16, 0x09, 0x09, 0x71, 0xb1, 0x24, 0xe5,
+	0xa7, 0x54, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x04, 0x81, 0xd9, 0x80, 0x00, 0x00, 0x00, 0xff,
+	0xff, 0x3a, 0x58, 0x92, 0x53, 0x36, 0x00, 0x00, 0x00,
 }

+ 0 - 1226
Godeps/_workspace/src/google.golang.org/grpc/test/end2end_test.go

@@ -1,1226 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package grpc_test
-
-import (
-	"fmt"
-	"io"
-	"math"
-	"net"
-	"reflect"
-	"runtime"
-	"sync"
-	"syscall"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/codes"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/credentials"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/health"
-	healthpb "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/health/grpc_health_v1alpha"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/metadata"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/peer"
-	testpb "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/test/grpc_testing"
-)
-
-var (
-	testMetadata = metadata.MD{
-		"key1": []string{"value1"},
-		"key2": []string{"value2"},
-	}
-	testAppUA = "myApp1/1.0 myApp2/0.9"
-)
-
-type testServer struct {
-	security string // indicate the authentication protocol used by this server.
-}
-
-func (s *testServer) EmptyCall(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
-	if md, ok := metadata.FromContext(ctx); ok {
-		// For testing purpose, returns an error if there is attached metadata other than
-		// the user agent set by the client application.
-		if _, ok := md["user-agent"]; !ok {
-			return nil, grpc.Errorf(codes.DataLoss, "got extra metadata")
-		}
-		var str []string
-		for _, entry := range md["user-agent"] {
-			str = append(str, "ua", entry)
-		}
-		grpc.SendHeader(ctx, metadata.Pairs(str...))
-	}
-	return new(testpb.Empty), nil
-}
-
-func newPayload(t testpb.PayloadType, size int32) (*testpb.Payload, error) {
-	if size < 0 {
-		return nil, fmt.Errorf("Requested a response with invalid length %d", size)
-	}
-	body := make([]byte, size)
-	switch t {
-	case testpb.PayloadType_COMPRESSABLE:
-	case testpb.PayloadType_UNCOMPRESSABLE:
-		return nil, fmt.Errorf("PayloadType UNCOMPRESSABLE is not supported")
-	default:
-		return nil, fmt.Errorf("Unsupported payload type: %d", t)
-	}
-	return &testpb.Payload{
-		Type: t.Enum(),
-		Body: body,
-	}, nil
-}
-
-func (s *testServer) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
-	md, ok := metadata.FromContext(ctx)
-	if ok {
-		if err := grpc.SendHeader(ctx, md); err != nil {
-			return nil, fmt.Errorf("grpc.SendHeader(%v, %v) = %v, want %v", ctx, md, err, nil)
-		}
-		grpc.SetTrailer(ctx, md)
-	}
-	pr, ok := peer.FromContext(ctx)
-	if !ok {
-		return nil, fmt.Errorf("failed to get peer from ctx")
-	}
-	if pr.Addr == net.Addr(nil) {
-		return nil, fmt.Errorf("failed to get peer address")
-	}
-	if s.security != "" {
-		// Check Auth info
-		var authType, serverName string
-		switch info := pr.AuthInfo.(type) {
-		case credentials.TLSInfo:
-			authType = info.AuthType()
-			serverName = info.State.ServerName
-		default:
-			return nil, fmt.Errorf("Unknown AuthInfo type")
-		}
-		if authType != s.security {
-			return nil, fmt.Errorf("Wrong auth type: got %q, want %q", authType, s.security)
-		}
-		if serverName != "x.test.youtube.com" {
-			return nil, fmt.Errorf("Unknown server name %q", serverName)
-		}
-	}
-
-	// Simulate some service delay.
-	time.Sleep(time.Second)
-
-	payload, err := newPayload(in.GetResponseType(), in.GetResponseSize())
-	if err != nil {
-		return nil, err
-	}
-	return &testpb.SimpleResponse{
-		Payload: payload,
-	}, nil
-}
-
-func (s *testServer) StreamingOutputCall(args *testpb.StreamingOutputCallRequest, stream testpb.TestService_StreamingOutputCallServer) error {
-	if md, ok := metadata.FromContext(stream.Context()); ok {
-		// For testing purpose, returns an error if there is attached metadata.
-		if len(md) > 0 {
-			return grpc.Errorf(codes.DataLoss, "got extra metadata")
-		}
-	}
-	cs := args.GetResponseParameters()
-	for _, c := range cs {
-		if us := c.GetIntervalUs(); us > 0 {
-			time.Sleep(time.Duration(us) * time.Microsecond)
-		}
-
-		payload, err := newPayload(args.GetResponseType(), c.GetSize())
-		if err != nil {
-			return err
-		}
-
-		if err := stream.Send(&testpb.StreamingOutputCallResponse{
-			Payload: payload,
-		}); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func (s *testServer) StreamingInputCall(stream testpb.TestService_StreamingInputCallServer) error {
-	var sum int
-	for {
-		in, err := stream.Recv()
-		if err == io.EOF {
-			return stream.SendAndClose(&testpb.StreamingInputCallResponse{
-				AggregatedPayloadSize: proto.Int32(int32(sum)),
-			})
-		}
-		if err != nil {
-			return err
-		}
-		p := in.GetPayload().GetBody()
-		sum += len(p)
-	}
-}
-
-func (s *testServer) FullDuplexCall(stream testpb.TestService_FullDuplexCallServer) error {
-	md, ok := metadata.FromContext(stream.Context())
-	if ok {
-		if err := stream.SendHeader(md); err != nil {
-			return fmt.Errorf("%v.SendHeader(%v) = %v, want %v", stream, md, err, nil)
-		}
-		stream.SetTrailer(md)
-	}
-	for {
-		in, err := stream.Recv()
-		if err == io.EOF {
-			// read done.
-			return nil
-		}
-		if err != nil {
-			return err
-		}
-		cs := in.GetResponseParameters()
-		for _, c := range cs {
-			if us := c.GetIntervalUs(); us > 0 {
-				time.Sleep(time.Duration(us) * time.Microsecond)
-			}
-
-			payload, err := newPayload(in.GetResponseType(), c.GetSize())
-			if err != nil {
-				return err
-			}
-
-			if err := stream.Send(&testpb.StreamingOutputCallResponse{
-				Payload: payload,
-			}); err != nil {
-				return err
-			}
-		}
-	}
-}
-
-func (s *testServer) HalfDuplexCall(stream testpb.TestService_HalfDuplexCallServer) error {
-	var msgBuf []*testpb.StreamingOutputCallRequest
-	for {
-		in, err := stream.Recv()
-		if err == io.EOF {
-			// read done.
-			break
-		}
-		if err != nil {
-			return err
-		}
-		msgBuf = append(msgBuf, in)
-	}
-	for _, m := range msgBuf {
-		cs := m.GetResponseParameters()
-		for _, c := range cs {
-			if us := c.GetIntervalUs(); us > 0 {
-				time.Sleep(time.Duration(us) * time.Microsecond)
-			}
-
-			payload, err := newPayload(m.GetResponseType(), c.GetSize())
-			if err != nil {
-				return err
-			}
-
-			if err := stream.Send(&testpb.StreamingOutputCallResponse{
-				Payload: payload,
-			}); err != nil {
-				return err
-			}
-		}
-	}
-	return nil
-}
-
-const tlsDir = "testdata/"
-
-func TestReconnectTimeout(t *testing.T) {
-	lis, err := net.Listen("tcp", ":0")
-	if err != nil {
-		t.Fatalf("Failed to listen: %v", err)
-	}
-	_, port, err := net.SplitHostPort(lis.Addr().String())
-	if err != nil {
-		t.Fatalf("Failed to parse listener address: %v", err)
-	}
-	addr := "localhost:" + port
-	conn, err := grpc.Dial(addr, grpc.WithTimeout(5*time.Second), grpc.WithBlock(), grpc.WithInsecure())
-	if err != nil {
-		t.Fatalf("Failed to dial to the server %q: %v", addr, err)
-	}
-	// Close unaccepted connection (i.e., conn).
-	lis.Close()
-	tc := testpb.NewTestServiceClient(conn)
-	waitC := make(chan struct{})
-	go func() {
-		defer close(waitC)
-		argSize := 271828
-		respSize := 314159
-
-		payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		req := &testpb.SimpleRequest{
-			ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-			ResponseSize: proto.Int32(int32(respSize)),
-			Payload:      payload,
-		}
-		if _, err := tc.UnaryCall(context.Background(), req); err == nil {
-			t.Fatalf("TestService/UnaryCall(_, _) = _, <nil>, want _, non-nil")
-		}
-	}()
-	// Block untill reconnect times out.
-	<-waitC
-	if err := conn.Close(); err != grpc.ErrClientConnClosing {
-		t.Fatalf("%v.Close() = %v, want %v", conn, err, grpc.ErrClientConnClosing)
-	}
-}
-
-func unixDialer(addr string, timeout time.Duration) (net.Conn, error) {
-	return net.DialTimeout("unix", addr, timeout)
-}
-
-type env struct {
-	network  string // The type of network such as tcp, unix, etc.
-	dialer   func(addr string, timeout time.Duration) (net.Conn, error)
-	security string // The security protocol such as TLS, SSH, etc.
-}
-
-func listTestEnv() []env {
-	if runtime.GOOS == "windows" {
-		return []env{{"tcp", nil, ""}, {"tcp", nil, "tls"}}
-	}
-	return []env{{"tcp", nil, ""}, {"tcp", nil, "tls"}, {"unix", unixDialer, ""}, {"unix", unixDialer, "tls"}}
-}
-
-func serverSetUp(t *testing.T, hs *health.HealthServer, maxStream uint32, cg grpc.CompressorGenerator, dg grpc.DecompressorGenerator, e env) (s *grpc.Server, addr string) {
-	sopts := []grpc.ServerOption{grpc.MaxConcurrentStreams(maxStream), grpc.CompressON(cg), grpc.DecompressON(dg)}
-	la := ":0"
-	switch e.network {
-	case "unix":
-		la = "/tmp/testsock" + fmt.Sprintf("%d", time.Now())
-		syscall.Unlink(la)
-	}
-	lis, err := net.Listen(e.network, la)
-	if err != nil {
-		t.Fatalf("Failed to listen: %v", err)
-	}
-	if e.security == "tls" {
-		creds, err := credentials.NewServerTLSFromFile(tlsDir+"server1.pem", tlsDir+"server1.key")
-		if err != nil {
-			t.Fatalf("Failed to generate credentials %v", err)
-		}
-		sopts = append(sopts, grpc.Creds(creds))
-	}
-	s = grpc.NewServer(sopts...)
-	if hs != nil {
-		healthpb.RegisterHealthServer(s, hs)
-	}
-	testpb.RegisterTestServiceServer(s, &testServer{security: e.security})
-	go s.Serve(lis)
-	addr = la
-	switch e.network {
-	case "unix":
-	default:
-		_, port, err := net.SplitHostPort(lis.Addr().String())
-		if err != nil {
-			t.Fatalf("Failed to parse listener address: %v", err)
-		}
-		addr = "localhost:" + port
-	}
-	return
-}
-
-func clientSetUp(t *testing.T, addr string, cg grpc.CompressorGenerator, dg grpc.DecompressorGenerator, ua string, e env) (cc *grpc.ClientConn) {
-	var derr error
-	if e.security == "tls" {
-		creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
-		if err != nil {
-			t.Fatalf("Failed to create credentials %v", err)
-		}
-		cc, derr = grpc.Dial(addr, grpc.WithTransportCredentials(creds), grpc.WithDialer(e.dialer), grpc.WithUserAgent(ua), grpc.WithCompressor(cg), grpc.WithDecompressor(dg))
-	} else {
-		cc, derr = grpc.Dial(addr, grpc.WithDialer(e.dialer), grpc.WithInsecure(), grpc.WithUserAgent(ua), grpc.WithCompressor(cg), grpc.WithDecompressor(dg))
-	}
-	if derr != nil {
-		t.Fatalf("Dial(%q) = %v", addr, derr)
-	}
-	return
-}
-
-func tearDown(s *grpc.Server, cc *grpc.ClientConn) {
-	cc.Close()
-	s.Stop()
-}
-
-func TestTimeoutOnDeadServer(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testTimeoutOnDeadServer(t, e)
-	}
-}
-
-func testTimeoutOnDeadServer(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	ctx, _ := context.WithTimeout(context.Background(), time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Idle); err != nil {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, %v, want _, <nil>", grpc.Idle, err)
-	}
-	ctx, _ = context.WithTimeout(context.Background(), time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Connecting); err != nil {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, %v, want _, <nil>", grpc.Connecting, err)
-	}
-	if state, err := cc.State(); err != nil || state != grpc.Ready {
-		t.Fatalf("cc.State() = %s, %v, want %s, <nil>", state, err, grpc.Ready)
-	}
-	ctx, _ = context.WithTimeout(context.Background(), time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Ready); err != context.DeadlineExceeded {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, %v, want _, %v", grpc.Ready, err, context.DeadlineExceeded)
-	}
-	s.Stop()
-	// Set -1 as the timeout to make sure if transportMonitor gets error
-	// notification in time the failure path of the 1st invoke of
-	// ClientConn.wait hits the deadline exceeded error.
-	ctx, _ = context.WithTimeout(context.Background(), -1)
-	if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); grpc.Code(err) != codes.DeadlineExceeded {
-		t.Fatalf("TestService/EmptyCall(%v, _) = _, error %v, want _, error code: %d", ctx, err, codes.DeadlineExceeded)
-	}
-	ctx, _ = context.WithTimeout(context.Background(), time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Ready); err != nil {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, %v, want _, <nil>", grpc.Ready, err)
-	}
-	if state, err := cc.State(); err != nil || (state != grpc.Connecting && state != grpc.TransientFailure) {
-		t.Fatalf("cc.State() = %s, %v, want %s or %s, <nil>", state, err, grpc.Connecting, grpc.TransientFailure)
-	}
-	cc.Close()
-}
-
-func healthCheck(t time.Duration, cc *grpc.ClientConn, serviceName string) (*healthpb.HealthCheckResponse, error) {
-	ctx, _ := context.WithTimeout(context.Background(), t)
-	hc := healthpb.NewHealthClient(cc)
-	req := &healthpb.HealthCheckRequest{
-		Service: serviceName,
-	}
-	return hc.Check(ctx, req)
-}
-
-func TestHealthCheckOnSuccess(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testHealthCheckOnSuccess(t, e)
-	}
-}
-
-func testHealthCheckOnSuccess(t *testing.T, e env) {
-	hs := health.NewHealthServer()
-	hs.SetServingStatus("grpc.health.v1alpha.Health", 1)
-	s, addr := serverSetUp(t, hs, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	defer tearDown(s, cc)
-	if _, err := healthCheck(1*time.Second, cc, "grpc.health.v1alpha.Health"); err != nil {
-		t.Fatalf("Health/Check(_, _) = _, %v, want _, <nil>", err)
-	}
-}
-
-func TestHealthCheckOnFailure(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testHealthCheckOnFailure(t, e)
-	}
-}
-
-func testHealthCheckOnFailure(t *testing.T, e env) {
-	hs := health.NewHealthServer()
-	hs.SetServingStatus("grpc.health.v1alpha.HealthCheck", 1)
-	s, addr := serverSetUp(t, hs, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	defer tearDown(s, cc)
-	if _, err := healthCheck(0*time.Second, cc, "grpc.health.v1alpha.Health"); err != grpc.Errorf(codes.DeadlineExceeded, "context deadline exceeded") {
-		t.Fatalf("Health/Check(_, _) = _, %v, want _, error code %d", err, codes.DeadlineExceeded)
-	}
-}
-
-func TestHealthCheckOff(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testHealthCheckOff(t, e)
-	}
-}
-
-func testHealthCheckOff(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	defer tearDown(s, cc)
-	if _, err := healthCheck(1*time.Second, cc, ""); err != grpc.Errorf(codes.Unimplemented, "unknown service grpc.health.v1alpha.Health") {
-		t.Fatalf("Health/Check(_, _) = _, %v, want _, error code %d", err, codes.Unimplemented)
-	}
-}
-
-func TestHealthCheckServingStatus(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testHealthCheckServingStatus(t, e)
-	}
-}
-
-func testHealthCheckServingStatus(t *testing.T, e env) {
-	hs := health.NewHealthServer()
-	s, addr := serverSetUp(t, hs, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	defer tearDown(s, cc)
-	out, err := healthCheck(1*time.Second, cc, "")
-	if err != nil {
-		t.Fatalf("Health/Check(_, _) = _, %v, want _, <nil>", err)
-	}
-	if out.Status != healthpb.HealthCheckResponse_SERVING {
-		t.Fatalf("Got the serving status %v, want SERVING", out.Status)
-	}
-	if _, err := healthCheck(1*time.Second, cc, "grpc.health.v1alpha.Health"); err != grpc.Errorf(codes.NotFound, "unknown service") {
-		t.Fatalf("Health/Check(_, _) = _, %v, want _, error code %d", err, codes.NotFound)
-	}
-	hs.SetServingStatus("grpc.health.v1alpha.Health", healthpb.HealthCheckResponse_SERVING)
-	out, err = healthCheck(1*time.Second, cc, "grpc.health.v1alpha.Health")
-	if err != nil {
-		t.Fatalf("Health/Check(_, _) = _, %v, want _, <nil>", err)
-	}
-	if out.Status != healthpb.HealthCheckResponse_SERVING {
-		t.Fatalf("Got the serving status %v, want SERVING", out.Status)
-	}
-	hs.SetServingStatus("grpc.health.v1alpha.Health", healthpb.HealthCheckResponse_NOT_SERVING)
-	out, err = healthCheck(1*time.Second, cc, "grpc.health.v1alpha.Health")
-	if err != nil {
-		t.Fatalf("Health/Check(_, _) = _, %v, want _, <nil>", err)
-	}
-	if out.Status != healthpb.HealthCheckResponse_NOT_SERVING {
-		t.Fatalf("Got the serving status %v, want NOT_SERVING", out.Status)
-	}
-
-}
-
-func TestEmptyUnaryWithUserAgent(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testEmptyUnaryWithUserAgent(t, e)
-	}
-}
-
-func testEmptyUnaryWithUserAgent(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, testAppUA, e)
-	// Wait until cc is connected.
-	ctx, _ := context.WithTimeout(context.Background(), time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Idle); err != nil {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, %v, want _, <nil>", grpc.Idle, err)
-	}
-	ctx, _ = context.WithTimeout(context.Background(), time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Connecting); err != nil {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, %v, want _, <nil>", grpc.Connecting, err)
-	}
-	if state, err := cc.State(); err != nil || state != grpc.Ready {
-		t.Fatalf("cc.State() = %s, %v, want %s, <nil>", state, err, grpc.Ready)
-	}
-	ctx, _ = context.WithTimeout(context.Background(), time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Ready); err == nil {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, <nil>, want _, %v", grpc.Ready, context.DeadlineExceeded)
-	}
-	tc := testpb.NewTestServiceClient(cc)
-	var header metadata.MD
-	reply, err := tc.EmptyCall(context.Background(), &testpb.Empty{}, grpc.Header(&header))
-	if err != nil || !proto.Equal(&testpb.Empty{}, reply) {
-		t.Fatalf("TestService/EmptyCall(_, _) = %v, %v, want %v, <nil>", reply, err, &testpb.Empty{})
-	}
-	if v, ok := header["ua"]; !ok || v[0] != testAppUA {
-		t.Fatalf("header[\"ua\"] = %q, %t, want %q, true", v, ok, testAppUA)
-	}
-	tearDown(s, cc)
-	ctx, _ = context.WithTimeout(context.Background(), 5*time.Second)
-	if _, err := cc.WaitForStateChange(ctx, grpc.Ready); err != nil {
-		t.Fatalf("cc.WaitForStateChange(_, %s) = _, %v, want _, <nil>", grpc.Ready, err)
-	}
-	if state, err := cc.State(); err != nil || state != grpc.Shutdown {
-		t.Fatalf("cc.State() = %s, %v, want %s, <nil>", state, err, grpc.Shutdown)
-	}
-}
-
-func TestFailedEmptyUnary(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testFailedEmptyUnary(t, e)
-	}
-}
-
-func testFailedEmptyUnary(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	ctx := metadata.NewContext(context.Background(), testMetadata)
-	if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != grpc.Errorf(codes.DataLoss, "got extra metadata") {
-		t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, %v", err, grpc.Errorf(codes.DataLoss, "got extra metadata"))
-	}
-}
-
-func TestLargeUnary(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testLargeUnary(t, e)
-	}
-}
-
-func testLargeUnary(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	argSize := 271828
-	respSize := 314159
-
-	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	req := &testpb.SimpleRequest{
-		ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseSize: proto.Int32(int32(respSize)),
-		Payload:      payload,
-	}
-	reply, err := tc.UnaryCall(context.Background(), req)
-	if err != nil {
-		t.Fatalf("TestService/UnaryCall(_, _) = _, %v, want _, <nil>", err)
-	}
-	pt := reply.GetPayload().GetType()
-	ps := len(reply.GetPayload().GetBody())
-	if pt != testpb.PayloadType_COMPRESSABLE || ps != respSize {
-		t.Fatalf("Got the reply with type %d len %d; want %d, %d", pt, ps, testpb.PayloadType_COMPRESSABLE, respSize)
-	}
-}
-
-func TestMetadataUnaryRPC(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testMetadataUnaryRPC(t, e)
-	}
-}
-
-func testMetadataUnaryRPC(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	argSize := 2718
-	respSize := 314
-
-	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	req := &testpb.SimpleRequest{
-		ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseSize: proto.Int32(int32(respSize)),
-		Payload:      payload,
-	}
-	var header, trailer metadata.MD
-	ctx := metadata.NewContext(context.Background(), testMetadata)
-	if _, err := tc.UnaryCall(ctx, req, grpc.Header(&header), grpc.Trailer(&trailer)); err != nil {
-		t.Fatalf("TestService.UnaryCall(%v, _, _, _) = _, %v; want _, <nil>", ctx, err)
-	}
-	if !reflect.DeepEqual(testMetadata, header) {
-		t.Fatalf("Received header metadata %v, want %v", header, testMetadata)
-	}
-	if !reflect.DeepEqual(testMetadata, trailer) {
-		t.Fatalf("Received trailer metadata %v, want %v", trailer, testMetadata)
-	}
-}
-
-func performOneRPC(t *testing.T, tc testpb.TestServiceClient, wg *sync.WaitGroup) {
-	argSize := 2718
-	respSize := 314
-
-	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	req := &testpb.SimpleRequest{
-		ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseSize: proto.Int32(int32(respSize)),
-		Payload:      payload,
-	}
-	reply, err := tc.UnaryCall(context.Background(), req)
-	if err != nil {
-		t.Fatalf("TestService/UnaryCall(_, _) = _, %v, want _, <nil>", err)
-	}
-	pt := reply.GetPayload().GetType()
-	ps := len(reply.GetPayload().GetBody())
-	if pt != testpb.PayloadType_COMPRESSABLE || ps != respSize {
-		t.Fatalf("Got the reply with type %d len %d; want %d, %d", pt, ps, testpb.PayloadType_COMPRESSABLE, respSize)
-	}
-	wg.Done()
-}
-
-func TestRetry(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testRetry(t, e)
-	}
-}
-
-// This test mimics a user who sends 1000 RPCs concurrently on a faulty transport.
-// TODO(zhaoq): Refactor to make this clearer and add more cases to test racy
-// and error-prone paths.
-func testRetry(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	var wg sync.WaitGroup
-	wg.Add(1)
-	go func() {
-		time.Sleep(1 * time.Second)
-		// The server shuts down the network connection to make a
-		// transport error which will be detected by the client side
-		// code.
-		s.TestingCloseConns()
-		wg.Done()
-	}()
-	// All these RPCs should succeed eventually.
-	for i := 0; i < 1000; i++ {
-		time.Sleep(2 * time.Millisecond)
-		wg.Add(1)
-		go performOneRPC(t, tc, &wg)
-	}
-	wg.Wait()
-}
-
-func TestRPCTimeout(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testRPCTimeout(t, e)
-	}
-}
-
-// TODO(zhaoq): Have a better test coverage of timeout and cancellation mechanism.
-func testRPCTimeout(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	argSize := 2718
-	respSize := 314
-
-	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	req := &testpb.SimpleRequest{
-		ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseSize: proto.Int32(int32(respSize)),
-		Payload:      payload,
-	}
-	for i := -1; i <= 10; i++ {
-		ctx, _ := context.WithTimeout(context.Background(), time.Duration(i)*time.Millisecond)
-		reply, err := tc.UnaryCall(ctx, req)
-		if grpc.Code(err) != codes.DeadlineExceeded {
-			t.Fatalf(`TestService/UnaryCallv(_, _) = %v, %v; want <nil>, error code: %d`, reply, err, codes.DeadlineExceeded)
-		}
-	}
-}
-
-func TestCancel(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testCancel(t, e)
-	}
-}
-
-func testCancel(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	argSize := 2718
-	respSize := 314
-
-	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	req := &testpb.SimpleRequest{
-		ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseSize: proto.Int32(int32(respSize)),
-		Payload:      payload,
-	}
-	ctx, cancel := context.WithCancel(context.Background())
-	time.AfterFunc(1*time.Millisecond, cancel)
-	reply, err := tc.UnaryCall(ctx, req)
-	if grpc.Code(err) != codes.Canceled {
-		t.Fatalf(`TestService/UnaryCall(_, _) = %v, %v; want <nil>, error code: %d`, reply, err, codes.Canceled)
-	}
-}
-
-func TestCancelNoIO(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testCancelNoIO(t, e)
-	}
-}
-
-func testCancelNoIO(t *testing.T, e env) {
-	// Only allows 1 live stream per server transport.
-	s, addr := serverSetUp(t, nil, 1, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	ctx, cancel := context.WithCancel(context.Background())
-	_, err := tc.StreamingInputCall(ctx)
-	if err != nil {
-		t.Fatalf("%v.StreamingInputCall(_) = _, %v, want _, <nil>", tc, err)
-	}
-	// Loop until receiving the new max stream setting from the server.
-	for {
-		ctx, _ := context.WithTimeout(context.Background(), time.Second)
-		_, err := tc.StreamingInputCall(ctx)
-		if err == nil {
-			time.Sleep(time.Second)
-			continue
-		}
-		if grpc.Code(err) == codes.DeadlineExceeded {
-			break
-		}
-		t.Fatalf("%v.StreamingInputCall(_) = _, %v, want _, %d", tc, err, codes.DeadlineExceeded)
-	}
-	// If there are any RPCs slipping before the client receives the max streams setting,
-	// let them be expired.
-	time.Sleep(2 * time.Second)
-	ch := make(chan struct{})
-	go func() {
-		defer close(ch)
-		// This should be blocked until the 1st is canceled.
-		ctx, _ := context.WithTimeout(context.Background(), 2*time.Second)
-		if _, err := tc.StreamingInputCall(ctx); err != nil {
-			t.Errorf("%v.StreamingInputCall(_) = _, %v, want _, <nil>", tc, err)
-		}
-	}()
-	cancel()
-	<-ch
-}
-
-// The following tests the gRPC streaming RPC implementations.
-// TODO(zhaoq): Have better coverage on error cases.
-var (
-	reqSizes  = []int{27182, 8, 1828, 45904}
-	respSizes = []int{31415, 9, 2653, 58979}
-)
-
-func TestPingPong(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testPingPong(t, e)
-	}
-}
-
-func testPingPong(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	stream, err := tc.FullDuplexCall(context.Background())
-	if err != nil {
-		t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err)
-	}
-	var index int
-	for index < len(reqSizes) {
-		respParam := []*testpb.ResponseParameters{
-			{
-				Size: proto.Int32(int32(respSizes[index])),
-			},
-		}
-
-		payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(reqSizes[index]))
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		req := &testpb.StreamingOutputCallRequest{
-			ResponseType:       testpb.PayloadType_COMPRESSABLE.Enum(),
-			ResponseParameters: respParam,
-			Payload:            payload,
-		}
-		if err := stream.Send(req); err != nil {
-			t.Fatalf("%v.Send(%v) = %v, want <nil>", stream, req, err)
-		}
-		reply, err := stream.Recv()
-		if err != nil {
-			t.Fatalf("%v.Recv() = %v, want <nil>", stream, err)
-		}
-		pt := reply.GetPayload().GetType()
-		if pt != testpb.PayloadType_COMPRESSABLE {
-			t.Fatalf("Got the reply of type %d, want %d", pt, testpb.PayloadType_COMPRESSABLE)
-		}
-		size := len(reply.GetPayload().GetBody())
-		if size != int(respSizes[index]) {
-			t.Fatalf("Got reply body of length %d, want %d", size, respSizes[index])
-		}
-		index++
-	}
-	if err := stream.CloseSend(); err != nil {
-		t.Fatalf("%v.CloseSend() got %v, want %v", stream, err, nil)
-	}
-	if _, err := stream.Recv(); err != io.EOF {
-		t.Fatalf("%v failed to complele the ping pong test: %v", stream, err)
-	}
-}
-
-func TestMetadataStreamingRPC(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testMetadataStreamingRPC(t, e)
-	}
-}
-
-func testMetadataStreamingRPC(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	ctx := metadata.NewContext(context.Background(), testMetadata)
-	stream, err := tc.FullDuplexCall(ctx)
-	if err != nil {
-		t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err)
-	}
-	go func() {
-		headerMD, err := stream.Header()
-		if e.security == "tls" {
-			delete(headerMD, "transport_security_type")
-		}
-		if err != nil || !reflect.DeepEqual(testMetadata, headerMD) {
-			t.Errorf("#1 %v.Header() = %v, %v, want %v, <nil>", stream, headerMD, err, testMetadata)
-		}
-		// test the cached value.
-		headerMD, err = stream.Header()
-		if err != nil || !reflect.DeepEqual(testMetadata, headerMD) {
-			t.Errorf("#2 %v.Header() = %v, %v, want %v, <nil>", stream, headerMD, err, testMetadata)
-		}
-		var index int
-		for index < len(reqSizes) {
-			respParam := []*testpb.ResponseParameters{
-				{
-					Size: proto.Int32(int32(respSizes[index])),
-				},
-			}
-
-			payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(reqSizes[index]))
-			if err != nil {
-				t.Fatal(err)
-			}
-
-			req := &testpb.StreamingOutputCallRequest{
-				ResponseType:       testpb.PayloadType_COMPRESSABLE.Enum(),
-				ResponseParameters: respParam,
-				Payload:            payload,
-			}
-			if err := stream.Send(req); err != nil {
-				t.Errorf("%v.Send(%v) = %v, want <nil>", stream, req, err)
-				return
-			}
-			index++
-		}
-		// Tell the server we're done sending args.
-		stream.CloseSend()
-	}()
-	for {
-		if _, err := stream.Recv(); err != nil {
-			break
-		}
-	}
-	trailerMD := stream.Trailer()
-	if !reflect.DeepEqual(testMetadata, trailerMD) {
-		t.Fatalf("%v.Trailer() = %v, want %v", stream, trailerMD, testMetadata)
-	}
-}
-
-func TestServerStreaming(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testServerStreaming(t, e)
-	}
-}
-
-func testServerStreaming(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	respParam := make([]*testpb.ResponseParameters, len(respSizes))
-	for i, s := range respSizes {
-		respParam[i] = &testpb.ResponseParameters{
-			Size: proto.Int32(int32(s)),
-		}
-	}
-	req := &testpb.StreamingOutputCallRequest{
-		ResponseType:       testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseParameters: respParam,
-	}
-	stream, err := tc.StreamingOutputCall(context.Background(), req)
-	if err != nil {
-		t.Fatalf("%v.StreamingOutputCall(_) = _, %v, want <nil>", tc, err)
-	}
-	var rpcStatus error
-	var respCnt int
-	var index int
-	for {
-		reply, err := stream.Recv()
-		if err != nil {
-			rpcStatus = err
-			break
-		}
-		pt := reply.GetPayload().GetType()
-		if pt != testpb.PayloadType_COMPRESSABLE {
-			t.Fatalf("Got the reply of type %d, want %d", pt, testpb.PayloadType_COMPRESSABLE)
-		}
-		size := len(reply.GetPayload().GetBody())
-		if size != int(respSizes[index]) {
-			t.Fatalf("Got reply body of length %d, want %d", size, respSizes[index])
-		}
-		index++
-		respCnt++
-	}
-	if rpcStatus != io.EOF {
-		t.Fatalf("Failed to finish the server streaming rpc: %v, want <EOF>", rpcStatus)
-	}
-	if respCnt != len(respSizes) {
-		t.Fatalf("Got %d reply, want %d", len(respSizes), respCnt)
-	}
-}
-
-func TestFailedServerStreaming(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testFailedServerStreaming(t, e)
-	}
-}
-
-func testFailedServerStreaming(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	respParam := make([]*testpb.ResponseParameters, len(respSizes))
-	for i, s := range respSizes {
-		respParam[i] = &testpb.ResponseParameters{
-			Size: proto.Int32(int32(s)),
-		}
-	}
-	req := &testpb.StreamingOutputCallRequest{
-		ResponseType:       testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseParameters: respParam,
-	}
-	ctx := metadata.NewContext(context.Background(), testMetadata)
-	stream, err := tc.StreamingOutputCall(ctx, req)
-	if err != nil {
-		t.Fatalf("%v.StreamingOutputCall(_) = _, %v, want <nil>", tc, err)
-	}
-	if _, err := stream.Recv(); err != grpc.Errorf(codes.DataLoss, "got extra metadata") {
-		t.Fatalf("%v.Recv() = _, %v, want _, %v", stream, err, grpc.Errorf(codes.DataLoss, "got extra metadata"))
-	}
-}
-
-func TestClientStreaming(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testClientStreaming(t, e)
-	}
-}
-
-func testClientStreaming(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	stream, err := tc.StreamingInputCall(context.Background())
-	if err != nil {
-		t.Fatalf("%v.StreamingInputCall(_) = _, %v, want <nil>", tc, err)
-	}
-	var sum int
-
-	for _, s := range reqSizes {
-		payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(s))
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		req := &testpb.StreamingInputCallRequest{
-			Payload: payload,
-		}
-		if err := stream.Send(req); err != nil {
-			t.Fatalf("%v.Send(%v) = %v, want <nil>", stream, req, err)
-		}
-		sum += s
-	}
-	reply, err := stream.CloseAndRecv()
-	if err != nil {
-		t.Fatalf("%v.CloseAndRecv() got error %v, want %v", stream, err, nil)
-	}
-	if reply.GetAggregatedPayloadSize() != int32(sum) {
-		t.Fatalf("%v.CloseAndRecv().GetAggregatePayloadSize() = %v; want %v", stream, reply.GetAggregatedPayloadSize(), sum)
-	}
-}
-
-func TestExceedMaxStreamsLimit(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testExceedMaxStreamsLimit(t, e)
-	}
-}
-
-func testExceedMaxStreamsLimit(t *testing.T, e env) {
-	// Only allows 1 live stream per server transport.
-	s, addr := serverSetUp(t, nil, 1, nil, nil, e)
-	cc := clientSetUp(t, addr, nil, nil, "", e)
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	_, err := tc.StreamingInputCall(context.Background())
-	if err != nil {
-		t.Fatalf("%v.StreamingInputCall(_) = _, %v, want _, <nil>", tc, err)
-	}
-	// Loop until receiving the new max stream setting from the server.
-	for {
-		ctx, _ := context.WithTimeout(context.Background(), time.Second)
-		_, err := tc.StreamingInputCall(ctx)
-		if err == nil {
-			time.Sleep(time.Second)
-			continue
-		}
-		if grpc.Code(err) == codes.DeadlineExceeded {
-			break
-		}
-		t.Fatalf("%v.StreamingInputCall(_) = _, %v, want _, %d", tc, err, codes.DeadlineExceeded)
-	}
-}
-
-func TestCompressServerHasNoSupport(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testCompressServerHasNoSupport(t, e)
-	}
-}
-
-func testCompressServerHasNoSupport(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, nil, nil, e)
-	cc := clientSetUp(t, addr, grpc.NewGZIPCompressor, nil, "", e)
-	// Unary call
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	argSize := 271828
-	respSize := 314159
-	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-	if err != nil {
-		t.Fatal(err)
-	}
-	req := &testpb.SimpleRequest{
-		ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseSize: proto.Int32(int32(respSize)),
-		Payload:      payload,
-	}
-	if _, err := tc.UnaryCall(context.Background(), req); err == nil || grpc.Code(err) != codes.InvalidArgument {
-		t.Fatalf("TestService/UnaryCall(_, _) = _, %v, want _, error code %d", err, codes.InvalidArgument)
-	}
-	// Streaming RPC
-	stream, err := tc.FullDuplexCall(context.Background())
-	if err != nil {
-		t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err)
-	}
-	respParam := []*testpb.ResponseParameters{
-		{
-			Size: proto.Int32(31415),
-		},
-	}
-	payload, err = newPayload(testpb.PayloadType_COMPRESSABLE, int32(31415))
-	if err != nil {
-		t.Fatal(err)
-	}
-	sreq := &testpb.StreamingOutputCallRequest{
-		ResponseType:       testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseParameters: respParam,
-		Payload:            payload,
-	}
-	if err := stream.Send(sreq); err != nil {
-		t.Fatalf("%v.Send(%v) = %v, want <nil>", stream, sreq, err)
-	}
-	if _, err := stream.Recv(); err == nil || grpc.Code(err) != codes.InvalidArgument {
-		t.Fatalf("%v.Recv() = %v, want error code %d", stream, err, codes.InvalidArgument)
-	}
-}
-
-func TestCompressOK(t *testing.T) {
-	for _, e := range listTestEnv() {
-		testCompressOK(t, e)
-	}
-}
-
-func testCompressOK(t *testing.T, e env) {
-	s, addr := serverSetUp(t, nil, math.MaxUint32, grpc.NewGZIPCompressor, grpc.NewGZIPDecompressor, e)
-	cc := clientSetUp(t, addr, grpc.NewGZIPCompressor, grpc.NewGZIPDecompressor, "", e)
-	// Unary call
-	tc := testpb.NewTestServiceClient(cc)
-	defer tearDown(s, cc)
-	argSize := 271828
-	respSize := 314159
-	payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(argSize))
-	if err != nil {
-		t.Fatal(err)
-	}
-	req := &testpb.SimpleRequest{
-		ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseSize: proto.Int32(int32(respSize)),
-		Payload:      payload,
-	}
-	if _, err := tc.UnaryCall(context.Background(), req); err != nil {
-		t.Fatalf("TestService/UnaryCall(_, _) = _, %v, want _, <nil>", err)
-	}
-	// Streaming RPC
-	stream, err := tc.FullDuplexCall(context.Background())
-	if err != nil {
-		t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err)
-	}
-	respParam := []*testpb.ResponseParameters{
-		{
-			Size: proto.Int32(31415),
-		},
-	}
-	payload, err = newPayload(testpb.PayloadType_COMPRESSABLE, int32(31415))
-	if err != nil {
-		t.Fatal(err)
-	}
-	sreq := &testpb.StreamingOutputCallRequest{
-		ResponseType:       testpb.PayloadType_COMPRESSABLE.Enum(),
-		ResponseParameters: respParam,
-		Payload:            payload,
-	}
-	if err := stream.Send(sreq); err != nil {
-		t.Fatalf("%v.Send(%v) = %v, want <nil>", stream, sreq, err)
-	}
-	if _, err := stream.Recv(); err != nil {
-		t.Fatalf("%v.Recv() = %v, want <nil>", stream, err)
-	}
-}

+ 96 - 31
Godeps/_workspace/src/google.golang.org/grpc/test/grpc_testing/test.pb.go

@@ -22,6 +22,7 @@ It has these top-level messages:
 package grpc_testing
 
 import proto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/golang/protobuf/proto"
+import fmt "fmt"
 import math "math"
 
 import (
@@ -29,14 +30,15 @@ import (
 	grpc "github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
 )
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConn
-
 // Reference imports to suppress errors if they are not otherwise used.
 var _ = proto.Marshal
+var _ = fmt.Errorf
 var _ = math.Inf
 
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.ProtoPackageIsVersion1
+
 // The type of payload that should be returned.
 type PayloadType int32
 
@@ -76,14 +78,16 @@ func (x *PayloadType) UnmarshalJSON(data []byte) error {
 	*x = PayloadType(value)
 	return nil
 }
+func (PayloadType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 type Empty struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *Empty) Reset()         { *m = Empty{} }
-func (m *Empty) String() string { return proto.CompactTextString(m) }
-func (*Empty) ProtoMessage()    {}
+func (m *Empty) Reset()                    { *m = Empty{} }
+func (m *Empty) String() string            { return proto.CompactTextString(m) }
+func (*Empty) ProtoMessage()               {}
+func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
 
 // A block of data, to simply increase gRPC message size.
 type Payload struct {
@@ -94,9 +98,10 @@ type Payload struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *Payload) Reset()         { *m = Payload{} }
-func (m *Payload) String() string { return proto.CompactTextString(m) }
-func (*Payload) ProtoMessage()    {}
+func (m *Payload) Reset()                    { *m = Payload{} }
+func (m *Payload) String() string            { return proto.CompactTextString(m) }
+func (*Payload) ProtoMessage()               {}
+func (*Payload) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
 
 func (m *Payload) GetType() PayloadType {
 	if m != nil && m.Type != nil {
@@ -129,9 +134,10 @@ type SimpleRequest struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *SimpleRequest) Reset()         { *m = SimpleRequest{} }
-func (m *SimpleRequest) String() string { return proto.CompactTextString(m) }
-func (*SimpleRequest) ProtoMessage()    {}
+func (m *SimpleRequest) Reset()                    { *m = SimpleRequest{} }
+func (m *SimpleRequest) String() string            { return proto.CompactTextString(m) }
+func (*SimpleRequest) ProtoMessage()               {}
+func (*SimpleRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
 
 func (m *SimpleRequest) GetResponseType() PayloadType {
 	if m != nil && m.ResponseType != nil {
@@ -180,9 +186,10 @@ type SimpleResponse struct {
 	XXX_unrecognized []byte  `json:"-"`
 }
 
-func (m *SimpleResponse) Reset()         { *m = SimpleResponse{} }
-func (m *SimpleResponse) String() string { return proto.CompactTextString(m) }
-func (*SimpleResponse) ProtoMessage()    {}
+func (m *SimpleResponse) Reset()                    { *m = SimpleResponse{} }
+func (m *SimpleResponse) String() string            { return proto.CompactTextString(m) }
+func (*SimpleResponse) ProtoMessage()               {}
+func (*SimpleResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
 
 func (m *SimpleResponse) GetPayload() *Payload {
 	if m != nil {
@@ -212,9 +219,10 @@ type StreamingInputCallRequest struct {
 	XXX_unrecognized []byte   `json:"-"`
 }
 
-func (m *StreamingInputCallRequest) Reset()         { *m = StreamingInputCallRequest{} }
-func (m *StreamingInputCallRequest) String() string { return proto.CompactTextString(m) }
-func (*StreamingInputCallRequest) ProtoMessage()    {}
+func (m *StreamingInputCallRequest) Reset()                    { *m = StreamingInputCallRequest{} }
+func (m *StreamingInputCallRequest) String() string            { return proto.CompactTextString(m) }
+func (*StreamingInputCallRequest) ProtoMessage()               {}
+func (*StreamingInputCallRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
 
 func (m *StreamingInputCallRequest) GetPayload() *Payload {
 	if m != nil {
@@ -230,9 +238,10 @@ type StreamingInputCallResponse struct {
 	XXX_unrecognized      []byte `json:"-"`
 }
 
-func (m *StreamingInputCallResponse) Reset()         { *m = StreamingInputCallResponse{} }
-func (m *StreamingInputCallResponse) String() string { return proto.CompactTextString(m) }
-func (*StreamingInputCallResponse) ProtoMessage()    {}
+func (m *StreamingInputCallResponse) Reset()                    { *m = StreamingInputCallResponse{} }
+func (m *StreamingInputCallResponse) String() string            { return proto.CompactTextString(m) }
+func (*StreamingInputCallResponse) ProtoMessage()               {}
+func (*StreamingInputCallResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
 
 func (m *StreamingInputCallResponse) GetAggregatedPayloadSize() int32 {
 	if m != nil && m.AggregatedPayloadSize != nil {
@@ -252,9 +261,10 @@ type ResponseParameters struct {
 	XXX_unrecognized []byte `json:"-"`
 }
 
-func (m *ResponseParameters) Reset()         { *m = ResponseParameters{} }
-func (m *ResponseParameters) String() string { return proto.CompactTextString(m) }
-func (*ResponseParameters) ProtoMessage()    {}
+func (m *ResponseParameters) Reset()                    { *m = ResponseParameters{} }
+func (m *ResponseParameters) String() string            { return proto.CompactTextString(m) }
+func (*ResponseParameters) ProtoMessage()               {}
+func (*ResponseParameters) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
 
 func (m *ResponseParameters) GetSize() int32 {
 	if m != nil && m.Size != nil {
@@ -284,9 +294,10 @@ type StreamingOutputCallRequest struct {
 	XXX_unrecognized []byte   `json:"-"`
 }
 
-func (m *StreamingOutputCallRequest) Reset()         { *m = StreamingOutputCallRequest{} }
-func (m *StreamingOutputCallRequest) String() string { return proto.CompactTextString(m) }
-func (*StreamingOutputCallRequest) ProtoMessage()    {}
+func (m *StreamingOutputCallRequest) Reset()                    { *m = StreamingOutputCallRequest{} }
+func (m *StreamingOutputCallRequest) String() string            { return proto.CompactTextString(m) }
+func (*StreamingOutputCallRequest) ProtoMessage()               {}
+func (*StreamingOutputCallRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
 
 func (m *StreamingOutputCallRequest) GetResponseType() PayloadType {
 	if m != nil && m.ResponseType != nil {
@@ -316,9 +327,10 @@ type StreamingOutputCallResponse struct {
 	XXX_unrecognized []byte   `json:"-"`
 }
 
-func (m *StreamingOutputCallResponse) Reset()         { *m = StreamingOutputCallResponse{} }
-func (m *StreamingOutputCallResponse) String() string { return proto.CompactTextString(m) }
-func (*StreamingOutputCallResponse) ProtoMessage()    {}
+func (m *StreamingOutputCallResponse) Reset()                    { *m = StreamingOutputCallResponse{} }
+func (m *StreamingOutputCallResponse) String() string            { return proto.CompactTextString(m) }
+func (*StreamingOutputCallResponse) ProtoMessage()               {}
+func (*StreamingOutputCallResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
 
 func (m *StreamingOutputCallResponse) GetPayload() *Payload {
 	if m != nil {
@@ -328,9 +340,22 @@ func (m *StreamingOutputCallResponse) GetPayload() *Payload {
 }
 
 func init() {
+	proto.RegisterType((*Empty)(nil), "grpc.testing.Empty")
+	proto.RegisterType((*Payload)(nil), "grpc.testing.Payload")
+	proto.RegisterType((*SimpleRequest)(nil), "grpc.testing.SimpleRequest")
+	proto.RegisterType((*SimpleResponse)(nil), "grpc.testing.SimpleResponse")
+	proto.RegisterType((*StreamingInputCallRequest)(nil), "grpc.testing.StreamingInputCallRequest")
+	proto.RegisterType((*StreamingInputCallResponse)(nil), "grpc.testing.StreamingInputCallResponse")
+	proto.RegisterType((*ResponseParameters)(nil), "grpc.testing.ResponseParameters")
+	proto.RegisterType((*StreamingOutputCallRequest)(nil), "grpc.testing.StreamingOutputCallRequest")
+	proto.RegisterType((*StreamingOutputCallResponse)(nil), "grpc.testing.StreamingOutputCallResponse")
 	proto.RegisterEnum("grpc.testing.PayloadType", PayloadType_name, PayloadType_value)
 }
 
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
 // Client API for TestService service
 
 type TestServiceClient interface {
@@ -700,3 +725,43 @@ var _TestService_serviceDesc = grpc.ServiceDesc{
 		},
 	},
 }
+
+var fileDescriptor0 = []byte{
+	// 567 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x54, 0x51, 0x6f, 0xd2, 0x50,
+	0x14, 0xb6, 0x03, 0x64, 0x1c, 0x58, 0x43, 0x0e, 0x59, 0x64, 0x9d, 0x89, 0x4b, 0x7d, 0xb0, 0x9a,
+	0x88, 0x86, 0x44, 0x1f, 0x35, 0x73, 0x63, 0x71, 0x09, 0x03, 0x6c, 0xe1, 0x99, 0x5c, 0xe1, 0x0e,
+	0x9b, 0x94, 0xb6, 0xb6, 0xb7, 0x46, 0x7c, 0xf0, 0x8f, 0xf9, 0x67, 0xfc, 0x11, 0xfe, 0x00, 0xef,
+	0xbd, 0x6d, 0xa1, 0x40, 0x17, 0x99, 0xc6, 0xbd, 0xb5, 0xdf, 0xf9, 0xce, 0x77, 0xbe, 0xef, 0x9e,
+	0xdb, 0x02, 0x30, 0x1a, 0xb2, 0x96, 0x1f, 0x78, 0xcc, 0xc3, 0xda, 0x2c, 0xf0, 0x27, 0x2d, 0x01,
+	0xd8, 0xee, 0x4c, 0x2f, 0x43, 0xa9, 0x33, 0xf7, 0xd9, 0x42, 0xef, 0x42, 0x79, 0x40, 0x16, 0x8e,
+	0x47, 0xa6, 0xf8, 0x1c, 0x8a, 0x6c, 0xe1, 0xd3, 0xa6, 0x72, 0xa2, 0x18, 0x6a, 0xfb, 0xa8, 0x95,
+	0x6d, 0x68, 0x25, 0xa4, 0x21, 0x27, 0x98, 0x92, 0x86, 0x08, 0xc5, 0x8f, 0xde, 0x74, 0xd1, 0xdc,
+	0xe3, 0xf4, 0x9a, 0x29, 0x9f, 0xf5, 0x5f, 0x0a, 0x1c, 0x58, 0xf6, 0xdc, 0x77, 0xa8, 0x49, 0x3f,
+	0x47, 0xbc, 0x15, 0xdf, 0xc0, 0x41, 0x40, 0x43, 0xdf, 0x73, 0x43, 0x3a, 0xde, 0x4d, 0xbd, 0x96,
+	0xf2, 0xc5, 0x1b, 0x3e, 0xce, 0xf4, 0x87, 0xf6, 0x37, 0x2a, 0xc7, 0x95, 0x56, 0x24, 0x8b, 0x63,
+	0xf8, 0x02, 0xca, 0x7e, 0xac, 0xd0, 0x2c, 0xf0, 0x72, 0xb5, 0x7d, 0x98, 0x2b, 0x6f, 0xa6, 0x2c,
+	0xa1, 0x7a, 0x6d, 0x3b, 0xce, 0x38, 0x0a, 0x69, 0xe0, 0x92, 0x39, 0x6d, 0x16, 0x79, 0xdb, 0xbe,
+	0x59, 0x13, 0xe0, 0x28, 0xc1, 0xd0, 0x80, 0xba, 0x24, 0x79, 0x24, 0x62, 0x9f, 0xc6, 0xe1, 0xc4,
+	0xe3, 0xee, 0x4b, 0x92, 0xa7, 0x0a, 0xbc, 0x2f, 0x60, 0x4b, 0xa0, 0xfa, 0x77, 0x50, 0xd3, 0xd4,
+	0xb1, 0xab, 0xac, 0x23, 0x65, 0x27, 0x47, 0x1a, 0xec, 0x2f, 0xcd, 0x88, 0x88, 0x15, 0x73, 0xf9,
+	0x8e, 0x8f, 0xa0, 0x9a, 0xf5, 0x50, 0x90, 0x65, 0xf0, 0x56, 0xf3, 0xbb, 0x70, 0x64, 0xb1, 0x80,
+	0x92, 0x39, 0x97, 0xbe, 0x74, 0xfd, 0x88, 0x9d, 0x11, 0xc7, 0x49, 0x37, 0x70, 0x5b, 0x2b, 0xfa,
+	0x10, 0xb4, 0x3c, 0xb5, 0x24, 0xd9, 0x6b, 0x78, 0x40, 0x66, 0xb3, 0x80, 0xce, 0x08, 0xa3, 0xd3,
+	0x71, 0xd2, 0x13, 0xaf, 0x46, 0x91, 0xab, 0x39, 0x5c, 0x95, 0x13, 0x69, 0xb1, 0x23, 0xfd, 0x12,
+	0x30, 0xd5, 0x18, 0x90, 0x80, 0xc7, 0x62, 0x34, 0x08, 0xc5, 0x25, 0xca, 0xb4, 0xca, 0x67, 0x11,
+	0xd7, 0x76, 0x79, 0xf5, 0x0b, 0x11, 0x0b, 0x4a, 0x16, 0x0e, 0x29, 0x34, 0x0a, 0xf5, 0x9f, 0x4a,
+	0xc6, 0x61, 0x3f, 0x62, 0x1b, 0x81, 0xff, 0xf5, 0xca, 0x7d, 0x80, 0xc6, 0xb2, 0xdf, 0x5f, 0x5a,
+	0xe5, 0x3e, 0x0a, 0xfc, 0xf0, 0x4e, 0xd6, 0x55, 0xb6, 0x23, 0x99, 0x18, 0x6c, 0xc7, 0xbc, 0xed,
+	0x05, 0xd5, 0x7b, 0x70, 0x9c, 0x9b, 0xf0, 0x2f, 0xaf, 0xd7, 0xb3, 0xb7, 0x50, 0xcd, 0x04, 0xc6,
+	0x3a, 0xd4, 0xce, 0xfa, 0x57, 0x03, 0xb3, 0x63, 0x59, 0xa7, 0xef, 0xba, 0x9d, 0xfa, 0x3d, 0xbe,
+	0x08, 0x75, 0xd4, 0x5b, 0xc3, 0x14, 0x04, 0xb8, 0x6f, 0x9e, 0xf6, 0xce, 0xfb, 0x57, 0xf5, 0xbd,
+	0xf6, 0x8f, 0x22, 0x54, 0x87, 0x5c, 0xdd, 0xe2, 0x4b, 0xb0, 0x27, 0x14, 0x5f, 0x41, 0x45, 0xfe,
+	0x40, 0x84, 0x2d, 0x6c, 0xac, 0x4f, 0x97, 0x05, 0x2d, 0x0f, 0xc4, 0x0b, 0xa8, 0x8c, 0x5c, 0x12,
+	0xc4, 0x6d, 0xc7, 0xeb, 0x8c, 0xb5, 0x1f, 0x87, 0xf6, 0x30, 0xbf, 0x98, 0x1c, 0x80, 0x03, 0x8d,
+	0x9c, 0xf3, 0x41, 0x63, 0xa3, 0xe9, 0xc6, 0x4b, 0xa2, 0x3d, 0xdd, 0x81, 0x19, 0xcf, 0x7a, 0xa9,
+	0xa0, 0x0d, 0xb8, 0xfd, 0x45, 0xe0, 0x93, 0x1b, 0x24, 0x36, 0xbf, 0x40, 0xcd, 0xf8, 0x33, 0x31,
+	0x1e, 0x65, 0x88, 0x51, 0xea, 0x45, 0xe4, 0x38, 0xe7, 0x11, 0x4f, 0xfb, 0xf5, 0xbf, 0x65, 0x32,
+	0x14, 0x99, 0x4a, 0x7d, 0x4f, 0x9c, 0xeb, 0x3b, 0x18, 0xf5, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x4c,
+	0x41, 0xfe, 0xb6, 0x89, 0x06, 0x00, 0x00,
+}

+ 0 - 15
Godeps/_workspace/src/google.golang.org/grpc/test/testdata/ca.pem

@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
-Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
-YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
-BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
-+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
-g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
-Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
-sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
-oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
-Dfcog5wrJytaQ6UA0wE=
------END CERTIFICATE-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/test/testdata/server1.key

@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
-M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
-3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
-AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
-V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
-tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
-dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
-K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
-81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
-DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
-aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
-ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
-XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
-F98XJ7tIFfJq
------END PRIVATE KEY-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/test/testdata/server1.pem

@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
-MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
-ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
-LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
-zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
-9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
-CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
-em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
-CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
-hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
-y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
------END CERTIFICATE-----

+ 0 - 15
Godeps/_workspace/src/google.golang.org/grpc/testdata/ca.pem

@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
-Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
-YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
-BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
-+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
-g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
-Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
-sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
-oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
-Dfcog5wrJytaQ6UA0wE=
------END CERTIFICATE-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/testdata/server1.key

@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
-M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
-3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
-AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
-V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
-tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
-dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
-K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
-81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
-DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
-aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
-ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
-XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
-F98XJ7tIFfJq
------END PRIVATE KEY-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/testdata/server1.pem

@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
-MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
-ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
-LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
-zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
-9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
-CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
-em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
-CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
-hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
-y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
------END CERTIFICATE-----

+ 377 - 0
Godeps/_workspace/src/google.golang.org/grpc/transport/handler_server.go

@@ -0,0 +1,377 @@
+/*
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// This file is the implementation of a gRPC server using HTTP/2 which
+// uses the standard Go http2 Server implementation (via the
+// http.Handler interface), rather than speaking low-level HTTP/2
+// frames itself. It is the implementation of *grpc.Server.ServeHTTP.
+
+package transport
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
+	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2"
+	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/codes"
+	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/credentials"
+	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/metadata"
+	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/peer"
+)
+
+// NewServerHandlerTransport returns a ServerTransport handling gRPC
+// from inside an http.Handler. It requires that the http Server
+// supports HTTP/2.
+func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request) (ServerTransport, error) {
+	if r.ProtoMajor != 2 {
+		return nil, errors.New("gRPC requires HTTP/2")
+	}
+	if r.Method != "POST" {
+		return nil, errors.New("invalid gRPC request method")
+	}
+	if !strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
+		return nil, errors.New("invalid gRPC request content-type")
+	}
+	if _, ok := w.(http.Flusher); !ok {
+		return nil, errors.New("gRPC requires a ResponseWriter supporting http.Flusher")
+	}
+	if _, ok := w.(http.CloseNotifier); !ok {
+		return nil, errors.New("gRPC requires a ResponseWriter supporting http.CloseNotifier")
+	}
+
+	st := &serverHandlerTransport{
+		rw:       w,
+		req:      r,
+		closedCh: make(chan struct{}),
+		writes:   make(chan func()),
+	}
+
+	if v := r.Header.Get("grpc-timeout"); v != "" {
+		to, err := timeoutDecode(v)
+		if err != nil {
+			return nil, StreamErrorf(codes.Internal, "malformed time-out: %v", err)
+		}
+		st.timeoutSet = true
+		st.timeout = to
+	}
+
+	var metakv []string
+	for k, vv := range r.Header {
+		k = strings.ToLower(k)
+		if isReservedHeader(k) {
+			continue
+		}
+		for _, v := range vv {
+			if k == "user-agent" {
+				// user-agent is special. Copying logic of http_util.go.
+				if i := strings.LastIndex(v, " "); i == -1 {
+					// There is no application user agent string being set
+					continue
+				} else {
+					v = v[:i]
+				}
+			}
+			metakv = append(metakv, k, v)
+
+		}
+	}
+	st.headerMD = metadata.Pairs(metakv...)
+
+	return st, nil
+}
+
+// serverHandlerTransport is an implementation of ServerTransport
+// which replies to exactly one gRPC request (exactly one HTTP request),
+// using the net/http.Handler interface. This http.Handler is guranteed
+// at this point to be speaking over HTTP/2, so it's able to speak valid
+// gRPC.
+type serverHandlerTransport struct {
+	rw               http.ResponseWriter
+	req              *http.Request
+	timeoutSet       bool
+	timeout          time.Duration
+	didCommonHeaders bool
+
+	headerMD metadata.MD
+
+	closeOnce sync.Once
+	closedCh  chan struct{} // closed on Close
+
+	// writes is a channel of code to run serialized in the
+	// ServeHTTP (HandleStreams) goroutine. The channel is closed
+	// when WriteStatus is called.
+	writes chan func()
+}
+
+func (ht *serverHandlerTransport) Close() error {
+	ht.closeOnce.Do(ht.closeCloseChanOnce)
+	return nil
+}
+
+func (ht *serverHandlerTransport) closeCloseChanOnce() { close(ht.closedCh) }
+
+func (ht *serverHandlerTransport) RemoteAddr() net.Addr { return strAddr(ht.req.RemoteAddr) }
+
+// strAddr is a net.Addr backed by either a TCP "ip:port" string, or
+// the empty string if unknown.
+type strAddr string
+
+func (a strAddr) Network() string {
+	if a != "" {
+		// Per the documentation on net/http.Request.RemoteAddr, if this is
+		// set, it's set to the IP:port of the peer (hence, TCP):
+		// https://golang.org/pkg/net/http/#Request
+		//
+		// If we want to support Unix sockets later, we can
+		// add our own grpc-specific convention within the
+		// grpc codebase to set RemoteAddr to a different
+		// format, or probably better: we can attach it to the
+		// context and use that from serverHandlerTransport.RemoteAddr.
+		return "tcp"
+	}
+	return ""
+}
+
+func (a strAddr) String() string { return string(a) }
+
+// do runs fn in the ServeHTTP goroutine.
+func (ht *serverHandlerTransport) do(fn func()) error {
+	select {
+	case ht.writes <- fn:
+		return nil
+	case <-ht.closedCh:
+		return ErrConnClosing
+	}
+}
+
+func (ht *serverHandlerTransport) WriteStatus(s *Stream, statusCode codes.Code, statusDesc string) error {
+	err := ht.do(func() {
+		ht.writeCommonHeaders(s)
+
+		// And flush, in case no header or body has been sent yet.
+		// This forces a separation of headers and trailers if this is the
+		// first call (for example, in end2end tests's TestNoService).
+		ht.rw.(http.Flusher).Flush()
+
+		h := ht.rw.Header()
+		h.Set("Grpc-Status", fmt.Sprintf("%d", statusCode))
+		if statusDesc != "" {
+			h.Set("Grpc-Message", statusDesc)
+		}
+		if md := s.Trailer(); len(md) > 0 {
+			for k, vv := range md {
+				for _, v := range vv {
+					// http2 ResponseWriter mechanism to
+					// send undeclared Trailers after the
+					// headers have possibly been written.
+					h.Add(http2.TrailerPrefix+k, v)
+				}
+			}
+		}
+	})
+	close(ht.writes)
+	return err
+}
+
+// writeCommonHeaders sets common headers on the first write
+// call (Write, WriteHeader, or WriteStatus).
+func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) {
+	if ht.didCommonHeaders {
+		return
+	}
+	ht.didCommonHeaders = true
+
+	h := ht.rw.Header()
+	h["Date"] = nil // suppress Date to make tests happy; TODO: restore
+	h.Set("Content-Type", "application/grpc")
+
+	// Predeclare trailers we'll set later in WriteStatus (after the body).
+	// This is a SHOULD in the HTTP RFC, and the way you add (known)
+	// Trailers per the net/http.ResponseWriter contract.
+	// See https://golang.org/pkg/net/http/#ResponseWriter
+	// and https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+	h.Add("Trailer", "Grpc-Status")
+	h.Add("Trailer", "Grpc-Message")
+
+	if s.sendCompress != "" {
+		h.Set("Grpc-Encoding", s.sendCompress)
+	}
+}
+
+func (ht *serverHandlerTransport) Write(s *Stream, data []byte, opts *Options) error {
+	return ht.do(func() {
+		ht.writeCommonHeaders(s)
+		ht.rw.Write(data)
+		if !opts.Delay {
+			ht.rw.(http.Flusher).Flush()
+		}
+	})
+}
+
+func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error {
+	return ht.do(func() {
+		ht.writeCommonHeaders(s)
+		h := ht.rw.Header()
+		for k, vv := range md {
+			for _, v := range vv {
+				h.Add(k, v)
+			}
+		}
+		ht.rw.WriteHeader(200)
+		ht.rw.(http.Flusher).Flush()
+	})
+}
+
+func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream)) {
+	// With this transport type there will be exactly 1 stream: this HTTP request.
+
+	var ctx context.Context
+	var cancel context.CancelFunc
+	if ht.timeoutSet {
+		ctx, cancel = context.WithTimeout(context.Background(), ht.timeout)
+	} else {
+		ctx, cancel = context.WithCancel(context.Background())
+	}
+
+	// requestOver is closed when either the request's context is done
+	// or the status has been written via WriteStatus.
+	requestOver := make(chan struct{})
+
+	// clientGone receives a single value if peer is gone, either
+	// because the underlying connection is dead or because the
+	// peer sends an http2 RST_STREAM.
+	clientGone := ht.rw.(http.CloseNotifier).CloseNotify()
+	go func() {
+		select {
+		case <-requestOver:
+			return
+		case <-ht.closedCh:
+		case <-clientGone:
+		}
+		cancel()
+	}()
+
+	req := ht.req
+
+	s := &Stream{
+		id:            0,            // irrelevant
+		windowHandler: func(int) {}, // nothing
+		cancel:        cancel,
+		buf:           newRecvBuffer(),
+		st:            ht,
+		method:        req.URL.Path,
+		recvCompress:  req.Header.Get("grpc-encoding"),
+	}
+	pr := &peer.Peer{
+		Addr: ht.RemoteAddr(),
+	}
+	if req.TLS != nil {
+		pr.AuthInfo = credentials.TLSInfo{*req.TLS}
+	}
+	ctx = metadata.NewContext(ctx, ht.headerMD)
+	ctx = peer.NewContext(ctx, pr)
+	s.ctx = newContextWithStream(ctx, s)
+	s.dec = &recvBufferReader{ctx: s.ctx, recv: s.buf}
+
+	// readerDone is closed when the Body.Read-ing goroutine exits.
+	readerDone := make(chan struct{})
+	go func() {
+		defer close(readerDone)
+		for {
+			buf := make([]byte, 1024) // TODO: minimize garbage, optimize recvBuffer code/ownership
+			n, err := req.Body.Read(buf)
+			if n > 0 {
+				s.buf.put(&recvMsg{data: buf[:n]})
+			}
+			if err != nil {
+				s.buf.put(&recvMsg{err: mapRecvMsgError(err)})
+				return
+			}
+		}
+	}()
+
+	// startStream is provided by the *grpc.Server's serveStreams.
+	// It starts a goroutine serving s and exits immediately.
+	// The goroutine that is started is the one that then calls
+	// into ht, calling WriteHeader, Write, WriteStatus, Close, etc.
+	startStream(s)
+
+	ht.runStream()
+	close(requestOver)
+
+	// Wait for reading goroutine to finish.
+	req.Body.Close()
+	<-readerDone
+}
+
+func (ht *serverHandlerTransport) runStream() {
+	for {
+		select {
+		case fn, ok := <-ht.writes:
+			if !ok {
+				return
+			}
+			fn()
+		case <-ht.closedCh:
+			return
+		}
+	}
+}
+
+// mapRecvMsgError returns the non-nil err into the appropriate
+// error value as expected by callers of *grpc.parser.recvMsg.
+// In particular, in can only be:
+//   * io.EOF
+//   * io.ErrUnexpectedEOF
+//   * of type transport.ConnectionError
+//   * of type transport.StreamError
+func mapRecvMsgError(err error) error {
+	if err == io.EOF || err == io.ErrUnexpectedEOF {
+		return err
+	}
+	if se, ok := err.(http2.StreamError); ok {
+		if code, ok := http2ErrConvTab[se.Code]; ok {
+			return StreamError{
+				Code: code,
+				Desc: se.Error(),
+			}
+		}
+	}
+	return ConnectionError{Desc: err.Error()}
+}

+ 45 - 50
Godeps/_workspace/src/google.golang.org/grpc/transport/http2_client.go

@@ -353,6 +353,10 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea
 		} else {
 			endHeaders = true
 		}
+		var flush bool
+		if endHeaders && (hasMD || callHdr.Flush) {
+			flush = true
+		}
 		if first {
 			// Sends a HeadersFrame to server to start a new stream.
 			p := http2.HeadersFrameParam{
@@ -364,11 +368,11 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea
 			// Do a force flush for the buffered frames iff it is the last headers frame
 			// and there is header metadata to be sent. Otherwise, there is flushing until
 			// the corresponding data frame is written.
-			err = t.framer.writeHeaders(hasMD && endHeaders, p)
+			err = t.framer.writeHeaders(flush, p)
 			first = false
 		} else {
 			// Sends Continuation frames for the leftover headers.
-			err = t.framer.writeContinuation(hasMD && endHeaders, s.id, endHeaders, t.hBuf.Next(size))
+			err = t.framer.writeContinuation(flush, s.id, endHeaders, t.hBuf.Next(size))
 		}
 		if err != nil {
 			t.notifyError(err)
@@ -546,14 +550,8 @@ func (t *http2Client) Write(s *Stream, data []byte, opts *Options) error {
 func (t *http2Client) getStream(f http2.Frame) (*Stream, bool) {
 	t.mu.Lock()
 	defer t.mu.Unlock()
-	if t.activeStreams == nil {
-		// The transport is closing.
-		return nil, false
-	}
-	if s, ok := t.activeStreams[f.Header().StreamID]; ok {
-		return s, true
-	}
-	return nil, false
+	s, ok := t.activeStreams[f.Header().StreamID]
+	return s, ok
 }
 
 // updateWindow adjusts the inbound quota for the stream and the transport.
@@ -633,7 +631,7 @@ func (t *http2Client) handleRSTStream(f *http2.RSTStreamFrame) {
 		close(s.headerChan)
 		s.headerDone = true
 	}
-	s.statusCode, ok = http2RSTErrConvTab[http2.ErrCode(f.ErrCode)]
+	s.statusCode, ok = http2ErrConvTab[http2.ErrCode(f.ErrCode)]
 	if !ok {
 		grpclog.Println("transport: http2Client.handleRSTStream found no mapped gRPC status for the received http2 error ", f.ErrCode)
 	}
@@ -676,54 +674,49 @@ func (t *http2Client) handleWindowUpdate(f *http2.WindowUpdateFrame) {
 	}
 }
 
-// operateHeader takes action on the decoded headers. It returns the current
-// stream if there are remaining headers on the wire (in the following
-// Continuation frame).
-func (t *http2Client) operateHeaders(hDec *hpackDecoder, s *Stream, frame headerFrame, endStream bool) (pendingStream *Stream) {
-	defer func() {
-		if pendingStream == nil {
-			hDec.state = decodeState{}
-		}
-	}()
-	endHeaders, err := hDec.decodeClientHTTP2Headers(frame)
-	if s == nil {
-		// s has been closed.
-		return nil
+// operateHeaders takes action on the decoded headers.
+func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
+	s, ok := t.getStream(frame)
+	if !ok {
+		return
 	}
-	if err != nil {
-		s.write(recvMsg{err: err})
-		// Something wrong. Stops reading even when there is remaining.
-		return nil
+	var state decodeState
+	for _, hf := range frame.Fields {
+		state.processHeaderField(hf)
 	}
-	if !endHeaders {
-		return s
+	if state.err != nil {
+		s.write(recvMsg{err: state.err})
+		// Something wrong. Stops reading even when there is remaining.
+		return
 	}
+
+	endStream := frame.StreamEnded()
+
 	s.mu.Lock()
 	if !endStream {
-		s.recvCompress = hDec.state.encoding
+		s.recvCompress = state.encoding
 	}
 	if !s.headerDone {
-		if !endStream && len(hDec.state.mdata) > 0 {
-			s.header = hDec.state.mdata
+		if !endStream && len(state.mdata) > 0 {
+			s.header = state.mdata
 		}
 		close(s.headerChan)
 		s.headerDone = true
 	}
 	if !endStream || s.state == streamDone {
 		s.mu.Unlock()
-		return nil
+		return
 	}
 
-	if len(hDec.state.mdata) > 0 {
-		s.trailer = hDec.state.mdata
+	if len(state.mdata) > 0 {
+		s.trailer = state.mdata
 	}
 	s.state = streamDone
-	s.statusCode = hDec.state.statusCode
-	s.statusDesc = hDec.state.statusDesc
+	s.statusCode = state.statusCode
+	s.statusDesc = state.statusDesc
 	s.mu.Unlock()
 
 	s.write(recvMsg{err: io.EOF})
-	return nil
 }
 
 // reader runs as a separate goroutine in charge of reading data from network
@@ -746,8 +739,6 @@ func (t *http2Client) reader() {
 	}
 	t.handleSettings(sf)
 
-	hDec := newHPACKDecoder()
-	var curStream *Stream
 	// loop to keep reading incoming messages on this transport.
 	for {
 		frame, err := t.framer.readFrame()
@@ -756,15 +747,8 @@ func (t *http2Client) reader() {
 			return
 		}
 		switch frame := frame.(type) {
-		case *http2.HeadersFrame:
-			// operateHeaders has to be invoked regardless the value of curStream
-			// because the HPACK decoder needs to be updated using the received
-			// headers.
-			curStream, _ = t.getStream(frame)
-			endStream := frame.Header().Flags.Has(http2.FlagHeadersEndStream)
-			curStream = t.operateHeaders(hDec, curStream, frame, endStream)
-		case *http2.ContinuationFrame:
-			curStream = t.operateHeaders(hDec, curStream, frame, frame.HeadersEnded())
+		case *http2.MetaHeadersFrame:
+			t.operateHeaders(frame)
 		case *http2.DataFrame:
 			t.handleData(frame)
 		case *http2.RSTStreamFrame:
@@ -862,6 +846,17 @@ func (t *http2Client) Error() <-chan struct{} {
 func (t *http2Client) notifyError(err error) {
 	t.mu.Lock()
 	defer t.mu.Unlock()
+
+	// Abort an active stream if the http2.Framer returns a
+	// http2.StreamError. This can happen only if the server's response
+	// is malformed http2.
+	if se, ok := err.(http2.StreamError); ok {
+		if s, ok := t.activeStreams[se.StreamID]; ok {
+			s.write(recvMsg{err: StreamErrorf(http2ErrConvTab[se.Code], "%v", err)})
+			return
+		}
+	}
+
 	// make sure t.errorChan is closed only once.
 	if t.state == reachable {
 		t.state = unreachable

+ 34 - 50
Godeps/_workspace/src/google.golang.org/grpc/transport/http2_server.go

@@ -62,8 +62,8 @@ type http2Server struct {
 	maxStreamID uint32               // max stream ID ever seen
 	authInfo    credentials.AuthInfo // auth info about the connection
 	// writableChan synchronizes write access to the transport.
-	// A writer acquires the write lock by sending a value on writableChan
-	// and releases it by receiving from writableChan.
+	// A writer acquires the write lock by receiving a value on writableChan
+	// and releases it by sending on writableChan.
 	writableChan chan int
 	// shutdownChan is closed when Close is called.
 	// Blocking operations should select on shutdownChan to avoid
@@ -136,37 +136,38 @@ func newHTTP2Server(conn net.Conn, maxStreams uint32, authInfo credentials.AuthI
 	return t, nil
 }
 
-// operateHeader takes action on the decoded headers. It returns the current
-// stream if there are remaining headers on the wire (in the following
-// Continuation frame).
-func (t *http2Server) operateHeaders(hDec *hpackDecoder, s *Stream, frame headerFrame, endStream bool, handle func(*Stream)) (pendingStream *Stream) {
-	defer func() {
-		if pendingStream == nil {
-			hDec.state = decodeState{}
-		}
-	}()
-	endHeaders, err := hDec.decodeServerHTTP2Headers(frame)
-	if s == nil {
-		// s has been closed.
-		return nil
+// operateHeader takes action on the decoded headers.
+func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream)) {
+	buf := newRecvBuffer()
+	fc := &inFlow{
+		limit: initialWindowSize,
+		conn:  t.fc,
+	}
+	s := &Stream{
+		id:  frame.Header().StreamID,
+		st:  t,
+		buf: buf,
+		fc:  fc,
 	}
-	if err != nil {
-		grpclog.Printf("transport: http2Server.operateHeader found %v", err)
+
+	var state decodeState
+	for _, hf := range frame.Fields {
+		state.processHeaderField(hf)
+	}
+	if err := state.err; err != nil {
 		if se, ok := err.(StreamError); ok {
 			t.controlBuf.put(&resetStream{s.id, statusCodeConvTab[se.Code]})
 		}
-		return nil
+		return
 	}
-	if endStream {
+
+	if frame.StreamEnded() {
 		// s is just created by the caller. No lock needed.
 		s.state = streamReadDone
 	}
-	if !endHeaders {
-		return s
-	}
-	s.recvCompress = hDec.state.encoding
-	if hDec.state.timeoutSet {
-		s.ctx, s.cancel = context.WithTimeout(context.TODO(), hDec.state.timeout)
+	s.recvCompress = state.encoding
+	if state.timeoutSet {
+		s.ctx, s.cancel = context.WithTimeout(context.TODO(), state.timeout)
 	} else {
 		s.ctx, s.cancel = context.WithCancel(context.TODO())
 	}
@@ -183,25 +184,25 @@ func (t *http2Server) operateHeaders(hDec *hpackDecoder, s *Stream, frame header
 	// back to the client (unary call only).
 	s.ctx = newContextWithStream(s.ctx, s)
 	// Attach the received metadata to the context.
-	if len(hDec.state.mdata) > 0 {
-		s.ctx = metadata.NewContext(s.ctx, hDec.state.mdata)
+	if len(state.mdata) > 0 {
+		s.ctx = metadata.NewContext(s.ctx, state.mdata)
 	}
 
 	s.dec = &recvBufferReader{
 		ctx:  s.ctx,
 		recv: s.buf,
 	}
-	s.recvCompress = hDec.state.encoding
-	s.method = hDec.state.method
+	s.recvCompress = state.encoding
+	s.method = state.method
 	t.mu.Lock()
 	if t.state != reachable {
 		t.mu.Unlock()
-		return nil
+		return
 	}
 	if uint32(len(t.activeStreams)) >= t.maxStreams {
 		t.mu.Unlock()
 		t.controlBuf.put(&resetStream{s.id, http2.ErrCodeRefusedStream})
-		return nil
+		return
 	}
 	s.sendQuotaPool = newQuotaPool(int(t.streamSendQuota))
 	t.activeStreams[s.id] = s
@@ -210,7 +211,6 @@ func (t *http2Server) operateHeaders(hDec *hpackDecoder, s *Stream, frame header
 		t.updateWindow(s, uint32(n))
 	}
 	handle(s)
-	return nil
 }
 
 // HandleStreams receives incoming streams using the given handler. This is
@@ -243,8 +243,6 @@ func (t *http2Server) HandleStreams(handle func(*Stream)) {
 	}
 	t.handleSettings(sf)
 
-	hDec := newHPACKDecoder()
-	var curStream *Stream
 	for {
 		frame, err := t.framer.readFrame()
 		if err != nil {
@@ -252,7 +250,7 @@ func (t *http2Server) HandleStreams(handle func(*Stream)) {
 			return
 		}
 		switch frame := frame.(type) {
-		case *http2.HeadersFrame:
+		case *http2.MetaHeadersFrame:
 			id := frame.Header().StreamID
 			if id%2 != 1 || id <= t.maxStreamID {
 				// illegal gRPC stream id.
@@ -261,21 +259,7 @@ func (t *http2Server) HandleStreams(handle func(*Stream)) {
 				break
 			}
 			t.maxStreamID = id
-			buf := newRecvBuffer()
-			fc := &inFlow{
-				limit: initialWindowSize,
-				conn:  t.fc,
-			}
-			curStream = &Stream{
-				id:  frame.Header().StreamID,
-				st:  t,
-				buf: buf,
-				fc:  fc,
-			}
-			endStream := frame.Header().Flags.Has(http2.FlagHeadersEndStream)
-			curStream = t.operateHeaders(hDec, curStream, frame, endStream, handle)
-		case *http2.ContinuationFrame:
-			curStream = t.operateHeaders(hDec, curStream, frame, frame.HeadersEnded(), handle)
+			t.operateHeaders(frame, handle)
 		case *http2.DataFrame:
 			t.handleData(frame)
 		case *http2.RSTStreamFrame:

+ 56 - 104
Godeps/_workspace/src/google.golang.org/grpc/transport/http_util.go

@@ -62,8 +62,8 @@ const (
 )
 
 var (
-	clientPreface      = []byte(http2.ClientPreface)
-	http2RSTErrConvTab = map[http2.ErrCode]codes.Code{
+	clientPreface   = []byte(http2.ClientPreface)
+	http2ErrConvTab = map[http2.ErrCode]codes.Code{
 		http2.ErrCodeNo:                 codes.Internal,
 		http2.ErrCodeProtocol:           codes.Internal,
 		http2.ErrCodeInternal:           codes.Internal,
@@ -76,6 +76,7 @@ var (
 		http2.ErrCodeConnect:            codes.Internal,
 		http2.ErrCodeEnhanceYourCalm:    codes.ResourceExhausted,
 		http2.ErrCodeInadequateSecurity: codes.PermissionDenied,
+		http2.ErrCodeHTTP11Required:     codes.FailedPrecondition,
 	}
 	statusCodeConvTab = map[codes.Code]http2.ErrCode{
 		codes.Internal:          http2.ErrCodeInternal,
@@ -89,6 +90,8 @@ var (
 // Records the states during HPACK decoding. Must be reset once the
 // decoding of the entire headers are finished.
 type decodeState struct {
+	err error // first error encountered decoding
+
 	encoding string
 	// statusCode caches the stream status received from the trailer
 	// the server sent. Client side only.
@@ -102,25 +105,11 @@ type decodeState struct {
 	mdata map[string][]string
 }
 
-// An hpackDecoder decodes HTTP2 headers which may span multiple frames.
-type hpackDecoder struct {
-	h     *hpack.Decoder
-	state decodeState
-	err   error // The err when decoding
-}
-
-// A headerFrame is either a http2.HeaderFrame or http2.ContinuationFrame.
-type headerFrame interface {
-	Header() http2.FrameHeader
-	HeaderBlockFragment() []byte
-	HeadersEnded() bool
-}
-
 // isReservedHeader checks whether hdr belongs to HTTP2 headers
 // reserved by gRPC protocol. Any other headers are classified as the
 // user-specified metadata.
 func isReservedHeader(hdr string) bool {
-	if hdr[0] == ':' {
+	if hdr != "" && hdr[0] == ':' {
 		return true
 	}
 	switch hdr {
@@ -137,100 +126,62 @@ func isReservedHeader(hdr string) bool {
 	}
 }
 
-func newHPACKDecoder() *hpackDecoder {
-	d := &hpackDecoder{}
-	d.h = hpack.NewDecoder(http2InitHeaderTableSize, func(f hpack.HeaderField) {
-		switch f.Name {
-		case "content-type":
-			if !strings.Contains(f.Value, "application/grpc") {
-				d.err = StreamErrorf(codes.FailedPrecondition, "transport: received the unexpected header")
-				return
+func (d *decodeState) setErr(err error) {
+	if d.err == nil {
+		d.err = err
+	}
+}
+
+func (d *decodeState) processHeaderField(f hpack.HeaderField) {
+	switch f.Name {
+	case "content-type":
+		if !strings.Contains(f.Value, "application/grpc") {
+			d.setErr(StreamErrorf(codes.FailedPrecondition, "transport: received the unexpected content-type %q", f.Value))
+			return
+		}
+	case "grpc-encoding":
+		d.encoding = f.Value
+	case "grpc-status":
+		code, err := strconv.Atoi(f.Value)
+		if err != nil {
+			d.setErr(StreamErrorf(codes.Internal, "transport: malformed grpc-status: %v", err))
+			return
+		}
+		d.statusCode = codes.Code(code)
+	case "grpc-message":
+		d.statusDesc = f.Value
+	case "grpc-timeout":
+		d.timeoutSet = true
+		var err error
+		d.timeout, err = timeoutDecode(f.Value)
+		if err != nil {
+			d.setErr(StreamErrorf(codes.Internal, "transport: malformed time-out: %v", err))
+			return
+		}
+	case ":path":
+		d.method = f.Value
+	default:
+		if !isReservedHeader(f.Name) {
+			if f.Name == "user-agent" {
+				i := strings.LastIndex(f.Value, " ")
+				if i == -1 {
+					// There is no application user agent string being set.
+					return
+				}
+				// Extract the application user agent string.
+				f.Value = f.Value[:i]
 			}
-		case "grpc-encoding":
-			d.state.encoding = f.Value
-		case "grpc-status":
-			code, err := strconv.Atoi(f.Value)
-			if err != nil {
-				d.err = StreamErrorf(codes.Internal, "transport: malformed grpc-status: %v", err)
-				return
+			if d.mdata == nil {
+				d.mdata = make(map[string][]string)
 			}
-			d.state.statusCode = codes.Code(code)
-		case "grpc-message":
-			d.state.statusDesc = f.Value
-		case "grpc-timeout":
-			d.state.timeoutSet = true
-			var err error
-			d.state.timeout, err = timeoutDecode(f.Value)
+			k, v, err := metadata.DecodeKeyValue(f.Name, f.Value)
 			if err != nil {
-				d.err = StreamErrorf(codes.Internal, "transport: malformed time-out: %v", err)
+				grpclog.Printf("Failed to decode (%q, %q): %v", f.Name, f.Value, err)
 				return
 			}
-		case ":path":
-			d.state.method = f.Value
-		default:
-			if !isReservedHeader(f.Name) {
-				if f.Name == "user-agent" {
-					i := strings.LastIndex(f.Value, " ")
-					if i == -1 {
-						// There is no application user agent string being set.
-						return
-					}
-					// Extract the application user agent string.
-					f.Value = f.Value[:i]
-				}
-				if d.state.mdata == nil {
-					d.state.mdata = make(map[string][]string)
-				}
-				k, v, err := metadata.DecodeKeyValue(f.Name, f.Value)
-				if err != nil {
-					grpclog.Printf("Failed to decode (%q, %q): %v", f.Name, f.Value, err)
-					return
-				}
-				d.state.mdata[k] = append(d.state.mdata[k], v)
-			}
-		}
-	})
-	return d
-}
-
-func (d *hpackDecoder) decodeClientHTTP2Headers(frame headerFrame) (endHeaders bool, err error) {
-	d.err = nil
-	_, err = d.h.Write(frame.HeaderBlockFragment())
-	if err != nil {
-		err = StreamErrorf(codes.Internal, "transport: HPACK header decode error: %v", err)
-	}
-
-	if frame.HeadersEnded() {
-		if closeErr := d.h.Close(); closeErr != nil && err == nil {
-			err = StreamErrorf(codes.Internal, "transport: HPACK decoder close error: %v", closeErr)
-		}
-		endHeaders = true
-	}
-
-	if err == nil && d.err != nil {
-		err = d.err
-	}
-	return
-}
-
-func (d *hpackDecoder) decodeServerHTTP2Headers(frame headerFrame) (endHeaders bool, err error) {
-	d.err = nil
-	_, err = d.h.Write(frame.HeaderBlockFragment())
-	if err != nil {
-		err = StreamErrorf(codes.Internal, "transport: HPACK header decode error: %v", err)
-	}
-
-	if frame.HeadersEnded() {
-		if closeErr := d.h.Close(); closeErr != nil && err == nil {
-			err = StreamErrorf(codes.Internal, "transport: HPACK decoder close error: %v", closeErr)
+			d.mdata[k] = append(d.mdata[k], v)
 		}
-		endHeaders = true
 	}
-
-	if err == nil && d.err != nil {
-		err = d.err
-	}
-	return
 }
 
 type timeoutUnit uint8
@@ -325,6 +276,7 @@ func newFramer(conn net.Conn) *framer {
 		writer: bufio.NewWriterSize(conn, http2IOBufSize),
 	}
 	f.fr = http2.NewFramer(f.writer, f.reader)
+	f.fr.ReadMetaHeaders = hpack.NewDecoder(http2InitHeaderTableSize, nil)
 	return f
 }
 

+ 0 - 87
Godeps/_workspace/src/google.golang.org/grpc/transport/http_util_test.go

@@ -1,87 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package transport
-
-import (
-	"fmt"
-	"testing"
-	"time"
-)
-
-func TestTimeoutEncode(t *testing.T) {
-	for _, test := range []struct {
-		in  string
-		out string
-	}{
-		{"12345678ns", "12345678n"},
-		{"123456789ns", "123457u"},
-		{"12345678us", "12345678u"},
-		{"123456789us", "123457m"},
-		{"12345678ms", "12345678m"},
-		{"123456789ms", "123457S"},
-		{"12345678s", "12345678S"},
-		{"123456789s", "2057614M"},
-		{"12345678m", "12345678M"},
-		{"123456789m", "2057614H"},
-	} {
-		d, err := time.ParseDuration(test.in)
-		if err != nil {
-			t.Fatalf("failed to parse duration string %s: %v", test.in, err)
-		}
-		out := timeoutEncode(d)
-		if out != test.out {
-			t.Fatalf("timeoutEncode(%s) = %s, want %s", test.in, out, test.out)
-		}
-	}
-}
-
-func TestTimeoutDecode(t *testing.T) {
-	for _, test := range []struct {
-		// input
-		s string
-		// output
-		d   time.Duration
-		err error
-	}{
-		{"1234S", time.Second * 1234, nil},
-		{"1234x", 0, fmt.Errorf("transport: timeout unit is not recognized: %q", "1234x")},
-		{"1", 0, fmt.Errorf("transport: timeout string is too short: %q", "1")},
-		{"", 0, fmt.Errorf("transport: timeout string is too short: %q", "")},
-	} {
-		d, err := timeoutDecode(test.s)
-		if d != test.d || fmt.Sprint(err) != fmt.Sprint(test.err) {
-			t.Fatalf("timeoutDecode(%q) = %d, %v, want %d, %v", test.s, int64(d), err, int64(test.d), test.err)
-		}
-	}
-}

+ 0 - 15
Godeps/_workspace/src/google.golang.org/grpc/transport/testdata/ca.pem

@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
-Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
-YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
-BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
-+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
-g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
-Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
-sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
-oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
-Dfcog5wrJytaQ6UA0wE=
------END CERTIFICATE-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/transport/testdata/server1.key

@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
-M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
-3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
-AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
-V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
-tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
-dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
-K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
-81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
-DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
-aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
-ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
-XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
-F98XJ7tIFfJq
------END PRIVATE KEY-----

+ 0 - 16
Godeps/_workspace/src/google.golang.org/grpc/transport/testdata/server1.pem

@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
-MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
-ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
-LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
-zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
-9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
-CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
-em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
-CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
-hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
-y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
------END CERTIFICATE-----

+ 40 - 14
Godeps/_workspace/src/google.golang.org/grpc/transport/transport.go

@@ -352,26 +352,40 @@ func NewClientTransport(target string, opts *ConnectOptions) (ClientTransport, e
 // Options provides additional hints and information for message
 // transmission.
 type Options struct {
-	// Indicate whether it is the last piece for this stream.
+	// Last indicates whether this write is the last piece for
+	// this stream.
 	Last bool
-	// The hint to transport impl whether the data could be buffered for
-	// batching write. Transport impl can feel free to ignore it.
+
+	// Delay is a hint to the transport implementation for whether
+	// the data could be buffered for a batching write. The
+	// Transport implementation may ignore the hint.
 	Delay bool
 }
 
 // CallHdr carries the information of a particular RPC.
 type CallHdr struct {
-	// Host specifies peer host.
+	// Host specifies the peer's host.
 	Host string
+
 	// Method specifies the operation to perform.
 	Method string
-	// RecvCompress specifies the compression algorithm applied on inbound messages.
+
+	// RecvCompress specifies the compression algorithm applied on
+	// inbound messages.
 	RecvCompress string
-	// SendCompress specifies the compression algorithm applied on outbound message.
+
+	// SendCompress specifies the compression algorithm applied on
+	// outbound message.
 	SendCompress string
+
+	// Flush indicates whether a new stream command should be sent
+	// to the peer without waiting for the first data. This is
+	// only a hint. The transport may modify the flush decision
+	// for performance purposes.
+	Flush bool
 }
 
-// ClientTransport is the common interface for all gRPC client side transport
+// ClientTransport is the common interface for all gRPC client-side transport
 // implementations.
 type ClientTransport interface {
 	// Close tears down this transport. Once it returns, the transport
@@ -400,21 +414,33 @@ type ClientTransport interface {
 	Error() <-chan struct{}
 }
 
-// ServerTransport is the common interface for all gRPC server side transport
+// ServerTransport is the common interface for all gRPC server-side transport
 // implementations.
+//
+// Methods may be called concurrently from multiple goroutines, but
+// Write methods for a given Stream will be called serially.
 type ServerTransport interface {
-	// WriteStatus sends the status of a stream to the client.
-	WriteStatus(s *Stream, statusCode codes.Code, statusDesc string) error
-	// Write sends the data for the given stream.
-	Write(s *Stream, data []byte, opts *Options) error
-	// WriteHeader sends the header metedata for the given stream.
-	WriteHeader(s *Stream, md metadata.MD) error
 	// HandleStreams receives incoming streams using the given handler.
 	HandleStreams(func(*Stream))
+
+	// WriteHeader sends the header metadata for the given stream.
+	// WriteHeader may not be called on all streams.
+	WriteHeader(s *Stream, md metadata.MD) error
+
+	// Write sends the data for the given stream.
+	// Write may not be called on all streams.
+	Write(s *Stream, data []byte, opts *Options) error
+
+	// WriteStatus sends the status of a stream to the client.
+	// WriteStatus is the final call made on a stream and always
+	// occurs.
+	WriteStatus(s *Stream, statusCode codes.Code, statusDesc string) error
+
 	// Close tears down the transport. Once it is called, the transport
 	// should not be accessed any more. All the pending streams and their
 	// handlers will be terminated asynchronously.
 	Close() error
+
 	// RemoteAddr returns the remote network address.
 	RemoteAddr() net.Addr
 }

+ 0 - 659
Godeps/_workspace/src/google.golang.org/grpc/transport/transport_test.go

@@ -1,659 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-package transport
-
-import (
-	"bytes"
-	"io"
-	"math"
-	"net"
-	"reflect"
-	"strconv"
-	"sync"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
-	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/http2"
-	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/codes"
-)
-
-type server struct {
-	lis  net.Listener
-	port string
-	// channel to signal server is ready to serve.
-	readyChan chan bool
-	mu        sync.Mutex
-	conns     map[ServerTransport]bool
-}
-
-var (
-	expectedRequest       = []byte("ping")
-	expectedResponse      = []byte("pong")
-	expectedRequestLarge  = make([]byte, initialWindowSize*2)
-	expectedResponseLarge = make([]byte, initialWindowSize*2)
-)
-
-type testStreamHandler struct {
-	t ServerTransport
-}
-
-type hType int
-
-const (
-	normal hType = iota
-	suspended
-	misbehaved
-)
-
-func (h *testStreamHandler) handleStream(t *testing.T, s *Stream) {
-	req := expectedRequest
-	resp := expectedResponse
-	if s.Method() == "foo.Large" {
-		req = expectedRequestLarge
-		resp = expectedResponseLarge
-	}
-	p := make([]byte, len(req))
-	_, err := io.ReadFull(s, p)
-	if err != nil {
-		return
-	}
-	if !bytes.Equal(p, req) {
-		t.Fatalf("handleStream got %v, want %v", p, req)
-	}
-	// send a response back to the client.
-	h.t.Write(s, resp, &Options{})
-	// send the trailer to end the stream.
-	h.t.WriteStatus(s, codes.OK, "")
-}
-
-// handleStreamSuspension blocks until s.ctx is canceled.
-func (h *testStreamHandler) handleStreamSuspension(s *Stream) {
-	go func() {
-		<-s.ctx.Done()
-	}()
-}
-
-func (h *testStreamHandler) handleStreamMisbehave(t *testing.T, s *Stream) {
-	conn, ok := s.ServerTransport().(*http2Server)
-	if !ok {
-		t.Fatalf("Failed to convert %v to *http2Server", s.ServerTransport())
-	}
-	size := 1
-	if s.Method() == "foo.MaxFrame" {
-		size = http2MaxFrameLen
-	}
-	// Drain the client side stream flow control window.
-	var sent int
-	for sent <= initialWindowSize {
-		<-conn.writableChan
-		if err := conn.framer.writeData(true, s.id, false, make([]byte, size)); err != nil {
-			conn.writableChan <- 0
-			break
-		}
-		conn.writableChan <- 0
-		sent += size
-	}
-}
-
-// start starts server. Other goroutines should block on s.readyChan for futher operations.
-func (s *server) start(t *testing.T, port int, maxStreams uint32, ht hType) {
-	var err error
-	if port == 0 {
-		s.lis, err = net.Listen("tcp", ":0")
-	} else {
-		s.lis, err = net.Listen("tcp", ":"+strconv.Itoa(port))
-	}
-	if err != nil {
-		t.Fatalf("failed to listen: %v", err)
-	}
-	_, p, err := net.SplitHostPort(s.lis.Addr().String())
-	if err != nil {
-		t.Fatalf("failed to parse listener address: %v", err)
-	}
-	s.port = p
-	s.conns = make(map[ServerTransport]bool)
-	if s.readyChan != nil {
-		close(s.readyChan)
-	}
-	for {
-		conn, err := s.lis.Accept()
-		if err != nil {
-			return
-		}
-		transport, err := NewServerTransport("http2", conn, maxStreams, nil)
-		if err != nil {
-			return
-		}
-		s.mu.Lock()
-		if s.conns == nil {
-			s.mu.Unlock()
-			transport.Close()
-			return
-		}
-		s.conns[transport] = true
-		s.mu.Unlock()
-		h := &testStreamHandler{transport}
-		switch ht {
-		case suspended:
-			go transport.HandleStreams(h.handleStreamSuspension)
-		case misbehaved:
-			go transport.HandleStreams(func(s *Stream) {
-				go h.handleStreamMisbehave(t, s)
-			})
-		default:
-			go transport.HandleStreams(func(s *Stream) {
-				go h.handleStream(t, s)
-			})
-		}
-	}
-}
-
-func (s *server) wait(t *testing.T, timeout time.Duration) {
-	select {
-	case <-s.readyChan:
-	case <-time.After(timeout):
-		t.Fatalf("Timed out after %v waiting for server to be ready", timeout)
-	}
-}
-
-func (s *server) stop() {
-	s.lis.Close()
-	s.mu.Lock()
-	for c := range s.conns {
-		c.Close()
-	}
-	s.conns = nil
-	s.mu.Unlock()
-}
-
-func setUp(t *testing.T, port int, maxStreams uint32, ht hType) (*server, ClientTransport) {
-	server := &server{readyChan: make(chan bool)}
-	go server.start(t, port, maxStreams, ht)
-	server.wait(t, 2*time.Second)
-	addr := "localhost:" + server.port
-	var (
-		ct      ClientTransport
-		connErr error
-	)
-	ct, connErr = NewClientTransport(addr, &ConnectOptions{})
-	if connErr != nil {
-		t.Fatalf("failed to create transport: %v", connErr)
-	}
-	return server, ct
-}
-
-func TestClientSendAndReceive(t *testing.T) {
-	server, ct := setUp(t, 0, math.MaxUint32, normal)
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo.Small",
-	}
-	s1, err1 := ct.NewStream(context.Background(), callHdr)
-	if err1 != nil {
-		t.Fatalf("failed to open stream: %v", err1)
-	}
-	if s1.id != 1 {
-		t.Fatalf("wrong stream id: %d", s1.id)
-	}
-	s2, err2 := ct.NewStream(context.Background(), callHdr)
-	if err2 != nil {
-		t.Fatalf("failed to open stream: %v", err2)
-	}
-	if s2.id != 3 {
-		t.Fatalf("wrong stream id: %d", s2.id)
-	}
-	opts := Options{
-		Last:  true,
-		Delay: false,
-	}
-	if err := ct.Write(s1, expectedRequest, &opts); err != nil {
-		t.Fatalf("failed to send data: %v", err)
-	}
-	p := make([]byte, len(expectedResponse))
-	_, recvErr := io.ReadFull(s1, p)
-	if recvErr != nil || !bytes.Equal(p, expectedResponse) {
-		t.Fatalf("Error: %v, want <nil>; Result: %v, want %v", recvErr, p, expectedResponse)
-	}
-	_, recvErr = io.ReadFull(s1, p)
-	if recvErr != io.EOF {
-		t.Fatalf("Error: %v; want <EOF>", recvErr)
-	}
-	ct.Close()
-	server.stop()
-}
-
-func TestClientErrorNotify(t *testing.T) {
-	server, ct := setUp(t, 0, math.MaxUint32, normal)
-	go server.stop()
-	// ct.reader should detect the error and activate ct.Error().
-	<-ct.Error()
-	ct.Close()
-}
-
-func performOneRPC(ct ClientTransport) {
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo.Small",
-	}
-	s, err := ct.NewStream(context.Background(), callHdr)
-	if err != nil {
-		return
-	}
-	opts := Options{
-		Last:  true,
-		Delay: false,
-	}
-	if err := ct.Write(s, expectedRequest, &opts); err == nil {
-		time.Sleep(5 * time.Millisecond)
-		// The following s.Recv()'s could error out because the
-		// underlying transport is gone.
-		//
-		// Read response
-		p := make([]byte, len(expectedResponse))
-		io.ReadFull(s, p)
-		// Read io.EOF
-		io.ReadFull(s, p)
-	}
-}
-
-func TestClientMix(t *testing.T) {
-	s, ct := setUp(t, 0, math.MaxUint32, normal)
-	go func(s *server) {
-		time.Sleep(5 * time.Second)
-		s.stop()
-	}(s)
-	go func(ct ClientTransport) {
-		<-ct.Error()
-		ct.Close()
-	}(ct)
-	for i := 0; i < 1000; i++ {
-		time.Sleep(10 * time.Millisecond)
-		go performOneRPC(ct)
-	}
-}
-
-func TestLargeMessage(t *testing.T) {
-	server, ct := setUp(t, 0, math.MaxUint32, normal)
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo.Large",
-	}
-	var wg sync.WaitGroup
-	for i := 0; i < 2; i++ {
-		wg.Add(1)
-		go func() {
-			defer wg.Done()
-			s, err := ct.NewStream(context.Background(), callHdr)
-			if err != nil {
-				t.Errorf("failed to open stream: %v", err)
-			}
-			if err := ct.Write(s, expectedRequestLarge, &Options{Last: true, Delay: false}); err != nil {
-				t.Errorf("failed to send data: %v", err)
-			}
-			p := make([]byte, len(expectedResponseLarge))
-			_, recvErr := io.ReadFull(s, p)
-			if recvErr != nil || !bytes.Equal(p, expectedResponseLarge) {
-				t.Errorf("Error: %v, want <nil>; Result len: %d, want len %d", recvErr, len(p), len(expectedResponseLarge))
-			}
-			_, recvErr = io.ReadFull(s, p)
-			if recvErr != io.EOF {
-				t.Errorf("Error: %v; want <EOF>", recvErr)
-			}
-		}()
-	}
-	wg.Wait()
-	ct.Close()
-	server.stop()
-}
-
-func TestLargeMessageSuspension(t *testing.T) {
-	server, ct := setUp(t, 0, math.MaxUint32, suspended)
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo.Large",
-	}
-	// Set a long enough timeout for writing a large message out.
-	ctx, _ := context.WithTimeout(context.Background(), time.Second)
-	s, err := ct.NewStream(ctx, callHdr)
-	if err != nil {
-		t.Fatalf("failed to open stream: %v", err)
-	}
-	// Write should not be done successfully due to flow control.
-	err = ct.Write(s, expectedRequestLarge, &Options{Last: true, Delay: false})
-	expectedErr := StreamErrorf(codes.DeadlineExceeded, "%v", context.DeadlineExceeded)
-	if err == nil || err != expectedErr {
-		t.Fatalf("Write got %v, want %v", err, expectedErr)
-	}
-	ct.Close()
-	server.stop()
-}
-
-func TestMaxStreams(t *testing.T) {
-	server, ct := setUp(t, 0, 1, suspended)
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo.Large",
-	}
-	// Have a pending stream which takes all streams quota.
-	s, err := ct.NewStream(context.Background(), callHdr)
-	if err != nil {
-		t.Fatalf("Failed to open stream: %v", err)
-	}
-	cc, ok := ct.(*http2Client)
-	if !ok {
-		t.Fatalf("Failed to convert %v to *http2Client", ct)
-	}
-	done := make(chan struct{})
-	ch := make(chan int)
-	go func() {
-		for {
-			select {
-			case <-time.After(5 * time.Millisecond):
-				ch <- 0
-			case <-time.After(5 * time.Second):
-				close(done)
-				return
-			}
-		}
-	}()
-	for {
-		select {
-		case <-ch:
-		case <-done:
-			t.Fatalf("Client has not received the max stream setting in 5 seconds.")
-		}
-		cc.mu.Lock()
-		// cc.streamsQuota should be initialized once receiving the 1st setting frame from
-		// the server.
-		if cc.streamsQuota != nil {
-			cc.mu.Unlock()
-			select {
-			case <-cc.streamsQuota.acquire():
-				t.Fatalf("streamsQuota.acquire() becomes readable mistakenly.")
-			default:
-				if cc.streamsQuota.quota != 0 {
-					t.Fatalf("streamsQuota.quota got non-zero quota mistakenly.")
-				}
-			}
-			break
-		}
-		cc.mu.Unlock()
-	}
-	// Close the pending stream so that the streams quota becomes available for the next new stream.
-	ct.CloseStream(s, nil)
-	select {
-	case i := <-cc.streamsQuota.acquire():
-		if i != 1 {
-			t.Fatalf("streamsQuota.acquire() got %d quota, want 1.", i)
-		}
-		cc.streamsQuota.add(i)
-	default:
-		t.Fatalf("streamsQuota.acquire() is not readable.")
-	}
-	if _, err := ct.NewStream(context.Background(), callHdr); err != nil {
-		t.Fatalf("Failed to open stream: %v", err)
-	}
-	ct.Close()
-	server.stop()
-}
-
-func TestServerContextCanceledOnClosedConnection(t *testing.T) {
-	server, ct := setUp(t, 0, math.MaxUint32, suspended)
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo",
-	}
-	var sc *http2Server
-	// Wait until the server transport is setup.
-	for {
-		server.mu.Lock()
-		if len(server.conns) == 0 {
-			server.mu.Unlock()
-			time.Sleep(time.Millisecond)
-			continue
-		}
-		for k := range server.conns {
-			var ok bool
-			sc, ok = k.(*http2Server)
-			if !ok {
-				t.Fatalf("Failed to convert %v to *http2Server", k)
-			}
-		}
-		server.mu.Unlock()
-		break
-	}
-	cc, ok := ct.(*http2Client)
-	if !ok {
-		t.Fatalf("Failed to convert %v to *http2Client", ct)
-	}
-	s, err := ct.NewStream(context.Background(), callHdr)
-	if err != nil {
-		t.Fatalf("Failed to open stream: %v", err)
-	}
-	// Make sure the headers frame is flushed out.
-	<-cc.writableChan
-	if err = cc.framer.writeData(true, s.id, false, make([]byte, http2MaxFrameLen)); err != nil {
-		t.Fatalf("Failed to write data: %v", err)
-	}
-	cc.writableChan <- 0
-	// Loop until the server side stream is created.
-	var ss *Stream
-	for {
-		time.Sleep(time.Second)
-		sc.mu.Lock()
-		if len(sc.activeStreams) == 0 {
-			sc.mu.Unlock()
-			continue
-		}
-		ss = sc.activeStreams[s.id]
-		sc.mu.Unlock()
-		break
-	}
-	cc.Close()
-	select {
-	case <-ss.Context().Done():
-		if ss.Context().Err() != context.Canceled {
-			t.Fatalf("ss.Context().Err() got %v, want %v", ss.Context().Err(), context.Canceled)
-		}
-	case <-time.After(5 * time.Second):
-		t.Fatalf("Failed to cancel the context of the sever side stream.")
-	}
-}
-
-func TestServerWithMisbehavedClient(t *testing.T) {
-	server, ct := setUp(t, 0, math.MaxUint32, suspended)
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo",
-	}
-	var sc *http2Server
-	// Wait until the server transport is setup.
-	for {
-		server.mu.Lock()
-		if len(server.conns) == 0 {
-			server.mu.Unlock()
-			time.Sleep(time.Millisecond)
-			continue
-		}
-		for k := range server.conns {
-			var ok bool
-			sc, ok = k.(*http2Server)
-			if !ok {
-				t.Fatalf("Failed to convert %v to *http2Server", k)
-			}
-		}
-		server.mu.Unlock()
-		break
-	}
-	cc, ok := ct.(*http2Client)
-	if !ok {
-		t.Fatalf("Failed to convert %v to *http2Client", ct)
-	}
-	// Test server behavior for violation of stream flow control window size restriction.
-	s, err := ct.NewStream(context.Background(), callHdr)
-	if err != nil {
-		t.Fatalf("Failed to open stream: %v", err)
-	}
-	var sent int
-	// Drain the stream flow control window
-	<-cc.writableChan
-	if err = cc.framer.writeData(true, s.id, false, make([]byte, http2MaxFrameLen)); err != nil {
-		t.Fatalf("Failed to write data: %v", err)
-	}
-	cc.writableChan <- 0
-	sent += http2MaxFrameLen
-	// Wait until the server creates the corresponding stream and receive some data.
-	var ss *Stream
-	for {
-		time.Sleep(time.Millisecond)
-		sc.mu.Lock()
-		if len(sc.activeStreams) == 0 {
-			sc.mu.Unlock()
-			continue
-		}
-		ss = sc.activeStreams[s.id]
-		sc.mu.Unlock()
-		ss.fc.mu.Lock()
-		if ss.fc.pendingData > 0 {
-			ss.fc.mu.Unlock()
-			break
-		}
-		ss.fc.mu.Unlock()
-	}
-	if ss.fc.pendingData != http2MaxFrameLen || ss.fc.pendingUpdate != 0 || sc.fc.pendingData != http2MaxFrameLen || sc.fc.pendingUpdate != 0 {
-		t.Fatalf("Server mistakenly updates inbound flow control params: got %d, %d, %d, %d; want %d, %d, %d, %d", ss.fc.pendingData, ss.fc.pendingUpdate, sc.fc.pendingData, sc.fc.pendingUpdate, http2MaxFrameLen, 0, http2MaxFrameLen, 0)
-	}
-	// Keep sending until the server inbound window is drained for that stream.
-	for sent <= initialWindowSize {
-		<-cc.writableChan
-		if err = cc.framer.writeData(true, s.id, false, make([]byte, 1)); err != nil {
-			t.Fatalf("Failed to write data: %v", err)
-		}
-		cc.writableChan <- 0
-		sent++
-	}
-	// Server sent a resetStream for s already.
-	code := http2RSTErrConvTab[http2.ErrCodeFlowControl]
-	if _, err := io.ReadFull(s, make([]byte, 1)); err != io.EOF || s.statusCode != code {
-		t.Fatalf("%v got err %v with statusCode %d, want err <EOF> with statusCode %d", s, err, s.statusCode, code)
-	}
-
-	if ss.fc.pendingData != 0 || ss.fc.pendingUpdate != 0 || sc.fc.pendingData != 0 || sc.fc.pendingUpdate != initialWindowSize {
-		t.Fatalf("Server mistakenly resets inbound flow control params: got %d, %d, %d, %d; want 0, 0, 0, %d", ss.fc.pendingData, ss.fc.pendingUpdate, sc.fc.pendingData, sc.fc.pendingUpdate, initialWindowSize)
-	}
-	ct.CloseStream(s, nil)
-	// Test server behavior for violation of connection flow control window size restriction.
-	//
-	// Keep creating new streams until the connection window is drained on the server and
-	// the server tears down the connection.
-	for {
-		s, err := ct.NewStream(context.Background(), callHdr)
-		if err != nil {
-			// The server tears down the connection.
-			break
-		}
-		<-cc.writableChan
-		cc.framer.writeData(true, s.id, true, make([]byte, http2MaxFrameLen))
-		cc.writableChan <- 0
-	}
-	ct.Close()
-	server.stop()
-}
-
-func TestClientWithMisbehavedServer(t *testing.T) {
-	server, ct := setUp(t, 0, math.MaxUint32, misbehaved)
-	callHdr := &CallHdr{
-		Host:   "localhost",
-		Method: "foo",
-	}
-	conn, ok := ct.(*http2Client)
-	if !ok {
-		t.Fatalf("Failed to convert %v to *http2Client", ct)
-	}
-	// Test the logic for the violation of stream flow control window size restriction.
-	s, err := ct.NewStream(context.Background(), callHdr)
-	if err != nil {
-		t.Fatalf("Failed to open stream: %v", err)
-	}
-	if err := ct.Write(s, expectedRequest, &Options{Last: true, Delay: false}); err != nil {
-		t.Fatalf("Failed to write: %v", err)
-	}
-	// Read without window update.
-	for {
-		p := make([]byte, http2MaxFrameLen)
-		if _, err = s.dec.Read(p); err != nil {
-			break
-		}
-	}
-	if s.fc.pendingData != initialWindowSize || s.fc.pendingUpdate != 0 || conn.fc.pendingData != initialWindowSize || conn.fc.pendingUpdate != 0 {
-		t.Fatalf("Client mistakenly updates inbound flow control params: got %d, %d, %d, %d; want %d, %d, %d, %d", s.fc.pendingData, s.fc.pendingUpdate, conn.fc.pendingData, conn.fc.pendingUpdate, initialWindowSize, 0, initialWindowSize, 0)
-	}
-	if err != io.EOF || s.statusCode != codes.Internal {
-		t.Fatalf("Got err %v and the status code %d, want <EOF> and the code %d", err, s.statusCode, codes.Internal)
-	}
-	conn.CloseStream(s, err)
-	if s.fc.pendingData != 0 || s.fc.pendingUpdate != 0 || conn.fc.pendingData != 0 || conn.fc.pendingUpdate != initialWindowSize {
-		t.Fatalf("Client mistakenly resets inbound flow control params: got %d, %d, %d, %d; want 0, 0, 0, %d", s.fc.pendingData, s.fc.pendingUpdate, conn.fc.pendingData, conn.fc.pendingUpdate, initialWindowSize)
-	}
-	// Test the logic for the violation of the connection flow control window size restriction.
-	//
-	// Generate enough streams to drain the connection window.
-	callHdr = &CallHdr{
-		Host:   "localhost",
-		Method: "foo.MaxFrame",
-	}
-	for i := 0; i < int(initialConnWindowSize/initialWindowSize+10); i++ {
-		s, err := ct.NewStream(context.Background(), callHdr)
-		if err != nil {
-			break
-		}
-		if err := ct.Write(s, expectedRequest, &Options{Last: true, Delay: false}); err != nil {
-			break
-		}
-	}
-	// http2Client.errChan is closed due to connection flow control window size violation.
-	<-conn.Error()
-	ct.Close()
-	server.stop()
-}
-
-func TestStreamContext(t *testing.T) {
-	expectedStream := Stream{}
-	ctx := newContextWithStream(context.Background(), &expectedStream)
-	s, ok := StreamFromContext(ctx)
-	if !ok || !reflect.DeepEqual(expectedStream, *s) {
-		t.Fatalf("GetStreamFromContext(%v) = %v, %t, want: %v, true", ctx, *s, ok, expectedStream)
-	}
-}