github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/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 "oustanding 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  	defer s.mu.Unlock()
   207  	for c := range s.conns {
   208  		s.closeConn(c)
   209  	}
   210  }
   211  
   212  func (s *Server) goServe() {
   213  	s.wg.Add(1)
   214  	go func() {
   215  		defer s.wg.Done()
   216  		s.Config.Serve(s.Listener)
   217  	}()
   218  }
   219  
   220  // wrap installs the connection state-tracking hook to know which
   221  // connections are idle.
   222  func (s *Server) wrap() {
   223  	oldHook := s.Config.ConnState
   224  	s.Config.ConnState = func(c net.Conn, cs http.ConnState) {
   225  		s.mu.Lock()
   226  		defer s.mu.Unlock()
   227  		switch cs {
   228  		case http.StateNew:
   229  			s.wg.Add(1)
   230  			if _, exists := s.conns[c]; exists {
   231  				panic("invalid state transition")
   232  			}
   233  			if s.conns == nil {
   234  				s.conns = make(map[net.Conn]http.ConnState)
   235  			}
   236  			s.conns[c] = cs
   237  			if s.closed {
   238  				// Probably just a socket-late-binding dial from
   239  				// the default transport that lost the race (and
   240  				// thus this connection is now idle and will
   241  				// never be used).
   242  				s.closeConn(c)
   243  			}
   244  		case http.StateActive:
   245  			if oldState, ok := s.conns[c]; ok {
   246  				if oldState != http.StateNew && oldState != http.StateIdle {
   247  					panic("invalid state transition")
   248  				}
   249  				s.conns[c] = cs
   250  			}
   251  		case http.StateIdle:
   252  			if oldState, ok := s.conns[c]; ok {
   253  				if oldState != http.StateActive {
   254  					panic("invalid state transition")
   255  				}
   256  				s.conns[c] = cs
   257  			}
   258  			if s.closed {
   259  				s.closeConn(c)
   260  			}
   261  		case http.StateHijacked, http.StateClosed:
   262  			s.forgetConn(c)
   263  		}
   264  		if oldHook != nil {
   265  			oldHook(c, cs)
   266  		}
   267  	}
   268  }
   269  
   270  // closeConn closes c. Except on plan9, which is special. See comment below.
   271  // s.mu must be held.
   272  func (s *Server) closeConn(c net.Conn) {
   273  	if runtime.GOOS == "plan9" {
   274  		// Go's Plan 9 net package isn't great at unblocking reads when
   275  		// their underlying TCP connections are closed.  Don't trust
   276  		// that that the ConnState state machine will get to
   277  		// StateClosed. Instead, just go there directly. Plan 9 may leak
   278  		// resources if the syscall doesn't end up returning. Oh well.
   279  		s.forgetConn(c)
   280  	}
   281  	go c.Close()
   282  }
   283  
   284  // forgetConn removes c from the set of tracked conns and decrements it from the
   285  // waitgroup, unless it was previously removed.
   286  // s.mu must be held.
   287  func (s *Server) forgetConn(c net.Conn) {
   288  	if _, ok := s.conns[c]; ok {
   289  		delete(s.conns, c)
   290  		s.wg.Done()
   291  	}
   292  }