github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/net/http/httptest/server.go (about)

     1  // Copyright 2011 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  
     5  // Implementation of Server
     6  
     7  package httptest
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/tls"
    12  	"flag"
    13  	"fmt"
    14  	"log"
    15  	"net"
    16  	"net/http"
    17  	"net/http/internal"
    18  	"os"
    19  	"runtime"
    20  	"sync"
    21  	"time"
    22  )
    23  
    24  // A Server is an HTTP server listening on a system-chosen port on the
    25  // local loopback interface, for use in end-to-end HTTP tests.
    26  type Server struct {
    27  	URL      string // base URL of form http://ipaddr:port with no trailing slash
    28  	Listener net.Listener
    29  
    30  	// TLS is the optional TLS configuration, populated with a new config
    31  	// after TLS is started. If set on an unstarted server before StartTLS
    32  	// is called, existing fields are copied into the new config.
    33  	TLS *tls.Config
    34  
    35  	// Config may be changed after calling NewUnstartedServer and
    36  	// before Start or StartTLS.
    37  	Config *http.Server
    38  
    39  	// wg counts the number of outstanding HTTP requests on this server.
    40  	// Close blocks until all requests are finished.
    41  	wg sync.WaitGroup
    42  
    43  	mu     sync.Mutex // guards closed and conns
    44  	closed bool
    45  	conns  map[net.Conn]http.ConnState // except terminal states
    46  }
    47  
    48  func newLocalListener() net.Listener {
    49  	if *serve != "" {
    50  		l, err := net.Listen("tcp", *serve)
    51  		if err != nil {
    52  			panic(fmt.Sprintf("httptest: failed to listen on %v: %v", *serve, err))
    53  		}
    54  		return l
    55  	}
    56  	l, err := net.Listen("tcp", "127.0.0.1:0")
    57  	if err != nil {
    58  		if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
    59  			panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err))
    60  		}
    61  	}
    62  	return l
    63  }
    64  
    65  // When debugging a particular http server-based test,
    66  // this flag lets you run
    67  //	go test -run=BrokenTest -httptest.serve=127.0.0.1:8000
    68  // to start the broken server so you can interact with it manually.
    69  var serve = flag.String("httptest.serve", "", "if non-empty, httptest.NewServer serves on this address and blocks")
    70  
    71  // NewServer starts and returns a new Server.
    72  // The caller should call Close when finished, to shut it down.
    73  func NewServer(handler http.Handler) *Server {
    74  	ts := NewUnstartedServer(handler)
    75  	ts.Start()
    76  	return ts
    77  }
    78  
    79  // NewUnstartedServer returns a new Server but doesn't start it.
    80  //
    81  // After changing its configuration, the caller should call Start or
    82  // StartTLS.
    83  //
    84  // The caller should call Close when finished, to shut it down.
    85  func NewUnstartedServer(handler http.Handler) *Server {
    86  	return &Server{
    87  		Listener: newLocalListener(),
    88  		Config:   &http.Server{Handler: handler},
    89  	}
    90  }
    91  
    92  // Start starts a server from NewUnstartedServer.
    93  func (s *Server) Start() {
    94  	if s.URL != "" {
    95  		panic("Server already started")
    96  	}
    97  	s.URL = "http://" + s.Listener.Addr().String()
    98  	s.wrap()
    99  	s.goServe()
   100  	if *serve != "" {
   101  		fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL)
   102  		select {}
   103  	}
   104  }
   105  
   106  // StartTLS starts TLS on a server from NewUnstartedServer.
   107  func (s *Server) StartTLS() {
   108  	if s.URL != "" {
   109  		panic("Server already started")
   110  	}
   111  	cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
   112  	if err != nil {
   113  		panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
   114  	}
   115  
   116  	existingConfig := s.TLS
   117  	s.TLS = new(tls.Config)
   118  	if existingConfig != nil {
   119  		*s.TLS = *existingConfig
   120  	}
   121  	if s.TLS.NextProtos == nil {
   122  		s.TLS.NextProtos = []string{"http/1.1"}
   123  	}
   124  	if len(s.TLS.Certificates) == 0 {
   125  		s.TLS.Certificates = []tls.Certificate{cert}
   126  	}
   127  	s.Listener = tls.NewListener(s.Listener, s.TLS)
   128  	s.URL = "https://" + s.Listener.Addr().String()
   129  	s.wrap()
   130  	s.goServe()
   131  }
   132  
   133  // NewTLSServer starts and returns a new Server using TLS.
   134  // The caller should call Close when finished, to shut it down.
   135  func NewTLSServer(handler http.Handler) *Server {
   136  	ts := NewUnstartedServer(handler)
   137  	ts.StartTLS()
   138  	return ts
   139  }
   140  
   141  type closeIdleTransport interface {
   142  	CloseIdleConnections()
   143  }
   144  
   145  // Close shuts down the server and blocks until all outstanding
   146  // requests on this server have completed.
   147  func (s *Server) Close() {
   148  	s.mu.Lock()
   149  	if !s.closed {
   150  		s.closed = true
   151  		s.Listener.Close()
   152  		s.Config.SetKeepAlivesEnabled(false)
   153  		for c, st := range s.conns {
   154  			// Force-close any idle connections (those between
   155  			// requests) and new connections (those which connected
   156  			// but never sent a request). StateNew connections are
   157  			// super rare and have only been seen (in
   158  			// previously-flaky tests) in the case of
   159  			// socket-late-binding races from the http Client
   160  			// dialing this server and then getting an idle
   161  			// connection before the dial completed. There is thus
   162  			// a connected connection in StateNew with no
   163  			// associated Request. We only close StateIdle and
   164  			// StateNew because they're not doing anything. It's
   165  			// possible StateNew is about to do something in a few
   166  			// milliseconds, but a previous CL to check again in a
   167  			// few milliseconds wasn't liked (early versions of
   168  			// https://golang.org/cl/15151) so now we just
   169  			// forcefully close StateNew. The docs for Server.Close say
   170  			// we wait for "outstanding requests", so we don't close things
   171  			// in StateActive.
   172  			if st == http.StateIdle || st == http.StateNew {
   173  				s.closeConn(c)
   174  			}
   175  		}
   176  		// If this server doesn't shut down in 5 seconds, tell the user why.
   177  		t := time.AfterFunc(5*time.Second, s.logCloseHangDebugInfo)
   178  		defer t.Stop()
   179  	}
   180  	s.mu.Unlock()
   181  
   182  	// Not part of httptest.Server's correctness, but assume most
   183  	// users of httptest.Server will be using the standard
   184  	// transport, so help them out and close any idle connections for them.
   185  	if t, ok := http.DefaultTransport.(closeIdleTransport); ok {
   186  		t.CloseIdleConnections()
   187  	}
   188  
   189  	s.wg.Wait()
   190  }
   191  
   192  func (s *Server) logCloseHangDebugInfo() {
   193  	s.mu.Lock()
   194  	defer s.mu.Unlock()
   195  	var buf bytes.Buffer
   196  	buf.WriteString("httptest.Server blocked in Close after 5 seconds, waiting for connections:\n")
   197  	for c, st := range s.conns {
   198  		fmt.Fprintf(&buf, "  %T %p %v in state %v\n", c, c, c.RemoteAddr(), st)
   199  	}
   200  	log.Print(buf.String())
   201  }
   202  
   203  // CloseClientConnections closes any open HTTP connections to the test Server.
   204  func (s *Server) CloseClientConnections() {
   205  	s.mu.Lock()
   206  	nconn := len(s.conns)
   207  	ch := make(chan struct{}, nconn)
   208  	for c := range s.conns {
   209  		s.closeConnChan(c, ch)
   210  	}
   211  	s.mu.Unlock()
   212  
   213  	// Wait for outstanding closes to finish.
   214  	//
   215  	// Out of paranoia for making a late change in Go 1.6, we
   216  	// bound how long this can wait, since golang.org/issue/14291
   217  	// isn't fully understood yet. At least this should only be used
   218  	// in tests.
   219  	timer := time.NewTimer(5 * time.Second)
   220  	defer timer.Stop()
   221  	for i := 0; i < nconn; i++ {
   222  		select {
   223  		case <-ch:
   224  		case <-timer.C:
   225  			// Too slow. Give up.
   226  			return
   227  		}
   228  	}
   229  }
   230  
   231  func (s *Server) goServe() {
   232  	s.wg.Add(1)
   233  	go func() {
   234  		defer s.wg.Done()
   235  		s.Config.Serve(s.Listener)
   236  	}()
   237  }
   238  
   239  // wrap installs the connection state-tracking hook to know which
   240  // connections are idle.
   241  func (s *Server) wrap() {
   242  	oldHook := s.Config.ConnState
   243  	s.Config.ConnState = func(c net.Conn, cs http.ConnState) {
   244  		s.mu.Lock()
   245  		defer s.mu.Unlock()
   246  		switch cs {
   247  		case http.StateNew:
   248  			s.wg.Add(1)
   249  			if _, exists := s.conns[c]; exists {
   250  				panic("invalid state transition")
   251  			}
   252  			if s.conns == nil {
   253  				s.conns = make(map[net.Conn]http.ConnState)
   254  			}
   255  			s.conns[c] = cs
   256  			if s.closed {
   257  				// Probably just a socket-late-binding dial from
   258  				// the default transport that lost the race (and
   259  				// thus this connection is now idle and will
   260  				// never be used).
   261  				s.closeConn(c)
   262  			}
   263  		case http.StateActive:
   264  			if oldState, ok := s.conns[c]; ok {
   265  				if oldState != http.StateNew && oldState != http.StateIdle {
   266  					panic("invalid state transition")
   267  				}
   268  				s.conns[c] = cs
   269  			}
   270  		case http.StateIdle:
   271  			if oldState, ok := s.conns[c]; ok {
   272  				if oldState != http.StateActive {
   273  					panic("invalid state transition")
   274  				}
   275  				s.conns[c] = cs
   276  			}
   277  			if s.closed {
   278  				s.closeConn(c)
   279  			}
   280  		case http.StateHijacked, http.StateClosed:
   281  			s.forgetConn(c)
   282  		}
   283  		if oldHook != nil {
   284  			oldHook(c, cs)
   285  		}
   286  	}
   287  }
   288  
   289  // closeConn closes c.
   290  // s.mu must be held.
   291  func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
   292  
   293  // closeConnChan is like closeConn, but takes an optional channel to receive a value
   294  // when the goroutine closing c is done.
   295  func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) {
   296  	if runtime.GOOS == "plan9" {
   297  		// Go's Plan 9 net package isn't great at unblocking reads when
   298  		// their underlying TCP connections are closed. Don't trust
   299  		// that that the ConnState state machine will get to
   300  		// StateClosed. Instead, just go there directly. Plan 9 may leak
   301  		// resources if the syscall doesn't end up returning. Oh well.
   302  		s.forgetConn(c)
   303  	}
   304  
   305  	c.Close()
   306  	if done != nil {
   307  		done <- struct{}{}
   308  	}
   309  }
   310  
   311  // forgetConn removes c from the set of tracked conns and decrements it from the
   312  // waitgroup, unless it was previously removed.
   313  // s.mu must be held.
   314  func (s *Server) forgetConn(c net.Conn) {
   315  	if _, ok := s.conns[c]; ok {
   316  		delete(s.conns, c)
   317  		s.wg.Done()
   318  	}
   319  }