Adding ability to serve TLS directly from Mattermost server (#4119)

Этот коммит содержится в:
Christopher Speller
2016-10-03 16:03:15 -04:00
коммит произвёл GitHub
родитель 5f8e5c401b
Коммит 8f91c77755
734 изменённых файлов: 190367 добавлений и 82 удалений

23
vendor/github.com/tylerb/graceful/.gitignore сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,23 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test

13
vendor/github.com/tylerb/graceful/.travis.yml сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,13 @@
language: go
sudo: false
go:
- 1.7
- 1.6.2
- 1.5.4
- 1.4.3
- 1.3.3
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

21
vendor/github.com/tylerb/graceful/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Tyler Bunnell
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.

152
vendor/github.com/tylerb/graceful/README.md сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,152 @@
graceful [![GoDoc](https://godoc.org/github.com/tylerb/graceful?status.png)](http://godoc.org/github.com/tylerb/graceful) [![Build Status](https://travis-ci.org/tylerb/graceful.svg?branch=master)](https://travis-ci.org/tylerb/graceful) [![Coverage Status](https://coveralls.io/repos/tylerb/graceful/badge.svg)](https://coveralls.io/r/tylerb/graceful) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tylerb/graceful?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
========
Graceful is a Go 1.3+ package enabling graceful shutdown of http.Handler servers.
## Installation
To install, simply execute:
```
go get gopkg.in/tylerb/graceful.v1
```
I am using [gopkg.in](http://labix.org/gopkg.in) to control releases.
## Usage
Using Graceful is easy. Simply create your http.Handler and pass it to the `Run` function:
```go
package main
import (
"gopkg.in/tylerb/graceful.v1"
"net/http"
"fmt"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
graceful.Run(":3001",10*time.Second,mux)
}
```
Another example, using [Negroni](https://github.com/codegangsta/negroni), functions in much the same manner:
```go
package main
import (
"github.com/codegangsta/negroni"
"gopkg.in/tylerb/graceful.v1"
"net/http"
"fmt"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
n := negroni.Classic()
n.UseHandler(mux)
//n.Run(":3000")
graceful.Run(":3001",10*time.Second,n)
}
```
In addition to Run there are the http.Server counterparts ListenAndServe, ListenAndServeTLS and Serve, which allow you to configure HTTPS, custom timeouts and error handling.
Graceful may also be used by instantiating its Server type directly, which embeds an http.Server:
```go
mux := // ...
srv := &graceful.Server{
Timeout: 10 * time.Second,
Server: &http.Server{
Addr: ":1234",
Handler: mux,
},
}
srv.ListenAndServe()
```
This form allows you to set the ConnState callback, which works in the same way as in http.Server:
```go
mux := // ...
srv := &graceful.Server{
Timeout: 10 * time.Second,
ConnState: func(conn net.Conn, state http.ConnState) {
// conn has a new state
},
Server: &http.Server{
Addr: ":1234",
Handler: mux,
},
}
srv.ListenAndServe()
```
## Behaviour
When Graceful is sent a SIGINT or SIGTERM (possibly from ^C or a kill command), it:
1. Disables keepalive connections.
2. Closes the listening socket, allowing another process to listen on that port immediately.
3. Starts a timer of `timeout` duration to give active requests a chance to finish.
4. When timeout expires, closes all active connections.
5. Closes the `stopChan`, waking up any blocking goroutines.
6. Returns from the function, allowing the server to terminate.
## Notes
If the `timeout` argument to `Run` is 0, the server never times out, allowing all active requests to complete.
If you wish to stop the server in some way other than an OS signal, you may call the `Stop()` function.
This function stops the server, gracefully, using the new timeout value you provide. The `StopChan()` function
returns a channel on which you can block while waiting for the server to stop. This channel will be closed when
the server is stopped, allowing your execution to proceed. Multiple goroutines can block on this channel at the
same time and all will be signalled when stopping is complete.
### Important things to note when setting `timeout` to 0:
If you set the `timeout` to `0`, it waits for all connections to the server to disconnect before shutting down.
This means that even though requests over a connection have finished, it is possible for the client to hold the
connection open and block the server from shutting down indefinitely.
This is especially evident when graceful is used to run HTTP/2 servers. Clients like Chrome and Firefox have been
observed to hold onto the open connection indefinitely over HTTP/2, preventing the server from shutting down. In
addition, there is also the risk of malicious clients holding and keeping the connection alive.
It is understandable that sometimes, you might want to wait for the client indefinitely because they might be
uploading large files. In these type of cases, it is recommended that you set a reasonable timeout to kill the
connection, and have the client perform resumable uploads. For example, the client can divide the file into chunks
and reupload chunks that were in transit when the connection was terminated.
## Contributing
If you would like to contribute, please:
1. Create a GitHub issue regarding the contribution. Features and bugs should be discussed beforehand.
2. Fork the repository.
3. Create a pull request with your solution. This pull request should reference and close the issues (Fix #2).
All pull requests should:
1. Pass [gometalinter -t .](https://github.com/alecthomas/gometalinter) with no warnings.
2. Be `go fmt` formatted.

487
vendor/github.com/tylerb/graceful/graceful.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,487 @@
package graceful
import (
"crypto/tls"
"log"
"net"
"net/http"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
// Server wraps an http.Server with graceful connection handling.
// It may be used directly in the same way as http.Server, or may
// be constructed with the global functions in this package.
//
// Example:
// srv := &graceful.Server{
// Timeout: 5 * time.Second,
// Server: &http.Server{Addr: ":1234", Handler: handler},
// }
// srv.ListenAndServe()
type Server struct {
*http.Server
// Timeout is the duration to allow outstanding requests to survive
// before forcefully terminating them.
Timeout time.Duration
// Limit the number of outstanding requests
ListenLimit int
// TCPKeepAlive sets the TCP keep-alive timeouts on accepted
// connections. It prunes dead TCP connections ( e.g. closing
// laptop mid-download)
TCPKeepAlive time.Duration
// ConnState specifies an optional callback function that is
// called when a client connection changes state. This is a proxy
// to the underlying http.Server's ConnState, and the original
// must not be set directly.
ConnState func(net.Conn, http.ConnState)
// BeforeShutdown is an optional callback function that is called
// before the listener is closed. Returns true if shutdown is allowed
BeforeShutdown func() bool
// ShutdownInitiated is an optional callback function that is called
// when shutdown is initiated. It can be used to notify the client
// side of long lived connections (e.g. websockets) to reconnect.
ShutdownInitiated func()
// NoSignalHandling prevents graceful from automatically shutting down
// on SIGINT and SIGTERM. If set to true, you must shut down the server
// manually with Stop().
NoSignalHandling bool
// Logger used to notify of errors on startup and on stop.
Logger *log.Logger
// LogFunc can be assigned with a logging function of your choice, allowing
// you to use whatever logging approach you would like
LogFunc func(format string, args ...interface{})
// Interrupted is true if the server is handling a SIGINT or SIGTERM
// signal and is thus shutting down.
Interrupted bool
// interrupt signals the listener to stop serving connections,
// and the server to shut down.
interrupt chan os.Signal
// stopLock is used to protect against concurrent calls to Stop
stopLock sync.Mutex
// stopChan is the channel on which callers may block while waiting for
// the server to stop.
stopChan chan struct{}
// chanLock is used to protect access to the various channel constructors.
chanLock sync.RWMutex
// connections holds all connections managed by graceful
connections map[net.Conn]struct{}
// idleConnections holds all idle connections managed by graceful
idleConnections map[net.Conn]struct{}
}
// Run serves the http.Handler with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Run(addr string, timeout time.Duration, n http.Handler) {
srv := &Server{
Timeout: timeout,
TCPKeepAlive: 3 * time.Minute,
Server: &http.Server{Addr: addr, Handler: n},
// Logger: DefaultLogger(),
}
if err := srv.ListenAndServe(); err != nil {
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
srv.logf("%s", err)
os.Exit(1)
}
}
}
// RunWithErr is an alternative version of Run function which can return error.
//
// Unlike Run this version will not exit the program if an error is encountered but will
// return it instead.
func RunWithErr(addr string, timeout time.Duration, n http.Handler) error {
srv := &Server{
Timeout: timeout,
TCPKeepAlive: 3 * time.Minute,
Server: &http.Server{Addr: addr, Handler: n},
Logger: DefaultLogger(),
}
return srv.ListenAndServe()
}
// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServe(server *http.Server, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.ListenAndServe()
}
// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
func (srv *Server) ListenAndServe() error {
// Create the listener so we can control their lifetime
addr := srv.Addr
if addr == "" {
addr = ":http"
}
conn, err := srv.newTCPListener(addr)
if err != nil {
return err
}
return srv.Serve(conn)
}
// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.ListenAndServeTLS(certFile, keyFile)
}
// ListenTLS is a convenience method that creates an https listener using the
// provided cert and key files. Use this method if you need access to the
// listener object directly. When ready, pass it to the Serve method.
func (srv *Server) ListenTLS(certFile, keyFile string) (net.Listener, error) {
// Create the listener ourselves so we can control its lifetime
addr := srv.Addr
if addr == "" {
addr = ":https"
}
config := &tls.Config{}
if srv.TLSConfig != nil {
*config = *srv.TLSConfig
}
var err error
config.Certificates = make([]tls.Certificate, 1)
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
// Enable http2
enableHTTP2ForTLSConfig(config)
conn, err := srv.newTCPListener(addr)
if err != nil {
return nil, err
}
srv.TLSConfig = config
tlsListener := tls.NewListener(conn, config)
return tlsListener, nil
}
// Enable HTTP2ForTLSConfig explicitly enables http/2 for a TLS Config. This is due to changes in Go 1.7 where
// http servers are no longer automatically configured to enable http/2 if the server's TLSConfig is set.
// See https://github.com/golang/go/issues/15908
func enableHTTP2ForTLSConfig(t *tls.Config) {
if TLSConfigHasHTTP2Enabled(t) {
return
}
t.NextProtos = append(t.NextProtos, "h2")
}
// TLSConfigHasHTTP2Enabled checks to see if a given TLS Config has http2 enabled.
func TLSConfigHasHTTP2Enabled(t *tls.Config) bool {
for _, value := range t.NextProtos {
if value == "h2" {
return true
}
}
return false
}
// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
l, err := srv.ListenTLS(certFile, keyFile)
if err != nil {
return err
}
return srv.Serve(l)
}
// ListenAndServeTLSConfig can be used with an existing TLS config and is equivalent to
// http.Server.ListenAndServeTLS with graceful shutdown enabled,
func (srv *Server) ListenAndServeTLSConfig(config *tls.Config) error {
addr := srv.Addr
if addr == "" {
addr = ":https"
}
conn, err := srv.newTCPListener(addr)
if err != nil {
return err
}
srv.TLSConfig = config
tlsListener := tls.NewListener(conn, config)
return srv.Serve(tlsListener)
}
// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Serve(server *http.Server, l net.Listener, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.Serve(l)
}
// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
func (srv *Server) Serve(listener net.Listener) error {
if srv.ListenLimit != 0 {
listener = LimitListener(listener, srv.ListenLimit)
}
// Make our stopchan
srv.StopChan()
// Track connection state
add := make(chan net.Conn)
idle := make(chan net.Conn)
active := make(chan net.Conn)
remove := make(chan net.Conn)
srv.Server.ConnState = func(conn net.Conn, state http.ConnState) {
switch state {
case http.StateNew:
add <- conn
case http.StateActive:
active <- conn
case http.StateIdle:
idle <- conn
case http.StateClosed, http.StateHijacked:
remove <- conn
}
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
if srv.ConnState != nil {
srv.ConnState(conn, state)
}
}
// Manage open connections
shutdown := make(chan chan struct{})
kill := make(chan struct{})
go srv.manageConnections(add, idle, active, remove, shutdown, kill)
interrupt := srv.interruptChan()
// Set up the interrupt handler
if !srv.NoSignalHandling {
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
}
quitting := make(chan struct{})
go srv.handleInterrupt(interrupt, quitting, listener)
// Serve with graceful listener.
// Execution blocks here until listener.Close() is called, above.
err := srv.Server.Serve(listener)
if err != nil {
// If the underlying listening is closed, Serve returns an error
// complaining about listening on a closed socket. This is expected, so
// let's ignore the error if we are the ones who explicitly closed the
// socket.
select {
case <-quitting:
err = nil
default:
}
}
srv.shutdown(shutdown, kill)
return err
}
// Stop instructs the type to halt operations and close
// the stop channel when it is finished.
//
// timeout is grace period for which to wait before shutting
// down the server. The timeout value passed here will override the
// timeout given when constructing the server, as this is an explicit
// command to stop the server.
func (srv *Server) Stop(timeout time.Duration) {
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
srv.Timeout = timeout
interrupt := srv.interruptChan()
interrupt <- syscall.SIGINT
}
// StopChan gets the stop channel which will block until
// stopping has completed, at which point it is closed.
// Callers should never close the stop channel.
func (srv *Server) StopChan() <-chan struct{} {
srv.chanLock.Lock()
defer srv.chanLock.Unlock()
if srv.stopChan == nil {
srv.stopChan = make(chan struct{})
}
return srv.stopChan
}
// DefaultLogger returns the logger used by Run, RunWithErr, ListenAndServe, ListenAndServeTLS and Serve.
// The logger outputs to STDERR by default.
func DefaultLogger() *log.Logger {
return log.New(os.Stderr, "[graceful] ", 0)
}
func (srv *Server) manageConnections(add, idle, active, remove chan net.Conn, shutdown chan chan struct{}, kill chan struct{}) {
var done chan struct{}
srv.connections = map[net.Conn]struct{}{}
srv.idleConnections = map[net.Conn]struct{}{}
for {
select {
case conn := <-add:
srv.connections[conn] = struct{}{}
case conn := <-idle:
srv.idleConnections[conn] = struct{}{}
case conn := <-active:
delete(srv.idleConnections, conn)
case conn := <-remove:
delete(srv.connections, conn)
delete(srv.idleConnections, conn)
if done != nil && len(srv.connections) == 0 {
done <- struct{}{}
return
}
case done = <-shutdown:
if len(srv.connections) == 0 && len(srv.idleConnections) == 0 {
done <- struct{}{}
return
}
// a shutdown request has been received. if we have open idle
// connections, we must close all of them now. this prevents idle
// connections from holding the server open while waiting for them to
// hit their idle timeout.
for k := range srv.idleConnections {
if err := k.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
}
case <-kill:
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
srv.Server.ConnState = nil
for k := range srv.connections {
if err := k.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
}
return
}
}
}
func (srv *Server) interruptChan() chan os.Signal {
srv.chanLock.Lock()
defer srv.chanLock.Unlock()
if srv.interrupt == nil {
srv.interrupt = make(chan os.Signal, 1)
}
return srv.interrupt
}
func (srv *Server) handleInterrupt(interrupt chan os.Signal, quitting chan struct{}, listener net.Listener) {
for _ = range interrupt {
if srv.Interrupted {
srv.logf("already shutting down")
continue
}
srv.logf("shutdown initiated")
srv.Interrupted = true
if srv.BeforeShutdown != nil {
if !srv.BeforeShutdown() {
srv.Interrupted = false
continue
}
}
close(quitting)
srv.SetKeepAlivesEnabled(false)
if err := listener.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
if srv.ShutdownInitiated != nil {
srv.ShutdownInitiated()
}
}
}
func (srv *Server) logf(format string, args ...interface{}) {
if srv.LogFunc != nil {
srv.LogFunc(format, args...)
} else if srv.Logger != nil {
srv.Logger.Printf(format, args...)
}
}
func (srv *Server) shutdown(shutdown chan chan struct{}, kill chan struct{}) {
// Request done notification
done := make(chan struct{})
shutdown <- done
if srv.Timeout > 0 {
select {
case <-done:
case <-time.After(srv.Timeout):
close(kill)
}
} else {
<-done
}
// Close the stopChan to wake up any blocked goroutines.
srv.chanLock.Lock()
if srv.stopChan != nil {
close(srv.stopChan)
}
srv.chanLock.Unlock()
}
func (srv *Server) newTCPListener(addr string) (net.Listener, error) {
conn, err := net.Listen("tcp", addr)
if err != nil {
return conn, err
}
if srv.TCPKeepAlive != 0 {
conn = keepAliveListener{conn, srv.TCPKeepAlive}
}
return conn, nil
}

692
vendor/github.com/tylerb/graceful/graceful_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,692 @@
package graceful
import (
"bytes"
"fmt"
"io"
"log"
"net"
"net/http"
"net/url"
"os"
"reflect"
"strings"
"sync"
"syscall"
"testing"
"time"
)
const (
// The tests will run a test server on this port.
port = 9654
concurrentRequestN = 8
killTime = 500 * time.Millisecond
timeoutTime = 1000 * time.Millisecond
waitTime = 100 * time.Millisecond
)
func runQuery(t *testing.T, expected int, shouldErr bool, wg *sync.WaitGroup, once *sync.Once) {
defer wg.Done()
client := http.Client{}
r, err := client.Get(fmt.Sprintf("http://localhost:%d", port))
if shouldErr && err == nil {
once.Do(func() {
t.Error("Expected an error but none was encountered.")
})
} else if shouldErr && err != nil {
if checkErr(t, err, once) {
return
}
}
if r != nil && r.StatusCode != expected {
once.Do(func() {
t.Errorf("Incorrect status code on response. Expected %d. Got %d", expected, r.StatusCode)
})
} else if r == nil {
once.Do(func() {
t.Error("No response when a response was expected.")
})
}
}
func checkErr(t *testing.T, err error, once *sync.Once) bool {
if err.(*url.Error).Err == io.EOF {
return true
}
var errno syscall.Errno
switch oe := err.(*url.Error).Err.(type) {
case *net.OpError:
switch e := oe.Err.(type) {
case syscall.Errno:
errno = e
case *os.SyscallError:
errno = e.Err.(syscall.Errno)
}
if errno == syscall.ECONNREFUSED {
return true
} else if err != nil {
once.Do(func() {
t.Error("Error on Get:", err)
})
}
default:
if strings.Contains(err.Error(), "transport closed before response was received") {
return true
}
if strings.Contains(err.Error(), "server closed connection") {
return true
}
fmt.Printf("unknown err: %s, %#v\n", err, err)
}
return false
}
func createListener(sleep time.Duration) (*http.Server, net.Listener, error) {
mux := http.NewServeMux()
mux.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
time.Sleep(sleep)
rw.WriteHeader(http.StatusOK)
})
server := &http.Server{Addr: fmt.Sprintf(":%d", port), Handler: mux}
l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
return server, l, err
}
func launchTestQueries(t *testing.T, wg *sync.WaitGroup, c chan os.Signal) {
defer wg.Done()
var once sync.Once
for i := 0; i < concurrentRequestN; i++ {
wg.Add(1)
go runQuery(t, http.StatusOK, false, wg, &once)
}
time.Sleep(waitTime)
c <- os.Interrupt
time.Sleep(waitTime)
for i := 0; i < concurrentRequestN; i++ {
wg.Add(1)
go runQuery(t, 0, true, wg, &once)
}
}
func TestGracefulRun(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime / 2)
if err != nil {
t.Fatal(err)
}
wg.Add(1)
go func() {
defer wg.Done()
srv := &Server{Timeout: killTime, Server: server, interrupt: c}
srv.Serve(l)
}()
wg.Add(1)
go launchTestQueries(t, &wg, c)
}
func TestGracefulRunLimitKeepAliveListener(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime / 2)
if err != nil {
t.Fatal(err)
}
wg.Add(1)
go func() {
defer wg.Done()
srv := &Server{
Timeout: killTime,
ListenLimit: concurrentRequestN,
TCPKeepAlive: 1 * time.Second,
Server: server,
interrupt: c,
}
srv.Serve(l)
}()
wg.Add(1)
go launchTestQueries(t, &wg, c)
}
func TestGracefulRunTimesOut(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime * 10)
if err != nil {
t.Fatal(err)
}
wg.Add(1)
go func() {
defer wg.Done()
srv := &Server{Timeout: killTime, Server: server, interrupt: c}
srv.Serve(l)
}()
wg.Add(1)
go func() {
defer wg.Done()
var once sync.Once
for i := 0; i < concurrentRequestN; i++ {
wg.Add(1)
go runQuery(t, 0, true, &wg, &once)
}
time.Sleep(waitTime)
c <- os.Interrupt
time.Sleep(waitTime)
for i := 0; i < concurrentRequestN; i++ {
wg.Add(1)
go runQuery(t, 0, true, &wg, &once)
}
}()
}
func TestGracefulRunDoesntTimeOut(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime * 2)
if err != nil {
t.Fatal(err)
}
wg.Add(1)
go func() {
defer wg.Done()
srv := &Server{Timeout: 0, Server: server, interrupt: c}
srv.Serve(l)
}()
wg.Add(1)
go launchTestQueries(t, &wg, c)
}
func TestGracefulRunDoesntTimeOutAfterConnectionCreated(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime)
if err != nil {
t.Fatal(err)
}
wg.Add(1)
go func() {
defer wg.Done()
srv := &Server{Timeout: 0, Server: server, interrupt: c}
srv.Serve(l)
}()
time.Sleep(waitTime)
// Make a sample first request. The connection will be left idle.
resp, err := http.Get(fmt.Sprintf("http://localhost:%d", port))
if err != nil {
panic(fmt.Sprintf("first request failed: %v", err))
}
resp.Body.Close()
wg.Add(1)
go func() {
defer wg.Done()
// With idle connections improperly handled, the server doesn't wait for this
// to complete and the request fails. It should be allowed to complete successfully.
_, err := http.Get(fmt.Sprintf("http://localhost:%d", port))
if err != nil {
t.Errorf("Get failed: %v", err)
}
}()
// Ensure the request goes out
time.Sleep(waitTime)
c <- os.Interrupt
wg.Wait()
}
func TestGracefulRunNoRequests(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime * 2)
if err != nil {
t.Fatal(err)
}
wg.Add(1)
go func() {
defer wg.Done()
srv := &Server{Timeout: 0, Server: server, interrupt: c}
srv.Serve(l)
}()
c <- os.Interrupt
}
func TestGracefulForwardsConnState(t *testing.T) {
var stateLock sync.Mutex
states := make(map[http.ConnState]int)
connState := func(conn net.Conn, state http.ConnState) {
stateLock.Lock()
states[state]++
stateLock.Unlock()
}
var wg sync.WaitGroup
defer wg.Wait()
expected := map[http.ConnState]int{
http.StateNew: concurrentRequestN,
http.StateActive: concurrentRequestN,
http.StateClosed: concurrentRequestN,
}
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime / 2)
if err != nil {
t.Fatal(err)
}
wg.Add(1)
go func() {
defer wg.Done()
srv := &Server{
ConnState: connState,
Timeout: killTime,
Server: server,
interrupt: c,
}
srv.Serve(l)
}()
wg.Add(1)
go launchTestQueries(t, &wg, c)
wg.Wait()
stateLock.Lock()
if !reflect.DeepEqual(states, expected) {
t.Errorf("Incorrect connection state tracking.\n actual: %v\nexpected: %v\n", states, expected)
}
stateLock.Unlock()
}
func TestGracefulExplicitStop(t *testing.T) {
server, l, err := createListener(1 * time.Millisecond)
if err != nil {
t.Fatal(err)
}
srv := &Server{Timeout: killTime, Server: server}
go func() {
go srv.Serve(l)
time.Sleep(waitTime)
srv.Stop(killTime)
}()
// block on the stopChan until the server has shut down
select {
case <-srv.StopChan():
case <-time.After(timeoutTime):
t.Fatal("Timed out while waiting for explicit stop to complete")
}
}
func TestGracefulExplicitStopOverride(t *testing.T) {
server, l, err := createListener(1 * time.Millisecond)
if err != nil {
t.Fatal(err)
}
srv := &Server{Timeout: killTime, Server: server}
go func() {
go srv.Serve(l)
time.Sleep(waitTime)
srv.Stop(killTime / 2)
}()
// block on the stopChan until the server has shut down
select {
case <-srv.StopChan():
case <-time.After(killTime):
t.Fatal("Timed out while waiting for explicit stop to complete")
}
}
func TestBeforeShutdownAndShutdownInitiatedCallbacks(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
server, l, err := createListener(1 * time.Millisecond)
if err != nil {
t.Fatal(err)
}
beforeShutdownCalled := make(chan struct{})
cb1 := func() bool { close(beforeShutdownCalled); return true }
shutdownInitiatedCalled := make(chan struct{})
cb2 := func() { close(shutdownInitiatedCalled) }
wg.Add(2)
srv := &Server{Server: server, BeforeShutdown: cb1, ShutdownInitiated: cb2}
go func() {
defer wg.Done()
srv.Serve(l)
}()
go func() {
defer wg.Done()
time.Sleep(waitTime)
srv.Stop(killTime)
}()
beforeShutdown := false
shutdownInitiated := false
for i := 0; i < 2; i++ {
select {
case <-beforeShutdownCalled:
beforeShutdownCalled = nil
beforeShutdown = true
case <-shutdownInitiatedCalled:
shutdownInitiatedCalled = nil
shutdownInitiated = true
case <-time.After(killTime):
t.Fatal("Timed out while waiting for ShutdownInitiated callback to be called")
}
}
if !beforeShutdown {
t.Fatal("beforeShutdown should be true")
}
if !shutdownInitiated {
t.Fatal("shutdownInitiated should be true")
}
}
func TestBeforeShutdownCanceled(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
server, l, err := createListener(1 * time.Millisecond)
if err != nil {
t.Fatal(err)
}
beforeShutdownCalled := make(chan struct{})
cb1 := func() bool { close(beforeShutdownCalled); return false }
shutdownInitiatedCalled := make(chan struct{})
cb2 := func() { close(shutdownInitiatedCalled) }
srv := &Server{Server: server, BeforeShutdown: cb1, ShutdownInitiated: cb2}
go func() {
srv.Serve(l)
wg.Done()
}()
go func() {
time.Sleep(waitTime)
srv.Stop(killTime)
}()
beforeShutdown := false
shutdownInitiated := false
timeouted := false
for i := 0; i < 2; i++ {
select {
case <-beforeShutdownCalled:
beforeShutdownCalled = nil
beforeShutdown = true
case <-shutdownInitiatedCalled:
shutdownInitiatedCalled = nil
shutdownInitiated = true
case <-time.After(killTime):
timeouted = true
}
}
if !beforeShutdown {
t.Fatal("beforeShutdown should be true")
}
if !timeouted {
t.Fatal("timeouted should be true")
}
if shutdownInitiated {
t.Fatal("shutdownInitiated shouldn't be true")
}
srv.BeforeShutdown = func() bool { return true }
srv.Stop(killTime)
wg.Wait()
}
func hijackingListener(srv *Server) (*http.Server, net.Listener, error) {
mux := http.NewServeMux()
mux.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
conn, bufrw, err := rw.(http.Hijacker).Hijack()
if err != nil {
http.Error(rw, "webserver doesn't support hijacking", http.StatusInternalServerError)
return
}
defer conn.Close()
bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n")
bufrw.Flush()
})
server := &http.Server{Addr: fmt.Sprintf(":%d", port), Handler: mux}
l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
return server, l, err
}
func TestNotifyClosed(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan os.Signal, 1)
srv := &Server{Timeout: killTime, interrupt: c}
server, l, err := hijackingListener(srv)
if err != nil {
t.Fatal(err)
}
srv.Server = server
wg.Add(1)
go func() {
defer wg.Done()
srv.Serve(l)
}()
var once sync.Once
for i := 0; i < concurrentRequestN; i++ {
wg.Add(1)
runQuery(t, http.StatusOK, false, &wg, &once)
}
srv.Stop(0)
// block on the stopChan until the server has shut down
select {
case <-srv.StopChan():
case <-time.After(timeoutTime):
t.Fatal("Timed out while waiting for explicit stop to complete")
}
if len(srv.connections) > 0 {
t.Fatal("hijacked connections should not be managed")
}
}
func TestStopDeadlock(t *testing.T) {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan struct{})
server, l, err := createListener(1 * time.Millisecond)
if err != nil {
t.Fatal(err)
}
srv := &Server{Server: server, NoSignalHandling: true}
wg.Add(2)
go func() {
defer wg.Done()
time.Sleep(waitTime)
srv.Serve(l)
}()
go func() {
defer wg.Done()
srv.Stop(0)
close(c)
}()
select {
case <-c:
l.Close()
case <-time.After(timeoutTime):
t.Fatal("Timed out while waiting for explicit stop to complete")
}
}
// Run with --race
func TestStopRace(t *testing.T) {
server, l, err := createListener(1 * time.Millisecond)
if err != nil {
t.Fatal(err)
}
srv := &Server{Timeout: killTime, Server: server}
go func() {
go srv.Serve(l)
srv.Stop(killTime)
}()
srv.Stop(0)
select {
case <-srv.StopChan():
case <-time.After(timeoutTime):
t.Fatal("Timed out while waiting for explicit stop to complete")
}
}
func TestInterruptLog(t *testing.T) {
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime * 10)
if err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
var tbuf bytes.Buffer
logger := log.New(&buf, "", 0)
expected := log.New(&tbuf, "", 0)
srv := &Server{Timeout: killTime, Server: server, Logger: logger, interrupt: c}
go func() { srv.Serve(l) }()
stop := srv.StopChan()
c <- os.Interrupt
expected.Print("shutdown initiated")
<-stop
if buf.String() != tbuf.String() {
t.Fatal("shutdown log incorrect - got '" + buf.String() + "'")
}
}
func TestMultiInterrupts(t *testing.T) {
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime * 10)
if err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
var bu bytes.Buffer
buf := SyncBuffer{&wg, &bu}
var tbuf bytes.Buffer
logger := log.New(&buf, "", 0)
expected := log.New(&tbuf, "", 0)
srv := &Server{Timeout: killTime, Server: server, Logger: logger, interrupt: c}
go func() { srv.Serve(l) }()
stop := srv.StopChan()
buf.Add(1 + 10) // Expecting 11 log calls
c <- os.Interrupt
expected.Printf("shutdown initiated")
for i := 0; i < 10; i++ {
c <- os.Interrupt
expected.Printf("already shutting down")
}
<-stop
wg.Wait()
bb, bt := buf.Bytes(), tbuf.Bytes()
for i, b := range bb {
if b != bt[i] {
t.Fatal(fmt.Sprintf("shutdown log incorrect - got '%s', expected '%s'", buf.String(), tbuf.String()))
}
}
}
func TestLogFunc(t *testing.T) {
c := make(chan os.Signal, 1)
server, l, err := createListener(killTime * 10)
if err != nil {
t.Fatal(err)
}
var called bool
srv := &Server{Timeout: killTime, Server: server,
LogFunc: func(format string, args ...interface{}) {
called = true
}, interrupt: c}
stop := srv.StopChan()
go func() { srv.Serve(l) }()
c <- os.Interrupt
<-stop
if called != true {
t.Fatal("Expected LogFunc to be called.")
}
}
// SyncBuffer calls Done on the embedded wait group after each call to Write.
type SyncBuffer struct {
*sync.WaitGroup
*bytes.Buffer
}
func (buf *SyncBuffer) Write(b []byte) (int, error) {
defer buf.Done()
return buf.Buffer.Write(b)
}

