Update vendor dependencies
Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
parent
8401cccff2
commit
1140ee6c64
357 changed files with 0 additions and 38269 deletions
19
vendor/github.com/mailgun/manners/LICENSE
generated
vendored
19
vendor/github.com/mailgun/manners/LICENSE
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
Copyright (c) 2014 Braintree, a division of PayPal, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
7
vendor/github.com/mailgun/manners/interfaces.go
generated
vendored
7
vendor/github.com/mailgun/manners/interfaces.go
generated
vendored
|
@ -1,7 +0,0 @@
|
|||
package manners
|
||||
|
||||
type waitGroup interface {
|
||||
Add(int)
|
||||
Done()
|
||||
Wait()
|
||||
}
|
155
vendor/github.com/mailgun/manners/listener.go
generated
vendored
155
vendor/github.com/mailgun/manners/listener.go
generated
vendored
|
@ -1,155 +0,0 @@
|
|||
package manners
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewListener wraps an existing listener for use with
|
||||
// GracefulServer.
|
||||
//
|
||||
// Note that you generally don't need to use this directly as
|
||||
// GracefulServer will automatically wrap any non-graceful listeners
|
||||
// supplied to it.
|
||||
func NewListener(l net.Listener) *GracefulListener {
|
||||
return &GracefulListener{
|
||||
listener: l,
|
||||
mutex: &sync.RWMutex{},
|
||||
open: true,
|
||||
}
|
||||
}
|
||||
|
||||
// A GracefulListener differs from a standard net.Listener in one way: if
|
||||
// Accept() is called after it is gracefully closed, it returns a
|
||||
// listenerAlreadyClosed error. The GracefulServer will ignore this error.
|
||||
type GracefulListener struct {
|
||||
listener net.Listener
|
||||
open bool
|
||||
mutex *sync.RWMutex
|
||||
}
|
||||
|
||||
func (l *GracefulListener) isClosed() bool {
|
||||
l.mutex.RLock()
|
||||
defer l.mutex.RUnlock()
|
||||
return !l.open
|
||||
}
|
||||
|
||||
func (l *GracefulListener) Addr() net.Addr {
|
||||
return l.listener.Addr()
|
||||
}
|
||||
|
||||
// Accept implements the Accept method in the Listener interface.
|
||||
func (l *GracefulListener) Accept() (net.Conn, error) {
|
||||
conn, err := l.listener.Accept()
|
||||
if err != nil {
|
||||
if l.isClosed() {
|
||||
err = fmt.Errorf("listener already closed: err=(%s)", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Close tells the wrapped listener to stop listening. It is idempotent.
|
||||
func (l *GracefulListener) Close() error {
|
||||
l.mutex.Lock()
|
||||
defer l.mutex.Unlock()
|
||||
if !l.open {
|
||||
return nil
|
||||
}
|
||||
l.open = false
|
||||
return l.listener.Close()
|
||||
}
|
||||
|
||||
func (l *GracefulListener) GetFile() (*os.File, error) {
|
||||
return getListenerFile(l.listener)
|
||||
}
|
||||
|
||||
func (l *GracefulListener) Clone() (net.Listener, error) {
|
||||
l.mutex.Lock()
|
||||
defer l.mutex.Unlock()
|
||||
|
||||
if !l.open {
|
||||
return nil, errors.New("listener is already closed")
|
||||
}
|
||||
|
||||
file, err := l.GetFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fl, err := net.FileListener(file)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return fl, nil
|
||||
}
|
||||
|
||||
// A listener implements a network listener (net.Listener) for TLS connections.
|
||||
// direct lift from crypto/tls.go
|
||||
type TLSListener struct {
|
||||
net.Listener
|
||||
config *tls.Config
|
||||
}
|
||||
|
||||
// Accept waits for and returns the next incoming TLS connection.
|
||||
// The returned connection c is a *tls.Conn.
|
||||
func (l *TLSListener) Accept() (c net.Conn, err error) {
|
||||
c, err = l.Listener.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c = tls.Server(c, l.config)
|
||||
return
|
||||
}
|
||||
|
||||
// NewListener creates a Listener which accepts connections from an inner
|
||||
// Listener and wraps each connection with Server.
|
||||
// The configuration config must be non-nil and must have
|
||||
// at least one certificate.
|
||||
func NewTLSListener(inner net.Listener, config *tls.Config) net.Listener {
|
||||
l := new(TLSListener)
|
||||
l.Listener = inner
|
||||
l.config = config
|
||||
return l
|
||||
}
|
||||
|
||||
// TCPKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||||
// connections. It's used by ListenAndServe and ListenAndServeTLS so
|
||||
// dead TCP connections (e.g. closing laptop mid-download) eventually
|
||||
// go away.
|
||||
//
|
||||
// direct lift from net/http/server.go
|
||||
type TCPKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
func (ln TCPKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
tc, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tc.SetKeepAlive(true)
|
||||
tc.SetKeepAlivePeriod(3 * time.Minute)
|
||||
return tc, nil
|
||||
}
|
||||
|
||||
func getListenerFile(listener net.Listener) (*os.File, error) {
|
||||
switch t := listener.(type) {
|
||||
case *net.TCPListener:
|
||||
return t.File()
|
||||
case *net.UnixListener:
|
||||
return t.File()
|
||||
case TCPKeepAliveListener:
|
||||
return t.TCPListener.File()
|
||||
case *TLSListener:
|
||||
return getListenerFile(t.Listener)
|
||||
}
|
||||
return nil, fmt.Errorf("Unsupported listener: %T", listener)
|
||||
}
|
379
vendor/github.com/mailgun/manners/server.go
generated
vendored
379
vendor/github.com/mailgun/manners/server.go
generated
vendored
|
@ -1,379 +0,0 @@
|
|||
/*
|
||||
Package manners provides a wrapper for a standard net/http server that
|
||||
ensures all active HTTP client have completed their current request
|
||||
before the server shuts down.
|
||||
|
||||
It can be used a drop-in replacement for the standard http package,
|
||||
or can wrap a pre-configured Server.
|
||||
|
||||
eg.
|
||||
|
||||
http.Handle("/hello", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Hello\n"))
|
||||
})
|
||||
|
||||
log.Fatal(manners.ListenAndServe(":8080", nil))
|
||||
|
||||
or for a customized server:
|
||||
|
||||
s := manners.NewWithServer(&http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: myHandler,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
})
|
||||
log.Fatal(s.ListenAndServe())
|
||||
|
||||
The server will shut down cleanly when the Close() method is called:
|
||||
|
||||
go func() {
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigchan, os.Interrupt, os.Kill)
|
||||
<-sigchan
|
||||
log.Info("Shutting down...")
|
||||
manners.Close()
|
||||
}()
|
||||
|
||||
http.Handle("/hello", myHandler)
|
||||
log.Fatal(manners.ListenAndServe(":8080", nil))
|
||||
*/
|
||||
package manners
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// StateHandler can be called by the server if the state of the connection changes.
|
||||
// Notice that it passed previous state and the new state as parameters.
|
||||
type StateHandler func(net.Conn, http.ConnState, http.ConnState)
|
||||
|
||||
// Options used by NewWithOptions to provide parameters for a GracefulServer
|
||||
// instance to be created.
|
||||
type Options struct {
|
||||
Server *http.Server
|
||||
StateHandler StateHandler
|
||||
Listener net.Listener
|
||||
}
|
||||
|
||||
// A GracefulServer maintains a WaitGroup that counts how many in-flight
|
||||
// requests the server is handling. When it receives a shutdown signal,
|
||||
// it stops accepting new requests but does not actually shut down until
|
||||
// all in-flight requests terminate.
|
||||
//
|
||||
// GracefulServer embeds the underlying net/http.Server making its non-override
|
||||
// methods and properties avaiable.
|
||||
//
|
||||
// It must be initialized by calling NewServer or NewWithServer
|
||||
type GracefulServer struct {
|
||||
*http.Server
|
||||
shutdown chan bool
|
||||
shutdownFinished chan bool
|
||||
wg waitGroup
|
||||
routinesCount int32
|
||||
listener *GracefulListener
|
||||
stateHandler StateHandler
|
||||
connToProps map[net.Conn]connProperties
|
||||
connToPropsMtx sync.RWMutex
|
||||
|
||||
up chan net.Listener // Only used by test code.
|
||||
}
|
||||
|
||||
// NewServer creates a new GracefulServer.
|
||||
func NewServer() *GracefulServer {
|
||||
return NewWithOptions(Options{})
|
||||
}
|
||||
|
||||
// NewWithServer wraps an existing http.Server object and returns a
|
||||
// GracefulServer that supports all of the original Server operations.
|
||||
func NewWithServer(s *http.Server) *GracefulServer {
|
||||
return NewWithOptions(Options{Server: s})
|
||||
}
|
||||
|
||||
// NewWithOptions creates a GracefulServer instance with the specified options.
|
||||
func NewWithOptions(o Options) *GracefulServer {
|
||||
var listener *GracefulListener
|
||||
if o.Listener != nil {
|
||||
g, ok := o.Listener.(*GracefulListener)
|
||||
if !ok {
|
||||
listener = NewListener(o.Listener)
|
||||
} else {
|
||||
listener = g
|
||||
}
|
||||
}
|
||||
if o.Server == nil {
|
||||
o.Server = new(http.Server)
|
||||
}
|
||||
return &GracefulServer{
|
||||
Server: o.Server,
|
||||
listener: listener,
|
||||
stateHandler: o.StateHandler,
|
||||
shutdown: make(chan bool),
|
||||
shutdownFinished: make(chan bool, 1),
|
||||
wg: new(sync.WaitGroup),
|
||||
connToProps: make(map[net.Conn]connProperties),
|
||||
}
|
||||
}
|
||||
|
||||
// Close stops the server from accepting new requets and begins shutting down.
|
||||
// It returns true if it's the first time Close is called.
|
||||
func (gs *GracefulServer) Close() bool {
|
||||
return <-gs.shutdown
|
||||
}
|
||||
|
||||
// BlockingClose is similar to Close, except that it blocks until the last
|
||||
// connection has been closed.
|
||||
func (gs *GracefulServer) BlockingClose() bool {
|
||||
result := gs.Close()
|
||||
<-gs.shutdownFinished
|
||||
return result
|
||||
}
|
||||
|
||||
// ListenAndServe provides a graceful equivalent of net/http.Serve.ListenAndServe.
|
||||
func (gs *GracefulServer) ListenAndServe() error {
|
||||
if gs.listener == nil {
|
||||
oldListener, err := net.Listen("tcp", gs.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gs.listener = NewListener(oldListener.(*net.TCPListener))
|
||||
}
|
||||
return gs.Serve(gs.listener)
|
||||
}
|
||||
|
||||
// ListenAndServeTLS provides a graceful equivalent of net/http.Serve.ListenAndServeTLS.
|
||||
func (gs *GracefulServer) ListenAndServeTLS(certFile, keyFile string) error {
|
||||
// direct lift from net/http/server.go
|
||||
addr := gs.Addr
|
||||
if addr == "" {
|
||||
addr = ":https"
|
||||
}
|
||||
config := &tls.Config{}
|
||||
if gs.TLSConfig != nil {
|
||||
*config = *gs.TLSConfig
|
||||
}
|
||||
if config.NextProtos == nil {
|
||||
config.NextProtos = []string{"http/1.1"}
|
||||
}
|
||||
|
||||
var err error
|
||||
config.Certificates = make([]tls.Certificate, 1)
|
||||
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gs.ListenAndServeTLSWithConfig(config)
|
||||
}
|
||||
|
||||
// ListenAndServeTLS provides a graceful equivalent of net/http.Serve.ListenAndServeTLS.
|
||||
func (gs *GracefulServer) ListenAndServeTLSWithConfig(config *tls.Config) error {
|
||||
addr := gs.Addr
|
||||
if addr == "" {
|
||||
addr = ":https"
|
||||
}
|
||||
|
||||
if gs.listener == nil {
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsListener := NewTLSListener(TCPKeepAliveListener{ln.(*net.TCPListener)}, config)
|
||||
gs.listener = NewListener(tlsListener)
|
||||
}
|
||||
return gs.Serve(gs.listener)
|
||||
}
|
||||
|
||||
func (gs *GracefulServer) GetFile() (*os.File, error) {
|
||||
return gs.listener.GetFile()
|
||||
}
|
||||
|
||||
func (gs *GracefulServer) HijackListener(s *http.Server, config *tls.Config) (*GracefulServer, error) {
|
||||
listenerUnsafePtr := unsafe.Pointer(gs.listener)
|
||||
listener, err := (*GracefulListener)(atomic.LoadPointer(&listenerUnsafePtr)).Clone()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config != nil {
|
||||
listener = NewTLSListener(TCPKeepAliveListener{listener.(*net.TCPListener)}, config)
|
||||
}
|
||||
|
||||
other := NewWithServer(s)
|
||||
other.listener = NewListener(listener)
|
||||
return other, nil
|
||||
}
|
||||
|
||||
// Serve provides a graceful equivalent net/http.Server.Serve.
|
||||
//
|
||||
// If listener is not an instance of *GracefulListener it will be wrapped
|
||||
// to become one.
|
||||
func (gs *GracefulServer) Serve(listener net.Listener) error {
|
||||
// Accept a net.Listener to preserve the interface compatibility with the
|
||||
// standard http.Server. If it is not a GracefulListener then wrap it into
|
||||
// one.
|
||||
gracefulListener, ok := listener.(*GracefulListener)
|
||||
if !ok {
|
||||
gracefulListener = NewListener(listener)
|
||||
listener = gracefulListener
|
||||
}
|
||||
listenerUnsafePtr := unsafe.Pointer(gs.listener)
|
||||
atomic.StorePointer(&listenerUnsafePtr, unsafe.Pointer(gracefulListener))
|
||||
|
||||
// Wrap the server HTTP handler into graceful one, that will close kept
|
||||
// alive connections if a new request is received after shutdown.
|
||||
gracefulHandler := newGracefulHandler(gs.Server.Handler)
|
||||
gs.Server.Handler = gracefulHandler
|
||||
|
||||
// Start a goroutine that waits for a shutdown signal and will stop the
|
||||
// listener when it receives the signal. That in turn will result in
|
||||
// unblocking of the http.Serve call.
|
||||
go func() {
|
||||
gs.shutdown <- true
|
||||
close(gs.shutdown)
|
||||
gracefulHandler.Close()
|
||||
gs.Server.SetKeepAlivesEnabled(false)
|
||||
gracefulListener.Close()
|
||||
}()
|
||||
|
||||
originalConnState := gs.Server.ConnState
|
||||
|
||||
// s.ConnState is invoked by the net/http.Server every time a connection
|
||||
// changes state. It keeps track of each connection's state over time,
|
||||
// enabling manners to handle persisted connections correctly.
|
||||
gs.ConnState = func(conn net.Conn, newState http.ConnState) {
|
||||
gs.connToPropsMtx.RLock()
|
||||
connProps := gs.connToProps[conn]
|
||||
gs.connToPropsMtx.RUnlock()
|
||||
|
||||
switch newState {
|
||||
|
||||
case http.StateNew:
|
||||
// New connection -> StateNew
|
||||
connProps.protected = true
|
||||
gs.StartRoutine()
|
||||
|
||||
case http.StateActive:
|
||||
// (StateNew, StateIdle) -> StateActive
|
||||
if gracefulHandler.IsClosed() {
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
|
||||
if !connProps.protected {
|
||||
connProps.protected = true
|
||||
gs.StartRoutine()
|
||||
}
|
||||
|
||||
default:
|
||||
// (StateNew, StateActive) -> (StateIdle, StateClosed, StateHiJacked)
|
||||
if connProps.protected {
|
||||
gs.FinishRoutine()
|
||||
connProps.protected = false
|
||||
}
|
||||
}
|
||||
|
||||
if gs.stateHandler != nil {
|
||||
gs.stateHandler(conn, connProps.state, newState)
|
||||
}
|
||||
connProps.state = newState
|
||||
|
||||
gs.connToPropsMtx.Lock()
|
||||
if newState == http.StateClosed || newState == http.StateHijacked {
|
||||
delete(gs.connToProps, conn)
|
||||
} else {
|
||||
gs.connToProps[conn] = connProps
|
||||
}
|
||||
gs.connToPropsMtx.Unlock()
|
||||
|
||||
if originalConnState != nil {
|
||||
originalConnState(conn, newState)
|
||||
}
|
||||
}
|
||||
|
||||
// A hook to allow the server to notify others when it is ready to receive
|
||||
// requests; only used by tests.
|
||||
if gs.up != nil {
|
||||
gs.up <- listener
|
||||
}
|
||||
|
||||
err := gs.Server.Serve(listener)
|
||||
// An error returned on shutdown is not worth reporting.
|
||||
if err != nil && gracefulHandler.IsClosed() {
|
||||
err = nil
|
||||
}
|
||||
|
||||
// Wait for pending requests to complete regardless the Serve result.
|
||||
gs.wg.Wait()
|
||||
gs.shutdownFinished <- true
|
||||
return err
|
||||
}
|
||||
|
||||
// StartRoutine increments the server's WaitGroup. Use this if a web request
|
||||
// starts more goroutines and these goroutines are not guaranteed to finish
|
||||
// before the request.
|
||||
func (gs *GracefulServer) StartRoutine() {
|
||||
gs.wg.Add(1)
|
||||
atomic.AddInt32(&gs.routinesCount, 1)
|
||||
}
|
||||
|
||||
// FinishRoutine decrements the server's WaitGroup. Use this to complement
|
||||
// StartRoutine().
|
||||
func (gs *GracefulServer) FinishRoutine() {
|
||||
gs.wg.Done()
|
||||
atomic.AddInt32(&gs.routinesCount, -1)
|
||||
}
|
||||
|
||||
// RoutinesCount returns the number of currently running routines
|
||||
func (gs *GracefulServer) RoutinesCount() int {
|
||||
return int(atomic.LoadInt32(&gs.routinesCount))
|
||||
}
|
||||
|
||||
// gracefulHandler is used by GracefulServer to prevent calling ServeHTTP on
|
||||
// to be closed kept-alive connections during the server shutdown.
|
||||
type gracefulHandler struct {
|
||||
closed int32 // accessed atomically.
|
||||
wrapped http.Handler
|
||||
}
|
||||
|
||||
func newGracefulHandler(wrapped http.Handler) *gracefulHandler {
|
||||
return &gracefulHandler{
|
||||
wrapped: wrapped,
|
||||
}
|
||||
}
|
||||
|
||||
func (gh *gracefulHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if atomic.LoadInt32(&gh.closed) == 0 {
|
||||
gh.wrapped.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
r.Body.Close()
|
||||
// Server is shutting down at this moment, and the connection that this
|
||||
// handler is being called on is about to be closed. So we do not need to
|
||||
// actually execute the handler logic.
|
||||
}
|
||||
|
||||
func (gh *gracefulHandler) Close() {
|
||||
atomic.StoreInt32(&gh.closed, 1)
|
||||
}
|
||||
|
||||
func (gh *gracefulHandler) IsClosed() bool {
|
||||
return atomic.LoadInt32(&gh.closed) == 1
|
||||
}
|
||||
|
||||
// connProperties is used to keep track of various properties of connections
|
||||
// maintained by a gracefulServer.
|
||||
type connProperties struct {
|
||||
// Last known connection state.
|
||||
state http.ConnState
|
||||
// Tells whether the connection is going to defer server shutdown until
|
||||
// the current HTTP request is completed.
|
||||
protected bool
|
||||
}
|
47
vendor/github.com/mailgun/manners/static.go
generated
vendored
47
vendor/github.com/mailgun/manners/static.go
generated
vendored
|
@ -1,47 +0,0 @@
|
|||
package manners
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultServer *GracefulServer
|
||||
defaultServerLock = &sync.Mutex{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultServerLock.Lock()
|
||||
}
|
||||
|
||||
// ListenAndServe provides a graceful version of the function provided by the
|
||||
// net/http package. Call Close() to stop the server.
|
||||
func ListenAndServe(addr string, handler http.Handler) error {
|
||||
defaultServer = NewWithServer(&http.Server{Addr: addr, Handler: handler})
|
||||
defaultServerLock.Unlock()
|
||||
return defaultServer.ListenAndServe()
|
||||
}
|
||||
|
||||
// ListenAndServeTLS provides a graceful version of the function provided by the
|
||||
// net/http package. Call Close() to stop the server.
|
||||
func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error {
|
||||
defaultServer = NewWithServer(&http.Server{Addr: addr, Handler: handler})
|
||||
defaultServerLock.Unlock()
|
||||
return defaultServer.ListenAndServeTLS(certFile, keyFile)
|
||||
}
|
||||
|
||||
// Serve provides a graceful version of the function provided by the net/http
|
||||
// package. Call Close() to stop the server.
|
||||
func Serve(l net.Listener, handler http.Handler) error {
|
||||
defaultServer = NewWithServer(&http.Server{Handler: handler})
|
||||
defaultServerLock.Unlock()
|
||||
return defaultServer.Serve(l)
|
||||
}
|
||||
|
||||
// Shuts down the default server used by ListenAndServe, ListenAndServeTLS and
|
||||
// Serve. It returns true if it's the first time Close is called.
|
||||
func Close() bool {
|
||||
defaultServerLock.Lock()
|
||||
return defaultServer.Close()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue