h2demo.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2014 The Go Authors.
  2. // See https://code.google.com/p/go/source/browse/CONTRIBUTORS
  3. // Licensed under the same terms as Go itself:
  4. // https://code.google.com/p/go/source/browse/LICENSE
  5. package main
  6. import (
  7. "crypto/tls"
  8. "flag"
  9. "fmt"
  10. "io"
  11. "io/ioutil"
  12. "log"
  13. "net"
  14. "net/http"
  15. "os/exec"
  16. "runtime"
  17. "time"
  18. "camlistore.org/pkg/googlestorage"
  19. "github.com/bradfitz/http2"
  20. )
  21. var (
  22. openFirefox = flag.Bool("openff", false, "Open Firefox")
  23. prod = flag.Bool("prod", false, "Whether to configure itself to be the production http2.golang.org server.")
  24. )
  25. func oldHTTPHandler(w http.ResponseWriter, r *http.Request) {
  26. io.WriteString(w, `<html>
  27. <body>
  28. <h1>Go + HTTP/2</h1>
  29. <p>Welcome to <a href="https://golang.org/">the Go language</a>'s <a href="https://http2.github.io/">HTTP/2</a> demo & interop server.</p>
  30. <p>Unfortunately, <b>you're not using HTTP/2 right now</b>.</p>
  31. <p>See code & instructions for connecting at <a href="https://github.com/bradfitz/http2">https://github.com/bradfitz/http2</a>.</p>
  32. </body></html>`)
  33. }
  34. func registerHandlers() {
  35. mux := http.NewServeMux()
  36. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  37. if r.TLS == nil {
  38. http.Redirect(w, r, "https://http2.golang.org/", http.StatusFound)
  39. return
  40. }
  41. if r.ProtoMajor == 1 {
  42. oldHTTPHandler(w, r)
  43. return
  44. }
  45. mux.ServeHTTP(w, r)
  46. })
  47. mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  48. // TODO: more
  49. io.WriteString(w, "<h1>Hello, world!</h1>Greetings from Go's HTTP/2 server. You're speaking HTTP/2.")
  50. })
  51. }
  52. func serveProdTLS() error {
  53. c, err := googlestorage.NewServiceClient()
  54. if err != nil {
  55. return err
  56. }
  57. slurp := func(key string) ([]byte, error) {
  58. const bucket = "http2-demo-server-tls"
  59. rc, _, err := c.GetObject(&googlestorage.Object{
  60. Bucket: bucket,
  61. Key: key,
  62. })
  63. if err != nil {
  64. return nil, fmt.Errorf("Error fetching GCS object %q in bucket %q: %v", key, bucket, err)
  65. }
  66. defer rc.Close()
  67. return ioutil.ReadAll(rc)
  68. }
  69. certPem, err := slurp("http2.golang.org.chained.pem")
  70. if err != nil {
  71. return err
  72. }
  73. keyPem, err := slurp("http2.golang.org.key")
  74. if err != nil {
  75. return err
  76. }
  77. cert, err := tls.X509KeyPair(certPem, keyPem)
  78. if err != nil {
  79. return err
  80. }
  81. srv := &http.Server{
  82. TLSConfig: &tls.Config{
  83. Certificates: []tls.Certificate{cert},
  84. },
  85. }
  86. http2.ConfigureServer(srv, &http2.Server{})
  87. ln, err := net.Listen("tcp", ":443")
  88. if err != nil {
  89. return err
  90. }
  91. return srv.Serve(tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig))
  92. }
  93. type tcpKeepAliveListener struct {
  94. *net.TCPListener
  95. }
  96. func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
  97. tc, err := ln.AcceptTCP()
  98. if err != nil {
  99. return
  100. }
  101. tc.SetKeepAlive(true)
  102. tc.SetKeepAlivePeriod(3 * time.Minute)
  103. return tc, nil
  104. }
  105. func serveProd() error {
  106. errc := make(chan error, 2)
  107. go func() { errc <- http.ListenAndServe(":80", nil) }()
  108. go func() { errc <- serveProdTLS() }()
  109. return <-errc
  110. }
  111. func main() {
  112. var srv http.Server
  113. flag.BoolVar(&http2.VerboseLogs, "verbose", false, "Verbose HTTP/2 debugging.")
  114. flag.StringVar(&srv.Addr, "addr", "localhost:4430", "host:port to listen on ")
  115. flag.Parse()
  116. registerHandlers()
  117. if *prod {
  118. log.Fatal(serveProd())
  119. }
  120. url := "https://" + srv.Addr + "/"
  121. log.Printf("Listening on " + url)
  122. http2.ConfigureServer(&srv, &http2.Server{})
  123. go func() {
  124. log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key"))
  125. }()
  126. if *openFirefox && runtime.GOOS == "darwin" {
  127. time.Sleep(250 * time.Millisecond)
  128. exec.Command("open", "-b", "org.mozilla.nightly", "https://localhost:4430/").Run()
  129. }
  130. select {}
  131. }