github.com/aloncn/graphics-go@v0.0.1/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  	var conns int
   206  	ch := make(chan bool)
   207  
   208  	s.mu.Lock()
   209  	for c := range s.conns {
   210  		conns++
   211  		s.closeConnChan(c, ch)
   212  	}
   213  	s.mu.Unlock()
   214  
   215  	// Wait for outstanding closes to finish.
   216  	//
   217  	// Out of paranoia for making a late change in Go 1.6, we
   218  	// bound how long this can wait, since golang.org/issue/14291
   219  	// isn't fully understood yet. At least this should only be used
   220  	// in tests.
   221  	timer := time.NewTimer(5 * time.Second)
   222  	defer timer.Stop()
   223  	for i := 0; i < conns; i++ {
   224  		select {
   225  		case <-ch:
   226  		case <-timer.C:
   227  			// Too slow. Give up.
   228  			return
   229  		}
   230  	}
   231  }
   232  
   233  func (s *Server) goServe() {
   234  	s.wg.Add(1)
   235  	go func() {
   236  		defer s.wg.Done()
   237  		s.Config.Serve(s.Listener)
   238  	}()
   239  }
   240  
   241  // wrap installs the connection state-tracking hook to know which
   242  // connections are idle.
   243  func (s *Server) wrap() {
   244  	oldHook := s.Config.ConnState
   245  	s.Config.ConnState = func(c net.Conn, cs http.ConnState) {
   246  		s.mu.Lock()
   247  		defer s.mu.Unlock()
   248  		switch cs {
   249  		case http.StateNew:
   250  			s.wg.Add(1)
   251  			if _, exists := s.conns[c]; exists {
   252  				panic("invalid state transition")
   253  			}
   254  			if s.conns == nil {
   255  				s.conns = make(map[net.Conn]http.ConnState)
   256  			}
   257  			s.conns[c] = cs
   258  			if s.closed {
   259  				// Probably just a socket-late-binding dial from
   260  				// the default transport that lost the race (and
   261  				// thus this connection is now idle and will
   262  				// never be used).
   263  				s.closeConn(c)
   264  			}
   265  		case http.StateActive:
   266  			if oldState, ok := s.conns[c]; ok {
   267  				if oldState != http.StateNew && oldState != http.StateIdle {
   268  					panic("invalid state transition")
   269  				}
   270  				s.conns[c] = cs
   271  			}
   272  		case http.StateIdle:
   273  			if oldState, ok := s.conns[c]; ok {
   274  				if oldState != http.StateActive {
   275  					panic("invalid state transition")
   276  				}
   277  				s.conns[c] = cs
   278  			}
   279  			if s.closed {
   280  				s.closeConn(c)
   281  			}
   282  		case http.StateHijacked, http.StateClosed:
   283  			s.forgetConn(c)
   284  		}
   285  		if oldHook != nil {
   286  			oldHook(c, cs)
   287  		}
   288  	}
   289  }
   290  
   291  // closeConn closes c.
   292  // s.mu must be held.
   293  func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
   294  
   295  // closeConnChan is like closeConn, but takes an optional channel to receive a value
   296  // when the goroutine closing c is done.
   297  func (s *Server) closeConnChan(c net.Conn, done chan<- bool) {
   298  	if runtime.GOOS == "plan9" {
   299  		// Go's Plan 9 net package isn't great at unblocking reads when
   300  		// their underlying TCP connections are closed.  Don't trust
   301  		// that that the ConnState state machine will get to
   302  		// StateClosed. Instead, just go there directly. Plan 9 may leak
   303  		// resources if the syscall doesn't end up returning. Oh well.
   304  		s.forgetConn(c)
   305  	}
   306  
   307  	// Somewhere in the chaos of https://golang.org/cl/15151 we found that
   308  	// some types of conns were blocking in Close too long (or deadlocking?)
   309  	// and we had to call Close in a goroutine. I (bradfitz) forget what
   310  	// that was at this point, but I suspect it was *tls.Conns, which
   311  	// were later fixed in https://golang.org/cl/18572, so this goroutine
   312  	// is _probably_ unnecessary now. But it's too late in Go 1.6 too remove
   313  	// it with confidence.
   314  	// TODO(bradfitz): try to remove it for Go 1.7. (golang.org/issue/14291)
   315  	go func() {
   316  		c.Close()
   317  		if done != nil {
   318  			done <- true
   319  		}
   320  	}()
   321  }
   322  
   323  // forgetConn removes c from the set of tracked conns and decrements it from the
   324  // waitgroup, unless it was previously removed.
   325  // s.mu must be held.
   326  func (s *Server) forgetConn(c net.Conn) {
   327  	if _, ok := s.conns[c]; ok {
   328  		delete(s.conns, c)
   329  		s.wg.Done()
   330  	}
   331  }