github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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  	if existingConfig != nil {
   118  		s.TLS = existingConfig.Clone()
   119  	} else {
   120  		s.TLS = new(tls.Config)
   121  	}
   122  	if s.TLS.NextProtos == nil {
   123  		s.TLS.NextProtos = []string{"http/1.1"}
   124  	}
   125  	if len(s.TLS.Certificates) == 0 {
   126  		s.TLS.Certificates = []tls.Certificate{cert}
   127  	}
   128  	s.Listener = tls.NewListener(s.Listener, s.TLS)
   129  	s.URL = "https://" + s.Listener.Addr().String()
   130  	s.wrap()
   131  	s.goServe()
   132  }
   133  
   134  // NewTLSServer starts and returns a new Server using TLS.
   135  // The caller should call Close when finished, to shut it down.
   136  func NewTLSServer(handler http.Handler) *Server {
   137  	ts := NewUnstartedServer(handler)
   138  	ts.StartTLS()
   139  	return ts
   140  }
   141  
   142  type closeIdleTransport interface {
   143  	CloseIdleConnections()
   144  }
   145  
   146  // Close shuts down the server and blocks until all outstanding
   147  // requests on this server have completed.
   148  func (s *Server) Close() {
   149  	s.mu.Lock()
   150  	if !s.closed {
   151  		s.closed = true
   152  		s.Listener.Close()
   153  		s.Config.SetKeepAlivesEnabled(false)
   154  		for c, st := range s.conns {
   155  			// Force-close any idle connections (those between
   156  			// requests) and new connections (those which connected
   157  			// but never sent a request). StateNew connections are
   158  			// super rare and have only been seen (in
   159  			// previously-flaky tests) in the case of
   160  			// socket-late-binding races from the http Client
   161  			// dialing this server and then getting an idle
   162  			// connection before the dial completed. There is thus
   163  			// a connected connection in StateNew with no
   164  			// associated Request. We only close StateIdle and
   165  			// StateNew because they're not doing anything. It's
   166  			// possible StateNew is about to do something in a few
   167  			// milliseconds, but a previous CL to check again in a
   168  			// few milliseconds wasn't liked (early versions of
   169  			// https://golang.org/cl/15151) so now we just
   170  			// forcefully close StateNew. The docs for Server.Close say
   171  			// we wait for "outstanding requests", so we don't close things
   172  			// in StateActive.
   173  			if st == http.StateIdle || st == http.StateNew {
   174  				s.closeConn(c)
   175  			}
   176  		}
   177  		// If this server doesn't shut down in 5 seconds, tell the user why.
   178  		t := time.AfterFunc(5*time.Second, s.logCloseHangDebugInfo)
   179  		defer t.Stop()
   180  	}
   181  	s.mu.Unlock()
   182  
   183  	// Not part of httptest.Server's correctness, but assume most
   184  	// users of httptest.Server will be using the standard
   185  	// transport, so help them out and close any idle connections for them.
   186  	if t, ok := http.DefaultTransport.(closeIdleTransport); ok {
   187  		t.CloseIdleConnections()
   188  	}
   189  
   190  	s.wg.Wait()
   191  }
   192  
   193  func (s *Server) logCloseHangDebugInfo() {
   194  	s.mu.Lock()
   195  	defer s.mu.Unlock()
   196  	var buf bytes.Buffer
   197  	buf.WriteString("httptest.Server blocked in Close after 5 seconds, waiting for connections:\n")
   198  	for c, st := range s.conns {
   199  		fmt.Fprintf(&buf, "  %T %p %v in state %v\n", c, c, c.RemoteAddr(), st)
   200  	}
   201  	log.Print(buf.String())
   202  }
   203  
   204  // CloseClientConnections closes any open HTTP connections to the test Server.
   205  func (s *Server) CloseClientConnections() {
   206  	s.mu.Lock()
   207  	nconn := len(s.conns)
   208  	ch := make(chan struct{}, nconn)
   209  	for c := range s.conns {
   210  		s.closeConnChan(c, ch)
   211  	}
   212  	s.mu.Unlock()
   213  
   214  	// Wait for outstanding closes to finish.
   215  	//
   216  	// Out of paranoia for making a late change in Go 1.6, we
   217  	// bound how long this can wait, since golang.org/issue/14291
   218  	// isn't fully understood yet. At least this should only be used
   219  	// in tests.
   220  	timer := time.NewTimer(5 * time.Second)
   221  	defer timer.Stop()
   222  	for i := 0; i < nconn; i++ {
   223  		select {
   224  		case <-ch:
   225  		case <-timer.C:
   226  			// Too slow. Give up.
   227  			return
   228  		}
   229  	}
   230  }
   231  
   232  func (s *Server) goServe() {
   233  	s.wg.Add(1)
   234  	go func() {
   235  		defer s.wg.Done()
   236  		s.Config.Serve(s.Listener)
   237  	}()
   238  }
   239  
   240  // wrap installs the connection state-tracking hook to know which
   241  // connections are idle.
   242  func (s *Server) wrap() {
   243  	oldHook := s.Config.ConnState
   244  	s.Config.ConnState = func(c net.Conn, cs http.ConnState) {
   245  		s.mu.Lock()
   246  		defer s.mu.Unlock()
   247  		switch cs {
   248  		case http.StateNew:
   249  			s.wg.Add(1)
   250  			if _, exists := s.conns[c]; exists {
   251  				panic("invalid state transition")
   252  			}
   253  			if s.conns == nil {
   254  				s.conns = make(map[net.Conn]http.ConnState)
   255  			}
   256  			s.conns[c] = cs
   257  			if s.closed {
   258  				// Probably just a socket-late-binding dial from
   259  				// the default transport that lost the race (and
   260  				// thus this connection is now idle and will
   261  				// never be used).
   262  				s.closeConn(c)
   263  			}
   264  		case http.StateActive:
   265  			if oldState, ok := s.conns[c]; ok {
   266  				if oldState != http.StateNew && oldState != http.StateIdle {
   267  					panic("invalid state transition")
   268  				}
   269  				s.conns[c] = cs
   270  			}
   271  		case http.StateIdle:
   272  			if oldState, ok := s.conns[c]; ok {
   273  				if oldState != http.StateActive {
   274  					panic("invalid state transition")
   275  				}
   276  				s.conns[c] = cs
   277  			}
   278  			if s.closed {
   279  				s.closeConn(c)
   280  			}
   281  		case http.StateHijacked, http.StateClosed:
   282  			s.forgetConn(c)
   283  		}
   284  		if oldHook != nil {
   285  			oldHook(c, cs)
   286  		}
   287  	}
   288  }
   289  
   290  // closeConn closes c.
   291  // s.mu must be held.
   292  func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
   293  
   294  // closeConnChan is like closeConn, but takes an optional channel to receive a value
   295  // when the goroutine closing c is done.
   296  func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) {
   297  	if runtime.GOOS == "plan9" {
   298  		// Go's Plan 9 net package isn't great at unblocking reads when
   299  		// their underlying TCP connections are closed. Don't trust
   300  		// that that the ConnState state machine will get to
   301  		// StateClosed. Instead, just go there directly. Plan 9 may leak
   302  		// resources if the syscall doesn't end up returning. Oh well.
   303  		s.forgetConn(c)
   304  	}
   305  
   306  	c.Close()
   307  	if done != nil {
   308  		done <- struct{}{}
   309  	}
   310  }
   311  
   312  // forgetConn removes c from the set of tracked conns and decrements it from the
   313  // waitgroup, unless it was previously removed.
   314  // s.mu must be held.
   315  func (s *Server) forgetConn(c net.Conn) {
   316  	if _, ok := s.conns[c]; ok {
   317  		delete(s.conns, c)
   318  		s.wg.Done()
   319  	}
   320  }