125
vendor/github.com/tylerb/graceful/http2_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,125 @@
// +build go1.6
package graceful
import (
"crypto/tls"
"fmt"
"net/http"
"os"
"sync"
"testing"
"time"
"golang.org/x/net/http2"
)
func createServer() *http.Server {
mux := http.NewServeMux()
mux.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
})
server := &http.Server{Addr: fmt.Sprintf(":%d", port), Handler: mux}
return server
}
func checkIfConnectionToServerIsHTTP2(t *testing.T, wg *sync.WaitGroup, c chan os.Signal) {
defer wg.Done()
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
err := http2.ConfigureTransport(tr)
if err != nil {
t.Fatal("Unable to upgrade client transport to HTTP/2")
}
client := http.Client{Transport: tr}
r, err := client.Get(fmt.Sprintf("https://localhost:%d", port))
c <- os.Interrupt
if err != nil {
t.Fatalf("Error encountered while connecting to test server: %s", err)
}
if !r.ProtoAtLeast(2, 0) {
t.Fatalf("Expected HTTP/2 connection to server, but connection was using %s", r.Proto)
}
}
func TestHTTP2ListenAndServeTLS(t *testing.T) {
c := make(chan os.Signal, 1)
var wg sync.WaitGroup
wg.Add(1)
server := createServer()
var srv *Server
go func() {
// set timeout of 0 to test idle connection closing
srv = &Server{Timeout: 0, TCPKeepAlive: 1 * time.Minute, Server: server, interrupt: c}
srv.ListenAndServeTLS("test-fixtures/cert.crt", "test-fixtures/key.pem")
wg.Done()
}()
time.Sleep(waitTime) // Wait for the server to start
wg.Add(1)
go checkIfConnectionToServerIsHTTP2(t, &wg, c)
wg.Wait()
c <- os.Interrupt // kill the server to close idle connections
// block on the stopChan until the server has shut down
select {
case <-srv.StopChan():
case <-time.After(killTime * 2):
t.Fatal("Timed out while waiting for explicit stop to complete")
}
}
func TestHTTP2ListenAndServeTLSConfig(t *testing.T) {
c := make(chan os.Signal, 1)
var wg sync.WaitGroup
wg.Add(1)
server2 := createServer()
go func() {
srv := &Server{Timeout: killTime, TCPKeepAlive: 1 * time.Minute, Server: server2, interrupt: c}
cert, err := tls.LoadX509KeyPair("test-fixtures/cert.crt", "test-fixtures/key.pem")
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
tlsConf := &tls.Config{
Certificates: []tls.Certificate{cert},
NextProtos: []string{"h2"}, // We need to explicitly enable http/2 in Go 1.7+
}
tlsConf.BuildNameToCertificate()
srv.ListenAndServeTLSConfig(tlsConf)
wg.Done()
}()
time.Sleep(waitTime) // Wait for the server to start
wg.Add(1)
go checkIfConnectionToServerIsHTTP2(t, &wg, c)
wg.Wait()
}

