http2_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // See https://code.google.com/p/go/source/browse/CONTRIBUTORS
  5. // Licensed under the same terms as Go itself:
  6. // https://code.google.com/p/go/source/browse/LICENSE
  7. package http2
  8. import (
  9. "bytes"
  10. "crypto/tls"
  11. "errors"
  12. "flag"
  13. "fmt"
  14. "io"
  15. "log"
  16. "net"
  17. "net/http"
  18. "net/http/httptest"
  19. "os"
  20. "os/exec"
  21. "reflect"
  22. "strconv"
  23. "strings"
  24. "sync/atomic"
  25. "testing"
  26. "time"
  27. "github.com/bradfitz/http2/hpack"
  28. )
  29. func init() {
  30. DebugGoroutines = true
  31. flag.BoolVar(&VerboseLogs, "verboseh2", false, "Verbose HTTP/2 debug logging")
  32. }
  33. type serverTester struct {
  34. cc net.Conn // client conn
  35. t *testing.T
  36. ts *httptest.Server
  37. fr *Framer
  38. logBuf *bytes.Buffer
  39. }
  40. func newServerTester(t *testing.T, handler http.HandlerFunc) *serverTester {
  41. logBuf := new(bytes.Buffer)
  42. ts := httptest.NewUnstartedServer(handler)
  43. ConfigureServer(ts.Config, &Server{})
  44. ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
  45. ts.Config.ErrorLog = log.New(io.MultiWriter(twriter{t: t}, logBuf), "", log.LstdFlags)
  46. ts.StartTLS()
  47. if VerboseLogs {
  48. t.Logf("Running test server at: %s", ts.URL)
  49. }
  50. cc, err := tls.Dial("tcp", ts.Listener.Addr().String(), &tls.Config{
  51. InsecureSkipVerify: true,
  52. NextProtos: []string{npnProto},
  53. })
  54. if err != nil {
  55. t.Fatal(err)
  56. }
  57. log.SetOutput(twriter{t})
  58. return &serverTester{
  59. t: t,
  60. ts: ts,
  61. cc: cc,
  62. fr: NewFramer(cc, cc),
  63. logBuf: logBuf,
  64. }
  65. }
  66. func (st *serverTester) Close() {
  67. st.ts.Close()
  68. st.cc.Close()
  69. log.SetOutput(os.Stderr)
  70. }
  71. // greet initiates the client's HTTP/2 connection into a state where
  72. // frames may be sent.
  73. func (st *serverTester) greet() {
  74. st.writePreface()
  75. st.writeInitialSettings()
  76. st.wantSettings()
  77. st.writeSettingsAck()
  78. st.wantSettingsAck()
  79. }
  80. func (st *serverTester) writePreface() {
  81. n, err := st.cc.Write(clientPreface)
  82. if err != nil {
  83. st.t.Fatalf("Error writing client preface: %v", err)
  84. }
  85. if n != len(clientPreface) {
  86. st.t.Fatalf("Writing client preface, wrote %d bytes; want %d", n, len(clientPreface))
  87. }
  88. }
  89. func (st *serverTester) writeInitialSettings() {
  90. if err := st.fr.WriteSettings(); err != nil {
  91. st.t.Fatalf("Error writing initial SETTINGS frame from client to server: %v", err)
  92. }
  93. }
  94. func (st *serverTester) writeSettingsAck() {
  95. if err := st.fr.WriteSettingsAck(); err != nil {
  96. st.t.Fatalf("Error writing ACK of server's SETTINGS: %v", err)
  97. }
  98. }
  99. func (st *serverTester) writeHeaders(p HeadersFrameParam) {
  100. if err := st.fr.WriteHeaders(p); err != nil {
  101. st.t.Fatalf("Error writing HEADERS: %v", err)
  102. }
  103. }
  104. // bodylessReq1 writes a HEADERS frames with StreamID 1 and EndStream and EndHeaders set.
  105. func (st *serverTester) bodylessReq1(headers ...string) {
  106. st.writeHeaders(HeadersFrameParam{
  107. StreamID: 1, // clients send odd numbers
  108. BlockFragment: encodeHeader(st.t, headers...),
  109. EndStream: true,
  110. EndHeaders: true,
  111. })
  112. }
  113. func (st *serverTester) writeData(streamID uint32, endStream bool, data []byte) {
  114. if err := st.fr.WriteData(streamID, endStream, data); err != nil {
  115. st.t.Fatalf("Error writing DATA: %v", err)
  116. }
  117. }
  118. func (st *serverTester) wantSettings() *SettingsFrame {
  119. f, err := st.fr.ReadFrame()
  120. if err != nil {
  121. st.t.Fatalf("Error while expecting a SETTINGS frame: %v", err)
  122. }
  123. sf, ok := f.(*SettingsFrame)
  124. if !ok {
  125. st.t.Fatalf("got a %T; want *SettingsFrame", f)
  126. }
  127. return sf
  128. }
  129. func (st *serverTester) wantRSTStream(streamID uint32, errCode ErrCode) {
  130. f, err := st.fr.ReadFrame()
  131. if err != nil {
  132. st.t.Fatalf("Error while expecting an RSTStream frame: %v", err)
  133. }
  134. rs, ok := f.(*RSTStreamFrame)
  135. if !ok {
  136. st.t.Fatalf("got a %T; want *RSTStream", f)
  137. }
  138. if rs.FrameHeader.StreamID != streamID {
  139. st.t.Fatalf("RSTStream StreamID = %d; want %d", rs.FrameHeader.StreamID, streamID)
  140. }
  141. if rs.ErrCode != uint32(errCode) {
  142. st.t.Fatalf("RSTStream ErrCode = %d (%s); want %d (%s)", rs.ErrCode, rs.ErrCode, errCode, errCode)
  143. }
  144. }
  145. func (st *serverTester) wantSettingsAck() {
  146. f, err := st.fr.ReadFrame()
  147. if err != nil {
  148. st.t.Fatal(err)
  149. }
  150. sf, ok := f.(*SettingsFrame)
  151. if !ok {
  152. st.t.Fatalf("Wanting a settings ACK, received a %T", f)
  153. }
  154. if !sf.Header().Flags.Has(FlagSettingsAck) {
  155. st.t.Fatal("Settings Frame didn't have ACK set")
  156. }
  157. }
  158. func TestServer(t *testing.T) {
  159. gotReq := make(chan bool, 1)
  160. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  161. w.Header().Set("Foo", "Bar")
  162. gotReq <- true
  163. })
  164. defer st.Close()
  165. covers("3.5", `
  166. The server connection preface consists of a potentially empty
  167. SETTINGS frame ([SETTINGS]) that MUST be the first frame the
  168. server sends in the HTTP/2 connection.
  169. `)
  170. st.writePreface()
  171. st.writeInitialSettings()
  172. st.wantSettings().ForeachSetting(func(s Setting) {
  173. t.Logf("Server sent setting %v = %v", s.ID, s.Val)
  174. })
  175. st.writeSettingsAck()
  176. st.wantSettingsAck()
  177. st.writeHeaders(HeadersFrameParam{
  178. StreamID: 1, // clients send odd numbers
  179. BlockFragment: encodeHeader(t),
  180. EndStream: true, // no DATA frames
  181. EndHeaders: true,
  182. })
  183. select {
  184. case <-gotReq:
  185. case <-time.After(2 * time.Second):
  186. t.Error("timeout waiting for request")
  187. }
  188. }
  189. func TestServer_Request_Get(t *testing.T) {
  190. testServerRequest(t, func(st *serverTester) {
  191. st.writeHeaders(HeadersFrameParam{
  192. StreamID: 1, // clients send odd numbers
  193. BlockFragment: encodeHeader(t, "foo-bar", "some-value"),
  194. EndStream: true, // no DATA frames
  195. EndHeaders: true,
  196. })
  197. }, func(r *http.Request) {
  198. if r.Method != "GET" {
  199. t.Errorf("Method = %q; want GET", r.Method)
  200. }
  201. if r.ContentLength != 0 {
  202. t.Errorf("ContentLength = %v; want 0", r.ContentLength)
  203. }
  204. if r.Close {
  205. t.Error("Close = true; want false")
  206. }
  207. if !strings.Contains(r.RemoteAddr, ":") {
  208. t.Errorf("RemoteAddr = %q; want something with a colon", r.RemoteAddr)
  209. }
  210. if r.Proto != "HTTP/2.0" || r.ProtoMajor != 2 || r.ProtoMinor != 0 {
  211. t.Errorf("Proto = %q Major=%v,Minor=%v; want HTTP/2.0", r.Proto, r.ProtoMajor, r.ProtoMinor)
  212. }
  213. wantHeader := http.Header{
  214. "Foo-Bar": []string{"some-value"},
  215. }
  216. if !reflect.DeepEqual(r.Header, wantHeader) {
  217. t.Errorf("Header = %#v; want %#v", r.Header, wantHeader)
  218. }
  219. if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 {
  220. t.Errorf("Read = %d, %v; want 0, EOF", n, err)
  221. }
  222. })
  223. }
  224. // TODO: add a test with EndStream=true on the HEADERS but setting a
  225. // Content-Length anyway. Should we just omit it and force it to
  226. // zero?
  227. func TestServer_Request_Post_NoContentLength_EndStream(t *testing.T) {
  228. testServerRequest(t, func(st *serverTester) {
  229. st.writeHeaders(HeadersFrameParam{
  230. StreamID: 1, // clients send odd numbers
  231. BlockFragment: encodeHeader(t, ":method", "POST"),
  232. EndStream: true,
  233. EndHeaders: true,
  234. })
  235. }, func(r *http.Request) {
  236. if r.Method != "POST" {
  237. t.Errorf("Method = %q; want POST", r.Method)
  238. }
  239. if r.ContentLength != 0 {
  240. t.Errorf("ContentLength = %v; want 0", r.ContentLength)
  241. }
  242. if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 {
  243. t.Errorf("Read = %d, %v; want 0, EOF", n, err)
  244. }
  245. })
  246. }
  247. func TestServer_Request_Post_Body(t *testing.T) {
  248. t.Skip("TODO: post bodies not yet implemented")
  249. testServerRequest(t, func(st *serverTester) {
  250. st.writeHeaders(HeadersFrameParam{
  251. StreamID: 1, // clients send odd numbers
  252. BlockFragment: encodeHeader(t, ":method", "POST"),
  253. EndStream: false, // migth be DATA frames
  254. EndHeaders: true,
  255. })
  256. st.writeData(1, true, nil)
  257. }, func(r *http.Request) {
  258. if r.Method != "POST" {
  259. t.Errorf("Method = %q; want POST", r.Method)
  260. }
  261. if r.ContentLength != -1 {
  262. t.Errorf("ContentLength = %v; want -1", r.ContentLength)
  263. }
  264. if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 {
  265. t.Errorf("Read = %d, %v; want 0, EOF", n, err)
  266. }
  267. })
  268. }
  269. // Using a Host header, instead of :authority
  270. func TestServer_Request_Get_Host(t *testing.T) {
  271. const host = "example.com"
  272. testServerRequest(t, func(st *serverTester) {
  273. st.writeHeaders(HeadersFrameParam{
  274. StreamID: 1, // clients send odd numbers
  275. BlockFragment: encodeHeader(t, "host", host),
  276. EndStream: true,
  277. EndHeaders: true,
  278. })
  279. }, func(r *http.Request) {
  280. if r.Host != host {
  281. t.Errorf("Host = %q; want %q", r.Host, host)
  282. }
  283. })
  284. }
  285. // Using an :authority pseudo-header, instead of Host
  286. func TestServer_Request_Get_Authority(t *testing.T) {
  287. const host = "example.com"
  288. testServerRequest(t, func(st *serverTester) {
  289. st.writeHeaders(HeadersFrameParam{
  290. StreamID: 1, // clients send odd numbers
  291. BlockFragment: encodeHeader(t, ":authority", host),
  292. EndStream: true,
  293. EndHeaders: true,
  294. })
  295. }, func(r *http.Request) {
  296. if r.Host != host {
  297. t.Errorf("Host = %q; want %q", r.Host, host)
  298. }
  299. })
  300. }
  301. func TestServer_Request_WithContinuation(t *testing.T) {
  302. wantHeader := http.Header{
  303. "Foo-One": []string{"value-one"},
  304. "Foo-Two": []string{"value-two"},
  305. "Foo-Three": []string{"value-three"},
  306. }
  307. testServerRequest(t, func(st *serverTester) {
  308. fullHeaders := encodeHeader(t,
  309. "foo-one", "value-one",
  310. "foo-two", "value-two",
  311. "foo-three", "value-three",
  312. )
  313. remain := fullHeaders
  314. chunks := 0
  315. for len(remain) > 0 {
  316. const maxChunkSize = 5
  317. chunk := remain
  318. if len(chunk) > maxChunkSize {
  319. chunk = chunk[:maxChunkSize]
  320. }
  321. remain = remain[len(chunk):]
  322. if chunks == 0 {
  323. st.writeHeaders(HeadersFrameParam{
  324. StreamID: 1, // clients send odd numbers
  325. BlockFragment: chunk,
  326. EndStream: true, // no DATA frames
  327. EndHeaders: false, // we'll have continuation frames
  328. })
  329. } else {
  330. err := st.fr.WriteContinuation(1, len(remain) == 0, chunk)
  331. if err != nil {
  332. t.Fatal(err)
  333. }
  334. }
  335. chunks++
  336. }
  337. if chunks < 2 {
  338. t.Fatal("too few chunks")
  339. }
  340. }, func(r *http.Request) {
  341. if !reflect.DeepEqual(r.Header, wantHeader) {
  342. t.Errorf("Header = %#v; want %#v", r.Header, wantHeader)
  343. }
  344. })
  345. }
  346. // Concatenated cookie headers. ("8.1.2.5 Compressing the Cookie Header Field")
  347. func TestServer_Request_CookieConcat(t *testing.T) {
  348. const host = "example.com"
  349. testServerRequest(t, func(st *serverTester) {
  350. st.bodylessReq1(
  351. ":authority", host,
  352. "cookie", "a=b",
  353. "cookie", "c=d",
  354. "cookie", "e=f",
  355. )
  356. }, func(r *http.Request) {
  357. const want = "a=b; c=d; e=f"
  358. if got := r.Header.Get("Cookie"); got != want {
  359. t.Errorf("Cookie = %q; want %q", got, want)
  360. }
  361. })
  362. }
  363. func TestServer_Request_Reject_CapitalHeader(t *testing.T) {
  364. testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("UPPER", "v") })
  365. }
  366. func TestServer_Request_Reject_Pseudo_Missing_method(t *testing.T) {
  367. testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":method", "") })
  368. }
  369. func TestServer_Request_Reject_Pseudo_ExactlyOne(t *testing.T) {
  370. // 8.1.2.3 Request Pseudo-Header Fields
  371. // "All HTTP/2 requests MUST include exactly one valid value" ...
  372. testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":method", "GET", ":method", "POST") })
  373. }
  374. func TestServer_Request_Reject_Pseudo_AfterRegular(t *testing.T) {
  375. // 8.1.2.3 Request Pseudo-Header Fields
  376. // "All pseudo-header fields MUST appear in the header block
  377. // before regular header fields. Any request or response that
  378. // contains a pseudo-header field that appears in a header
  379. // block after a regular header field MUST be treated as
  380. // malformed (Section 8.1.2.6)."
  381. testRejectRequest(t, func(st *serverTester) {
  382. var buf bytes.Buffer
  383. enc := hpack.NewEncoder(&buf)
  384. enc.WriteField(hpack.HeaderField{Name: ":method", Value: "GET"})
  385. enc.WriteField(hpack.HeaderField{Name: "regular", Value: "foobar"})
  386. enc.WriteField(hpack.HeaderField{Name: ":path", Value: "/"})
  387. enc.WriteField(hpack.HeaderField{Name: ":scheme", Value: "https"})
  388. st.writeHeaders(HeadersFrameParam{
  389. StreamID: 1, // clients send odd numbers
  390. BlockFragment: buf.Bytes(),
  391. EndStream: true,
  392. EndHeaders: true,
  393. })
  394. })
  395. }
  396. func TestServer_Request_Reject_Pseudo_Missing_path(t *testing.T) {
  397. testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":path", "") })
  398. }
  399. func TestServer_Request_Reject_Pseudo_Missing_scheme(t *testing.T) {
  400. testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "") })
  401. }
  402. func TestServer_Request_Reject_Pseudo_scheme_invalid(t *testing.T) {
  403. testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "bogus") })
  404. }
  405. func TestServer_Request_Reject_Pseudo_Unknown(t *testing.T) {
  406. testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":unknown_thing", "") })
  407. }
  408. func testRejectRequest(t *testing.T, send func(*serverTester)) {
  409. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  410. t.Fatal("server request made it to handler; should've been rejected")
  411. })
  412. defer st.Close()
  413. st.greet()
  414. send(st)
  415. st.wantRSTStream(1, ErrCodeProtocol)
  416. }
  417. // TODO: test HEADERS w/o EndHeaders + another HEADERS (should get rejected)
  418. // TODO: test HEADERS w/ EndHeaders + a continuation HEADERS (should get rejected)
  419. // testServerRequest sets up an idle HTTP/2 connection and lets you
  420. // write a single request with writeReq, and then verify that the
  421. // *http.Request is built correctly in checkReq.
  422. func testServerRequest(t *testing.T, writeReq func(*serverTester), checkReq func(*http.Request)) {
  423. gotReq := make(chan bool, 1)
  424. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  425. if r.Body == nil {
  426. t.Fatal("nil Body")
  427. }
  428. checkReq(r)
  429. gotReq <- true
  430. })
  431. defer st.Close()
  432. st.greet()
  433. writeReq(st)
  434. select {
  435. case <-gotReq:
  436. case <-time.After(2 * time.Second):
  437. t.Error("timeout waiting for request")
  438. }
  439. }
  440. func TestServerWithCurl(t *testing.T) {
  441. requireCurl(t)
  442. ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  443. // TODO: add a bunch of different tests with different
  444. // behavior, as a function of r or a table.
  445. // -- with request body, without.
  446. // -- no interaction with w.
  447. // -- panic
  448. // -- modify Header only, but no writes or writeheader (this test)
  449. // -- WriteHeader only
  450. // -- Write only
  451. // -- WriteString
  452. // -- both
  453. // -- huge headers over a frame size so we get continuation headers.
  454. // Look at net/http's Server tests for inspiration.
  455. w.Header().Set("Foo", "Bar")
  456. }))
  457. ConfigureServer(ts.Config, &Server{})
  458. ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
  459. ts.StartTLS()
  460. defer ts.Close()
  461. var gotConn int32
  462. testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) }
  463. t.Logf("Running test server for curl to hit at: %s", ts.URL)
  464. container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL)
  465. defer kill(container)
  466. resc := make(chan interface{}, 1)
  467. go func() {
  468. res, err := dockerLogs(container)
  469. if err != nil {
  470. resc <- err
  471. } else {
  472. resc <- res
  473. }
  474. }()
  475. select {
  476. case res := <-resc:
  477. if err, ok := res.(error); ok {
  478. t.Fatal(err)
  479. }
  480. if !strings.Contains(string(res.([]byte)), "< foo:Bar") {
  481. t.Errorf("didn't see foo:Bar header")
  482. t.Logf("Got: %s", res)
  483. }
  484. case <-time.After(3 * time.Second):
  485. t.Errorf("timeout waiting for curl")
  486. }
  487. if atomic.LoadInt32(&gotConn) == 0 {
  488. t.Error("never saw an http2 connection")
  489. }
  490. }
  491. func dockerLogs(container string) ([]byte, error) {
  492. out, err := exec.Command("docker", "wait", container).CombinedOutput()
  493. if err != nil {
  494. return out, err
  495. }
  496. exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
  497. if err != nil {
  498. return out, errors.New("unexpected exit status from docker wait")
  499. }
  500. out, err = exec.Command("docker", "logs", container).CombinedOutput()
  501. exec.Command("docker", "rm", container).Run()
  502. if err == nil && exitStatus != 0 {
  503. err = fmt.Errorf("exit status %d", exitStatus)
  504. }
  505. return out, err
  506. }
  507. func kill(container string) {
  508. exec.Command("docker", "kill", container).Run()
  509. exec.Command("docker", "rm", container).Run()
  510. }
  511. // Verify that curl has http2.
  512. func requireCurl(t *testing.T) {
  513. out, err := dockerLogs(curl(t, "--version"))
  514. if err != nil {
  515. t.Skipf("failed to determine curl features; skipping test")
  516. }
  517. if !strings.Contains(string(out), "HTTP2") {
  518. t.Skip("curl doesn't support HTTP2; skipping test")
  519. }
  520. }
  521. func curl(t *testing.T, args ...string) (container string) {
  522. out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).CombinedOutput()
  523. if err != nil {
  524. t.Skipf("Failed to run curl in docker: %v, %s", err, out)
  525. }
  526. return strings.TrimSpace(string(out))
  527. }
  528. type twriter struct {
  529. t testing.TB
  530. }
  531. func (w twriter) Write(p []byte) (n int, err error) {
  532. w.t.Logf("%s", p)
  533. return len(p), nil
  534. }
  535. // encodeHeader encodes headers and returns their HPACK bytes. headers
  536. // must contain an even number of key/value pairs. There may be
  537. // multiple pairs for keys (e.g. "cookie"). The :method, :path, and
  538. // :scheme headers default to GET, / and https.
  539. func encodeHeader(t *testing.T, headers ...string) []byte {
  540. pseudoCount := map[string]int{}
  541. if len(headers)%2 == 1 {
  542. panic("odd number of kv args")
  543. }
  544. keys := []string{":method", ":path", ":scheme"}
  545. vals := map[string][]string{
  546. ":method": {"GET"},
  547. ":path": {"/"},
  548. ":scheme": {"https"},
  549. }
  550. for len(headers) > 0 {
  551. k, v := headers[0], headers[1]
  552. headers = headers[2:]
  553. if _, ok := vals[k]; !ok {
  554. keys = append(keys, k)
  555. }
  556. if strings.HasPrefix(k, ":") {
  557. pseudoCount[k]++
  558. if pseudoCount[k] == 1 {
  559. vals[k] = []string{v}
  560. } else {
  561. // Allows testing of invalid headers w/ dup pseudo fields.
  562. vals[k] = append(vals[k], v)
  563. }
  564. } else {
  565. vals[k] = append(vals[k], v)
  566. }
  567. }
  568. var buf bytes.Buffer
  569. enc := hpack.NewEncoder(&buf)
  570. for _, k := range keys {
  571. for _, v := range vals[k] {
  572. if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil {
  573. t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
  574. }
  575. }
  576. }
  577. return buf.Bytes()
  578. }