// AddSPDY adds SPDY support to srv, and must be called before srv begins serving. func AddSPDY(srv *http.Server) { npnStrings := npn() if len(npnStrings) <= 1 { return } if srv.TLSConfig == nil { srv.TLSConfig = new(tls.Config) } if srv.TLSConfig.NextProtos == nil { srv.TLSConfig.NextProtos = npnStrings } else { // Collect compatible alternative protocols. others := make([]string, 0, len(srv.TLSConfig.NextProtos)) for _, other := range srv.TLSConfig.NextProtos { if !strings.Contains(other, "spdy/") && !strings.Contains(other, "http/") { others = append(others, other) } } // Start with spdy. srv.TLSConfig.NextProtos = make([]string, 0, len(others)+len(npnStrings)) srv.TLSConfig.NextProtos = append(srv.TLSConfig.NextProtos, npnStrings[:len(npnStrings)-1]...) // Add the others. srv.TLSConfig.NextProtos = append(srv.TLSConfig.NextProtos, others...) srv.TLSConfig.NextProtos = append(srv.TLSConfig.NextProtos, "http/1.1") } if srv.TLSNextProto == nil { srv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) } for _, str := range npnStrings { switch str { case "spdy/2": srv.TLSNextProto[str] = func(s *http.Server, tlsConn *tls.Conn, handler http.Handler) { conn, err := NewServerConn(tlsConn, s, 2) if err != nil { log.Println(err) return } conn.Run() conn = nil runtime.GC() } case "spdy/3": srv.TLSNextProto[str] = func(s *http.Server, tlsConn *tls.Conn, handler http.Handler) { conn, err := NewServerConn(tlsConn, s, 3) if err != nil { log.Println(err) return } conn.Run() conn = nil runtime.GC() } } } }
// AddSPDY adds SPDY support to srv, and must be called before srv begins serving. func AddSPDY(srv *http.Server) { if srv == nil { return } npnStrings := npn() if len(npnStrings) <= 1 { return } if srv.TLSConfig == nil { srv.TLSConfig = new(tls.Config) } if srv.TLSConfig.NextProtos == nil { srv.TLSConfig.NextProtos = npnStrings } else { // Collect compatible alternative protocols. others := make([]string, 0, len(srv.TLSConfig.NextProtos)) for _, other := range srv.TLSConfig.NextProtos { if !strings.Contains(other, "spdy/") && !strings.Contains(other, "http/") { others = append(others, other) } } // Start with spdy. srv.TLSConfig.NextProtos = make([]string, 0, len(others)+len(npnStrings)) srv.TLSConfig.NextProtos = append(srv.TLSConfig.NextProtos, npnStrings[:len(npnStrings)-1]...) // Add the others. srv.TLSConfig.NextProtos = append(srv.TLSConfig.NextProtos, others...) srv.TLSConfig.NextProtos = append(srv.TLSConfig.NextProtos, "http/1.1") } if srv.TLSNextProto == nil { srv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) } for _, str := range npnStrings { switch str { case "spdy/2": srv.TLSNextProto[str] = spdy2.NextProto case "spdy/3": srv.TLSNextProto[str] = spdy3.NextProto case "spdy/3.1": srv.TLSNextProto[str] = spdy3.NextProto1 } } }
// ConfigureServer adds HTTP/2 support to http.Server. func ConfigureServer(hs *http.Server, conf *Server) { // Mostof the code in this function was copied from // https://github.com/bradfitz/http2/blob/master/server.go if conf == nil { conf = new(Server) } if hs.TLSConfig == nil { hs.TLSConfig = new(tls.Config) } hs.TLSConfig.NextProtos = append(hs.TLSConfig.NextProtos, H2Protos...) if hs.TLSNextProto == nil { hs.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){} } for _, proto := range H2Protos { hs.TLSNextProto[proto] = func(hs *http.Server, c *tls.Conn, h http.Handler) { conf.handleConn(hs, c, h) } } }
// UpgradeServer operates similarly to ConfigureServer() with the exception that // it returns a clone copy of the original server that will be used to // exclusively serve HTTP/1.1 and HTTP/1.0 requests. The "HTTP/2 Configured" // server passed to UpgradeServer() should not be modified once this call has // been made, nor should it actively be listening for new connections. // // When an existing HTTP/1.1 connection requests an upgrade to h2c or h2c-14 mode, // the connection will be hijacked from the "clone server" (as returned by // UpgradeServer() and handed off to the internal http2 configured server. // // Ex usage: // // http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { // rw.Header().Set("Content-Type", "text/plain") // fmt.Fprintf(rw, "response to %v\n", r) // }) // // s := http2.UpgradeServer(&http.Server{Addr:":8080"},nil) // s.ListenAndServe() // // NB: Do *not* alter the returned server's Handler, as it is hooked in order to // perform the protocol switch. Any changes to uri handling must be made in the // "inner" server *before* it is passed to UpgradeServer(). The standard // http.DefaultServeMux will always be used as a last resort. // // NB: Note that HTTP/1.1 requests with bodies (i.e. HTTP POST) are not // supported in the initial Upgrade request but will work once the connection // is fully HTTP/2. Requests that have content entities will automatically // fallback to HTTP/1.1 (the upgrade silently fails but the normal handler // is invoked). func UpgradeServer(s *http.Server, conf *Server) *http.Server { if conf == nil { conf = new(Server) } handler := s.Handler if handler == nil { handler = http.DefaultServeMux } h1s := new(http.Server) *h1s = *s h1s.TLSConfig = nil h1s.TLSNextProto = nil h1s.Handler = &upgradeMux{ handler: handler, srv: s, conf: conf, } ConfigureServer(s, conf) return h1s }