mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-26 15:42:21 +08:00
vendor manners - for real this time
sorry everyone.
This commit is contained in:
19
Godeps/_workspace/src/github.com/braintree/manners/LICENSE
generated
vendored
Normal file
19
Godeps/_workspace/src/github.com/braintree/manners/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
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.
|
33
Godeps/_workspace/src/github.com/braintree/manners/README.md
generated
vendored
Normal file
33
Godeps/_workspace/src/github.com/braintree/manners/README.md
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
# Manners
|
||||
|
||||
A *polite* webserver for Go.
|
||||
|
||||
Manners allows you to shut your Go webserver down gracefully, without dropping any requests. It can act as a drop-in replacement for the standard library's http.ListenAndServe function:
|
||||
|
||||
```go
|
||||
func main() {
|
||||
handler := MyHTTPHandler()
|
||||
server := manners.NewServer()
|
||||
server.ListenAndServe(":7000", handler)
|
||||
}
|
||||
```
|
||||
|
||||
Then, when you want to shut the server down:
|
||||
|
||||
```go
|
||||
server.Shutdown <- true
|
||||
```
|
||||
|
||||
(Note that this does not block until all the requests are finished. Rather, the call to server.ListenAndServe will stop blocking when all the requests are finished.)
|
||||
|
||||
Manners ensures that all requests are served by incrementing a WaitGroup when a request comes in and decrementing it when the request finishes.
|
||||
|
||||
If your request handler spawns Goroutines that are not guaranteed to finish with the request, you can ensure they are also completed with the `StartRoutine` and `FinishRoutine` functions on the server.
|
||||
|
||||
### Compatability
|
||||
|
||||
Manners 0.3.0 and above uses standard library functionality introduced in Go 1.3.
|
||||
|
||||
### Installation
|
||||
|
||||
`go get github.com/braintree/manners`
|
34
Godeps/_workspace/src/github.com/braintree/manners/helper_test.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/braintree/manners/helper_test.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
package manners
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A response handler that blocks until it receives a signal; simulates an
|
||||
// arbitrarily long web request. The "ready" channel is to prevent a race
|
||||
// condition in the test where the test moves on before the server is ready
|
||||
// to handle the request.
|
||||
func newBlockingHandler(ready, done chan bool) *blockingHandler {
|
||||
return &blockingHandler{ready, done}
|
||||
}
|
||||
|
||||
type blockingHandler struct {
|
||||
ready chan bool
|
||||
done chan bool
|
||||
}
|
||||
|
||||
func (h *blockingHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
||||
h.ready <- true
|
||||
time.Sleep(1e2)
|
||||
h.done <- true
|
||||
}
|
||||
|
||||
// A response handler that does nothing.
|
||||
func newTestHandler() testHandler {
|
||||
return testHandler{}
|
||||
}
|
||||
|
||||
type testHandler struct{}
|
||||
|
||||
func (h testHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {}
|
49
Godeps/_workspace/src/github.com/braintree/manners/listener.go
generated
vendored
Normal file
49
Godeps/_workspace/src/github.com/braintree/manners/listener.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
package manners
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func NewListener(l net.Listener, s *GracefulServer) *GracefulListener {
|
||||
return &GracefulListener{l, true, s, sync.RWMutex{}}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
net.Listener
|
||||
open bool
|
||||
server *GracefulServer
|
||||
rw sync.RWMutex
|
||||
}
|
||||
|
||||
func (l *GracefulListener) Accept() (net.Conn, error) {
|
||||
conn, err := l.Listener.Accept()
|
||||
if err != nil {
|
||||
l.rw.RLock()
|
||||
defer l.rw.RUnlock()
|
||||
if !l.open {
|
||||
err = listenerAlreadyClosed{err}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (l *GracefulListener) Close() error {
|
||||
l.rw.Lock()
|
||||
defer l.rw.Unlock()
|
||||
if !l.open {
|
||||
return nil
|
||||
}
|
||||
l.open = false
|
||||
err := l.Listener.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
type listenerAlreadyClosed struct {
|
||||
error
|
||||
}
|
83
Godeps/_workspace/src/github.com/braintree/manners/server.go
generated
vendored
Normal file
83
Godeps/_workspace/src/github.com/braintree/manners/server.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
package manners
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Creates a new GracefulServer. The server will begin shutting down when
|
||||
// a value is passed to the Shutdown channel.
|
||||
func NewServer() *GracefulServer {
|
||||
return &GracefulServer{
|
||||
Shutdown: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
type GracefulServer struct {
|
||||
Shutdown chan bool
|
||||
wg sync.WaitGroup
|
||||
shutdownHandler func()
|
||||
InnerServer http.Server
|
||||
}
|
||||
|
||||
// A helper function that emulates the functionality of http.ListenAndServe.
|
||||
func (s *GracefulServer) ListenAndServe(addr string, handler http.Handler) error {
|
||||
oldListener, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listener := NewListener(oldListener, s)
|
||||
err = s.Serve(listener, handler)
|
||||
return err
|
||||
}
|
||||
|
||||
// Similar to http.Serve. The listener passed must wrap a GracefulListener.
|
||||
func (s *GracefulServer) Serve(listener net.Listener, handler http.Handler) error {
|
||||
s.shutdownHandler = func() { listener.Close() }
|
||||
s.listenForShutdown()
|
||||
s.InnerServer.Handler = handler
|
||||
s.InnerServer.ConnState = func(conn net.Conn, newState http.ConnState) {
|
||||
switch newState {
|
||||
case http.StateNew:
|
||||
s.StartRoutine()
|
||||
case http.StateClosed, http.StateHijacked:
|
||||
s.FinishRoutine()
|
||||
}
|
||||
}
|
||||
err := s.InnerServer.Serve(listener)
|
||||
|
||||
// This block is reached when the server has received a shut down command.
|
||||
if err == nil {
|
||||
s.wg.Wait()
|
||||
return nil
|
||||
} else if _, ok := err.(listenerAlreadyClosed); ok {
|
||||
s.wg.Wait()
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 (s *GracefulServer) StartRoutine() {
|
||||
s.wg.Add(1)
|
||||
}
|
||||
|
||||
// Decrement the server's WaitGroup. Used this to complement StartRoutine().
|
||||
func (s *GracefulServer) FinishRoutine() {
|
||||
s.wg.Done()
|
||||
}
|
||||
|
||||
func (s *GracefulServer) listenForShutdown() {
|
||||
go func() {
|
||||
<-s.Shutdown
|
||||
s.shutdownHandler()
|
||||
}()
|
||||
}
|
71
Godeps/_workspace/src/github.com/braintree/manners/server_test.go
generated
vendored
Normal file
71
Godeps/_workspace/src/github.com/braintree/manners/server_test.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
package manners
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Tests that the server allows in-flight requests to complete before shutting
|
||||
// down.
|
||||
func TestGracefulness(t *testing.T) {
|
||||
ready := make(chan bool)
|
||||
done := make(chan bool)
|
||||
|
||||
exited := false
|
||||
|
||||
handler := newBlockingHandler(ready, done)
|
||||
server := NewServer()
|
||||
|
||||
go func() {
|
||||
err := server.ListenAndServe(":7000", handler)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
exited = true
|
||||
}()
|
||||
|
||||
go func() {
|
||||
_, err := http.Get("http://localhost:7000")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// This will block until the server is inside the handler function.
|
||||
<-ready
|
||||
|
||||
server.Shutdown <- true
|
||||
<-done
|
||||
|
||||
if exited {
|
||||
t.Fatal("The request did not complete before server exited")
|
||||
} else {
|
||||
// The handler is being allowed to run to completion; test passes.
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the server begins to shut down when told to and does not accept
|
||||
// new requests
|
||||
func TestShutdown(t *testing.T) {
|
||||
handler := newTestHandler()
|
||||
server := NewServer()
|
||||
exited := make(chan bool)
|
||||
|
||||
go func() {
|
||||
err := server.ListenAndServe(":7100", handler)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
exited <- true
|
||||
}()
|
||||
|
||||
server.Shutdown <- true
|
||||
|
||||
<-exited
|
||||
_, err := http.Get("http://localhost:7100")
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Did not receive an error when trying to connect to server.")
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user