go/src/net/http/npn_test.go
Johan Brandhorst 3b988eb643 net/http: use httptest.Server Client in tests
After merging https://go-review.googlesource.com/c/34639/,
it was pointed out to me that a lot of tests under net/http
could use the new functionality to simplify and unify testing.

Using the httptest.Server provided Client removes the need to
call CloseIdleConnections() on all Transports created, as it
is automatically called on the Transport associated with the
client when Server.Close() is called.

Change the transport used by the non-TLS
httptest.Server to a new *http.Transport rather than using
http.DefaultTransport implicitly. The TLS version already
used its own *http.Transport. This change is to prevent
concurrency problems with using DefaultTransport implicitly
across several httptest.Server's.

Add tests to ensure the httptest.Server.Client().Transport
RoundTripper interface is implemented by a *http.Transport,
as is now assumed across large parts of net/http tests.

Change-Id: I9f9d15f59d72893deead5678d314388718c91821
Reviewed-on: https://go-review.googlesource.com/37771
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-03-08 15:51:48 +00:00

134 lines
3.0 KiB
Go

// 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