http2_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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. "crypto/tls"
  10. "errors"
  11. "fmt"
  12. "log"
  13. "net"
  14. "net/http"
  15. "net/http/httptest"
  16. "os"
  17. "os/exec"
  18. "strconv"
  19. "strings"
  20. "sync/atomic"
  21. "testing"
  22. "time"
  23. )
  24. type serverTester struct {
  25. cc net.Conn // client conn
  26. t *testing.T
  27. ts *httptest.Server
  28. fr *Framer
  29. }
  30. func newServerTester(t *testing.T, handler http.HandlerFunc) *serverTester {
  31. ts := httptest.NewUnstartedServer(handler)
  32. ConfigureServer(ts.Config, &Server{})
  33. ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
  34. ts.StartTLS()
  35. t.Logf("Running test server at: %s", ts.URL)
  36. cc, err := tls.Dial("tcp", ts.Listener.Addr().String(), &tls.Config{
  37. InsecureSkipVerify: true,
  38. NextProtos: []string{npnProto},
  39. })
  40. if err != nil {
  41. t.Fatal(err)
  42. }
  43. log.SetOutput(twriter{t})
  44. return &serverTester{
  45. t: t,
  46. ts: ts,
  47. cc: cc,
  48. fr: NewFramer(cc, cc),
  49. }
  50. }
  51. func (st *serverTester) Close() {
  52. st.ts.Close()
  53. st.cc.Close()
  54. log.SetOutput(os.Stderr)
  55. }
  56. func (st *serverTester) writePreface() {
  57. n, err := st.cc.Write(clientPreface)
  58. if err != nil {
  59. st.t.Fatalf("Error writing client preface: %v", err)
  60. }
  61. if n != len(clientPreface) {
  62. st.t.Fatalf("Writing client preface, wrote %d bytes; want %d", n, len(clientPreface))
  63. }
  64. }
  65. func (st *serverTester) writeInitialSettings() {
  66. if err := st.fr.WriteSettings(); err != nil {
  67. st.t.Fatalf("Error writing initial SETTINGS frame from client to server: %v", err)
  68. }
  69. }
  70. func (st *serverTester) writeSettingsAck() {
  71. if err := st.fr.WriteSettingsAck(); err != nil {
  72. st.t.Fatalf("Error writing ACK of server's SETTINGS: %v", err)
  73. }
  74. }
  75. func (st *serverTester) wantSettings() *SettingsFrame {
  76. f, err := st.fr.ReadFrame()
  77. if err != nil {
  78. st.t.Fatal(err)
  79. }
  80. sf, ok := f.(*SettingsFrame)
  81. if !ok {
  82. st.t.Fatalf("got a %T; want *SettingsFrame", f)
  83. }
  84. return sf
  85. }
  86. func (st *serverTester) wantSettingsAck() {
  87. f, err := st.fr.ReadFrame()
  88. if err != nil {
  89. st.t.Fatal(err)
  90. }
  91. sf, ok := f.(*SettingsFrame)
  92. if !ok {
  93. st.t.Fatalf("Wanting a settings ACK, received a %T", f)
  94. }
  95. if !sf.Header().Flags.Has(FlagSettingsAck) {
  96. st.t.Fatal("Settings Frame didn't have ACK set")
  97. }
  98. }
  99. func TestServer(t *testing.T) {
  100. st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
  101. w.Header().Set("Foo", "Bar")
  102. })
  103. defer st.Close()
  104. covers("3.5", `
  105. The server connection preface consists of a potentially empty
  106. SETTINGS frame ([SETTINGS]) that MUST be the first frame the
  107. server sends in the HTTP/2 connection.
  108. `)
  109. st.writePreface()
  110. st.writeInitialSettings()
  111. st.wantSettings().ForeachSetting(func(s Setting) {
  112. t.Logf("Server sent setting %v = %v", s.ID, s.Val)
  113. })
  114. st.writeSettingsAck()
  115. st.wantSettingsAck()
  116. // TODO: send a request
  117. }
  118. func TestServerWithCurl(t *testing.T) {
  119. requireCurl(t)
  120. ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  121. // TODO: add a bunch of different tests with different
  122. // behavior, as a function of r or a table.
  123. // -- with request body, without.
  124. // -- no interaction with w.
  125. // -- panic
  126. // -- modify Header only, but no writes or writeheader (this test)
  127. // -- WriteHeader only
  128. // -- Write only
  129. // -- WriteString
  130. // -- both
  131. // -- huge headers over a frame size so we get continuation headers.
  132. // Look at net/http's Server tests for inspiration.
  133. w.Header().Set("Foo", "Bar")
  134. }))
  135. ConfigureServer(ts.Config, &Server{})
  136. ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
  137. ts.StartTLS()
  138. defer ts.Close()
  139. var gotConn int32
  140. testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) }
  141. t.Logf("Running test server for curl to hit at: %s", ts.URL)
  142. container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL)
  143. defer kill(container)
  144. resc := make(chan interface{}, 1)
  145. go func() {
  146. res, err := dockerLogs(container)
  147. if err != nil {
  148. resc <- err
  149. } else {
  150. resc <- res
  151. }
  152. }()
  153. select {
  154. case res := <-resc:
  155. if err, ok := res.(error); ok {
  156. t.Fatal(err)
  157. }
  158. if !strings.Contains(string(res.([]byte)), "< foo:Bar") {
  159. t.Errorf("didn't see foo:Bar header")
  160. t.Logf("Got: %s", res)
  161. }
  162. case <-time.After(3 * time.Second):
  163. t.Errorf("timeout waiting for curl")
  164. }
  165. if atomic.LoadInt32(&gotConn) == 0 {
  166. t.Error("never saw an http2 connection")
  167. }
  168. }
  169. func dockerLogs(container string) ([]byte, error) {
  170. out, err := exec.Command("docker", "wait", container).CombinedOutput()
  171. if err != nil {
  172. return out, err
  173. }
  174. exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
  175. if err != nil {
  176. return out, errors.New("unexpected exit status from docker wait")
  177. }
  178. out, err = exec.Command("docker", "logs", container).CombinedOutput()
  179. exec.Command("docker", "rm", container).Run()
  180. if err == nil && exitStatus != 0 {
  181. err = fmt.Errorf("exit status %d", exitStatus)
  182. }
  183. return out, err
  184. }
  185. func kill(container string) {
  186. exec.Command("docker", "kill", container).Run()
  187. exec.Command("docker", "rm", container).Run()
  188. }
  189. // Verify that curl has http2.
  190. func requireCurl(t *testing.T) {
  191. out, err := dockerLogs(curl(t, "--version"))
  192. if err != nil {
  193. t.Skipf("failed to determine curl features; skipping test")
  194. }
  195. if !strings.Contains(string(out), "HTTP2") {
  196. t.Skip("curl doesn't support HTTP2; skipping test")
  197. }
  198. }
  199. func curl(t *testing.T, args ...string) (container string) {
  200. out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).CombinedOutput()
  201. if err != nil {
  202. t.Skipf("Failed to run curl in docker: %v, %s", err, out)
  203. }
  204. return strings.TrimSpace(string(out))
  205. }
  206. type twriter struct {
  207. t testing.TB
  208. }
  209. func (w twriter) Write(p []byte) (n int, err error) {
  210. w.t.Logf("%s", p)
  211. return len(p), nil
  212. }