32
vendor/github.com/tylerb/graceful/keepalive_listener.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,32 @@
package graceful
import (
"net"
"time"
)
type keepAliveConn interface {
SetKeepAlive(bool) error
SetKeepAlivePeriod(d time.Duration) error
}
// keepAliveListener 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.
type keepAliveListener struct {
net.Listener
keepAlivePeriod time.Duration
}
func (ln keepAliveListener) Accept() (net.Conn, error) {
c, err := ln.Listener.Accept()
if err != nil {
return nil, err
}
kac := c.(keepAliveConn)
kac.SetKeepAlive(true)
kac.SetKeepAlivePeriod(ln.keepAlivePeriod)
return c, nil
}

77
vendor/github.com/tylerb/graceful/limit_listen.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,77 @@
// Copyright 2013 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package graceful
import (
"errors"
"net"
"sync"
"time"
)
// ErrNotTCP indicates that network connection is not a TCP connection.
var ErrNotTCP = errors.New("only tcp connections have keepalive")
// LimitListener returns a Listener that accepts at most n simultaneous
// connections from the provided Listener.
func LimitListener(l net.Listener, n int) net.Listener {
return &limitListener{l, make(chan struct{}, n)}
}
type limitListener struct {
net.Listener
sem chan struct{}
}
func (l *limitListener) acquire() { l.sem <- struct{}{} }
func (l *limitListener) release() { <-l.sem }
func (l *limitListener) Accept() (net.Conn, error) {
l.acquire()
c, err := l.Listener.Accept()
if err != nil {
l.release()
return nil, err
}
return &limitListenerConn{Conn: c, release: l.release}, nil
}
type limitListenerConn struct {
net.Conn
releaseOnce sync.Once
release func()
}
func (l *limitListenerConn) Close() error {
err := l.Conn.Close()
l.releaseOnce.Do(l.release)
return err
}
func (l *limitListenerConn) SetKeepAlive(doKeepAlive bool) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlive(doKeepAlive)
}
func (l *limitListenerConn) SetKeepAlivePeriod(d time.Duration) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlivePeriod(d)
}

