|  | // Copyright 2013 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 http_test | 
|  |  | 
|  | import ( | 
|  | "bufio" | 
|  | "bytes" | 
|  | "crypto/tls" | 
|  | "crypto/x509" | 
|  | "fmt" | 
|  | "io" | 
|  | "io/ioutil" | 
|  | . "net/http" | 
|  | "net/http/httptest" | 
|  | "strings" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | func TestNextProtoUpgrade(t *testing.T) { | 
|  | setParallel(t) | 
|  | defer afterTest(t) | 
|  | ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { | 
|  | fmt.Fprintf(w, "path=%s,proto=", r.URL.Path) | 
|  | if r.TLS != nil { | 
|  | w.Write([]byte(r.TLS.NegotiatedProtocol)) | 
|  | } | 
|  | if r.RemoteAddr == "" { | 
|  | t.Error("request with no RemoteAddr") | 
|  | } | 
|  | if r.Body == nil { | 
|  | t.Errorf("request with nil Body") | 
|  | } | 
|  | })) | 
|  | ts.TLS = &tls.Config{ | 
|  | NextProtos: []string{"unhandled-proto", "tls-0.9"}, | 
|  | } | 
|  | ts.Config.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){ | 
|  | "tls-0.9": handleTLSProtocol09, | 
|  | } | 
|  | ts.StartTLS() | 
|  | defer ts.Close() | 
|  |  | 
|  | // Normal request, without NPN. | 
|  | { | 
|  | c := ts.Client() | 
|  | res, err := c.Get(ts.URL) | 
|  | if err != nil { | 
|  | t.Fatal(err) | 
|  | } | 
|  | body, err := ioutil.ReadAll(res.Body) | 
|  | if err != nil { | 
|  | t.Fatal(err) | 
|  | } | 
|  | if want := "path=/,proto="; string(body) != want { | 
|  | t.Errorf("plain request = %q; want %q", body, want) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Request to an advertised but unhandled NPN protocol. | 
|  | // Server will hang up. | 
|  | { | 
|  | certPool := x509.NewCertPool() | 
|  | certPool.AddCert(ts.Certificate()) | 
|  | tr := &Transport{ | 
|  | TLSClientConfig: &tls.Config{ | 
|  | RootCAs:    certPool, | 
|  | NextProtos: []string{"unhandled-proto"}, | 
|  | }, | 
|  | } | 
|  | defer tr.CloseIdleConnections() | 
|  | c := &Client{ | 
|  | Transport: tr, | 
|  | } | 
|  | res, err := c.Get(ts.URL) | 
|  | if err == nil { | 
|  | defer res.Body.Close() | 
|  | var buf bytes.Buffer | 
|  | res.Write(&buf) | 
|  | t.Errorf("expected error on unhandled-proto request; got: %s", buf.Bytes()) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Request using the "tls-0.9" protocol, which we register here. | 
|  | // It is HTTP/0.9 over TLS. | 
|  | { | 
|  | c := ts.Client() | 
|  | tlsConfig := c.Transport.(*Transport).TLSClientConfig | 
|  | tlsConfig.NextProtos = []string{"tls-0.9"} | 
|  | conn, err := tls.Dial("tcp", ts.Listener.Addr().String(), tlsConfig) | 
|  | if err != nil { | 
|  | t.Fatal(err) | 
|  | } | 
|  | conn.Write([]byte("GET /foo\n")) | 
|  | body, err := ioutil.ReadAll(conn) | 
|  | if err != nil { | 
|  | t.Fatal(err) | 
|  | } | 
|  | if want := "path=/foo,proto=tls-0.9"; string(body) != want { | 
|  | t.Errorf("plain request = %q; want %q", body, want) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // handleTLSProtocol09 implements the HTTP/0.9 protocol over TLS, for the | 
|  | // TestNextProtoUpgrade test. | 
|  | func handleTLSProtocol09(srv *Server, conn *tls.Conn, h Handler) { | 
|  | br := bufio.NewReader(conn) | 
|  | line, err := br.ReadString('\n') | 
|  | if err != nil { | 
|  | return | 
|  | } | 
|  | line = strings.TrimSpace(line) | 
|  | path := strings.TrimPrefix(line, "GET ") | 
|  | if path == line { | 
|  | return | 
|  | } | 
|  | req, _ := NewRequest("GET", path, nil) | 
|  | req.Proto = "HTTP/0.9" | 
|  | req.ProtoMajor = 0 | 
|  | req.ProtoMinor = 9 | 
|  | rw := &http09Writer{conn, make(Header)} | 
|  | h.ServeHTTP(rw, req) | 
|  | } | 
|  |  | 
|  | type http09Writer struct { | 
|  | io.Writer | 
|  | h Header | 
|  | } | 
|  |  | 
|  | func (w http09Writer) Header() Header  { return w.h } | 
|  | func (w http09Writer) WriteHeader(int) {} // no headers |