43
vendor/github.com/tylerb/graceful/test-fixtures/cert.crt сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,43 @@
-----BEGIN CERTIFICATE-----
MIIDhTCCAm2gAwIBAgIUDvdWhjUd/JS+E5bxZlmCM+giGHMwDQYJKoZIhvcNAQEL
BQAwHzEdMBsGA1UEAxMUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTYwNjAyMDMy
MjA0WhcNMTkwNjAyMDMyMjM0WjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDoyMTUK2OSp+XhKRXB/+uO6YAJE/W
2rzqARahWT6boHZMDhHXRtdwYxWwiUqoxlEeBrEerQ2qPFAqlWkDw8zliE/DWgXg
BiW+Vq5DAn3F1jZ5WskLWr1iP48oK4/l+BXEsDd44MHZFoSZiWlr2Fi4iaIHJE7+
LGBqPVQXwBYTyc7Jvi3HY8I4/waaAwXoSo8vDPjRiMCD2wlg24Rimocf4goa/2Xs
Z0NU76Uf2jPdsZ5MujjKRqwHDEAjiBq0aPvm6igkNGAGoZ6QYEptO+J4t1oFrbdP
gYRlpqCa3ekr9gc+wg5AO/V9x8/cypbQ8tpwFwvvSYg2TJaUMZ5abc+HAgMBAAGj
gcMwgcAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQC
R0Y69NLOfFCLRiB5N3uoacILXTAfBgNVHSMEGDAWgBRm0fFHSXtDCVHC8UW7/obv
DLp9tTBJBggrBgEFBQcBAQQ9MDswOQYIKwYBBQUHMAKGLWh0dHA6Ly9sb2NhbGhv
c3Qvc2VsZi1pc3N1ZWQtaW50ZXJtZWRpYXRlLmNydDAUBgNVHREEDTALgglsb2Nh
bGhvc3QwDQYJKoZIhvcNAQELBQADggEBALAf/nowwB0NJ7lGGaoVKhmMHxBEQkd1
K/jBAlJg9Kgmg1IJJ7zLE3SeYF8tGTNYATd4RLmqo1GakrMDaKWNXd74v3p/tWmb
4vqCh6WzFPHU1dpxDKtbbmaLt9Ije7s6DuQAz9bBXM0mN0vy5F0dORpx/j0h3u1B
j7B5O8kLejPY2w/8pd+QECCb1Q5A6Xx1EEsJpzTlGXO0SBla/oCg+nvirsBGVpWr
bGskAIwG9wNKuGfg4m5u1bL87iX80NemeLtWRWVM+Ry/RhfOokH59/EIFRAXeRz6
gXjIWa0vcXnhW1MOvbD1GFYhO6AJAnDwWes48WfBHysOhq0RycdpGw0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIUMzpit8+j2dWxdk1PdMqGWYalZyIwDQYJKoZIhvcNAQEL
BQAwFzEVMBMGA1UEAxMMVGVzdCBSb290IENBMB4XDTE2MDUyOTEwNDYwMFoXDTMx
MDUyNjEwNDYzMFowHzEdMBsGA1UEAxMUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDs6kY6mHJWzupq5dsSavPZHuv6
0E9PczHbujWLuzv7+qbwzcAgfRvaeR0xgvf7q9pjMgJ7/kNANgneWGpwciLgHtiJ
rSHii3RZfWlK4gdbCXya9EmHj8zO+9xGBHM0FrqfqA+IA70SimFcwGPrGHyERsdX
+mqO64Z95yI5uJpoS8OBAUPU8i6xvNLZGmgUEF3CRhDDTYVGcTEtKAPcnnBuZzZU
Ds+DrHf/MC7HHK0/l0auuRz3p+/GFNePGePG+FFbInS/vwHwrkMW2tzBKG41K+gD
GfkTjVU8xBSiMYOiEja6YcJ4GuzEPcmu5LS+6BkLlsIbazDW5IM8p+7+8RKjAgMB
AAGjgcgwgcUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
BBYEFGbR8UdJe0MJUcLxRbv+hu8Mun21MB8GA1UdIwQYMBaAFKmz0h3CW1HBO9uz
uCzg+MNPGZtkMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAoYlaHR0cDovL2xv
Y2FsaG9zdC9zZWxmLWlzc3VlZC1yb290LmNydDAfBgNVHREEGDAWghRUZXN0IElu
dGVybWVkaWF0ZSBDQTANBgkqhkiG9w0BAQsFAAOCAQEAaYVGqHbaE0c9F/kyIMgu
S3HuNn4pBh2EwGcKIlPkDe43hqXjhS/+itmWk75rQz+Rw+acevGoxbpDR38abTIS
RJd9L/3MA644z8F82er3pNjKqvS/vTre/wsvGYwmEM+GrgJw3HUcisc93qLgaWH2
kjky208k9kOuzJDiY45eu9TfSSmjSHSMCtxk8p5wYKDcfVz+uqlBhVEiHGjQIc2E
66SituusiwgQv/mdtEW7y48EvMGdzxPfLFcvj06B3vTsZaaYyB6GyKwMcaPFvHRr
V0yYaKRZgAh4X6LHlgPJqvIv3gjMdJR55durAO7tI9Pos0o5Lv5WJgi0g0KvMsco
qQ==
-----END CERTIFICATE-----

27
vendor/github.com/tylerb/graceful/test-fixtures/key.pem сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAw6MjE1Ctjkqfl4SkVwf/rjumACRP1tq86gEWoVk+m6B2TA4R
10bXcGMVsIlKqMZRHgaxHq0NqjxQKpVpA8PM5YhPw1oF4AYlvlauQwJ9xdY2eVrJ
C1q9Yj+PKCuP5fgVxLA3eODB2RaEmYlpa9hYuImiByRO/ixgaj1UF8AWE8nOyb4t
x2PCOP8GmgMF6EqPLwz40YjAg9sJYNuEYpqHH+IKGv9l7GdDVO+lH9oz3bGeTLo4
ykasBwxAI4gatGj75uooJDRgBqGekGBKbTvieLdaBa23T4GEZaagmt3pK/YHPsIO
QDv1fcfP3MqW0PLacBcL70mINkyWlDGeWm3PhwIDAQABAoIBAQC87HWa2XZAyt+D
OpxZT2ghoYiU6nwPR/zXHWX1OnGzaCnVGGEyOz8hUQ5JBMwMYDdFf8DbltJzavsf
pFldQWBE6HXeeLjjtgwM2zg9jdJXkp3YY0tyo5XvouFkMW0s735WCrYHDUUllxFG
E+SyOKK00nSd4PpHiiMxdTgYF286exwOpzjhcJfAkn7oBNeOGc5VLOvcvakrSrdq
OYBAJ25HSVFnSQbeAAsCzBEBZC0WLyB1BQGcidbtEn8sxyGnV8HWjbXY+MJQWHg+
q2iK+uvO4wtrE/WC6p4Ty44Myh+AB79s35HWKYd4okwKkpI1QdD543TIiZnkNEVI
aS/uH13BAoGBAP/psBxKzIft59hw+U9NscH6N9/ze8iAtOtqsWdER/qXCrlUn8+j
F/xquJR6gDj5GwGBt07asEuoG8CKJMQI0c3AeHF7XBcmUunBStktb9O97Zsp6bNJ
olsrWlM4yvVuCVizEwIYjHrMBOS3YIPErM1LmAyDHmzx3+yz+3+WxRQLAoGBAMO0
MaJDPisMC05pvieHRb91HlsiSrASeMkw1FmHI0b/gcC88mEnuXIze1ySoF6FE7B7
xaEm6Lf5Snl0JgXPDSj6ukd51NdaU2VmpKvDOrvQ5QQE9mXaDkXv/i2B0YkCh+Hy
bkziW1IKnWT2PTRAAEIJQ22oK51MdQnvCdmtsIP1AoGBAKnMiEl9Z9AZDmgSLZls
17D5MPGrQEp8+43oMOVv7MJcTYVCnPbMJDIbLXV3AnTK9Bw/0TzE5YyNcjyCbHqV
z39RYZkKXMQPbZwj4GHRQA2iS3FUkfeft9X+IeRuHlxSMmlkCAyv9SXVELog4i0L
5gwhSDWlGh73LbiEgy7Y/tKZAoGBALTiMhYGDMoA4dpiBi3G7AKgH6SgN2QyTo22
oi71pveSZb1dZrHB47fYOadApxV17tLqM6pVqjeRJPLJFfO8gi9kPxSdWMqLZBWP
H5jaY8kAtQxYAd32A8dEoSwylxcJzcpbJvPNLBbSVNPifIN0vEhNA5OxIk7LQkoi
NHqL/WCZAoGAPf3kb9Gw/NkBq4Cn86pQfP/xE0h7zcoNmFtLbdKIjId+DDDOPOeX
9tm33fZzw0SG4KlRQlsqgzFvm8aDD8rpW17341Z/rWlLo8uHNdRkMvbSabc34vPv
4lrs0rHSYW06MlqkJBNVraySRz7hmU4+n7YMvNI0Due9mVGmE1NU/vI=
-----END RSA PRIVATE KEY-----

40
vendor/github.com/tylerb/graceful/tests/main.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,40 @@
package main
import (
"fmt"
"sync"
"github.com/urfave/negroni"
"gopkg.in/tylerb/graceful.v1"
)
func main() {
var wg sync.WaitGroup
wg.Add(3)
go func() {
n := negroni.New()
fmt.Println("Launching server on :3000")
graceful.Run(":3000", 0, n)
fmt.Println("Terminated server on :3000")
wg.Done()
}()
go func() {
n := negroni.New()
fmt.Println("Launching server on :3001")
graceful.Run(":3001", 0, n)
fmt.Println("Terminated server on :3001")
wg.Done()
}()
go func() {
n := negroni.New()
fmt.Println("Launching server on :3002")
graceful.Run(":3002", 0, n)
fmt.Println("Terminated server on :3002")
wg.Done()
}()
fmt.Println("Press ctrl+c. All servers should terminate.")
wg.Wait()
}