diff --git a/cmd/apps/skychat/chat.go b/cmd/apps/skychat/chat.go index 1e1358c039..7b76f44313 100644 --- a/cmd/apps/skychat/chat.go +++ b/cmd/apps/skychat/chat.go @@ -4,6 +4,7 @@ skychat app for skywire visor package main import ( + "context" "embed" "encoding/json" "flag" @@ -19,9 +20,9 @@ import ( ipc "github.com/james-barrow/golang-ipc" "github.com/skycoin/dmsg/buildinfo" "github.com/skycoin/dmsg/cipher" + dmsgnetutil "github.com/skycoin/dmsg/netutil" "github.com/skycoin/skycoin/src/util/logging" - "github.com/skycoin/skywire/internal/netutil" "github.com/skycoin/skywire/pkg/app" "github.com/skycoin/skywire/pkg/app/appnet" "github.com/skycoin/skywire/pkg/routing" @@ -35,7 +36,7 @@ const ( var log = logging.MustGetLogger("chat") var addr = flag.String("addr", ":8001", "address to bind") -var r = netutil.NewRetrier(50*time.Millisecond, 5, 2, log) +var r = dmsgnetutil.NewRetrier(log, 50*time.Millisecond, dmsgnetutil.DefaultMaxBackoff, 5, 2) var ( appC *app.Client @@ -74,9 +75,11 @@ func main() { } go handleIPCSignal(ipcClient) } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() http.Handle("/", http.FileServer(getFileSystem())) - http.HandleFunc("/message", messageHandler) + http.HandleFunc("/message", messageHandler(ctx)) http.HandleFunc("/sse", sseHandler) fmt.Print("Serving HTTP on", *addr) @@ -140,55 +143,58 @@ func handleConn(conn net.Conn) { } } -func messageHandler(w http.ResponseWriter, req *http.Request) { - data := map[string]string{} - if err := json.NewDecoder(req.Body).Decode(&data); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - pk := cipher.PubKey{} - if err := pk.UnmarshalText([]byte(data["recipient"])); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } +func messageHandler(ctx context.Context) func(w http.ResponseWriter, rreq *http.Request) { + return func(w http.ResponseWriter, req *http.Request) { - addr := appnet.Addr{ - Net: netType, - PubKey: pk, - Port: 1, - } - connsMu.Lock() - conn, ok := conns[pk] - connsMu.Unlock() + data := map[string]string{} + if err := json.NewDecoder(req.Body).Decode(&data); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } - if !ok { - var err error - err = r.Do(func() error { - conn, err = appC.Dial(addr) - return err - }) - if err != nil { + pk := cipher.PubKey{} + if err := pk.UnmarshalText([]byte(data["recipient"])); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } + addr := appnet.Addr{ + Net: netType, + PubKey: pk, + Port: 1, + } connsMu.Lock() - conns[pk] = conn + conn, ok := conns[pk] connsMu.Unlock() - go handleConn(conn) - } + if !ok { + var err error + err = r.Do(ctx, func() error { + conn, err = appC.Dial(addr) + return err + }) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } - _, err := conn.Write([]byte(data["message"])) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) + connsMu.Lock() + conns[pk] = conn + connsMu.Unlock() - connsMu.Lock() - delete(conns, pk) - connsMu.Unlock() + go handleConn(conn) + } - return + _, err := conn.Write([]byte(data["message"])) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + + connsMu.Lock() + delete(conns, pk) + connsMu.Unlock() + + return + } } } diff --git a/cmd/apps/skysocks-client/skysocks-client.go b/cmd/apps/skysocks-client/skysocks-client.go index ac2962086f..37f52cee47 100644 --- a/cmd/apps/skysocks-client/skysocks-client.go +++ b/cmd/apps/skysocks-client/skysocks-client.go @@ -4,6 +4,7 @@ proxy client app for skywire visor package main import ( + "context" "flag" "io" "net" @@ -13,8 +14,8 @@ import ( "github.com/sirupsen/logrus" "github.com/skycoin/dmsg/buildinfo" "github.com/skycoin/dmsg/cipher" + dmsgnetutil "github.com/skycoin/dmsg/netutil" - "github.com/skycoin/skywire/internal/netutil" "github.com/skycoin/skywire/internal/skysocks" "github.com/skycoin/skywire/pkg/app" "github.com/skycoin/skywire/pkg/app/appnet" @@ -29,11 +30,11 @@ const ( var log = logrus.New() -var r = netutil.NewRetrier(time.Second, 0, 1, log) +var r = dmsgnetutil.NewRetrier(log, time.Second, dmsgnetutil.DefaultMaxBackoff, 0, 1) -func dialServer(appCl *app.Client, pk cipher.PubKey) (net.Conn, error) { +func dialServer(ctx context.Context, appCl *app.Client, pk cipher.PubKey) (net.Conn, error) { var conn net.Conn - err := r.Do(func() error { + err := r.Do(ctx, func() error { var err error conn, err = appCl.Dial(appnet.Addr{ Net: netType, @@ -55,6 +56,9 @@ func main() { skysocks.Log = log + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + if _, err := buildinfo.Get().WriteTo(os.Stdout); err != nil { log.Printf("Failed to output build info: %v", err) } @@ -74,7 +78,7 @@ func main() { } for { - conn, err := dialServer(appC, pk) + conn, err := dialServer(ctx, appC, pk) if err != nil { log.Fatalf("Failed to dial to a server: %v", err) } diff --git a/go.mod b/go.mod index 81c8ea0331..cc122c9565 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/pkg/profile v1.5.0 github.com/shirou/gopsutil/v3 v3.21.4 github.com/sirupsen/logrus v1.8.1 - github.com/skycoin/dmsg v0.0.0-20220125173526-46bb07d7fd64 + github.com/skycoin/dmsg v0.0.0-20220302151611-e4368629eed2 github.com/skycoin/skycoin v0.27.1 github.com/skycoin/yamux v0.0.0-20200803175205-571ceb89da9f github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 @@ -63,7 +63,6 @@ require ( github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect github.com/getlantern/errors v1.0.1 // indirect github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect - github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-ole/go-ole v1.2.4 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/google/go-querystring v1.0.0 // indirect diff --git a/go.sum b/go.sum index 7744e64ee5..1174bdd4d6 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,6 @@ github.com/getlantern/systray v1.1.0 h1:U0wCEqseLi2ok1fE6b88gJklzriavPJixZysZPkZ github.com/getlantern/systray v1.1.0/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= -github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi/v5 v5.0.8-0.20220103230436-7dbe9a0bd10f h1:6kLofhLkWj7lgCc+mvcVLnwhTzQYgL/yW/Y0e/JYwjg= github.com/go-chi/chi/v5 v5.0.8-0.20220103230436-7dbe9a0bd10f/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -405,8 +403,8 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skycoin/dmsg v0.0.0-20220125173526-46bb07d7fd64 h1:XEg/CXSPx2JbZpxLxuxm2CeZ648yMXz+pymY+VIHbyk= -github.com/skycoin/dmsg v0.0.0-20220125173526-46bb07d7fd64/go.mod h1:EgRg8fy5RjF67OJlh9w+vhq3+Phyn6AXKSedkzhf1ww= +github.com/skycoin/dmsg v0.0.0-20220302151611-e4368629eed2 h1:K3iy7UEWuHE55HFTZIcg5fNYkyO/P5oxErioEQixFfA= +github.com/skycoin/dmsg v0.0.0-20220302151611-e4368629eed2/go.mod h1:9Q9sh2ph1GqdtTBOq4rg8VHsbE/WGBH20mntnN4ckfM= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6 h1:1Nc5EBY6pjfw1kwW0duwyG+7WliWz5u9kgk1h5MnLuA= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:UXghlricA7J3aRD/k7p/zBObQfmBawwCxIVPVjz2Q3o= github.com/skycoin/skycoin v0.26.0/go.mod h1:78nHjQzd8KG0jJJVL/j0xMmrihXi70ti63fh8vXScJw= @@ -696,7 +694,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/netutil/retrier.go b/internal/netutil/retrier.go deleted file mode 100644 index 5aff01f138..0000000000 --- a/internal/netutil/retrier.go +++ /dev/null @@ -1,106 +0,0 @@ -package netutil - -import ( - "errors" - "time" - - "github.com/sirupsen/logrus" -) - -// Package errors -var ( - ErrMaximumRetriesReached = errors.New("maximum retries attempted without success") -) - -// RetryFunc is a function used as argument of (*Retrier).Do(), which will retry on error unless it is whitelisted -type RetryFunc func() error - -// Retrier holds a configuration for how retries should be performed -type Retrier struct { - exponentialBackoff time.Duration // multiplied on every retry by a exponentialFactor - exponentialFactor uint32 // multiplier for the backoff duration that is applied on every retry - times uint32 // number of times that the given function is going to be retried until success, if 0 it will be retried forever until success - errWhitelist map[error]struct{} - log logrus.FieldLogger -} - -// NewRetrier returns a retrier that is ready to call Do() method -func NewRetrier(exponentialBackoff time.Duration, times, factor uint32, log logrus.FieldLogger) *Retrier { - logger := log.WithField("func", "retrier") - return &Retrier{ - exponentialBackoff: exponentialBackoff, - times: times, - exponentialFactor: factor, - errWhitelist: make(map[error]struct{}), - log: logger, - } -} - -// WithErrWhitelist sets a list of errors into the retrier, if the RetryFunc provided to Do() fails with one of them it will return inmediatelly with such error. Calling -// this function is not thread-safe, and is advised to only use it when initializing the Retrier -func (r *Retrier) WithErrWhitelist(errors ...error) *Retrier { - m := make(map[error]struct{}) - for _, err := range errors { - m[err] = struct{}{} - } - - r.errWhitelist = m - return r -} - -// Do takes a RetryFunc and attempts to execute it, if it fails with an error it will be retried a maximum of given times with an exponentialBackoff, until it returns -// nil or an error that is whitelisted -func (r Retrier) Do(f RetryFunc) error { - if r.times == 0 { - return r.retryUntilSuccess(f) - } - - return r.retryNTimes(f) -} - -func (r Retrier) retryNTimes(f RetryFunc) error { - currentBackoff := r.exponentialBackoff - - for i := uint32(0); i < r.times; i++ { - err := f() - if err != nil { - if r.isWhitelisted(err) { - return err - } - - r.log.Warn(err) - currentBackoff *= time.Duration(r.exponentialFactor) - time.Sleep(currentBackoff) - continue - } - - return nil - } - - return ErrMaximumRetriesReached -} - -func (r Retrier) retryUntilSuccess(f RetryFunc) error { - currentBackoff := r.exponentialBackoff - - for { - err := f() - if err != nil { - if r.isWhitelisted(err) { - return err - } - - r.log.Warn(err) - currentBackoff *= time.Duration(r.exponentialFactor) - time.Sleep(currentBackoff) - continue - } - - return nil - } -} - -func (r Retrier) isWhitelisted(err error) bool { - _, ok := r.errWhitelist[err] - return ok -} diff --git a/internal/netutil/retrier_test.go b/internal/netutil/retrier_test.go deleted file mode 100644 index 7dff1d1962..0000000000 --- a/internal/netutil/retrier_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package netutil - -import ( - "errors" - "testing" - "time" - - "github.com/skycoin/skycoin/src/util/logging" - "github.com/stretchr/testify/require" -) - -func TestRetrier_Do(t *testing.T) { - log := logging.MustGetLogger("test") - r := NewRetrier(time.Millisecond*100, 3, 2, log) - c := 0 - threshold := 2 - f := func() error { - c++ - if c >= threshold { - return nil - } - - return errors.New("foo") - } - - t.Run("should retry", func(t *testing.T) { - c = 0 - - err := r.Do(f) - require.NoError(t, err) - }) - - t.Run("if retry reaches max number of times should error", func(t *testing.T) { - c = 0 - threshold = 4 - defer func() { - threshold = 2 - }() - - err := r.Do(f) - require.Error(t, err) - }) - - t.Run("should return whitelisted errors if any instead of retry", func(t *testing.T) { - bar := errors.New("bar") - wR := NewRetrier(50*time.Millisecond, 1, 2, log).WithErrWhitelist(bar) - barF := func() error { - return bar - } - - err := wR.Do(barF) - require.EqualError(t, err, bar.Error()) - }) - - t.Run("if times is 0, should retry until success", func(t *testing.T) { - c = 0 - loopR := NewRetrier(50*time.Millisecond, 0, 1, log) - err := loopR.Do(f) - require.NoError(t, err) - - require.Equal(t, threshold, c) - }) -} diff --git a/internal/utclient/client.go b/internal/utclient/client.go index efeec8b448..673c32304d 100644 --- a/internal/utclient/client.go +++ b/internal/utclient/client.go @@ -9,10 +9,10 @@ import ( "time" "github.com/skycoin/dmsg/cipher" + dmsgnetutil "github.com/skycoin/dmsg/netutil" "github.com/skycoin/skycoin/src/util/logging" "github.com/skycoin/skywire/internal/httpauth" - "github.com/skycoin/skywire/internal/netutil" ) //go:generate mockery -name APIClient -case underscore -inpkg @@ -46,7 +46,7 @@ func NewHTTP(addr string, pk cipher.PubKey, sk cipher.SecKey, httpC *http.Client log := mLogger.PackageLogger("utclient") - retrier := netutil.NewRetrier(createRetryDelay, 10, 2, log) + retrier := dmsgnetutil.NewRetrier(log, createRetryDelay, 0, 10, 2) retrierFunc := func() error { client, err = httpauth.NewClient(context.Background(), addr, pk, sk, httpC, clientPublicIP, mLogger) if err != nil { @@ -55,7 +55,7 @@ func NewHTTP(addr string, pk cipher.PubKey, sk cipher.SecKey, httpC *http.Client return nil } - if err := retrier.Do(retrierFunc); err != nil { + if err := retrier.Do(context.Background(), retrierFunc); err != nil { return nil, err } diff --git a/internal/vpn/client.go b/internal/vpn/client.go index 29e4e11def..6926490619 100644 --- a/internal/vpn/client.go +++ b/internal/vpn/client.go @@ -16,7 +16,7 @@ import ( ipc "github.com/james-barrow/golang-ipc" "github.com/sirupsen/logrus" "github.com/skycoin/dmsg/cipher" - "github.com/skycoin/dmsg/netutil" + dmsgnetutil "github.com/skycoin/dmsg/netutil" "github.com/skycoin/skywire/pkg/app" "github.com/skycoin/skywire/pkg/app/appnet" @@ -25,7 +25,7 @@ import ( "github.com/skycoin/skywire/pkg/router" "github.com/skycoin/skywire/pkg/routing" "github.com/skycoin/skywire/pkg/skyenv" - skynetutil "github.com/skycoin/skywire/pkg/util/netutil" + "github.com/skycoin/skywire/pkg/util/netutil" ) const ( @@ -198,7 +198,7 @@ func (c *Client) Serve() error { Err: rfclient.ErrTransportNotFound.Error(), } - r := netutil.NewRetrier(c.log, netutil.DefaultInitBackoff, netutil.DefaultMaxBackoff, 3, netutil.DefaultFactor). + r := dmsgnetutil.NewRetrier(c.log, dmsgnetutil.DefaultInitBackoff, dmsgnetutil.DefaultMaxBackoff, 3, dmsgnetutil.DefaultFactor). WithErrWhitelist(errHandshakeStatusForbidden, errHandshakeStatusInternalError, errHandshakeNoFreeIPs, errHandshakeStatusBadRequest, errNoTransportFound, errTransportNotFound) @@ -707,7 +707,7 @@ func stcpEntitiesFromEnv() ([]net.IP, error) { } func (c *Client) shakeHands(conn net.Conn) (TUNIP, TUNGateway net.IP, err error) { - unavailableIPs, err := skynetutil.LocalNetworkInterfaceIPs() + unavailableIPs, err := netutil.LocalNetworkInterfaceIPs() if err != nil { return nil, nil, fmt.Errorf("error getting unavailable private IPs: %w", err) } diff --git a/pkg/servicedisc/autoconnect.go b/pkg/servicedisc/autoconnect.go index 26f5aa25d5..7188e2746a 100644 --- a/pkg/servicedisc/autoconnect.go +++ b/pkg/servicedisc/autoconnect.go @@ -9,9 +9,9 @@ import ( "github.com/sirupsen/logrus" "github.com/skycoin/dmsg/cipher" + dmsgnetutil "github.com/skycoin/dmsg/netutil" "github.com/skycoin/skycoin/src/util/logging" - "github.com/skycoin/skywire/internal/netutil" "github.com/skycoin/skywire/pkg/transport" "github.com/skycoin/skywire/pkg/transport/network" ) @@ -105,7 +105,7 @@ func (a *autoconnector) tryEstablishTransport(ctx context.Context, pk cipher.Pub } func (a *autoconnector) fetchPubAddresses(ctx context.Context) ([]cipher.PubKey, error) { - retrier := netutil.NewRetrier(fetchServicesDelay, 5, 3, a.log) + retrier := dmsgnetutil.NewRetrier(a.log, fetchServicesDelay, 0, 5, 3) var services []Service fetch := func() (err error) { // "return" services up from the closure @@ -115,7 +115,7 @@ func (a *autoconnector) fetchPubAddresses(ctx context.Context) ([]cipher.PubKey, } return nil } - if err := retrier.Do(fetch); err != nil { + if err := retrier.Do(ctx, fetch); err != nil { return nil, err } pks := make([]cipher.PubKey, len(services)) diff --git a/pkg/servicedisc/client.go b/pkg/servicedisc/client.go index 1444399165..15d9b46694 100644 --- a/pkg/servicedisc/client.go +++ b/pkg/servicedisc/client.go @@ -16,10 +16,10 @@ import ( "github.com/sirupsen/logrus" "github.com/skycoin/dmsg/buildinfo" "github.com/skycoin/dmsg/cipher" + dmsgnetutil "github.com/skycoin/dmsg/netutil" "github.com/skycoin/skycoin/src/util/logging" "github.com/skycoin/skywire/internal/httpauth" - nu "github.com/skycoin/skywire/internal/netutil" "github.com/skycoin/skywire/pkg/util/netutil" ) @@ -282,7 +282,7 @@ func (c *HTTPClient) DeleteEntry(ctx context.Context) (err error) { // it performs exponential backoff in case of errors during register, unless // the error is unrecoverable from func (c *HTTPClient) Register(ctx context.Context) error { - retrier := nu.NewRetrier(updateRetryDelay, 0, 2, c.log).WithErrWhitelist(ErrVisorUnreachable) + retrier := dmsgnetutil.NewRetrier(c.log, updateRetryDelay, 0, 0, 2).WithErrWhitelist(ErrVisorUnreachable) run := func() error { err := c.RegisterEntry(ctx) @@ -292,10 +292,9 @@ func (c *HTTPClient) Register(ctx context.Context) error { } if err != nil { - c.log.WithError(err).Warn("Failed to register service entry in discovery. Retrying...") return err } return nil } - return retrier.Do(run) + return retrier.Do(ctx, run) } diff --git a/pkg/transport/managed_transport.go b/pkg/transport/managed_transport.go index b599dbe733..b0d4db183b 100644 --- a/pkg/transport/managed_transport.go +++ b/pkg/transport/managed_transport.go @@ -13,9 +13,9 @@ import ( "github.com/skycoin/dmsg/cipher" "github.com/skycoin/dmsg/httputil" + dmsgnetutil "github.com/skycoin/dmsg/netutil" "github.com/skycoin/skycoin/src/util/logging" - "github.com/skycoin/skywire/internal/netutil" "github.com/skycoin/skywire/pkg/app/appevent" "github.com/skycoin/skywire/pkg/routing" "github.com/skycoin/skywire/pkg/skyenv" @@ -338,8 +338,8 @@ func (mt *ManagedTransport) setTransport(newTransport network.Transport) error { } func (mt *ManagedTransport) deleteFromDiscovery() error { - retrier := netutil.NewRetrier(1*time.Second, 5, 2, mt.log) - return retrier.Do(func() error { + retrier := dmsgnetutil.NewRetrier(mt.log, 1*time.Second, dmsgnetutil.DefaultMaxBackoff, 5, 2) + return retrier.Do(context.Background(), func() error { err := mt.dc.DeleteTransport(context.Background(), mt.Entry.ID) mt.log.WithField("tp-id", mt.Entry.ID).WithError(err).Debug("Error deleting transport") if netErr, ok := err.(net.Error); ok && netErr.Temporary() { diff --git a/pkg/transport/network/addrresolver/client.go b/pkg/transport/network/addrresolver/client.go index 6165deade2..fe698cfec2 100644 --- a/pkg/transport/network/addrresolver/client.go +++ b/pkg/transport/network/addrresolver/client.go @@ -130,8 +130,7 @@ func (c *httpClient) initHTTPClient(httpC *http.Client) { c.log.WithError(err). Warnf("Failed to connect to address resolver. STCPR/SUDPH services are temporarily unavailable. Retrying...") - retryLog := c.mLog.PackageLogger("network.arclient.retrier") - retry := dmsgnetutil.NewRetrier(retryLog, 1*time.Second, 10*time.Second, 0, 1) + retry := dmsgnetutil.NewRetrier(c.log, 1*time.Second, 10*time.Second, 0, 1) err := retry.Do(context.Background(), func() error { httpAuthClient, err = httpauth.NewClient(context.Background(), c.remoteHTTPAddr, c.pk, c.sk, httpC, c.clientPublicIP, c.mLog) diff --git a/pkg/visor/init.go b/pkg/visor/init.go index bf74f305fd..f90a676cc5 100644 --- a/pkg/visor/init.go +++ b/pkg/visor/init.go @@ -416,7 +416,9 @@ func initStcpClient(ctx context.Context, v *Visor, log *logging.Logger) error { func initTransport(ctx context.Context, v *Visor, log *logging.Logger) error { - tpdC, err := connectToTpDisc(ctx, v) + managerLogger := v.MasterLogger().PackageLogger("transport_manager") + + tpdC, err := connectToTpDisc(ctx, v, managerLogger) if err != nil { err := fmt.Errorf("failed to create transport discovery client: %w", err) return err @@ -437,7 +439,6 @@ func initTransport(ctx context.Context, v *Visor, log *logging.Logger) error { LogStore: logS, PersistentTransportsCache: pTps, } - managerLogger := v.MasterLogger().PackageLogger("transport_manager") // todo: pass down configuration? var table stcp.PKTable @@ -1045,7 +1046,7 @@ func initHypervisor(_ context.Context, v *Visor, log *logging.Logger) error { return nil } -func connectToTpDisc(ctx context.Context, v *Visor) (transport.DiscoveryClient, error) { +func connectToTpDisc(ctx context.Context, v *Visor, log *logging.Logger) (transport.DiscoveryClient, error) { const ( initBO = 1 * time.Second maxBO = 10 * time.Second @@ -1067,7 +1068,6 @@ func connectToTpDisc(ctx context.Context, v *Visor) (transport.DiscoveryClient, return nil, err } - log := v.MasterLogger().PackageLogger("tp_disc_retrier") tpdCRetrier := dmsgnetutil.NewRetrier(log, initBO, maxBO, tries, factor) diff --git a/pkg/visor/rpc_client_serve.go b/pkg/visor/rpc_client_serve.go index c9e449225d..64a5b2fd70 100644 --- a/pkg/visor/rpc_client_serve.go +++ b/pkg/visor/rpc_client_serve.go @@ -8,7 +8,7 @@ import ( "github.com/sirupsen/logrus" "github.com/skycoin/dmsg" - "github.com/skycoin/dmsg/netutil" + dmsgnetutil "github.com/skycoin/dmsg/netutil" ) func isDone(ctx context.Context) bool { @@ -23,7 +23,7 @@ func isDone(ctx context.Context) bool { // ServeRPCClient repetitively dials to a remote dmsg address and serves a RPC server to that address. func ServeRPCClient(ctx context.Context, log logrus.FieldLogger, dmsgC *dmsg.Client, rpcS *rpc.Server, rAddr dmsg.Addr, errCh chan<- error) { const maxBackoff = time.Second * 5 - retry := netutil.NewRetrier(log, netutil.DefaultInitBackoff, maxBackoff, netutil.DefaultTries, netutil.DefaultFactor) + retry := dmsgnetutil.NewRetrier(log, dmsgnetutil.DefaultInitBackoff, maxBackoff, dmsgnetutil.DefaultTries, dmsgnetutil.DefaultFactor) for { var conn net.Conn diff --git a/vendor/github.com/go-chi/chi/.gitignore b/vendor/github.com/go-chi/chi/.gitignore deleted file mode 100644 index ba22c99a99..0000000000 --- a/vendor/github.com/go-chi/chi/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.idea -*.sw? -.vscode diff --git a/vendor/github.com/go-chi/chi/.travis.yml b/vendor/github.com/go-chi/chi/.travis.yml deleted file mode 100644 index 7b8e26bcee..0000000000 --- a/vendor/github.com/go-chi/chi/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: go - -go: - - 1.10.x - - 1.11.x - - 1.12.x - - 1.13.x - - 1.14.x - -script: - - go get -d -t ./... - - go vet ./... - - go test ./... - - > - go_version=$(go version); - if [ ${go_version:13:4} = "1.12" ]; then - go get -u golang.org/x/tools/cmd/goimports; - goimports -d -e ./ | grep '.*' && { echo; echo "Aborting due to non-empty goimports output."; exit 1; } || :; - fi - diff --git a/vendor/github.com/go-chi/chi/CHANGELOG.md b/vendor/github.com/go-chi/chi/CHANGELOG.md deleted file mode 100644 index 9a64a72eec..0000000000 --- a/vendor/github.com/go-chi/chi/CHANGELOG.md +++ /dev/null @@ -1,190 +0,0 @@ -# Changelog - -## v4.1.2 (2020-06-02) - -- fix that handles MethodNotAllowed with path variables, thank you @caseyhadden for your contribution -- fix to replace nested wildcards correctly in RoutePattern, thank you @@unmultimedio for your contribution -- History of changes: see https://github.com/go-chi/chi/compare/v4.1.1...v4.1.2 - - -## v4.1.1 (2020-04-16) - -- fix for issue https://github.com/go-chi/chi/issues/411 which allows for overlapping regexp - route to the correct handler through a recursive tree search, thanks to @Jahaja for the PR/fix! -- new middleware.RouteHeaders as a simple router for request headers with wildcard support -- History of changes: see https://github.com/go-chi/chi/compare/v4.1.0...v4.1.1 - - -## v4.1.0 (2020-04-1) - -- middleware.LogEntry: Write method on interface now passes the response header - and an extra interface type useful for custom logger implementations. -- middleware.WrapResponseWriter: minor fix -- middleware.Recoverer: a bit prettier -- History of changes: see https://github.com/go-chi/chi/compare/v4.0.4...v4.1.0 - - -## v4.0.4 (2020-03-24) - -- middleware.Recoverer: new pretty stack trace printing (https://github.com/go-chi/chi/pull/496) -- a few minor improvements and fixes -- History of changes: see https://github.com/go-chi/chi/compare/v4.0.3...v4.0.4 - - -## v4.0.3 (2020-01-09) - -- core: fix regexp routing to include default value when param is not matched -- middleware: rewrite of middleware.Compress -- middleware: suppress http.ErrAbortHandler in middleware.Recoverer -- History of changes: see https://github.com/go-chi/chi/compare/v4.0.2...v4.0.3 - - -## v4.0.2 (2019-02-26) - -- Minor fixes -- History of changes: see https://github.com/go-chi/chi/compare/v4.0.1...v4.0.2 - - -## v4.0.1 (2019-01-21) - -- Fixes issue with compress middleware: #382 #385 -- History of changes: see https://github.com/go-chi/chi/compare/v4.0.0...v4.0.1 - - -## v4.0.0 (2019-01-10) - -- chi v4 requires Go 1.10.3+ (or Go 1.9.7+) - we have deprecated support for Go 1.7 and 1.8 -- router: respond with 404 on router with no routes (#362) -- router: additional check to ensure wildcard is at the end of a url pattern (#333) -- middleware: deprecate use of http.CloseNotifier (#347) -- middleware: fix RedirectSlashes to include query params on redirect (#334) -- History of changes: see https://github.com/go-chi/chi/compare/v3.3.4...v4.0.0 - - -## v3.3.4 (2019-01-07) - -- Minor middleware improvements. No changes to core library/router. Moving v3 into its -- own branch as a version of chi for Go 1.7, 1.8, 1.9, 1.10, 1.11 -- History of changes: see https://github.com/go-chi/chi/compare/v3.3.3...v3.3.4 - - -## v3.3.3 (2018-08-27) - -- Minor release -- See https://github.com/go-chi/chi/compare/v3.3.2...v3.3.3 - - -## v3.3.2 (2017-12-22) - -- Support to route trailing slashes on mounted sub-routers (#281) -- middleware: new `ContentCharset` to check matching charsets. Thank you - @csucu for your community contribution! - - -## v3.3.1 (2017-11-20) - -- middleware: new `AllowContentType` handler for explicit whitelist of accepted request Content-Types -- middleware: new `SetHeader` handler for short-hand middleware to set a response header key/value -- Minor bug fixes - - -## v3.3.0 (2017-10-10) - -- New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage -- Deprecated LINK and UNLINK methods from the default list, please use `chi.RegisterMethod("LINK")` and `chi.RegisterMethod("UNLINK")` in an `init()` function - - -## v3.2.1 (2017-08-31) - -- Add new `Match(rctx *Context, method, path string) bool` method to `Routes` interface - and `Mux`. Match searches the mux's routing tree for a handler that matches the method/path -- Add new `RouteMethod` to `*Context` -- Add new `Routes` pointer to `*Context` -- Add new `middleware.GetHead` to route missing HEAD requests to GET handler -- Updated benchmarks (see README) - - -## v3.1.5 (2017-08-02) - -- Setup golint and go vet for the project -- As per golint, we've redefined `func ServerBaseContext(h http.Handler, baseCtx context.Context) http.Handler` - to `func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler` - - -## v3.1.0 (2017-07-10) - -- Fix a few minor issues after v3 release -- Move `docgen` sub-pkg to https://github.com/go-chi/docgen -- Move `render` sub-pkg to https://github.com/go-chi/render -- Add new `URLFormat` handler to chi/middleware sub-pkg to make working with url mime - suffixes easier, ie. parsing `/articles/1.json` and `/articles/1.xml`. See comments in - https://github.com/go-chi/chi/blob/master/middleware/url_format.go for example usage. - - -## v3.0.0 (2017-06-21) - -- Major update to chi library with many exciting updates, but also some *breaking changes* -- URL parameter syntax changed from `/:id` to `/{id}` for even more flexible routing, such as - `/articles/{month}-{day}-{year}-{slug}`, `/articles/{id}`, and `/articles/{id}.{ext}` on the - same router -- Support for regexp for routing patterns, in the form of `/{paramKey:regExp}` for example: - `r.Get("/articles/{name:[a-z]+}", h)` and `chi.URLParam(r, "name")` -- Add `Method` and `MethodFunc` to `chi.Router` to allow routing definitions such as - `r.Method("GET", "/", h)` which provides a cleaner interface for custom handlers like - in `_examples/custom-handler` -- Deprecating `mux#FileServer` helper function. Instead, we encourage users to create their - own using file handler with the stdlib, see `_examples/fileserver` for an example -- Add support for LINK/UNLINK http methods via `r.Method()` and `r.MethodFunc()` -- Moved the chi project to its own organization, to allow chi-related community packages to - be easily discovered and supported, at: https://github.com/go-chi -- *NOTE:* please update your import paths to `"github.com/go-chi/chi"` -- *NOTE:* chi v2 is still available at https://github.com/go-chi/chi/tree/v2 - - -## v2.1.0 (2017-03-30) - -- Minor improvements and update to the chi core library -- Introduced a brand new `chi/render` sub-package to complete the story of building - APIs to offer a pattern for managing well-defined request / response payloads. Please - check out the updated `_examples/rest` example for how it works. -- Added `MethodNotAllowed(h http.HandlerFunc)` to chi.Router interface - - -## v2.0.0 (2017-01-06) - -- After many months of v2 being in an RC state with many companies and users running it in - production, the inclusion of some improvements to the middlewares, we are very pleased to - announce v2.0.0 of chi. - - -## v2.0.0-rc1 (2016-07-26) - -- Huge update! chi v2 is a large refactor targetting Go 1.7+. As of Go 1.7, the popular - community `"net/context"` package has been included in the standard library as `"context"` and - utilized by `"net/http"` and `http.Request` to managing deadlines, cancelation signals and other - request-scoped values. We're very excited about the new context addition and are proud to - introduce chi v2, a minimal and powerful routing package for building large HTTP services, - with zero external dependencies. Chi focuses on idiomatic design and encourages the use of - stdlib HTTP handlers and middlwares. -- chi v2 deprecates its `chi.Handler` interface and requires `http.Handler` or `http.HandlerFunc` -- chi v2 stores URL routing parameters and patterns in the standard request context: `r.Context()` -- chi v2 lower-level routing context is accessible by `chi.RouteContext(r.Context()) *chi.Context`, - which provides direct access to URL routing parameters, the routing path and the matching - routing patterns. -- Users upgrading from chi v1 to v2, need to: - 1. Update the old chi.Handler signature, `func(ctx context.Context, w http.ResponseWriter, r *http.Request)` to - the standard http.Handler: `func(w http.ResponseWriter, r *http.Request)` - 2. Use `chi.URLParam(r *http.Request, paramKey string) string` - or `URLParamFromCtx(ctx context.Context, paramKey string) string` to access a url parameter value - - -## v1.0.0 (2016-07-01) - -- Released chi v1 stable https://github.com/go-chi/chi/tree/v1.0.0 for Go 1.6 and older. - - -## v0.9.0 (2016-03-31) - -- Reuse context objects via sync.Pool for zero-allocation routing [#33](https://github.com/go-chi/chi/pull/33) -- BREAKING NOTE: due to subtle API changes, previously `chi.URLParams(ctx)["id"]` used to access url parameters - has changed to: `chi.URLParam(ctx, "id")` diff --git a/vendor/github.com/go-chi/chi/CONTRIBUTING.md b/vendor/github.com/go-chi/chi/CONTRIBUTING.md deleted file mode 100644 index c0ac2dfe85..0000000000 --- a/vendor/github.com/go-chi/chi/CONTRIBUTING.md +++ /dev/null @@ -1,31 +0,0 @@ -# Contributing - -## Prerequisites - -1. [Install Go][go-install]. -2. Download the sources and switch the working directory: - - ```bash - go get -u -d github.com/go-chi/chi - cd $GOPATH/src/github.com/go-chi/chi - ``` - -## Submitting a Pull Request - -A typical workflow is: - -1. [Fork the repository.][fork] [This tip maybe also helpful.][go-fork-tip] -2. [Create a topic branch.][branch] -3. Add tests for your change. -4. Run `go test`. If your tests pass, return to the step 3. -5. Implement the change and ensure the steps from the previous step pass. -6. Run `goimports -w .`, to ensure the new code conforms to Go formatting guideline. -7. [Add, commit and push your changes.][git-help] -8. [Submit a pull request.][pull-req] - -[go-install]: https://golang.org/doc/install -[go-fork-tip]: http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html -[fork]: https://help.github.com/articles/fork-a-repo -[branch]: http://learn.github.com/p/branching.html -[git-help]: https://guides.github.com -[pull-req]: https://help.github.com/articles/using-pull-requests diff --git a/vendor/github.com/go-chi/chi/LICENSE b/vendor/github.com/go-chi/chi/LICENSE deleted file mode 100644 index d99f02ffac..0000000000 --- a/vendor/github.com/go-chi/chi/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc. - -MIT License - -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. diff --git a/vendor/github.com/go-chi/chi/README.md b/vendor/github.com/go-chi/chi/README.md deleted file mode 100644 index 5a8fc9d096..0000000000 --- a/vendor/github.com/go-chi/chi/README.md +++ /dev/null @@ -1,441 +0,0 @@ -# chi - - -[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis] - -`chi` is a lightweight, idiomatic and composable router for building Go HTTP services. It's -especially good at helping you write large REST API services that are kept maintainable as your -project grows and changes. `chi` is built on the new `context` package introduced in Go 1.7 to -handle signaling, cancelation and request-scoped values across a handler chain. - -The focus of the project has been to seek out an elegant and comfortable design for writing -REST API servers, written during the development of the Pressly API service that powers our -public API service, which in turn powers all of our client-side applications. - -The key considerations of chi's design are: project structure, maintainability, standard http -handlers (stdlib-only), developer productivity, and deconstructing a large system into many small -parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also -included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render) and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too! - -## Install - -`go get -u github.com/go-chi/chi` - - -## Features - -* **Lightweight** - cloc'd in ~1000 LOC for the chi router -* **Fast** - yes, see [benchmarks](#benchmarks) -* **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http` -* **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and subrouter mounting -* **Context control** - built on new `context` package, providing value chaining, cancellations and timeouts -* **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91)) -* **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown -* **No external dependencies** - plain ol' Go stdlib + net/http - - -## Examples - -See [_examples/](https://github.com/go-chi/chi/blob/master/_examples/) for a variety of examples. - - -**As easy as:** - -```go -package main - -import ( - "net/http" - - "github.com/go-chi/chi" - "github.com/go-chi/chi/middleware" -) - -func main() { - r := chi.NewRouter() - r.Use(middleware.Logger) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("welcome")) - }) - http.ListenAndServe(":3000", r) -} -``` - -**REST Preview:** - -Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs -in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in -Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)). - -I highly recommend reading the source of the [examples](https://github.com/go-chi/chi/blob/master/_examples/) listed -above, they will show you all the features of chi and serve as a good form of documentation. - -```go -import ( - //... - "context" - "github.com/go-chi/chi" - "github.com/go-chi/chi/middleware" -) - -func main() { - r := chi.NewRouter() - - // A good base middleware stack - r.Use(middleware.RequestID) - r.Use(middleware.RealIP) - r.Use(middleware.Logger) - r.Use(middleware.Recoverer) - - // Set a timeout value on the request context (ctx), that will signal - // through ctx.Done() that the request has timed out and further - // processing should be stopped. - r.Use(middleware.Timeout(60 * time.Second)) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hi")) - }) - - // RESTy routes for "articles" resource - r.Route("/articles", func(r chi.Router) { - r.With(paginate).Get("/", listArticles) // GET /articles - r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017 - - r.Post("/", createArticle) // POST /articles - r.Get("/search", searchArticles) // GET /articles/search - - // Regexp url parameters: - r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto - - // Subrouters: - r.Route("/{articleID}", func(r chi.Router) { - r.Use(ArticleCtx) - r.Get("/", getArticle) // GET /articles/123 - r.Put("/", updateArticle) // PUT /articles/123 - r.Delete("/", deleteArticle) // DELETE /articles/123 - }) - }) - - // Mount the admin sub-router - r.Mount("/admin", adminRouter()) - - http.ListenAndServe(":3333", r) -} - -func ArticleCtx(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - articleID := chi.URLParam(r, "articleID") - article, err := dbGetArticle(articleID) - if err != nil { - http.Error(w, http.StatusText(404), 404) - return - } - ctx := context.WithValue(r.Context(), "article", article) - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} - -func getArticle(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - article, ok := ctx.Value("article").(*Article) - if !ok { - http.Error(w, http.StatusText(422), 422) - return - } - w.Write([]byte(fmt.Sprintf("title:%s", article.Title))) -} - -// A completely separate router for administrator routes -func adminRouter() http.Handler { - r := chi.NewRouter() - r.Use(AdminOnly) - r.Get("/", adminIndex) - r.Get("/accounts", adminListAccounts) - return r -} - -func AdminOnly(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - perm, ok := ctx.Value("acl.permission").(YourPermissionType) - if !ok || !perm.IsAdmin() { - http.Error(w, http.StatusText(403), 403) - return - } - next.ServeHTTP(w, r) - }) -} -``` - - -## Router design - -chi's router is based on a kind of [Patricia Radix trie](https://en.wikipedia.org/wiki/Radix_tree). -The router is fully compatible with `net/http`. - -Built on top of the tree is the `Router` interface: - -```go -// Router consisting of the core routing methods used by chi's Mux, -// using only the standard net/http. -type Router interface { - http.Handler - Routes - - // Use appends one or more middlewares onto the Router stack. - Use(middlewares ...func(http.Handler) http.Handler) - - // With adds inline middlewares for an endpoint handler. - With(middlewares ...func(http.Handler) http.Handler) Router - - // Group adds a new inline-Router along the current routing - // path, with a fresh middleware stack for the inline-Router. - Group(fn func(r Router)) Router - - // Route mounts a sub-Router along a `pattern`` string. - Route(pattern string, fn func(r Router)) Router - - // Mount attaches another http.Handler along ./pattern/* - Mount(pattern string, h http.Handler) - - // Handle and HandleFunc adds routes for `pattern` that matches - // all HTTP methods. - Handle(pattern string, h http.Handler) - HandleFunc(pattern string, h http.HandlerFunc) - - // Method and MethodFunc adds routes for `pattern` that matches - // the `method` HTTP method. - Method(method, pattern string, h http.Handler) - MethodFunc(method, pattern string, h http.HandlerFunc) - - // HTTP-method routing along `pattern` - Connect(pattern string, h http.HandlerFunc) - Delete(pattern string, h http.HandlerFunc) - Get(pattern string, h http.HandlerFunc) - Head(pattern string, h http.HandlerFunc) - Options(pattern string, h http.HandlerFunc) - Patch(pattern string, h http.HandlerFunc) - Post(pattern string, h http.HandlerFunc) - Put(pattern string, h http.HandlerFunc) - Trace(pattern string, h http.HandlerFunc) - - // NotFound defines a handler to respond whenever a route could - // not be found. - NotFound(h http.HandlerFunc) - - // MethodNotAllowed defines a handler to respond whenever a method is - // not allowed. - MethodNotAllowed(h http.HandlerFunc) -} - -// Routes interface adds two methods for router traversal, which is also -// used by the github.com/go-chi/docgen package to generate documentation for Routers. -type Routes interface { - // Routes returns the routing tree in an easily traversable structure. - Routes() []Route - - // Middlewares returns the list of middlewares in use by the router. - Middlewares() Middlewares - - // Match searches the routing tree for a handler that matches - // the method/path - similar to routing a http request, but without - // executing the handler thereafter. - Match(rctx *Context, method, path string) bool -} -``` - -Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern -supports named params (ie. `/users/{userID}`) and wildcards (ie. `/admin/*`). URL parameters -can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters -and `chi.URLParam(r, "*")` for a wildcard parameter. - - -### Middleware handlers - -chi's middlewares are just stdlib net/http middleware handlers. There is nothing special -about them, which means the router and all the tooling is designed to be compatible and -friendly with any middleware in the community. This offers much better extensibility and reuse -of packages and is at the heart of chi's purpose. - -Here is an example of a standard net/http middleware handler using the new request context -available in Go. This middleware sets a hypothetical user identifier on the request -context and calls the next handler in the chain. - -```go -// HTTP middleware setting a value on the request context -func MyMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), "user", "123") - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} -``` - - -### Request handlers - -chi uses standard net/http request handlers. This little snippet is an example of a http.Handler -func that reads a user identifier from the request context - hypothetically, identifying -the user sending an authenticated request, validated+set by a previous middleware handler. - -```go -// HTTP handler accessing data from the request context. -func MyRequestHandler(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value("user").(string) - w.Write([]byte(fmt.Sprintf("hi %s", user))) -} -``` - - -### URL parameters - -chi's router parses and stores URL parameters right onto the request context. Here is -an example of how to access URL params in your net/http handlers. And of course, middlewares -are able to access the same information. - -```go -// HTTP handler accessing the url routing parameters. -func MyRequestHandler(w http.ResponseWriter, r *http.Request) { - userID := chi.URLParam(r, "userID") // from a route like /users/{userID} - - ctx := r.Context() - key := ctx.Value("key").(string) - - w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key))) -} -``` - - -## Middlewares - -chi comes equipped with an optional `middleware` package, providing a suite of standard -`net/http` middlewares. Please note, any middleware in the ecosystem that is also compatible -with `net/http` can be used with chi's mux. - -### Core middlewares - ------------------------------------------------------------------------------------------------------------ -| chi/middleware Handler | description | -|:----------------------|:--------------------------------------------------------------------------------- -| AllowContentType | Explicit whitelist of accepted request Content-Types | -| BasicAuth | Basic HTTP authentication | -| Compress | Gzip compression for clients that accept compressed responses | -| GetHead | Automatically route undefined HEAD requests to GET handlers | -| Heartbeat | Monitoring endpoint to check the servers pulse | -| Logger | Logs the start and end of each request with the elapsed processing time | -| NoCache | Sets response headers to prevent clients from caching | -| Profiler | Easily attach net/http/pprof to your routers | -| RealIP | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP | -| Recoverer | Gracefully absorb panics and prints the stack trace | -| RequestID | Injects a request ID into the context of each request | -| RedirectSlashes | Redirect slashes on routing paths | -| SetHeader | Short-hand middleware to set a response header key/value | -| StripSlashes | Strip slashes on routing paths | -| Throttle | Puts a ceiling on the number of concurrent requests | -| Timeout | Signals to the request context when the timeout deadline is reached | -| URLFormat | Parse extension from url and put it on request context | -| WithValue | Short-hand middleware to set a key/value on the request context | ------------------------------------------------------------------------------------------------------------ - -### Extra middlewares & packages - -Please see https://github.com/go-chi for additional packages. - --------------------------------------------------------------------------------------------------------------------- -| package | description | -|:---------------------------------------------------|:------------------------------------------------------------- -| [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) | -| [docgen](https://github.com/go-chi/docgen) | Print chi.Router routes at runtime | -| [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication | -| [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing | -| [httplog](https://github.com/go-chi/httplog) | Small but powerful structured HTTP request logging | -| [httprate](https://github.com/go-chi/httprate) | HTTP request rate limiter | -| [httptracer](https://github.com/go-chi/httptracer) | HTTP request performance tracing library | -| [httpvcr](https://github.com/go-chi/httpvcr) | Write deterministic tests for external sources | -| [stampede](https://github.com/go-chi/stampede) | HTTP request coalescer | --------------------------------------------------------------------------------------------------------------------- - -please [submit a PR](./CONTRIBUTING.md) if you'd like to include a link to a chi-compatible middleware - - -## context? - -`context` is a tiny pkg that provides simple interface to signal context across call stacks -and goroutines. It was originally written by [Sameer Ajmani](https://github.com/Sajmani) -and is available in stdlib since go1.7. - -Learn more at https://blog.golang.org/context - -and.. -* Docs: https://golang.org/pkg/context -* Source: https://github.com/golang/go/tree/master/src/context - - -## Benchmarks - -The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark - -Results as of Jan 9, 2019 with Go 1.11.4 on Linux X1 Carbon laptop - -```shell -BenchmarkChi_Param 3000000 475 ns/op 432 B/op 3 allocs/op -BenchmarkChi_Param5 2000000 696 ns/op 432 B/op 3 allocs/op -BenchmarkChi_Param20 1000000 1275 ns/op 432 B/op 3 allocs/op -BenchmarkChi_ParamWrite 3000000 505 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GithubStatic 3000000 508 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GithubParam 2000000 669 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GithubAll 10000 134627 ns/op 87699 B/op 609 allocs/op -BenchmarkChi_GPlusStatic 3000000 402 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GPlusParam 3000000 500 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GPlus2Params 3000000 586 ns/op 432 B/op 3 allocs/op -BenchmarkChi_GPlusAll 200000 7237 ns/op 5616 B/op 39 allocs/op -BenchmarkChi_ParseStatic 3000000 408 ns/op 432 B/op 3 allocs/op -BenchmarkChi_ParseParam 3000000 488 ns/op 432 B/op 3 allocs/op -BenchmarkChi_Parse2Params 3000000 551 ns/op 432 B/op 3 allocs/op -BenchmarkChi_ParseAll 100000 13508 ns/op 11232 B/op 78 allocs/op -BenchmarkChi_StaticAll 20000 81933 ns/op 67826 B/op 471 allocs/op -``` - -Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc - -NOTE: the allocs in the benchmark above are from the calls to http.Request's -`WithContext(context.Context)` method that clones the http.Request, sets the `Context()` -on the duplicated (alloc'd) request and returns it the new request object. This is just -how setting context on a request in Go works. - - -## Credits - -* Carl Jackson for https://github.com/zenazn/goji - * Parts of chi's thinking comes from goji, and chi's middleware package - sources from goji. -* Armon Dadgar for https://github.com/armon/go-radix -* Contributions: [@VojtechVitek](https://github.com/VojtechVitek) - -We'll be more than happy to see [your contributions](./CONTRIBUTING.md)! - - -## Beyond REST - -chi is just a http router that lets you decompose request handling into many smaller layers. -Many companies use chi to write REST services for their public APIs. But, REST is just a convention -for managing state via HTTP, and there's a lot of other pieces required to write a complete client-server -system or network of microservices. - -Looking beyond REST, I also recommend some newer works in the field: -* [webrpc](https://github.com/webrpc/webrpc) - Web-focused RPC client+server framework with code-gen -* [gRPC](https://github.com/grpc/grpc-go) - Google's RPC framework via protobufs -* [graphql](https://github.com/99designs/gqlgen) - Declarative query language -* [NATS](https://nats.io) - lightweight pub-sub - - -## License - -Copyright (c) 2015-present [Peter Kieltyka](https://github.com/pkieltyka) - -Licensed under [MIT License](./LICENSE) - -[GoDoc]: https://godoc.org/github.com/go-chi/chi -[GoDoc Widget]: https://godoc.org/github.com/go-chi/chi?status.svg -[Travis]: https://travis-ci.org/go-chi/chi -[Travis Widget]: https://travis-ci.org/go-chi/chi.svg?branch=master diff --git a/vendor/github.com/go-chi/chi/chain.go b/vendor/github.com/go-chi/chi/chain.go deleted file mode 100644 index 88e6846138..0000000000 --- a/vendor/github.com/go-chi/chi/chain.go +++ /dev/null @@ -1,49 +0,0 @@ -package chi - -import "net/http" - -// Chain returns a Middlewares type from a slice of middleware handlers. -func Chain(middlewares ...func(http.Handler) http.Handler) Middlewares { - return Middlewares(middlewares) -} - -// Handler builds and returns a http.Handler from the chain of middlewares, -// with `h http.Handler` as the final handler. -func (mws Middlewares) Handler(h http.Handler) http.Handler { - return &ChainHandler{mws, h, chain(mws, h)} -} - -// HandlerFunc builds and returns a http.Handler from the chain of middlewares, -// with `h http.Handler` as the final handler. -func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler { - return &ChainHandler{mws, h, chain(mws, h)} -} - -// ChainHandler is a http.Handler with support for handler composition and -// execution. -type ChainHandler struct { - Middlewares Middlewares - Endpoint http.Handler - chain http.Handler -} - -func (c *ChainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - c.chain.ServeHTTP(w, r) -} - -// chain builds a http.Handler composed of an inline middleware stack and endpoint -// handler in the order they are passed. -func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler { - // Return ahead of time if there aren't any middlewares for the chain - if len(middlewares) == 0 { - return endpoint - } - - // Wrap the end handler with the middleware chain - h := middlewares[len(middlewares)-1](endpoint) - for i := len(middlewares) - 2; i >= 0; i-- { - h = middlewares[i](h) - } - - return h -} diff --git a/vendor/github.com/go-chi/chi/chi.go b/vendor/github.com/go-chi/chi/chi.go deleted file mode 100644 index b7063dc297..0000000000 --- a/vendor/github.com/go-chi/chi/chi.go +++ /dev/null @@ -1,134 +0,0 @@ -// -// Package chi is a small, idiomatic and composable router for building HTTP services. -// -// chi requires Go 1.10 or newer. -// -// Example: -// package main -// -// import ( -// "net/http" -// -// "github.com/go-chi/chi" -// "github.com/go-chi/chi/middleware" -// ) -// -// func main() { -// r := chi.NewRouter() -// r.Use(middleware.Logger) -// r.Use(middleware.Recoverer) -// -// r.Get("/", func(w http.ResponseWriter, r *http.Request) { -// w.Write([]byte("root.")) -// }) -// -// http.ListenAndServe(":3333", r) -// } -// -// See github.com/go-chi/chi/_examples/ for more in-depth examples. -// -// URL patterns allow for easy matching of path components in HTTP -// requests. The matching components can then be accessed using -// chi.URLParam(). All patterns must begin with a slash. -// -// A simple named placeholder {name} matches any sequence of characters -// up to the next / or the end of the URL. Trailing slashes on paths must -// be handled explicitly. -// -// A placeholder with a name followed by a colon allows a regular -// expression match, for example {number:\\d+}. The regular expression -// syntax is Go's normal regexp RE2 syntax, except that regular expressions -// including { or } are not supported, and / will never be -// matched. An anonymous regexp pattern is allowed, using an empty string -// before the colon in the placeholder, such as {:\\d+} -// -// The special placeholder of asterisk matches the rest of the requested -// URL. Any trailing characters in the pattern are ignored. This is the only -// placeholder which will match / characters. -// -// Examples: -// "/user/{name}" matches "/user/jsmith" but not "/user/jsmith/info" or "/user/jsmith/" -// "/user/{name}/info" matches "/user/jsmith/info" -// "/page/*" matches "/page/intro/latest" -// "/page/*/index" also matches "/page/intro/latest" -// "/date/{yyyy:\\d\\d\\d\\d}/{mm:\\d\\d}/{dd:\\d\\d}" matches "/date/2017/04/01" -// -package chi - -import "net/http" - -// NewRouter returns a new Mux object that implements the Router interface. -func NewRouter() *Mux { - return NewMux() -} - -// Router consisting of the core routing methods used by chi's Mux, -// using only the standard net/http. -type Router interface { - http.Handler - Routes - - // Use appends one or more middlewares onto the Router stack. - Use(middlewares ...func(http.Handler) http.Handler) - - // With adds inline middlewares for an endpoint handler. - With(middlewares ...func(http.Handler) http.Handler) Router - - // Group adds a new inline-Router along the current routing - // path, with a fresh middleware stack for the inline-Router. - Group(fn func(r Router)) Router - - // Route mounts a sub-Router along a `pattern`` string. - Route(pattern string, fn func(r Router)) Router - - // Mount attaches another http.Handler along ./pattern/* - Mount(pattern string, h http.Handler) - - // Handle and HandleFunc adds routes for `pattern` that matches - // all HTTP methods. - Handle(pattern string, h http.Handler) - HandleFunc(pattern string, h http.HandlerFunc) - - // Method and MethodFunc adds routes for `pattern` that matches - // the `method` HTTP method. - Method(method, pattern string, h http.Handler) - MethodFunc(method, pattern string, h http.HandlerFunc) - - // HTTP-method routing along `pattern` - Connect(pattern string, h http.HandlerFunc) - Delete(pattern string, h http.HandlerFunc) - Get(pattern string, h http.HandlerFunc) - Head(pattern string, h http.HandlerFunc) - Options(pattern string, h http.HandlerFunc) - Patch(pattern string, h http.HandlerFunc) - Post(pattern string, h http.HandlerFunc) - Put(pattern string, h http.HandlerFunc) - Trace(pattern string, h http.HandlerFunc) - - // NotFound defines a handler to respond whenever a route could - // not be found. - NotFound(h http.HandlerFunc) - - // MethodNotAllowed defines a handler to respond whenever a method is - // not allowed. - MethodNotAllowed(h http.HandlerFunc) -} - -// Routes interface adds two methods for router traversal, which is also -// used by the `docgen` subpackage to generation documentation for Routers. -type Routes interface { - // Routes returns the routing tree in an easily traversable structure. - Routes() []Route - - // Middlewares returns the list of middlewares in use by the router. - Middlewares() Middlewares - - // Match searches the routing tree for a handler that matches - // the method/path - similar to routing a http request, but without - // executing the handler thereafter. - Match(rctx *Context, method, path string) bool -} - -// Middlewares type is a slice of standard middleware handlers with methods -// to compose middleware chains and http.Handler's. -type Middlewares []func(http.Handler) http.Handler diff --git a/vendor/github.com/go-chi/chi/context.go b/vendor/github.com/go-chi/chi/context.go deleted file mode 100644 index 26c609ea2c..0000000000 --- a/vendor/github.com/go-chi/chi/context.go +++ /dev/null @@ -1,172 +0,0 @@ -package chi - -import ( - "context" - "net" - "net/http" - "strings" -) - -// URLParam returns the url parameter from a http.Request object. -func URLParam(r *http.Request, key string) string { - if rctx := RouteContext(r.Context()); rctx != nil { - return rctx.URLParam(key) - } - return "" -} - -// URLParamFromCtx returns the url parameter from a http.Request Context. -func URLParamFromCtx(ctx context.Context, key string) string { - if rctx := RouteContext(ctx); rctx != nil { - return rctx.URLParam(key) - } - return "" -} - -// RouteContext returns chi's routing Context object from a -// http.Request Context. -func RouteContext(ctx context.Context) *Context { - val, _ := ctx.Value(RouteCtxKey).(*Context) - return val -} - -// ServerBaseContext wraps an http.Handler to set the request context to the -// `baseCtx`. -func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler { - fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - baseCtx := baseCtx - - // Copy over default net/http server context keys - if v, ok := ctx.Value(http.ServerContextKey).(*http.Server); ok { - baseCtx = context.WithValue(baseCtx, http.ServerContextKey, v) - } - if v, ok := ctx.Value(http.LocalAddrContextKey).(net.Addr); ok { - baseCtx = context.WithValue(baseCtx, http.LocalAddrContextKey, v) - } - - h.ServeHTTP(w, r.WithContext(baseCtx)) - }) - return fn -} - -// NewRouteContext returns a new routing Context object. -func NewRouteContext() *Context { - return &Context{} -} - -var ( - // RouteCtxKey is the context.Context key to store the request context. - RouteCtxKey = &contextKey{"RouteContext"} -) - -// Context is the default routing context set on the root node of a -// request context to track route patterns, URL parameters and -// an optional routing path. -type Context struct { - Routes Routes - - // Routing path/method override used during the route search. - // See Mux#routeHTTP method. - RoutePath string - RouteMethod string - - // Routing pattern stack throughout the lifecycle of the request, - // across all connected routers. It is a record of all matching - // patterns across a stack of sub-routers. - RoutePatterns []string - - // URLParams are the stack of routeParams captured during the - // routing lifecycle across a stack of sub-routers. - URLParams RouteParams - - // The endpoint routing pattern that matched the request URI path - // or `RoutePath` of the current sub-router. This value will update - // during the lifecycle of a request passing through a stack of - // sub-routers. - routePattern string - - // Route parameters matched for the current sub-router. It is - // intentionally unexported so it cant be tampered. - routeParams RouteParams - - // methodNotAllowed hint - methodNotAllowed bool -} - -// Reset a routing context to its initial state. -func (x *Context) Reset() { - x.Routes = nil - x.RoutePath = "" - x.RouteMethod = "" - x.RoutePatterns = x.RoutePatterns[:0] - x.URLParams.Keys = x.URLParams.Keys[:0] - x.URLParams.Values = x.URLParams.Values[:0] - - x.routePattern = "" - x.routeParams.Keys = x.routeParams.Keys[:0] - x.routeParams.Values = x.routeParams.Values[:0] - x.methodNotAllowed = false -} - -// URLParam returns the corresponding URL parameter value from the request -// routing context. -func (x *Context) URLParam(key string) string { - for k := len(x.URLParams.Keys) - 1; k >= 0; k-- { - if x.URLParams.Keys[k] == key { - return x.URLParams.Values[k] - } - } - return "" -} - -// RoutePattern builds the routing pattern string for the particular -// request, at the particular point during routing. This means, the value -// will change throughout the execution of a request in a router. That is -// why its advised to only use this value after calling the next handler. -// -// For example, -// -// func Instrument(next http.Handler) http.Handler { -// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// next.ServeHTTP(w, r) -// routePattern := chi.RouteContext(r.Context()).RoutePattern() -// measure(w, r, routePattern) -// }) -// } -func (x *Context) RoutePattern() string { - routePattern := strings.Join(x.RoutePatterns, "") - return replaceWildcards(routePattern) -} - -// replaceWildcards takes a route pattern and recursively replaces all -// occurrences of "/*/" to "/". -func replaceWildcards(p string) string { - if strings.Contains(p, "/*/") { - return replaceWildcards(strings.Replace(p, "/*/", "/", -1)) - } - - return p -} - -// RouteParams is a structure to track URL routing parameters efficiently. -type RouteParams struct { - Keys, Values []string -} - -// Add will append a URL parameter to the end of the route param -func (s *RouteParams) Add(key, value string) { - s.Keys = append(s.Keys, key) - s.Values = append(s.Values, value) -} - -// contextKey is a value for use with context.WithValue. It's used as -// a pointer so it fits in an interface{} without allocation. This technique -// for defining context keys was copied from Go 1.7's new use of context in net/http. -type contextKey struct { - name string -} - -func (k *contextKey) String() string { - return "chi context value " + k.name -} diff --git a/vendor/github.com/go-chi/chi/middleware/basic_auth.go b/vendor/github.com/go-chi/chi/middleware/basic_auth.go deleted file mode 100644 index 87b2641a6a..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/basic_auth.go +++ /dev/null @@ -1,32 +0,0 @@ -package middleware - -import ( - "fmt" - "net/http" -) - -// BasicAuth implements a simple middleware handler for adding basic http auth to a route. -func BasicAuth(realm string, creds map[string]string) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - user, pass, ok := r.BasicAuth() - if !ok { - basicAuthFailed(w, realm) - return - } - - credPass, credUserOk := creds[user] - if !credUserOk || pass != credPass { - basicAuthFailed(w, realm) - return - } - - next.ServeHTTP(w, r) - }) - } -} - -func basicAuthFailed(w http.ResponseWriter, realm string) { - w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm)) - w.WriteHeader(http.StatusUnauthorized) -} diff --git a/vendor/github.com/go-chi/chi/middleware/compress.go b/vendor/github.com/go-chi/chi/middleware/compress.go deleted file mode 100644 index 2f40cc15af..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/compress.go +++ /dev/null @@ -1,399 +0,0 @@ -package middleware - -import ( - "bufio" - "compress/flate" - "compress/gzip" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "strings" - "sync" -) - -var defaultCompressibleContentTypes = []string{ - "text/html", - "text/css", - "text/plain", - "text/javascript", - "application/javascript", - "application/x-javascript", - "application/json", - "application/atom+xml", - "application/rss+xml", - "image/svg+xml", -} - -// Compress is a middleware that compresses response -// body of a given content types to a data format based -// on Accept-Encoding request header. It uses a given -// compression level. -// -// NOTE: make sure to set the Content-Type header on your response -// otherwise this middleware will not compress the response body. For ex, in -// your handler you should set w.Header().Set("Content-Type", http.DetectContentType(yourBody)) -// or set it manually. -// -// Passing a compression level of 5 is sensible value -func Compress(level int, types ...string) func(next http.Handler) http.Handler { - compressor := NewCompressor(level, types...) - return compressor.Handler -} - -// Compressor represents a set of encoding configurations. -type Compressor struct { - level int // The compression level. - // The mapping of encoder names to encoder functions. - encoders map[string]EncoderFunc - // The mapping of pooled encoders to pools. - pooledEncoders map[string]*sync.Pool - // The set of content types allowed to be compressed. - allowedTypes map[string]struct{} - allowedWildcards map[string]struct{} - // The list of encoders in order of decreasing precedence. - encodingPrecedence []string -} - -// NewCompressor creates a new Compressor that will handle encoding responses. -// -// The level should be one of the ones defined in the flate package. -// The types are the content types that are allowed to be compressed. -func NewCompressor(level int, types ...string) *Compressor { - // If types are provided, set those as the allowed types. If none are - // provided, use the default list. - allowedTypes := make(map[string]struct{}) - allowedWildcards := make(map[string]struct{}) - if len(types) > 0 { - for _, t := range types { - if strings.Contains(strings.TrimSuffix(t, "/*"), "*") { - panic(fmt.Sprintf("middleware/compress: Unsupported content-type wildcard pattern '%s'. Only '/*' supported", t)) - } - if strings.HasSuffix(t, "/*") { - allowedWildcards[strings.TrimSuffix(t, "/*")] = struct{}{} - } else { - allowedTypes[t] = struct{}{} - } - } - } else { - for _, t := range defaultCompressibleContentTypes { - allowedTypes[t] = struct{}{} - } - } - - c := &Compressor{ - level: level, - encoders: make(map[string]EncoderFunc), - pooledEncoders: make(map[string]*sync.Pool), - allowedTypes: allowedTypes, - allowedWildcards: allowedWildcards, - } - - // Set the default encoders. The precedence order uses the reverse - // ordering that the encoders were added. This means adding new encoders - // will move them to the front of the order. - // - // TODO: - // lzma: Opera. - // sdch: Chrome, Android. Gzip output + dictionary header. - // br: Brotli, see https://github.com/go-chi/chi/pull/326 - - // HTTP 1.1 "deflate" (RFC 2616) stands for DEFLATE data (RFC 1951) - // wrapped with zlib (RFC 1950). The zlib wrapper uses Adler-32 - // checksum compared to CRC-32 used in "gzip" and thus is faster. - // - // But.. some old browsers (MSIE, Safari 5.1) incorrectly expect - // raw DEFLATE data only, without the mentioned zlib wrapper. - // Because of this major confusion, most modern browsers try it - // both ways, first looking for zlib headers. - // Quote by Mark Adler: http://stackoverflow.com/a/9186091/385548 - // - // The list of browsers having problems is quite big, see: - // http://zoompf.com/blog/2012/02/lose-the-wait-http-compression - // https://web.archive.org/web/20120321182910/http://www.vervestudios.co/projects/compression-tests/results - // - // That's why we prefer gzip over deflate. It's just more reliable - // and not significantly slower than gzip. - c.SetEncoder("deflate", encoderDeflate) - - // TODO: Exception for old MSIE browsers that can't handle non-HTML? - // https://zoompf.com/blog/2012/02/lose-the-wait-http-compression - c.SetEncoder("gzip", encoderGzip) - - // NOTE: Not implemented, intentionally: - // case "compress": // LZW. Deprecated. - // case "bzip2": // Too slow on-the-fly. - // case "zopfli": // Too slow on-the-fly. - // case "xz": // Too slow on-the-fly. - return c -} - -// SetEncoder can be used to set the implementation of a compression algorithm. -// -// The encoding should be a standardised identifier. See: -// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding -// -// For example, add the Brotli algortithm: -// -// import brotli_enc "gopkg.in/kothar/brotli-go.v0/enc" -// -// compressor := middleware.NewCompressor(5, "text/html") -// compressor.SetEncoder("br", func(w http.ResponseWriter, level int) io.Writer { -// params := brotli_enc.NewBrotliParams() -// params.SetQuality(level) -// return brotli_enc.NewBrotliWriter(params, w) -// }) -func (c *Compressor) SetEncoder(encoding string, fn EncoderFunc) { - encoding = strings.ToLower(encoding) - if encoding == "" { - panic("the encoding can not be empty") - } - if fn == nil { - panic("attempted to set a nil encoder function") - } - - // If we are adding a new encoder that is already registered, we have to - // clear that one out first. - if _, ok := c.pooledEncoders[encoding]; ok { - delete(c.pooledEncoders, encoding) - } - if _, ok := c.encoders[encoding]; ok { - delete(c.encoders, encoding) - } - - // If the encoder supports Resetting (IoReseterWriter), then it can be pooled. - encoder := fn(ioutil.Discard, c.level) - if encoder != nil { - if _, ok := encoder.(ioResetterWriter); ok { - pool := &sync.Pool{ - New: func() interface{} { - return fn(ioutil.Discard, c.level) - }, - } - c.pooledEncoders[encoding] = pool - } - } - // If the encoder is not in the pooledEncoders, add it to the normal encoders. - if _, ok := c.pooledEncoders[encoding]; !ok { - c.encoders[encoding] = fn - } - - for i, v := range c.encodingPrecedence { - if v == encoding { - c.encodingPrecedence = append(c.encodingPrecedence[:i], c.encodingPrecedence[i+1:]...) - } - } - - c.encodingPrecedence = append([]string{encoding}, c.encodingPrecedence...) -} - -// Handler returns a new middleware that will compress the response based on the -// current Compressor. -func (c *Compressor) Handler(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - encoder, encoding, cleanup := c.selectEncoder(r.Header, w) - - cw := &compressResponseWriter{ - ResponseWriter: w, - w: w, - contentTypes: c.allowedTypes, - contentWildcards: c.allowedWildcards, - encoding: encoding, - compressable: false, // determined in post-handler - } - if encoder != nil { - cw.w = encoder - } - // Re-add the encoder to the pool if applicable. - defer cleanup() - defer cw.Close() - - next.ServeHTTP(cw, r) - }) -} - -// selectEncoder returns the encoder, the name of the encoder, and a closer function. -func (c *Compressor) selectEncoder(h http.Header, w io.Writer) (io.Writer, string, func()) { - header := h.Get("Accept-Encoding") - - // Parse the names of all accepted algorithms from the header. - accepted := strings.Split(strings.ToLower(header), ",") - - // Find supported encoder by accepted list by precedence - for _, name := range c.encodingPrecedence { - if matchAcceptEncoding(accepted, name) { - if pool, ok := c.pooledEncoders[name]; ok { - encoder := pool.Get().(ioResetterWriter) - cleanup := func() { - pool.Put(encoder) - } - encoder.Reset(w) - return encoder, name, cleanup - - } - if fn, ok := c.encoders[name]; ok { - return fn(w, c.level), name, func() {} - } - } - - } - - // No encoder found to match the accepted encoding - return nil, "", func() {} -} - -func matchAcceptEncoding(accepted []string, encoding string) bool { - for _, v := range accepted { - if strings.Contains(v, encoding) { - return true - } - } - return false -} - -// An EncoderFunc is a function that wraps the provided io.Writer with a -// streaming compression algorithm and returns it. -// -// In case of failure, the function should return nil. -type EncoderFunc func(w io.Writer, level int) io.Writer - -// Interface for types that allow resetting io.Writers. -type ioResetterWriter interface { - io.Writer - Reset(w io.Writer) -} - -type compressResponseWriter struct { - http.ResponseWriter - - // The streaming encoder writer to be used if there is one. Otherwise, - // this is just the normal writer. - w io.Writer - encoding string - contentTypes map[string]struct{} - contentWildcards map[string]struct{} - wroteHeader bool - compressable bool -} - -func (cw *compressResponseWriter) isCompressable() bool { - // Parse the first part of the Content-Type response header. - contentType := cw.Header().Get("Content-Type") - if idx := strings.Index(contentType, ";"); idx >= 0 { - contentType = contentType[0:idx] - } - - // Is the content type compressable? - if _, ok := cw.contentTypes[contentType]; ok { - return true - } - if idx := strings.Index(contentType, "/"); idx > 0 { - contentType = contentType[0:idx] - _, ok := cw.contentWildcards[contentType] - return ok - } - return false -} - -func (cw *compressResponseWriter) WriteHeader(code int) { - if cw.wroteHeader { - cw.ResponseWriter.WriteHeader(code) // Allow multiple calls to propagate. - return - } - cw.wroteHeader = true - defer cw.ResponseWriter.WriteHeader(code) - - // Already compressed data? - if cw.Header().Get("Content-Encoding") != "" { - return - } - - if !cw.isCompressable() { - cw.compressable = false - return - } - - if cw.encoding != "" { - cw.compressable = true - cw.Header().Set("Content-Encoding", cw.encoding) - cw.Header().Set("Vary", "Accept-Encoding") - - // The content-length after compression is unknown - cw.Header().Del("Content-Length") - } -} - -func (cw *compressResponseWriter) Write(p []byte) (int, error) { - if !cw.wroteHeader { - cw.WriteHeader(http.StatusOK) - } - - return cw.writer().Write(p) -} - -func (cw *compressResponseWriter) writer() io.Writer { - if cw.compressable { - return cw.w - } else { - return cw.ResponseWriter - } -} - -type compressFlusher interface { - Flush() error -} - -func (cw *compressResponseWriter) Flush() { - if f, ok := cw.writer().(http.Flusher); ok { - f.Flush() - } - // If the underlying writer has a compression flush signature, - // call this Flush() method instead - if f, ok := cw.writer().(compressFlusher); ok { - f.Flush() - - // Also flush the underlying response writer - if f, ok := cw.ResponseWriter.(http.Flusher); ok { - f.Flush() - } - } -} - -func (cw *compressResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - if hj, ok := cw.writer().(http.Hijacker); ok { - return hj.Hijack() - } - return nil, nil, errors.New("chi/middleware: http.Hijacker is unavailable on the writer") -} - -func (cw *compressResponseWriter) Push(target string, opts *http.PushOptions) error { - if ps, ok := cw.writer().(http.Pusher); ok { - return ps.Push(target, opts) - } - return errors.New("chi/middleware: http.Pusher is unavailable on the writer") -} - -func (cw *compressResponseWriter) Close() error { - if c, ok := cw.writer().(io.WriteCloser); ok { - return c.Close() - } - return errors.New("chi/middleware: io.WriteCloser is unavailable on the writer") -} - -func encoderGzip(w io.Writer, level int) io.Writer { - gw, err := gzip.NewWriterLevel(w, level) - if err != nil { - return nil - } - return gw -} - -func encoderDeflate(w io.Writer, level int) io.Writer { - dw, err := flate.NewWriter(w, level) - if err != nil { - return nil - } - return dw -} diff --git a/vendor/github.com/go-chi/chi/middleware/content_charset.go b/vendor/github.com/go-chi/chi/middleware/content_charset.go deleted file mode 100644 index 07b5ce6f66..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/content_charset.go +++ /dev/null @@ -1,51 +0,0 @@ -package middleware - -import ( - "net/http" - "strings" -) - -// ContentCharset generates a handler that writes a 415 Unsupported Media Type response if none of the charsets match. -// An empty charset will allow requests with no Content-Type header or no specified charset. -func ContentCharset(charsets ...string) func(next http.Handler) http.Handler { - for i, c := range charsets { - charsets[i] = strings.ToLower(c) - } - - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !contentEncoding(r.Header.Get("Content-Type"), charsets...) { - w.WriteHeader(http.StatusUnsupportedMediaType) - return - } - - next.ServeHTTP(w, r) - }) - } -} - -// Check the content encoding against a list of acceptable values. -func contentEncoding(ce string, charsets ...string) bool { - _, ce = split(strings.ToLower(ce), ";") - _, ce = split(ce, "charset=") - ce, _ = split(ce, ";") - for _, c := range charsets { - if ce == c { - return true - } - } - - return false -} - -// Split a string in two parts, cleaning any whitespace. -func split(str, sep string) (string, string) { - var a, b string - var parts = strings.SplitN(str, sep, 2) - a = strings.TrimSpace(parts[0]) - if len(parts) == 2 { - b = strings.TrimSpace(parts[1]) - } - - return a, b -} diff --git a/vendor/github.com/go-chi/chi/middleware/content_encoding.go b/vendor/github.com/go-chi/chi/middleware/content_encoding.go deleted file mode 100644 index e0b9ccc08a..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/content_encoding.go +++ /dev/null @@ -1,34 +0,0 @@ -package middleware - -import ( - "net/http" - "strings" -) - -// AllowContentEncoding enforces a whitelist of request Content-Encoding otherwise responds -// with a 415 Unsupported Media Type status. -func AllowContentEncoding(contentEncoding ...string) func(next http.Handler) http.Handler { - allowedEncodings := make(map[string]struct{}, len(contentEncoding)) - for _, encoding := range contentEncoding { - allowedEncodings[strings.TrimSpace(strings.ToLower(encoding))] = struct{}{} - } - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - requestEncodings := r.Header["Content-Encoding"] - // skip check for empty content body or no Content-Encoding - if r.ContentLength == 0 { - next.ServeHTTP(w, r) - return - } - // All encodings in the request must be allowed - for _, encoding := range requestEncodings { - if _, ok := allowedEncodings[strings.TrimSpace(strings.ToLower(encoding))]; !ok { - w.WriteHeader(http.StatusUnsupportedMediaType) - return - } - } - next.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/content_type.go b/vendor/github.com/go-chi/chi/middleware/content_type.go deleted file mode 100644 index ee4957874f..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/content_type.go +++ /dev/null @@ -1,51 +0,0 @@ -package middleware - -import ( - "net/http" - "strings" -) - -// SetHeader is a convenience handler to set a response header key/value -func SetHeader(key, value string) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set(key, value) - next.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) - } -} - -// AllowContentType enforces a whitelist of request Content-Types otherwise responds -// with a 415 Unsupported Media Type status. -func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handler { - cT := []string{} - for _, t := range contentTypes { - cT = append(cT, strings.ToLower(t)) - } - - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - if r.ContentLength == 0 { - // skip check for empty content body - next.ServeHTTP(w, r) - return - } - - s := strings.ToLower(strings.TrimSpace(r.Header.Get("Content-Type"))) - if i := strings.Index(s, ";"); i > -1 { - s = s[0:i] - } - - for _, t := range cT { - if t == s { - next.ServeHTTP(w, r) - return - } - } - - w.WriteHeader(http.StatusUnsupportedMediaType) - } - return http.HandlerFunc(fn) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/get_head.go b/vendor/github.com/go-chi/chi/middleware/get_head.go deleted file mode 100644 index 86068a96db..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/get_head.go +++ /dev/null @@ -1,39 +0,0 @@ -package middleware - -import ( - "net/http" - - "github.com/go-chi/chi" -) - -// GetHead automatically route undefined HEAD requests to GET handlers. -func GetHead(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == "HEAD" { - rctx := chi.RouteContext(r.Context()) - routePath := rctx.RoutePath - if routePath == "" { - if r.URL.RawPath != "" { - routePath = r.URL.RawPath - } else { - routePath = r.URL.Path - } - } - - // Temporary routing context to look-ahead before routing the request - tctx := chi.NewRouteContext() - - // Attempt to find a HEAD handler for the routing path, if not found, traverse - // the router as through its a GET route, but proceed with the request - // with the HEAD method. - if !rctx.Routes.Match(tctx, "HEAD", routePath) { - rctx.RouteMethod = "GET" - rctx.RoutePath = routePath - next.ServeHTTP(w, r) - return - } - } - - next.ServeHTTP(w, r) - }) -} diff --git a/vendor/github.com/go-chi/chi/middleware/heartbeat.go b/vendor/github.com/go-chi/chi/middleware/heartbeat.go deleted file mode 100644 index fe822fb536..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/heartbeat.go +++ /dev/null @@ -1,26 +0,0 @@ -package middleware - -import ( - "net/http" - "strings" -) - -// Heartbeat endpoint middleware useful to setting up a path like -// `/ping` that load balancers or uptime testing external services -// can make a request before hitting any routes. It's also convenient -// to place this above ACL middlewares as well. -func Heartbeat(endpoint string) func(http.Handler) http.Handler { - f := func(h http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - if r.Method == "GET" && strings.EqualFold(r.URL.Path, endpoint) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - w.Write([]byte(".")) - return - } - h.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) - } - return f -} diff --git a/vendor/github.com/go-chi/chi/middleware/logger.go b/vendor/github.com/go-chi/chi/middleware/logger.go deleted file mode 100644 index 158a6a3905..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/logger.go +++ /dev/null @@ -1,155 +0,0 @@ -package middleware - -import ( - "bytes" - "context" - "log" - "net/http" - "os" - "time" -) - -var ( - // LogEntryCtxKey is the context.Context key to store the request log entry. - LogEntryCtxKey = &contextKey{"LogEntry"} - - // DefaultLogger is called by the Logger middleware handler to log each request. - // Its made a package-level variable so that it can be reconfigured for custom - // logging configurations. - DefaultLogger = RequestLogger(&DefaultLogFormatter{Logger: log.New(os.Stdout, "", log.LstdFlags), NoColor: false}) -) - -// Logger is a middleware that logs the start and end of each request, along -// with some useful data about what was requested, what the response status was, -// and how long it took to return. When standard output is a TTY, Logger will -// print in color, otherwise it will print in black and white. Logger prints a -// request ID if one is provided. -// -// Alternatively, look at https://github.com/goware/httplog for a more in-depth -// http logger with structured logging support. -func Logger(next http.Handler) http.Handler { - return DefaultLogger(next) -} - -// RequestLogger returns a logger handler using a custom LogFormatter. -func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - entry := f.NewLogEntry(r) - ww := NewWrapResponseWriter(w, r.ProtoMajor) - - t1 := time.Now() - defer func() { - entry.Write(ww.Status(), ww.BytesWritten(), ww.Header(), time.Since(t1), nil) - }() - - next.ServeHTTP(ww, WithLogEntry(r, entry)) - } - return http.HandlerFunc(fn) - } -} - -// LogFormatter initiates the beginning of a new LogEntry per request. -// See DefaultLogFormatter for an example implementation. -type LogFormatter interface { - NewLogEntry(r *http.Request) LogEntry -} - -// LogEntry records the final log when a request completes. -// See defaultLogEntry for an example implementation. -type LogEntry interface { - Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) - Panic(v interface{}, stack []byte) -} - -// GetLogEntry returns the in-context LogEntry for a request. -func GetLogEntry(r *http.Request) LogEntry { - entry, _ := r.Context().Value(LogEntryCtxKey).(LogEntry) - return entry -} - -// WithLogEntry sets the in-context LogEntry for a request. -func WithLogEntry(r *http.Request, entry LogEntry) *http.Request { - r = r.WithContext(context.WithValue(r.Context(), LogEntryCtxKey, entry)) - return r -} - -// LoggerInterface accepts printing to stdlib logger or compatible logger. -type LoggerInterface interface { - Print(v ...interface{}) -} - -// DefaultLogFormatter is a simple logger that implements a LogFormatter. -type DefaultLogFormatter struct { - Logger LoggerInterface - NoColor bool -} - -// NewLogEntry creates a new LogEntry for the request. -func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry { - useColor := !l.NoColor - entry := &defaultLogEntry{ - DefaultLogFormatter: l, - request: r, - buf: &bytes.Buffer{}, - useColor: useColor, - } - - reqID := GetReqID(r.Context()) - if reqID != "" { - cW(entry.buf, useColor, nYellow, "[%s] ", reqID) - } - cW(entry.buf, useColor, nCyan, "\"") - cW(entry.buf, useColor, bMagenta, "%s ", r.Method) - - scheme := "http" - if r.TLS != nil { - scheme = "https" - } - cW(entry.buf, useColor, nCyan, "%s://%s%s %s\" ", scheme, r.Host, r.RequestURI, r.Proto) - - entry.buf.WriteString("from ") - entry.buf.WriteString(r.RemoteAddr) - entry.buf.WriteString(" - ") - - return entry -} - -type defaultLogEntry struct { - *DefaultLogFormatter - request *http.Request - buf *bytes.Buffer - useColor bool -} - -func (l *defaultLogEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) { - switch { - case status < 200: - cW(l.buf, l.useColor, bBlue, "%03d", status) - case status < 300: - cW(l.buf, l.useColor, bGreen, "%03d", status) - case status < 400: - cW(l.buf, l.useColor, bCyan, "%03d", status) - case status < 500: - cW(l.buf, l.useColor, bYellow, "%03d", status) - default: - cW(l.buf, l.useColor, bRed, "%03d", status) - } - - cW(l.buf, l.useColor, bBlue, " %dB", bytes) - - l.buf.WriteString(" in ") - if elapsed < 500*time.Millisecond { - cW(l.buf, l.useColor, nGreen, "%s", elapsed) - } else if elapsed < 5*time.Second { - cW(l.buf, l.useColor, nYellow, "%s", elapsed) - } else { - cW(l.buf, l.useColor, nRed, "%s", elapsed) - } - - l.Logger.Print(l.buf.String()) -} - -func (l *defaultLogEntry) Panic(v interface{}, stack []byte) { - PrintPrettyStack(v) -} diff --git a/vendor/github.com/go-chi/chi/middleware/middleware.go b/vendor/github.com/go-chi/chi/middleware/middleware.go deleted file mode 100644 index cc371e00a8..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/middleware.go +++ /dev/null @@ -1,23 +0,0 @@ -package middleware - -import "net/http" - -// New will create a new middleware handler from a http.Handler. -func New(h http.Handler) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - h.ServeHTTP(w, r) - }) - } -} - -// contextKey is a value for use with context.WithValue. It's used as -// a pointer so it fits in an interface{} without allocation. This technique -// for defining context keys was copied from Go 1.7's new use of context in net/http. -type contextKey struct { - name string -} - -func (k *contextKey) String() string { - return "chi/middleware context value " + k.name -} diff --git a/vendor/github.com/go-chi/chi/middleware/nocache.go b/vendor/github.com/go-chi/chi/middleware/nocache.go deleted file mode 100644 index 2412829e1b..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/nocache.go +++ /dev/null @@ -1,58 +0,0 @@ -package middleware - -// Ported from Goji's middleware, source: -// https://github.com/zenazn/goji/tree/master/web/middleware - -import ( - "net/http" - "time" -) - -// Unix epoch time -var epoch = time.Unix(0, 0).Format(time.RFC1123) - -// Taken from https://github.com/mytrile/nocache -var noCacheHeaders = map[string]string{ - "Expires": epoch, - "Cache-Control": "no-cache, no-store, no-transform, must-revalidate, private, max-age=0", - "Pragma": "no-cache", - "X-Accel-Expires": "0", -} - -var etagHeaders = []string{ - "ETag", - "If-Modified-Since", - "If-Match", - "If-None-Match", - "If-Range", - "If-Unmodified-Since", -} - -// NoCache is a simple piece of middleware that sets a number of HTTP headers to prevent -// a router (or subrouter) from being cached by an upstream proxy and/or client. -// -// As per http://wiki.nginx.org/HttpProxyModule - NoCache sets: -// Expires: Thu, 01 Jan 1970 00:00:00 UTC -// Cache-Control: no-cache, private, max-age=0 -// X-Accel-Expires: 0 -// Pragma: no-cache (for HTTP/1.0 proxies/clients) -func NoCache(h http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - - // Delete any ETag headers that may have been set - for _, v := range etagHeaders { - if r.Header.Get(v) != "" { - r.Header.Del(v) - } - } - - // Set our NoCache headers - for k, v := range noCacheHeaders { - w.Header().Set(k, v) - } - - h.ServeHTTP(w, r) - } - - return http.HandlerFunc(fn) -} diff --git a/vendor/github.com/go-chi/chi/middleware/profiler.go b/vendor/github.com/go-chi/chi/middleware/profiler.go deleted file mode 100644 index 1d44b8259a..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/profiler.go +++ /dev/null @@ -1,55 +0,0 @@ -package middleware - -import ( - "expvar" - "fmt" - "net/http" - "net/http/pprof" - - "github.com/go-chi/chi" -) - -// Profiler is a convenient subrouter used for mounting net/http/pprof. ie. -// -// func MyService() http.Handler { -// r := chi.NewRouter() -// // ..middlewares -// r.Mount("/debug", middleware.Profiler()) -// // ..routes -// return r -// } -func Profiler() http.Handler { - r := chi.NewRouter() - r.Use(NoCache) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, r.RequestURI+"/pprof/", 301) - }) - r.HandleFunc("/pprof", func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, r.RequestURI+"/", 301) - }) - - r.HandleFunc("/pprof/*", pprof.Index) - r.HandleFunc("/pprof/cmdline", pprof.Cmdline) - r.HandleFunc("/pprof/profile", pprof.Profile) - r.HandleFunc("/pprof/symbol", pprof.Symbol) - r.HandleFunc("/pprof/trace", pprof.Trace) - r.HandleFunc("/vars", expVars) - - return r -} - -// Replicated from expvar.go as not public. -func expVars(w http.ResponseWriter, r *http.Request) { - first := true - w.Header().Set("Content-Type", "application/json") - fmt.Fprintf(w, "{\n") - expvar.Do(func(kv expvar.KeyValue) { - if !first { - fmt.Fprintf(w, ",\n") - } - first = false - fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value) - }) - fmt.Fprintf(w, "\n}\n") -} diff --git a/vendor/github.com/go-chi/chi/middleware/realip.go b/vendor/github.com/go-chi/chi/middleware/realip.go deleted file mode 100644 index 72db6ca9f5..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/realip.go +++ /dev/null @@ -1,54 +0,0 @@ -package middleware - -// Ported from Goji's middleware, source: -// https://github.com/zenazn/goji/tree/master/web/middleware - -import ( - "net/http" - "strings" -) - -var xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For") -var xRealIP = http.CanonicalHeaderKey("X-Real-IP") - -// RealIP is a middleware that sets a http.Request's RemoteAddr to the results -// of parsing either the X-Forwarded-For header or the X-Real-IP header (in that -// order). -// -// This middleware should be inserted fairly early in the middleware stack to -// ensure that subsequent layers (e.g., request loggers) which examine the -// RemoteAddr will see the intended value. -// -// You should only use this middleware if you can trust the headers passed to -// you (in particular, the two headers this middleware uses), for example -// because you have placed a reverse proxy like HAProxy or nginx in front of -// chi. If your reverse proxies are configured to pass along arbitrary header -// values from the client, or if you use this middleware without a reverse -// proxy, malicious clients will be able to make you very sad (or, depending on -// how you're using RemoteAddr, vulnerable to an attack of some sort). -func RealIP(h http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - if rip := realIP(r); rip != "" { - r.RemoteAddr = rip - } - h.ServeHTTP(w, r) - } - - return http.HandlerFunc(fn) -} - -func realIP(r *http.Request) string { - var ip string - - if xrip := r.Header.Get(xRealIP); xrip != "" { - ip = xrip - } else if xff := r.Header.Get(xForwardedFor); xff != "" { - i := strings.Index(xff, ", ") - if i == -1 { - i = len(xff) - } - ip = xff[:i] - } - - return ip -} diff --git a/vendor/github.com/go-chi/chi/middleware/recoverer.go b/vendor/github.com/go-chi/chi/middleware/recoverer.go deleted file mode 100644 index 785b18c52b..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/recoverer.go +++ /dev/null @@ -1,192 +0,0 @@ -package middleware - -// The original work was derived from Goji's middleware, source: -// https://github.com/zenazn/goji/tree/master/web/middleware - -import ( - "bytes" - "errors" - "fmt" - "net/http" - "os" - "runtime/debug" - "strings" -) - -// Recoverer is a middleware that recovers from panics, logs the panic (and a -// backtrace), and returns a HTTP 500 (Internal Server Error) status if -// possible. Recoverer prints a request ID if one is provided. -// -// Alternatively, look at https://github.com/pressly/lg middleware pkgs. -func Recoverer(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - defer func() { - if rvr := recover(); rvr != nil && rvr != http.ErrAbortHandler { - - logEntry := GetLogEntry(r) - if logEntry != nil { - logEntry.Panic(rvr, debug.Stack()) - } else { - PrintPrettyStack(rvr) - } - - w.WriteHeader(http.StatusInternalServerError) - } - }() - - next.ServeHTTP(w, r) - } - - return http.HandlerFunc(fn) -} - -func PrintPrettyStack(rvr interface{}) { - debugStack := debug.Stack() - s := prettyStack{} - out, err := s.parse(debugStack, rvr) - if err == nil { - os.Stderr.Write(out) - } else { - // print stdlib output as a fallback - os.Stderr.Write(debugStack) - } -} - -type prettyStack struct { -} - -func (s prettyStack) parse(debugStack []byte, rvr interface{}) ([]byte, error) { - var err error - useColor := true - buf := &bytes.Buffer{} - - cW(buf, false, bRed, "\n") - cW(buf, useColor, bCyan, " panic: ") - cW(buf, useColor, bBlue, "%v", rvr) - cW(buf, false, bWhite, "\n \n") - - // process debug stack info - stack := strings.Split(string(debugStack), "\n") - lines := []string{} - - // locate panic line, as we may have nested panics - for i := len(stack) - 1; i > 0; i-- { - lines = append(lines, stack[i]) - if strings.HasPrefix(stack[i], "panic(0x") { - lines = lines[0 : len(lines)-2] // remove boilerplate - break - } - } - - // reverse - for i := len(lines)/2 - 1; i >= 0; i-- { - opp := len(lines) - 1 - i - lines[i], lines[opp] = lines[opp], lines[i] - } - - // decorate - for i, line := range lines { - lines[i], err = s.decorateLine(line, useColor, i) - if err != nil { - return nil, err - } - } - - for _, l := range lines { - fmt.Fprintf(buf, "%s", l) - } - return buf.Bytes(), nil -} - -func (s prettyStack) decorateLine(line string, useColor bool, num int) (string, error) { - line = strings.TrimSpace(line) - if strings.HasPrefix(line, "\t") || strings.Contains(line, ".go:") { - return s.decorateSourceLine(line, useColor, num) - } else if strings.HasSuffix(line, ")") { - return s.decorateFuncCallLine(line, useColor, num) - } else { - if strings.HasPrefix(line, "\t") { - return strings.Replace(line, "\t", " ", 1), nil - } else { - return fmt.Sprintf(" %s\n", line), nil - } - } -} - -func (s prettyStack) decorateFuncCallLine(line string, useColor bool, num int) (string, error) { - idx := strings.LastIndex(line, "(") - if idx < 0 { - return "", errors.New("not a func call line") - } - - buf := &bytes.Buffer{} - pkg := line[0:idx] - // addr := line[idx:] - method := "" - - idx = strings.LastIndex(pkg, string(os.PathSeparator)) - if idx < 0 { - idx = strings.Index(pkg, ".") - method = pkg[idx:] - pkg = pkg[0:idx] - } else { - method = pkg[idx+1:] - pkg = pkg[0 : idx+1] - idx = strings.Index(method, ".") - pkg += method[0:idx] - method = method[idx:] - } - pkgColor := nYellow - methodColor := bGreen - - if num == 0 { - cW(buf, useColor, bRed, " -> ") - pkgColor = bMagenta - methodColor = bRed - } else { - cW(buf, useColor, bWhite, " ") - } - cW(buf, useColor, pkgColor, "%s", pkg) - cW(buf, useColor, methodColor, "%s\n", method) - // cW(buf, useColor, nBlack, "%s", addr) - return buf.String(), nil -} - -func (s prettyStack) decorateSourceLine(line string, useColor bool, num int) (string, error) { - idx := strings.LastIndex(line, ".go:") - if idx < 0 { - return "", errors.New("not a source line") - } - - buf := &bytes.Buffer{} - path := line[0 : idx+3] - lineno := line[idx+3:] - - idx = strings.LastIndex(path, string(os.PathSeparator)) - dir := path[0 : idx+1] - file := path[idx+1:] - - idx = strings.Index(lineno, " ") - if idx > 0 { - lineno = lineno[0:idx] - } - fileColor := bCyan - lineColor := bGreen - - if num == 1 { - cW(buf, useColor, bRed, " -> ") - fileColor = bRed - lineColor = bMagenta - } else { - cW(buf, false, bWhite, " ") - } - cW(buf, useColor, bWhite, "%s", dir) - cW(buf, useColor, fileColor, "%s", file) - cW(buf, useColor, lineColor, "%s", lineno) - if num == 1 { - cW(buf, false, bWhite, "\n") - } - cW(buf, false, bWhite, "\n") - - return buf.String(), nil -} diff --git a/vendor/github.com/go-chi/chi/middleware/request_id.go b/vendor/github.com/go-chi/chi/middleware/request_id.go deleted file mode 100644 index 4903ecc214..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/request_id.go +++ /dev/null @@ -1,96 +0,0 @@ -package middleware - -// Ported from Goji's middleware, source: -// https://github.com/zenazn/goji/tree/master/web/middleware - -import ( - "context" - "crypto/rand" - "encoding/base64" - "fmt" - "net/http" - "os" - "strings" - "sync/atomic" -) - -// Key to use when setting the request ID. -type ctxKeyRequestID int - -// RequestIDKey is the key that holds the unique request ID in a request context. -const RequestIDKey ctxKeyRequestID = 0 - -// RequestIDHeader is the name of the HTTP Header which contains the request id. -// Exported so that it can be changed by developers -var RequestIDHeader = "X-Request-Id" - -var prefix string -var reqid uint64 - -// A quick note on the statistics here: we're trying to calculate the chance that -// two randomly generated base62 prefixes will collide. We use the formula from -// http://en.wikipedia.org/wiki/Birthday_problem -// -// P[m, n] \approx 1 - e^{-m^2/2n} -// -// We ballpark an upper bound for $m$ by imagining (for whatever reason) a server -// that restarts every second over 10 years, for $m = 86400 * 365 * 10 = 315360000$ -// -// For a $k$ character base-62 identifier, we have $n(k) = 62^k$ -// -// Plugging this in, we find $P[m, n(10)] \approx 5.75%$, which is good enough for -// our purposes, and is surely more than anyone would ever need in practice -- a -// process that is rebooted a handful of times a day for a hundred years has less -// than a millionth of a percent chance of generating two colliding IDs. - -func init() { - hostname, err := os.Hostname() - if hostname == "" || err != nil { - hostname = "localhost" - } - var buf [12]byte - var b64 string - for len(b64) < 10 { - rand.Read(buf[:]) - b64 = base64.StdEncoding.EncodeToString(buf[:]) - b64 = strings.NewReplacer("+", "", "/", "").Replace(b64) - } - - prefix = fmt.Sprintf("%s/%s", hostname, b64[0:10]) -} - -// RequestID is a middleware that injects a request ID into the context of each -// request. A request ID is a string of the form "host.example.com/random-0001", -// where "random" is a base62 random string that uniquely identifies this go -// process, and where the last number is an atomically incremented request -// counter. -func RequestID(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - requestID := r.Header.Get(RequestIDHeader) - if requestID == "" { - myid := atomic.AddUint64(&reqid, 1) - requestID = fmt.Sprintf("%s-%06d", prefix, myid) - } - ctx = context.WithValue(ctx, RequestIDKey, requestID) - next.ServeHTTP(w, r.WithContext(ctx)) - } - return http.HandlerFunc(fn) -} - -// GetReqID returns a request ID from the given context if one is present. -// Returns the empty string if a request ID cannot be found. -func GetReqID(ctx context.Context) string { - if ctx == nil { - return "" - } - if reqID, ok := ctx.Value(RequestIDKey).(string); ok { - return reqID - } - return "" -} - -// NextRequestID generates the next request ID in the sequence. -func NextRequestID() uint64 { - return atomic.AddUint64(&reqid, 1) -} diff --git a/vendor/github.com/go-chi/chi/middleware/route_headers.go b/vendor/github.com/go-chi/chi/middleware/route_headers.go deleted file mode 100644 index 7ee30c8773..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/route_headers.go +++ /dev/null @@ -1,160 +0,0 @@ -package middleware - -import ( - "net/http" - "strings" -) - -// RouteHeaders is a neat little header-based router that allows you to direct -// the flow of a request through a middleware stack based on a request header. -// -// For example, lets say you'd like to setup multiple routers depending on the -// request Host header, you could then do something as so: -// -// r := chi.NewRouter() -// rSubdomain := chi.NewRouter() -// -// r.Use(middleware.RouteHeaders(). -// Route("Host", "example.com", middleware.New(r)). -// Route("Host", "*.example.com", middleware.New(rSubdomain)). -// Handler) -// -// r.Get("/", h) -// rSubdomain.Get("/", h2) -// -// -// Another example, imagine you want to setup multiple CORS handlers, where for -// your origin servers you allow authorized requests, but for third-party public -// requests, authorization is disabled. -// -// r := chi.NewRouter() -// -// r.Use(middleware.RouteHeaders(). -// Route("Origin", "https://app.skyweaver.net", cors.Handler(cors.Options{ -// AllowedOrigins: []string{"https://api.skyweaver.net"}, -// AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, -// AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"}, -// AllowCredentials: true, // <----------<<< allow credentials -// })). -// Route("Origin", "*", cors.Handler(cors.Options{ -// AllowedOrigins: []string{"*"}, -// AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, -// AllowedHeaders: []string{"Accept", "Content-Type"}, -// AllowCredentials: false, // <----------<<< do not allow credentials -// })). -// Handler) -// -func RouteHeaders() HeaderRouter { - return HeaderRouter{} -} - -type HeaderRouter map[string][]HeaderRoute - -func (hr HeaderRouter) Route(header string, match string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter { - header = strings.ToLower(header) - k := hr[header] - if k == nil { - hr[header] = []HeaderRoute{} - } - hr[header] = append(hr[header], HeaderRoute{MatchOne: NewPattern(match), Middleware: middlewareHandler}) - return hr -} - -func (hr HeaderRouter) RouteAny(header string, match []string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter { - header = strings.ToLower(header) - k := hr[header] - if k == nil { - hr[header] = []HeaderRoute{} - } - patterns := []Pattern{} - for _, m := range match { - patterns = append(patterns, NewPattern(m)) - } - hr[header] = append(hr[header], HeaderRoute{MatchAny: patterns, Middleware: middlewareHandler}) - return hr -} - -func (hr HeaderRouter) RouteDefault(handler func(next http.Handler) http.Handler) HeaderRouter { - hr["*"] = []HeaderRoute{{Middleware: handler}} - return hr -} - -func (hr HeaderRouter) Handler(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if len(hr) == 0 { - // skip if no routes set - next.ServeHTTP(w, r) - } - - // find first matching header route, and continue - for header, matchers := range hr { - headerValue := r.Header.Get(header) - if headerValue == "" { - continue - } - headerValue = strings.ToLower(headerValue) - for _, matcher := range matchers { - if matcher.IsMatch(headerValue) { - matcher.Middleware(next).ServeHTTP(w, r) - return - } - } - } - - // if no match, check for "*" default route - matcher, ok := hr["*"] - if !ok || matcher[0].Middleware == nil { - next.ServeHTTP(w, r) - return - } - matcher[0].Middleware(next).ServeHTTP(w, r) - }) -} - -type HeaderRoute struct { - MatchAny []Pattern - MatchOne Pattern - Middleware func(next http.Handler) http.Handler -} - -func (r HeaderRoute) IsMatch(value string) bool { - if len(r.MatchAny) > 0 { - for _, m := range r.MatchAny { - if m.Match(value) { - return true - } - } - } else if r.MatchOne.Match(value) { - return true - } - return false -} - -type Pattern struct { - prefix string - suffix string - wildcard bool -} - -func NewPattern(value string) Pattern { - p := Pattern{} - if i := strings.IndexByte(value, '*'); i >= 0 { - p.wildcard = true - p.prefix = value[0:i] - p.suffix = value[i+1:] - } else { - p.prefix = value - } - return p -} - -func (p Pattern) Match(v string) bool { - if !p.wildcard { - if p.prefix == v { - return true - } else { - return false - } - } - return len(v) >= len(p.prefix+p.suffix) && strings.HasPrefix(v, p.prefix) && strings.HasSuffix(v, p.suffix) -} diff --git a/vendor/github.com/go-chi/chi/middleware/strip.go b/vendor/github.com/go-chi/chi/middleware/strip.go deleted file mode 100644 index 2b8b1842ab..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/strip.go +++ /dev/null @@ -1,56 +0,0 @@ -package middleware - -import ( - "fmt" - "net/http" - - "github.com/go-chi/chi" -) - -// StripSlashes is a middleware that will match request paths with a trailing -// slash, strip it from the path and continue routing through the mux, if a route -// matches, then it will serve the handler. -func StripSlashes(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - var path string - rctx := chi.RouteContext(r.Context()) - if rctx.RoutePath != "" { - path = rctx.RoutePath - } else { - path = r.URL.Path - } - if len(path) > 1 && path[len(path)-1] == '/' { - rctx.RoutePath = path[:len(path)-1] - } - next.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) -} - -// RedirectSlashes is a middleware that will match request paths with a trailing -// slash and redirect to the same path, less the trailing slash. -// -// NOTE: RedirectSlashes middleware is *incompatible* with http.FileServer, -// see https://github.com/go-chi/chi/issues/343 -func RedirectSlashes(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - var path string - rctx := chi.RouteContext(r.Context()) - if rctx.RoutePath != "" { - path = rctx.RoutePath - } else { - path = r.URL.Path - } - if len(path) > 1 && path[len(path)-1] == '/' { - if r.URL.RawQuery != "" { - path = fmt.Sprintf("%s?%s", path[:len(path)-1], r.URL.RawQuery) - } else { - path = path[:len(path)-1] - } - http.Redirect(w, r, path, 301) - return - } - next.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) -} diff --git a/vendor/github.com/go-chi/chi/middleware/terminal.go b/vendor/github.com/go-chi/chi/middleware/terminal.go deleted file mode 100644 index 5ead7b9243..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/terminal.go +++ /dev/null @@ -1,63 +0,0 @@ -package middleware - -// Ported from Goji's middleware, source: -// https://github.com/zenazn/goji/tree/master/web/middleware - -import ( - "fmt" - "io" - "os" -) - -var ( - // Normal colors - nBlack = []byte{'\033', '[', '3', '0', 'm'} - nRed = []byte{'\033', '[', '3', '1', 'm'} - nGreen = []byte{'\033', '[', '3', '2', 'm'} - nYellow = []byte{'\033', '[', '3', '3', 'm'} - nBlue = []byte{'\033', '[', '3', '4', 'm'} - nMagenta = []byte{'\033', '[', '3', '5', 'm'} - nCyan = []byte{'\033', '[', '3', '6', 'm'} - nWhite = []byte{'\033', '[', '3', '7', 'm'} - // Bright colors - bBlack = []byte{'\033', '[', '3', '0', ';', '1', 'm'} - bRed = []byte{'\033', '[', '3', '1', ';', '1', 'm'} - bGreen = []byte{'\033', '[', '3', '2', ';', '1', 'm'} - bYellow = []byte{'\033', '[', '3', '3', ';', '1', 'm'} - bBlue = []byte{'\033', '[', '3', '4', ';', '1', 'm'} - bMagenta = []byte{'\033', '[', '3', '5', ';', '1', 'm'} - bCyan = []byte{'\033', '[', '3', '6', ';', '1', 'm'} - bWhite = []byte{'\033', '[', '3', '7', ';', '1', 'm'} - - reset = []byte{'\033', '[', '0', 'm'} -) - -var IsTTY bool - -func init() { - // This is sort of cheating: if stdout is a character device, we assume - // that means it's a TTY. Unfortunately, there are many non-TTY - // character devices, but fortunately stdout is rarely set to any of - // them. - // - // We could solve this properly by pulling in a dependency on - // code.google.com/p/go.crypto/ssh/terminal, for instance, but as a - // heuristic for whether to print in color or in black-and-white, I'd - // really rather not. - fi, err := os.Stdout.Stat() - if err == nil { - m := os.ModeDevice | os.ModeCharDevice - IsTTY = fi.Mode()&m == m - } -} - -// colorWrite -func cW(w io.Writer, useColor bool, color []byte, s string, args ...interface{}) { - if IsTTY && useColor { - w.Write(color) - } - fmt.Fprintf(w, s, args...) - if IsTTY && useColor { - w.Write(reset) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/throttle.go b/vendor/github.com/go-chi/chi/middleware/throttle.go deleted file mode 100644 index fdedd3c127..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/throttle.go +++ /dev/null @@ -1,132 +0,0 @@ -package middleware - -import ( - "net/http" - "strconv" - "time" -) - -const ( - errCapacityExceeded = "Server capacity exceeded." - errTimedOut = "Timed out while waiting for a pending request to complete." - errContextCanceled = "Context was canceled." -) - -var ( - defaultBacklogTimeout = time.Second * 60 -) - -// ThrottleOpts represents a set of throttling options. -type ThrottleOpts struct { - Limit int - BacklogLimit int - BacklogTimeout time.Duration - RetryAfterFn func(ctxDone bool) time.Duration -} - -// Throttle is a middleware that limits number of currently processed requests -// at a time across all users. Note: Throttle is not a rate-limiter per user, -// instead it just puts a ceiling on the number of currentl in-flight requests -// being processed from the point from where the Throttle middleware is mounted. -func Throttle(limit int) func(http.Handler) http.Handler { - return ThrottleWithOpts(ThrottleOpts{Limit: limit, BacklogTimeout: defaultBacklogTimeout}) -} - -// ThrottleBacklog is a middleware that limits number of currently processed -// requests at a time and provides a backlog for holding a finite number of -// pending requests. -func ThrottleBacklog(limit int, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler { - return ThrottleWithOpts(ThrottleOpts{Limit: limit, BacklogLimit: backlogLimit, BacklogTimeout: backlogTimeout}) -} - -// ThrottleWithOpts is a middleware that limits number of currently processed requests using passed ThrottleOpts. -func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler { - if opts.Limit < 1 { - panic("chi/middleware: Throttle expects limit > 0") - } - - if opts.BacklogLimit < 0 { - panic("chi/middleware: Throttle expects backlogLimit to be positive") - } - - t := throttler{ - tokens: make(chan token, opts.Limit), - backlogTokens: make(chan token, opts.Limit+opts.BacklogLimit), - backlogTimeout: opts.BacklogTimeout, - retryAfterFn: opts.RetryAfterFn, - } - - // Filling tokens. - for i := 0; i < opts.Limit+opts.BacklogLimit; i++ { - if i < opts.Limit { - t.tokens <- token{} - } - t.backlogTokens <- token{} - } - - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - select { - - case <-ctx.Done(): - t.setRetryAfterHeaderIfNeeded(w, true) - http.Error(w, errContextCanceled, http.StatusServiceUnavailable) - return - - case btok := <-t.backlogTokens: - timer := time.NewTimer(t.backlogTimeout) - - defer func() { - t.backlogTokens <- btok - }() - - select { - case <-timer.C: - t.setRetryAfterHeaderIfNeeded(w, false) - http.Error(w, errTimedOut, http.StatusServiceUnavailable) - return - case <-ctx.Done(): - timer.Stop() - t.setRetryAfterHeaderIfNeeded(w, true) - http.Error(w, errContextCanceled, http.StatusServiceUnavailable) - return - case tok := <-t.tokens: - defer func() { - timer.Stop() - t.tokens <- tok - }() - next.ServeHTTP(w, r) - } - return - - default: - t.setRetryAfterHeaderIfNeeded(w, false) - http.Error(w, errCapacityExceeded, http.StatusServiceUnavailable) - return - } - } - - return http.HandlerFunc(fn) - } -} - -// token represents a request that is being processed. -type token struct{} - -// throttler limits number of currently processed requests at a time. -type throttler struct { - tokens chan token - backlogTokens chan token - backlogTimeout time.Duration - retryAfterFn func(ctxDone bool) time.Duration -} - -// setRetryAfterHeaderIfNeeded sets Retry-After HTTP header if corresponding retryAfterFn option of throttler is initialized. -func (t throttler) setRetryAfterHeaderIfNeeded(w http.ResponseWriter, ctxDone bool) { - if t.retryAfterFn == nil { - return - } - w.Header().Set("Retry-After", strconv.Itoa(int(t.retryAfterFn(ctxDone).Seconds()))) -} diff --git a/vendor/github.com/go-chi/chi/middleware/timeout.go b/vendor/github.com/go-chi/chi/middleware/timeout.go deleted file mode 100644 index 8e373536cf..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/timeout.go +++ /dev/null @@ -1,49 +0,0 @@ -package middleware - -import ( - "context" - "net/http" - "time" -) - -// Timeout is a middleware that cancels ctx after a given timeout and return -// a 504 Gateway Timeout error to the client. -// -// It's required that you select the ctx.Done() channel to check for the signal -// if the context has reached its deadline and return, otherwise the timeout -// signal will be just ignored. -// -// ie. a route/handler may look like: -// -// r.Get("/long", func(w http.ResponseWriter, r *http.Request) { -// ctx := r.Context() -// processTime := time.Duration(rand.Intn(4)+1) * time.Second -// -// select { -// case <-ctx.Done(): -// return -// -// case <-time.After(processTime): -// // The above channel simulates some hard work. -// } -// -// w.Write([]byte("done")) -// }) -// -func Timeout(timeout time.Duration) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - ctx, cancel := context.WithTimeout(r.Context(), timeout) - defer func() { - cancel() - if ctx.Err() == context.DeadlineExceeded { - w.WriteHeader(http.StatusGatewayTimeout) - } - }() - - r = r.WithContext(ctx) - next.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/url_format.go b/vendor/github.com/go-chi/chi/middleware/url_format.go deleted file mode 100644 index 5749e4f32b..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/url_format.go +++ /dev/null @@ -1,72 +0,0 @@ -package middleware - -import ( - "context" - "net/http" - "strings" - - "github.com/go-chi/chi" -) - -var ( - // URLFormatCtxKey is the context.Context key to store the URL format data - // for a request. - URLFormatCtxKey = &contextKey{"URLFormat"} -) - -// URLFormat is a middleware that parses the url extension from a request path and stores it -// on the context as a string under the key `middleware.URLFormatCtxKey`. The middleware will -// trim the suffix from the routing path and continue routing. -// -// Routers should not include a url parameter for the suffix when using this middleware. -// -// Sample usage.. for url paths: `/articles/1`, `/articles/1.json` and `/articles/1.xml` -// -// func routes() http.Handler { -// r := chi.NewRouter() -// r.Use(middleware.URLFormat) -// -// r.Get("/articles/{id}", ListArticles) -// -// return r -// } -// -// func ListArticles(w http.ResponseWriter, r *http.Request) { -// urlFormat, _ := r.Context().Value(middleware.URLFormatCtxKey).(string) -// -// switch urlFormat { -// case "json": -// render.JSON(w, r, articles) -// case "xml:" -// render.XML(w, r, articles) -// default: -// render.JSON(w, r, articles) -// } -// } -// -func URLFormat(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var format string - path := r.URL.Path - - if strings.Index(path, ".") > 0 { - base := strings.LastIndex(path, "/") - idx := strings.Index(path[base:], ".") - - if idx > 0 { - idx += base - format = path[idx+1:] - - rctx := chi.RouteContext(r.Context()) - rctx.RoutePath = path[:idx] - } - } - - r = r.WithContext(context.WithValue(ctx, URLFormatCtxKey, format)) - - next.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) -} diff --git a/vendor/github.com/go-chi/chi/middleware/value.go b/vendor/github.com/go-chi/chi/middleware/value.go deleted file mode 100644 index fbbd0393fb..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/value.go +++ /dev/null @@ -1,17 +0,0 @@ -package middleware - -import ( - "context" - "net/http" -) - -// WithValue is a middleware that sets a given key/value in a context chain. -func WithValue(key interface{}, val interface{}) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - r = r.WithContext(context.WithValue(r.Context(), key, val)) - next.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/wrap_writer.go b/vendor/github.com/go-chi/chi/middleware/wrap_writer.go deleted file mode 100644 index 382a523e48..0000000000 --- a/vendor/github.com/go-chi/chi/middleware/wrap_writer.go +++ /dev/null @@ -1,180 +0,0 @@ -package middleware - -// The original work was derived from Goji's middleware, source: -// https://github.com/zenazn/goji/tree/master/web/middleware - -import ( - "bufio" - "io" - "net" - "net/http" -) - -// NewWrapResponseWriter wraps an http.ResponseWriter, returning a proxy that allows you to -// hook into various parts of the response process. -func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWriter { - _, fl := w.(http.Flusher) - - bw := basicWriter{ResponseWriter: w} - - if protoMajor == 2 { - _, ps := w.(http.Pusher) - if fl && ps { - return &http2FancyWriter{bw} - } - } else { - _, hj := w.(http.Hijacker) - _, rf := w.(io.ReaderFrom) - if fl && hj && rf { - return &httpFancyWriter{bw} - } - } - if fl { - return &flushWriter{bw} - } - - return &bw -} - -// WrapResponseWriter is a proxy around an http.ResponseWriter that allows you to hook -// into various parts of the response process. -type WrapResponseWriter interface { - http.ResponseWriter - // Status returns the HTTP status of the request, or 0 if one has not - // yet been sent. - Status() int - // BytesWritten returns the total number of bytes sent to the client. - BytesWritten() int - // Tee causes the response body to be written to the given io.Writer in - // addition to proxying the writes through. Only one io.Writer can be - // tee'd to at once: setting a second one will overwrite the first. - // Writes will be sent to the proxy before being written to this - // io.Writer. It is illegal for the tee'd writer to be modified - // concurrently with writes. - Tee(io.Writer) - // Unwrap returns the original proxied target. - Unwrap() http.ResponseWriter -} - -// basicWriter wraps a http.ResponseWriter that implements the minimal -// http.ResponseWriter interface. -type basicWriter struct { - http.ResponseWriter - wroteHeader bool - code int - bytes int - tee io.Writer -} - -func (b *basicWriter) WriteHeader(code int) { - if !b.wroteHeader { - b.code = code - b.wroteHeader = true - b.ResponseWriter.WriteHeader(code) - } -} - -func (b *basicWriter) Write(buf []byte) (int, error) { - b.maybeWriteHeader() - n, err := b.ResponseWriter.Write(buf) - if b.tee != nil { - _, err2 := b.tee.Write(buf[:n]) - // Prefer errors generated by the proxied writer. - if err == nil { - err = err2 - } - } - b.bytes += n - return n, err -} - -func (b *basicWriter) maybeWriteHeader() { - if !b.wroteHeader { - b.WriteHeader(http.StatusOK) - } -} - -func (b *basicWriter) Status() int { - return b.code -} - -func (b *basicWriter) BytesWritten() int { - return b.bytes -} - -func (b *basicWriter) Tee(w io.Writer) { - b.tee = w -} - -func (b *basicWriter) Unwrap() http.ResponseWriter { - return b.ResponseWriter -} - -type flushWriter struct { - basicWriter -} - -func (f *flushWriter) Flush() { - f.wroteHeader = true - fl := f.basicWriter.ResponseWriter.(http.Flusher) - fl.Flush() -} - -var _ http.Flusher = &flushWriter{} - -// httpFancyWriter is a HTTP writer that additionally satisfies -// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case -// of wrapping the http.ResponseWriter that package http gives you, in order to -// make the proxied object support the full method set of the proxied object. -type httpFancyWriter struct { - basicWriter -} - -func (f *httpFancyWriter) Flush() { - f.wroteHeader = true - fl := f.basicWriter.ResponseWriter.(http.Flusher) - fl.Flush() -} - -func (f *httpFancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hj := f.basicWriter.ResponseWriter.(http.Hijacker) - return hj.Hijack() -} - -func (f *http2FancyWriter) Push(target string, opts *http.PushOptions) error { - return f.basicWriter.ResponseWriter.(http.Pusher).Push(target, opts) -} - -func (f *httpFancyWriter) ReadFrom(r io.Reader) (int64, error) { - if f.basicWriter.tee != nil { - n, err := io.Copy(&f.basicWriter, r) - f.basicWriter.bytes += int(n) - return n, err - } - rf := f.basicWriter.ResponseWriter.(io.ReaderFrom) - f.basicWriter.maybeWriteHeader() - n, err := rf.ReadFrom(r) - f.basicWriter.bytes += int(n) - return n, err -} - -var _ http.Flusher = &httpFancyWriter{} -var _ http.Hijacker = &httpFancyWriter{} -var _ http.Pusher = &http2FancyWriter{} -var _ io.ReaderFrom = &httpFancyWriter{} - -// http2FancyWriter is a HTTP2 writer that additionally satisfies -// http.Flusher, and io.ReaderFrom. It exists for the common case -// of wrapping the http.ResponseWriter that package http gives you, in order to -// make the proxied object support the full method set of the proxied object. -type http2FancyWriter struct { - basicWriter -} - -func (f *http2FancyWriter) Flush() { - f.wroteHeader = true - fl := f.basicWriter.ResponseWriter.(http.Flusher) - fl.Flush() -} - -var _ http.Flusher = &http2FancyWriter{} diff --git a/vendor/github.com/go-chi/chi/mux.go b/vendor/github.com/go-chi/chi/mux.go deleted file mode 100644 index 52950e97b5..0000000000 --- a/vendor/github.com/go-chi/chi/mux.go +++ /dev/null @@ -1,466 +0,0 @@ -package chi - -import ( - "context" - "fmt" - "net/http" - "strings" - "sync" -) - -var _ Router = &Mux{} - -// Mux is a simple HTTP route multiplexer that parses a request path, -// records any URL params, and executes an end handler. It implements -// the http.Handler interface and is friendly with the standard library. -// -// Mux is designed to be fast, minimal and offer a powerful API for building -// modular and composable HTTP services with a large set of handlers. It's -// particularly useful for writing large REST API services that break a handler -// into many smaller parts composed of middlewares and end handlers. -type Mux struct { - // The radix trie router - tree *node - - // The middleware stack - middlewares []func(http.Handler) http.Handler - - // Controls the behaviour of middleware chain generation when a mux - // is registered as an inline group inside another mux. - inline bool - parent *Mux - - // The computed mux handler made of the chained middleware stack and - // the tree router - handler http.Handler - - // Routing context pool - pool *sync.Pool - - // Custom route not found handler - notFoundHandler http.HandlerFunc - - // Custom method not allowed handler - methodNotAllowedHandler http.HandlerFunc -} - -// NewMux returns a newly initialized Mux object that implements the Router -// interface. -func NewMux() *Mux { - mux := &Mux{tree: &node{}, pool: &sync.Pool{}} - mux.pool.New = func() interface{} { - return NewRouteContext() - } - return mux -} - -// ServeHTTP is the single method of the http.Handler interface that makes -// Mux interoperable with the standard library. It uses a sync.Pool to get and -// reuse routing contexts for each request. -func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // Ensure the mux has some routes defined on the mux - if mx.handler == nil { - mx.NotFoundHandler().ServeHTTP(w, r) - return - } - - // Check if a routing context already exists from a parent router. - rctx, _ := r.Context().Value(RouteCtxKey).(*Context) - if rctx != nil { - mx.handler.ServeHTTP(w, r) - return - } - - // Fetch a RouteContext object from the sync pool, and call the computed - // mx.handler that is comprised of mx.middlewares + mx.routeHTTP. - // Once the request is finished, reset the routing context and put it back - // into the pool for reuse from another request. - rctx = mx.pool.Get().(*Context) - rctx.Reset() - rctx.Routes = mx - - // NOTE: r.WithContext() causes 2 allocations and context.WithValue() causes 1 allocation - r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx)) - - // Serve the request and once its done, put the request context back in the sync pool - mx.handler.ServeHTTP(w, r) - mx.pool.Put(rctx) -} - -// Use appends a middleware handler to the Mux middleware stack. -// -// The middleware stack for any Mux will execute before searching for a matching -// route to a specific handler, which provides opportunity to respond early, -// change the course of the request execution, or set request-scoped values for -// the next http.Handler. -func (mx *Mux) Use(middlewares ...func(http.Handler) http.Handler) { - if mx.handler != nil { - panic("chi: all middlewares must be defined before routes on a mux") - } - mx.middlewares = append(mx.middlewares, middlewares...) -} - -// Handle adds the route `pattern` that matches any http method to -// execute the `handler` http.Handler. -func (mx *Mux) Handle(pattern string, handler http.Handler) { - mx.handle(mALL, pattern, handler) -} - -// HandleFunc adds the route `pattern` that matches any http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) HandleFunc(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mALL, pattern, handlerFn) -} - -// Method adds the route `pattern` that matches `method` http method to -// execute the `handler` http.Handler. -func (mx *Mux) Method(method, pattern string, handler http.Handler) { - m, ok := methodMap[strings.ToUpper(method)] - if !ok { - panic(fmt.Sprintf("chi: '%s' http method is not supported.", method)) - } - mx.handle(m, pattern, handler) -} - -// MethodFunc adds the route `pattern` that matches `method` http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) MethodFunc(method, pattern string, handlerFn http.HandlerFunc) { - mx.Method(method, pattern, handlerFn) -} - -// Connect adds the route `pattern` that matches a CONNECT http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Connect(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mCONNECT, pattern, handlerFn) -} - -// Delete adds the route `pattern` that matches a DELETE http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Delete(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mDELETE, pattern, handlerFn) -} - -// Get adds the route `pattern` that matches a GET http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Get(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mGET, pattern, handlerFn) -} - -// Head adds the route `pattern` that matches a HEAD http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Head(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mHEAD, pattern, handlerFn) -} - -// Options adds the route `pattern` that matches a OPTIONS http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Options(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mOPTIONS, pattern, handlerFn) -} - -// Patch adds the route `pattern` that matches a PATCH http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Patch(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mPATCH, pattern, handlerFn) -} - -// Post adds the route `pattern` that matches a POST http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Post(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mPOST, pattern, handlerFn) -} - -// Put adds the route `pattern` that matches a PUT http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Put(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mPUT, pattern, handlerFn) -} - -// Trace adds the route `pattern` that matches a TRACE http method to -// execute the `handlerFn` http.HandlerFunc. -func (mx *Mux) Trace(pattern string, handlerFn http.HandlerFunc) { - mx.handle(mTRACE, pattern, handlerFn) -} - -// NotFound sets a custom http.HandlerFunc for routing paths that could -// not be found. The default 404 handler is `http.NotFound`. -func (mx *Mux) NotFound(handlerFn http.HandlerFunc) { - // Build NotFound handler chain - m := mx - hFn := handlerFn - if mx.inline && mx.parent != nil { - m = mx.parent - hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP - } - - // Update the notFoundHandler from this point forward - m.notFoundHandler = hFn - m.updateSubRoutes(func(subMux *Mux) { - if subMux.notFoundHandler == nil { - subMux.NotFound(hFn) - } - }) -} - -// MethodNotAllowed sets a custom http.HandlerFunc for routing paths where the -// method is unresolved. The default handler returns a 405 with an empty body. -func (mx *Mux) MethodNotAllowed(handlerFn http.HandlerFunc) { - // Build MethodNotAllowed handler chain - m := mx - hFn := handlerFn - if mx.inline && mx.parent != nil { - m = mx.parent - hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP - } - - // Update the methodNotAllowedHandler from this point forward - m.methodNotAllowedHandler = hFn - m.updateSubRoutes(func(subMux *Mux) { - if subMux.methodNotAllowedHandler == nil { - subMux.MethodNotAllowed(hFn) - } - }) -} - -// With adds inline middlewares for an endpoint handler. -func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router { - // Similarly as in handle(), we must build the mux handler once additional - // middleware registration isn't allowed for this stack, like now. - if !mx.inline && mx.handler == nil { - mx.buildRouteHandler() - } - - // Copy middlewares from parent inline muxs - var mws Middlewares - if mx.inline { - mws = make(Middlewares, len(mx.middlewares)) - copy(mws, mx.middlewares) - } - mws = append(mws, middlewares...) - - im := &Mux{ - pool: mx.pool, inline: true, parent: mx, tree: mx.tree, middlewares: mws, - notFoundHandler: mx.notFoundHandler, methodNotAllowedHandler: mx.methodNotAllowedHandler, - } - - return im -} - -// Group creates a new inline-Mux with a fresh middleware stack. It's useful -// for a group of handlers along the same routing path that use an additional -// set of middlewares. See _examples/. -func (mx *Mux) Group(fn func(r Router)) Router { - im := mx.With().(*Mux) - if fn != nil { - fn(im) - } - return im -} - -// Route creates a new Mux with a fresh middleware stack and mounts it -// along the `pattern` as a subrouter. Effectively, this is a short-hand -// call to Mount. See _examples/. -func (mx *Mux) Route(pattern string, fn func(r Router)) Router { - subRouter := NewRouter() - if fn != nil { - fn(subRouter) - } - mx.Mount(pattern, subRouter) - return subRouter -} - -// Mount attaches another http.Handler or chi Router as a subrouter along a routing -// path. It's very useful to split up a large API as many independent routers and -// compose them as a single service using Mount. See _examples/. -// -// Note that Mount() simply sets a wildcard along the `pattern` that will continue -// routing at the `handler`, which in most cases is another chi.Router. As a result, -// if you define two Mount() routes on the exact same pattern the mount will panic. -func (mx *Mux) Mount(pattern string, handler http.Handler) { - // Provide runtime safety for ensuring a pattern isn't mounted on an existing - // routing pattern. - if mx.tree.findPattern(pattern+"*") || mx.tree.findPattern(pattern+"/*") { - panic(fmt.Sprintf("chi: attempting to Mount() a handler on an existing path, '%s'", pattern)) - } - - // Assign sub-Router's with the parent not found & method not allowed handler if not specified. - subr, ok := handler.(*Mux) - if ok && subr.notFoundHandler == nil && mx.notFoundHandler != nil { - subr.NotFound(mx.notFoundHandler) - } - if ok && subr.methodNotAllowedHandler == nil && mx.methodNotAllowedHandler != nil { - subr.MethodNotAllowed(mx.methodNotAllowedHandler) - } - - mountHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - rctx := RouteContext(r.Context()) - rctx.RoutePath = mx.nextRoutePath(rctx) - handler.ServeHTTP(w, r) - }) - - if pattern == "" || pattern[len(pattern)-1] != '/' { - mx.handle(mALL|mSTUB, pattern, mountHandler) - mx.handle(mALL|mSTUB, pattern+"/", mountHandler) - pattern += "/" - } - - method := mALL - subroutes, _ := handler.(Routes) - if subroutes != nil { - method |= mSTUB - } - n := mx.handle(method, pattern+"*", mountHandler) - - if subroutes != nil { - n.subroutes = subroutes - } -} - -// Routes returns a slice of routing information from the tree, -// useful for traversing available routes of a router. -func (mx *Mux) Routes() []Route { - return mx.tree.routes() -} - -// Middlewares returns a slice of middleware handler functions. -func (mx *Mux) Middlewares() Middlewares { - return mx.middlewares -} - -// Match searches the routing tree for a handler that matches the method/path. -// It's similar to routing a http request, but without executing the handler -// thereafter. -// -// Note: the *Context state is updated during execution, so manage -// the state carefully or make a NewRouteContext(). -func (mx *Mux) Match(rctx *Context, method, path string) bool { - m, ok := methodMap[method] - if !ok { - return false - } - - node, _, h := mx.tree.FindRoute(rctx, m, path) - - if node != nil && node.subroutes != nil { - rctx.RoutePath = mx.nextRoutePath(rctx) - return node.subroutes.Match(rctx, method, rctx.RoutePath) - } - - return h != nil -} - -// NotFoundHandler returns the default Mux 404 responder whenever a route -// cannot be found. -func (mx *Mux) NotFoundHandler() http.HandlerFunc { - if mx.notFoundHandler != nil { - return mx.notFoundHandler - } - return http.NotFound -} - -// MethodNotAllowedHandler returns the default Mux 405 responder whenever -// a method cannot be resolved for a route. -func (mx *Mux) MethodNotAllowedHandler() http.HandlerFunc { - if mx.methodNotAllowedHandler != nil { - return mx.methodNotAllowedHandler - } - return methodNotAllowedHandler -} - -// buildRouteHandler builds the single mux handler that is a chain of the middleware -// stack, as defined by calls to Use(), and the tree router (Mux) itself. After this -// point, no other middlewares can be registered on this Mux's stack. But you can still -// compose additional middlewares via Group()'s or using a chained middleware handler. -func (mx *Mux) buildRouteHandler() { - mx.handler = chain(mx.middlewares, http.HandlerFunc(mx.routeHTTP)) -} - -// handle registers a http.Handler in the routing tree for a particular http method -// and routing pattern. -func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *node { - if len(pattern) == 0 || pattern[0] != '/' { - panic(fmt.Sprintf("chi: routing pattern must begin with '/' in '%s'", pattern)) - } - - // Build the computed routing handler for this routing pattern. - if !mx.inline && mx.handler == nil { - mx.buildRouteHandler() - } - - // Build endpoint handler with inline middlewares for the route - var h http.Handler - if mx.inline { - mx.handler = http.HandlerFunc(mx.routeHTTP) - h = Chain(mx.middlewares...).Handler(handler) - } else { - h = handler - } - - // Add the endpoint to the tree and return the node - return mx.tree.InsertRoute(method, pattern, h) -} - -// routeHTTP routes a http.Request through the Mux routing tree to serve -// the matching handler for a particular http method. -func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) { - // Grab the route context object - rctx := r.Context().Value(RouteCtxKey).(*Context) - - // The request routing path - routePath := rctx.RoutePath - if routePath == "" { - if r.URL.RawPath != "" { - routePath = r.URL.RawPath - } else { - routePath = r.URL.Path - } - } - - // Check if method is supported by chi - if rctx.RouteMethod == "" { - rctx.RouteMethod = r.Method - } - method, ok := methodMap[rctx.RouteMethod] - if !ok { - mx.MethodNotAllowedHandler().ServeHTTP(w, r) - return - } - - // Find the route - if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil { - h.ServeHTTP(w, r) - return - } - if rctx.methodNotAllowed { - mx.MethodNotAllowedHandler().ServeHTTP(w, r) - } else { - mx.NotFoundHandler().ServeHTTP(w, r) - } -} - -func (mx *Mux) nextRoutePath(rctx *Context) string { - routePath := "/" - nx := len(rctx.routeParams.Keys) - 1 // index of last param in list - if nx >= 0 && rctx.routeParams.Keys[nx] == "*" && len(rctx.routeParams.Values) > nx { - routePath = "/" + rctx.routeParams.Values[nx] - } - return routePath -} - -// Recursively update data on child routers. -func (mx *Mux) updateSubRoutes(fn func(subMux *Mux)) { - for _, r := range mx.tree.routes() { - subMux, ok := r.SubRoutes.(*Mux) - if !ok { - continue - } - fn(subMux) - } -} - -// methodNotAllowedHandler is a helper function to respond with a 405, -// method not allowed. -func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(405) - w.Write(nil) -} diff --git a/vendor/github.com/go-chi/chi/tree.go b/vendor/github.com/go-chi/chi/tree.go deleted file mode 100644 index 59b5b5f7b0..0000000000 --- a/vendor/github.com/go-chi/chi/tree.go +++ /dev/null @@ -1,865 +0,0 @@ -package chi - -// Radix tree implementation below is a based on the original work by -// Armon Dadgar in https://github.com/armon/go-radix/blob/master/radix.go -// (MIT licensed). It's been heavily modified for use as a HTTP routing tree. - -import ( - "fmt" - "math" - "net/http" - "regexp" - "sort" - "strconv" - "strings" -) - -type methodTyp int - -const ( - mSTUB methodTyp = 1 << iota - mCONNECT - mDELETE - mGET - mHEAD - mOPTIONS - mPATCH - mPOST - mPUT - mTRACE -) - -var mALL = mCONNECT | mDELETE | mGET | mHEAD | - mOPTIONS | mPATCH | mPOST | mPUT | mTRACE - -var methodMap = map[string]methodTyp{ - http.MethodConnect: mCONNECT, - http.MethodDelete: mDELETE, - http.MethodGet: mGET, - http.MethodHead: mHEAD, - http.MethodOptions: mOPTIONS, - http.MethodPatch: mPATCH, - http.MethodPost: mPOST, - http.MethodPut: mPUT, - http.MethodTrace: mTRACE, -} - -// RegisterMethod adds support for custom HTTP method handlers, available -// via Router#Method and Router#MethodFunc -func RegisterMethod(method string) { - if method == "" { - return - } - method = strings.ToUpper(method) - if _, ok := methodMap[method]; ok { - return - } - n := len(methodMap) - if n > strconv.IntSize { - panic(fmt.Sprintf("chi: max number of methods reached (%d)", strconv.IntSize)) - } - mt := methodTyp(math.Exp2(float64(n))) - methodMap[method] = mt - mALL |= mt -} - -type nodeTyp uint8 - -const ( - ntStatic nodeTyp = iota // /home - ntRegexp // /{id:[0-9]+} - ntParam // /{user} - ntCatchAll // /api/v1/* -) - -type node struct { - // node type: static, regexp, param, catchAll - typ nodeTyp - - // first byte of the prefix - label byte - - // first byte of the child prefix - tail byte - - // prefix is the common prefix we ignore - prefix string - - // regexp matcher for regexp nodes - rex *regexp.Regexp - - // HTTP handler endpoints on the leaf node - endpoints endpoints - - // subroutes on the leaf node - subroutes Routes - - // child nodes should be stored in-order for iteration, - // in groups of the node type. - children [ntCatchAll + 1]nodes -} - -// endpoints is a mapping of http method constants to handlers -// for a given route. -type endpoints map[methodTyp]*endpoint - -type endpoint struct { - // endpoint handler - handler http.Handler - - // pattern is the routing pattern for handler nodes - pattern string - - // parameter keys recorded on handler nodes - paramKeys []string -} - -func (s endpoints) Value(method methodTyp) *endpoint { - mh, ok := s[method] - if !ok { - mh = &endpoint{} - s[method] = mh - } - return mh -} - -func (n *node) InsertRoute(method methodTyp, pattern string, handler http.Handler) *node { - var parent *node - search := pattern - - for { - // Handle key exhaustion - if len(search) == 0 { - // Insert or update the node's leaf handler - n.setEndpoint(method, handler, pattern) - return n - } - - // We're going to be searching for a wild node next, - // in this case, we need to get the tail - var label = search[0] - var segTail byte - var segEndIdx int - var segTyp nodeTyp - var segRexpat string - if label == '{' || label == '*' { - segTyp, _, segRexpat, segTail, _, segEndIdx = patNextSegment(search) - } - - var prefix string - if segTyp == ntRegexp { - prefix = segRexpat - } - - // Look for the edge to attach to - parent = n - n = n.getEdge(segTyp, label, segTail, prefix) - - // No edge, create one - if n == nil { - child := &node{label: label, tail: segTail, prefix: search} - hn := parent.addChild(child, search) - hn.setEndpoint(method, handler, pattern) - - return hn - } - - // Found an edge to match the pattern - - if n.typ > ntStatic { - // We found a param node, trim the param from the search path and continue. - // This param/wild pattern segment would already be on the tree from a previous - // call to addChild when creating a new node. - search = search[segEndIdx:] - continue - } - - // Static nodes fall below here. - // Determine longest prefix of the search key on match. - commonPrefix := longestPrefix(search, n.prefix) - if commonPrefix == len(n.prefix) { - // the common prefix is as long as the current node's prefix we're attempting to insert. - // keep the search going. - search = search[commonPrefix:] - continue - } - - // Split the node - child := &node{ - typ: ntStatic, - prefix: search[:commonPrefix], - } - parent.replaceChild(search[0], segTail, child) - - // Restore the existing node - n.label = n.prefix[commonPrefix] - n.prefix = n.prefix[commonPrefix:] - child.addChild(n, n.prefix) - - // If the new key is a subset, set the method/handler on this node and finish. - search = search[commonPrefix:] - if len(search) == 0 { - child.setEndpoint(method, handler, pattern) - return child - } - - // Create a new edge for the node - subchild := &node{ - typ: ntStatic, - label: search[0], - prefix: search, - } - hn := child.addChild(subchild, search) - hn.setEndpoint(method, handler, pattern) - return hn - } -} - -// addChild appends the new `child` node to the tree using the `pattern` as the trie key. -// For a URL router like chi's, we split the static, param, regexp and wildcard segments -// into different nodes. In addition, addChild will recursively call itself until every -// pattern segment is added to the url pattern tree as individual nodes, depending on type. -func (n *node) addChild(child *node, prefix string) *node { - search := prefix - - // handler leaf node added to the tree is the child. - // this may be overridden later down the flow - hn := child - - // Parse next segment - segTyp, _, segRexpat, segTail, segStartIdx, segEndIdx := patNextSegment(search) - - // Add child depending on next up segment - switch segTyp { - - case ntStatic: - // Search prefix is all static (that is, has no params in path) - // noop - - default: - // Search prefix contains a param, regexp or wildcard - - if segTyp == ntRegexp { - rex, err := regexp.Compile(segRexpat) - if err != nil { - panic(fmt.Sprintf("chi: invalid regexp pattern '%s' in route param", segRexpat)) - } - child.prefix = segRexpat - child.rex = rex - } - - if segStartIdx == 0 { - // Route starts with a param - child.typ = segTyp - - if segTyp == ntCatchAll { - segStartIdx = -1 - } else { - segStartIdx = segEndIdx - } - if segStartIdx < 0 { - segStartIdx = len(search) - } - child.tail = segTail // for params, we set the tail - - if segStartIdx != len(search) { - // add static edge for the remaining part, split the end. - // its not possible to have adjacent param nodes, so its certainly - // going to be a static node next. - - search = search[segStartIdx:] // advance search position - - nn := &node{ - typ: ntStatic, - label: search[0], - prefix: search, - } - hn = child.addChild(nn, search) - } - - } else if segStartIdx > 0 { - // Route has some param - - // starts with a static segment - child.typ = ntStatic - child.prefix = search[:segStartIdx] - child.rex = nil - - // add the param edge node - search = search[segStartIdx:] - - nn := &node{ - typ: segTyp, - label: search[0], - tail: segTail, - } - hn = child.addChild(nn, search) - - } - } - - n.children[child.typ] = append(n.children[child.typ], child) - n.children[child.typ].Sort() - return hn -} - -func (n *node) replaceChild(label, tail byte, child *node) { - for i := 0; i < len(n.children[child.typ]); i++ { - if n.children[child.typ][i].label == label && n.children[child.typ][i].tail == tail { - n.children[child.typ][i] = child - n.children[child.typ][i].label = label - n.children[child.typ][i].tail = tail - return - } - } - panic("chi: replacing missing child") -} - -func (n *node) getEdge(ntyp nodeTyp, label, tail byte, prefix string) *node { - nds := n.children[ntyp] - for i := 0; i < len(nds); i++ { - if nds[i].label == label && nds[i].tail == tail { - if ntyp == ntRegexp && nds[i].prefix != prefix { - continue - } - return nds[i] - } - } - return nil -} - -func (n *node) setEndpoint(method methodTyp, handler http.Handler, pattern string) { - // Set the handler for the method type on the node - if n.endpoints == nil { - n.endpoints = make(endpoints) - } - - paramKeys := patParamKeys(pattern) - - if method&mSTUB == mSTUB { - n.endpoints.Value(mSTUB).handler = handler - } - if method&mALL == mALL { - h := n.endpoints.Value(mALL) - h.handler = handler - h.pattern = pattern - h.paramKeys = paramKeys - for _, m := range methodMap { - h := n.endpoints.Value(m) - h.handler = handler - h.pattern = pattern - h.paramKeys = paramKeys - } - } else { - h := n.endpoints.Value(method) - h.handler = handler - h.pattern = pattern - h.paramKeys = paramKeys - } -} - -func (n *node) FindRoute(rctx *Context, method methodTyp, path string) (*node, endpoints, http.Handler) { - // Reset the context routing pattern and params - rctx.routePattern = "" - rctx.routeParams.Keys = rctx.routeParams.Keys[:0] - rctx.routeParams.Values = rctx.routeParams.Values[:0] - - // Find the routing handlers for the path - rn := n.findRoute(rctx, method, path) - if rn == nil { - return nil, nil, nil - } - - // Record the routing params in the request lifecycle - rctx.URLParams.Keys = append(rctx.URLParams.Keys, rctx.routeParams.Keys...) - rctx.URLParams.Values = append(rctx.URLParams.Values, rctx.routeParams.Values...) - - // Record the routing pattern in the request lifecycle - if rn.endpoints[method].pattern != "" { - rctx.routePattern = rn.endpoints[method].pattern - rctx.RoutePatterns = append(rctx.RoutePatterns, rctx.routePattern) - } - - return rn, rn.endpoints, rn.endpoints[method].handler -} - -// Recursive edge traversal by checking all nodeTyp groups along the way. -// It's like searching through a multi-dimensional radix trie. -func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node { - nn := n - search := path - - for t, nds := range nn.children { - ntyp := nodeTyp(t) - if len(nds) == 0 { - continue - } - - var xn *node - xsearch := search - - var label byte - if search != "" { - label = search[0] - } - - switch ntyp { - case ntStatic: - xn = nds.findEdge(label) - if xn == nil || !strings.HasPrefix(xsearch, xn.prefix) { - continue - } - xsearch = xsearch[len(xn.prefix):] - - case ntParam, ntRegexp: - // short-circuit and return no matching route for empty param values - if xsearch == "" { - continue - } - - // serially loop through each node grouped by the tail delimiter - for idx := 0; idx < len(nds); idx++ { - xn = nds[idx] - - // label for param nodes is the delimiter byte - p := strings.IndexByte(xsearch, xn.tail) - - if p < 0 { - if xn.tail == '/' { - p = len(xsearch) - } else { - continue - } - } - - if ntyp == ntRegexp && xn.rex != nil { - if !xn.rex.Match([]byte(xsearch[:p])) { - continue - } - } else if strings.IndexByte(xsearch[:p], '/') != -1 { - // avoid a match across path segments - continue - } - - prevlen := len(rctx.routeParams.Values) - rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p]) - xsearch = xsearch[p:] - - if len(xsearch) == 0 { - if xn.isLeaf() { - h := xn.endpoints[method] - if h != nil && h.handler != nil { - rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...) - return xn - } - - // flag that the routing context found a route, but not a corresponding - // supported method - rctx.methodNotAllowed = true - } - } - - // recursively find the next node on this branch - fin := xn.findRoute(rctx, method, xsearch) - if fin != nil { - return fin - } - - // not found on this branch, reset vars - rctx.routeParams.Values = rctx.routeParams.Values[:prevlen] - xsearch = search - } - - rctx.routeParams.Values = append(rctx.routeParams.Values, "") - - default: - // catch-all nodes - rctx.routeParams.Values = append(rctx.routeParams.Values, search) - xn = nds[0] - xsearch = "" - } - - if xn == nil { - continue - } - - // did we find it yet? - if len(xsearch) == 0 { - if xn.isLeaf() { - h := xn.endpoints[method] - if h != nil && h.handler != nil { - rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...) - return xn - } - - // flag that the routing context found a route, but not a corresponding - // supported method - rctx.methodNotAllowed = true - } - } - - // recursively find the next node.. - fin := xn.findRoute(rctx, method, xsearch) - if fin != nil { - return fin - } - - // Did not find final handler, let's remove the param here if it was set - if xn.typ > ntStatic { - if len(rctx.routeParams.Values) > 0 { - rctx.routeParams.Values = rctx.routeParams.Values[:len(rctx.routeParams.Values)-1] - } - } - - } - - return nil -} - -func (n *node) findEdge(ntyp nodeTyp, label byte) *node { - nds := n.children[ntyp] - num := len(nds) - idx := 0 - - switch ntyp { - case ntStatic, ntParam, ntRegexp: - i, j := 0, num-1 - for i <= j { - idx = i + (j-i)/2 - if label > nds[idx].label { - i = idx + 1 - } else if label < nds[idx].label { - j = idx - 1 - } else { - i = num // breaks cond - } - } - if nds[idx].label != label { - return nil - } - return nds[idx] - - default: // catch all - return nds[idx] - } -} - -func (n *node) isLeaf() bool { - return n.endpoints != nil -} - -func (n *node) findPattern(pattern string) bool { - nn := n - for _, nds := range nn.children { - if len(nds) == 0 { - continue - } - - n = nn.findEdge(nds[0].typ, pattern[0]) - if n == nil { - continue - } - - var idx int - var xpattern string - - switch n.typ { - case ntStatic: - idx = longestPrefix(pattern, n.prefix) - if idx < len(n.prefix) { - continue - } - - case ntParam, ntRegexp: - idx = strings.IndexByte(pattern, '}') + 1 - - case ntCatchAll: - idx = longestPrefix(pattern, "*") - - default: - panic("chi: unknown node type") - } - - xpattern = pattern[idx:] - if len(xpattern) == 0 { - return true - } - - return n.findPattern(xpattern) - } - return false -} - -func (n *node) routes() []Route { - rts := []Route{} - - n.walk(func(eps endpoints, subroutes Routes) bool { - if eps[mSTUB] != nil && eps[mSTUB].handler != nil && subroutes == nil { - return false - } - - // Group methodHandlers by unique patterns - pats := make(map[string]endpoints) - - for mt, h := range eps { - if h.pattern == "" { - continue - } - p, ok := pats[h.pattern] - if !ok { - p = endpoints{} - pats[h.pattern] = p - } - p[mt] = h - } - - for p, mh := range pats { - hs := make(map[string]http.Handler) - if mh[mALL] != nil && mh[mALL].handler != nil { - hs["*"] = mh[mALL].handler - } - - for mt, h := range mh { - if h.handler == nil { - continue - } - m := methodTypString(mt) - if m == "" { - continue - } - hs[m] = h.handler - } - - rt := Route{p, hs, subroutes} - rts = append(rts, rt) - } - - return false - }) - - return rts -} - -func (n *node) walk(fn func(eps endpoints, subroutes Routes) bool) bool { - // Visit the leaf values if any - if (n.endpoints != nil || n.subroutes != nil) && fn(n.endpoints, n.subroutes) { - return true - } - - // Recurse on the children - for _, ns := range n.children { - for _, cn := range ns { - if cn.walk(fn) { - return true - } - } - } - return false -} - -// patNextSegment returns the next segment details from a pattern: -// node type, param key, regexp string, param tail byte, param starting index, param ending index -func patNextSegment(pattern string) (nodeTyp, string, string, byte, int, int) { - ps := strings.Index(pattern, "{") - ws := strings.Index(pattern, "*") - - if ps < 0 && ws < 0 { - return ntStatic, "", "", 0, 0, len(pattern) // we return the entire thing - } - - // Sanity check - if ps >= 0 && ws >= 0 && ws < ps { - panic("chi: wildcard '*' must be the last pattern in a route, otherwise use a '{param}'") - } - - var tail byte = '/' // Default endpoint tail to / byte - - if ps >= 0 { - // Param/Regexp pattern is next - nt := ntParam - - // Read to closing } taking into account opens and closes in curl count (cc) - cc := 0 - pe := ps - for i, c := range pattern[ps:] { - if c == '{' { - cc++ - } else if c == '}' { - cc-- - if cc == 0 { - pe = ps + i - break - } - } - } - if pe == ps { - panic("chi: route param closing delimiter '}' is missing") - } - - key := pattern[ps+1 : pe] - pe++ // set end to next position - - if pe < len(pattern) { - tail = pattern[pe] - } - - var rexpat string - if idx := strings.Index(key, ":"); idx >= 0 { - nt = ntRegexp - rexpat = key[idx+1:] - key = key[:idx] - } - - if len(rexpat) > 0 { - if rexpat[0] != '^' { - rexpat = "^" + rexpat - } - if rexpat[len(rexpat)-1] != '$' { - rexpat += "$" - } - } - - return nt, key, rexpat, tail, ps, pe - } - - // Wildcard pattern as finale - if ws < len(pattern)-1 { - panic("chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead") - } - return ntCatchAll, "*", "", 0, ws, len(pattern) -} - -func patParamKeys(pattern string) []string { - pat := pattern - paramKeys := []string{} - for { - ptyp, paramKey, _, _, _, e := patNextSegment(pat) - if ptyp == ntStatic { - return paramKeys - } - for i := 0; i < len(paramKeys); i++ { - if paramKeys[i] == paramKey { - panic(fmt.Sprintf("chi: routing pattern '%s' contains duplicate param key, '%s'", pattern, paramKey)) - } - } - paramKeys = append(paramKeys, paramKey) - pat = pat[e:] - } -} - -// longestPrefix finds the length of the shared prefix -// of two strings -func longestPrefix(k1, k2 string) int { - max := len(k1) - if l := len(k2); l < max { - max = l - } - var i int - for i = 0; i < max; i++ { - if k1[i] != k2[i] { - break - } - } - return i -} - -func methodTypString(method methodTyp) string { - for s, t := range methodMap { - if method == t { - return s - } - } - return "" -} - -type nodes []*node - -// Sort the list of nodes by label -func (ns nodes) Sort() { sort.Sort(ns); ns.tailSort() } -func (ns nodes) Len() int { return len(ns) } -func (ns nodes) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] } -func (ns nodes) Less(i, j int) bool { return ns[i].label < ns[j].label } - -// tailSort pushes nodes with '/' as the tail to the end of the list for param nodes. -// The list order determines the traversal order. -func (ns nodes) tailSort() { - for i := len(ns) - 1; i >= 0; i-- { - if ns[i].typ > ntStatic && ns[i].tail == '/' { - ns.Swap(i, len(ns)-1) - return - } - } -} - -func (ns nodes) findEdge(label byte) *node { - num := len(ns) - idx := 0 - i, j := 0, num-1 - for i <= j { - idx = i + (j-i)/2 - if label > ns[idx].label { - i = idx + 1 - } else if label < ns[idx].label { - j = idx - 1 - } else { - i = num // breaks cond - } - } - if ns[idx].label != label { - return nil - } - return ns[idx] -} - -// Route describes the details of a routing handler. -// Handlers map key is an HTTP method -type Route struct { - Pattern string - Handlers map[string]http.Handler - SubRoutes Routes -} - -// WalkFunc is the type of the function called for each method and route visited by Walk. -type WalkFunc func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error - -// Walk walks any router tree that implements Routes interface. -func Walk(r Routes, walkFn WalkFunc) error { - return walk(r, walkFn, "") -} - -func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.Handler) http.Handler) error { - for _, route := range r.Routes() { - mws := make([]func(http.Handler) http.Handler, len(parentMw)) - copy(mws, parentMw) - mws = append(mws, r.Middlewares()...) - - if route.SubRoutes != nil { - if err := walk(route.SubRoutes, walkFn, parentRoute+route.Pattern, mws...); err != nil { - return err - } - continue - } - - for method, handler := range route.Handlers { - if method == "*" { - // Ignore a "catchAll" method, since we pass down all the specific methods for each route. - continue - } - - fullRoute := parentRoute + route.Pattern - fullRoute = strings.Replace(fullRoute, "/*/", "/", -1) - - if chain, ok := handler.(*ChainHandler); ok { - if err := walkFn(method, fullRoute, chain.Endpoint, append(mws, chain.Middlewares...)...); err != nil { - return err - } - } else { - if err := walkFn(method, fullRoute, handler, mws...); err != nil { - return err - } - } - } - } - - return nil -} diff --git a/vendor/github.com/skycoin/dmsg/direct/client.go b/vendor/github.com/skycoin/dmsg/direct/client.go index b78a266cd0..47f65711df 100644 --- a/vendor/github.com/skycoin/dmsg/direct/client.go +++ b/vendor/github.com/skycoin/dmsg/direct/client.go @@ -79,3 +79,15 @@ func (c *directClient) AvailableServers(ctx context.Context) (entries []*disc.En } return entries, nil } + +// AllServers return list of all servers from the entries field of directClient +func (c *directClient) AllServers(ctx context.Context) (entries []*disc.Entry, err error) { + c.mx.RLock() + defer c.mx.RUnlock() + for _, entry := range c.entries { + if entry.Server != nil { + entries = append(entries, entry) + } + } + return entries, nil +} diff --git a/vendor/github.com/skycoin/dmsg/disc/client.go b/vendor/github.com/skycoin/dmsg/disc/client.go index cb6f783c7e..e28cf8b17f 100644 --- a/vendor/github.com/skycoin/dmsg/disc/client.go +++ b/vendor/github.com/skycoin/dmsg/disc/client.go @@ -25,6 +25,7 @@ type APIClient interface { PutEntry(context.Context, cipher.SecKey, *Entry) error DelEntry(context.Context, *Entry) error AvailableServers(context.Context) ([]*Entry, error) + AllServers(context.Context) ([]*Entry, error) } // HTTPClient represents a client that communicates with a dmsg-discovery service through http, it @@ -272,3 +273,45 @@ func (c *httpClient) AvailableServers(ctx context.Context) ([]*Entry, error) { return entries, nil } + +// AllServers returns list of all servers. +func (c *httpClient) AllServers(ctx context.Context) ([]*Entry, error) { + var entries []*Entry + endpoint := c.address + "/dmsg-discovery/all_servers" + + req, err := http.NewRequest(http.MethodGet, endpoint, nil) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + + resp, err := c.client.Do(req) + if resp != nil { + defer func() { + if err := resp.Body.Close(); err != nil { + c.log.WithError(err).Warn("Failed to close response body") + } + }() + } + if err != nil { + return nil, err + } + + // if the response is an error it will be codified as an HTTPMessage + if resp.StatusCode != http.StatusOK { + var message HTTPMessage + err = json.NewDecoder(resp.Body).Decode(&message) + if err != nil { + return nil, err + } + + return nil, errFromString(message.Message) + } + + err = json.NewDecoder(resp.Body).Decode(&entries) + if err != nil { + return nil, err + } + + return entries, nil +} diff --git a/vendor/github.com/skycoin/dmsg/disc/testing.go b/vendor/github.com/skycoin/dmsg/disc/testing.go index 9fc87fe277..5c696afd50 100644 --- a/vendor/github.com/skycoin/dmsg/disc/testing.go +++ b/vendor/github.com/skycoin/dmsg/disc/testing.go @@ -129,7 +129,7 @@ func (m *mockClient) PutEntry(ctx context.Context, sk cipher.SecKey, e *Entry) e } } -// AvailableServers returns all the servers that the APIClient mock has +// AvailableServers returns available servers that the APIClient mock has func (m *mockClient) AvailableServers(_ context.Context) ([]*Entry, error) { m.mx.RLock() defer m.mx.RUnlock() @@ -141,3 +141,16 @@ func (m *mockClient) AvailableServers(_ context.Context) ([]*Entry, error) { } return list, nil } + +// AllServers returns all servers that the APIClient mock has +func (m *mockClient) AllServers(_ context.Context) ([]*Entry, error) { + m.mx.RLock() + defer m.mx.RUnlock() + list := make([]*Entry, 0, len(m.entries)) + for _, e := range m.entries { + if e := e; e.Server != nil { + list = append(list, &e) + } + } + return list, nil +} diff --git a/vendor/github.com/skycoin/dmsg/dmsghttp/util.go b/vendor/github.com/skycoin/dmsg/dmsghttp/util.go index 160a17ae7b..6bd03a9708 100644 --- a/vendor/github.com/skycoin/dmsg/dmsghttp/util.go +++ b/vendor/github.com/skycoin/dmsg/dmsghttp/util.go @@ -17,7 +17,7 @@ func GetServers(ctx context.Context, dmsgDisc string, log *logging.Logger) (entr ticker := time.NewTicker(time.Second * 10) defer ticker.Stop() for { - servers, err := dmsgclient.AvailableServers(ctx) + servers, err := dmsgclient.AllServers(ctx) if err != nil { log.WithError(err).Fatal("Error getting dmsg-servers.") } @@ -44,7 +44,7 @@ func UpdateServers(ctx context.Context, dClient disc.APIClient, dmsgDisc string, case <-ctx.Done(): return case <-ticker.C: - servers, err := dmsgclient.AvailableServers(ctx) + servers, err := dmsgclient.AllServers(ctx) if err != nil { log.WithError(err).Error("Error getting dmsg-servers.") break diff --git a/vendor/github.com/skycoin/dmsg/httputil/httputil.go b/vendor/github.com/skycoin/dmsg/httputil/httputil.go index b4b095f38f..49c482919b 100644 --- a/vendor/github.com/skycoin/dmsg/httputil/httputil.go +++ b/vendor/github.com/skycoin/dmsg/httputil/httputil.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - "github.com/go-chi/chi/middleware" + "github.com/go-chi/chi/v5/middleware" jsoniter "github.com/json-iterator/go" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" diff --git a/vendor/github.com/skycoin/dmsg/httputil/log.go b/vendor/github.com/skycoin/dmsg/httputil/log.go index ec6778414f..865a36571d 100644 --- a/vendor/github.com/skycoin/dmsg/httputil/log.go +++ b/vendor/github.com/skycoin/dmsg/httputil/log.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - "github.com/go-chi/chi/middleware" + "github.com/go-chi/chi/v5/middleware" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/skycoin/dmsg/metricsutil/http.go b/vendor/github.com/skycoin/dmsg/metricsutil/http.go index 2ab3fb86e2..2f67fcf729 100644 --- a/vendor/github.com/skycoin/dmsg/metricsutil/http.go +++ b/vendor/github.com/skycoin/dmsg/metricsutil/http.go @@ -4,8 +4,8 @@ import ( "net/http" "github.com/VictoriaMetrics/metrics" - "github.com/go-chi/chi" - "github.com/go-chi/chi/middleware" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/skycoin/dmsg/netutil/retrier.go b/vendor/github.com/skycoin/dmsg/netutil/retrier.go index 4eca48910f..e49229150a 100644 --- a/vendor/github.com/skycoin/dmsg/netutil/retrier.go +++ b/vendor/github.com/skycoin/dmsg/netutil/retrier.go @@ -36,13 +36,14 @@ type Retrier struct { // NewRetrier returns a retrier that is ready to call Do() method func NewRetrier(log logrus.FieldLogger, initBO, maxBO time.Duration, tries int64, factor float64) *Retrier { + logger := log.WithField("func", "retrier") return &Retrier{ initBO: initBO, maxBO: maxBO, tries: tries, factor: factor, errWl: make(map[error]struct{}), - log: log, + log: logger, } } @@ -77,11 +78,11 @@ func (r *Retrier) Do(ctx context.Context, f RetryFunc) error { if newBO := time.Duration(float64(bo) * r.factor); r.maxBO == 0 || newBO <= r.maxBO { bo = newBO } - if r.log != nil { - r.log.WithError(err).WithField("current_backoff", bo).Debug("Retrying...") - } select { case <-t.C: + if r.log != nil { + r.log.WithError(err).WithField("current_backoff", bo).Warn("Retrying...") + } t.Reset(bo) continue case <-ctx.Done(): diff --git a/vendor/modules.txt b/vendor/modules.txt index 26b64922c9..1946890931 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -54,12 +54,8 @@ github.com/getlantern/ops # github.com/getlantern/systray v1.1.0 ## explicit; go 1.13 github.com/getlantern/systray -# github.com/ghodss/yaml v1.0.0 -## explicit # github.com/go-chi/chi v4.1.2+incompatible ## explicit -github.com/go-chi/chi -github.com/go-chi/chi/middleware # github.com/go-chi/chi/v5 v5.0.8-0.20220103230436-7dbe9a0bd10f ## explicit; go 1.14 github.com/go-chi/chi/v5 @@ -92,8 +88,6 @@ github.com/inconshreveable/mousetrap # github.com/james-barrow/golang-ipc v0.0.0-20210227130457-95e7cc81f5e2 ## explicit; go 1.15 github.com/james-barrow/golang-ipc -# github.com/jaypipes/ghw v0.8.0 -## explicit; go 1.12 # github.com/json-iterator/go v1.1.12 ## explicit; go 1.12 github.com/json-iterator/go @@ -164,7 +158,7 @@ github.com/shirou/gopsutil/v3/process ## explicit; go 1.13 github.com/sirupsen/logrus github.com/sirupsen/logrus/hooks/syslog -# github.com/skycoin/dmsg v0.0.0-20220125173526-46bb07d7fd64 +# github.com/skycoin/dmsg v0.0.0-20220302151611-e4368629eed2 ## explicit; go 1.16 github.com/skycoin/dmsg github.com/skycoin/dmsg/buildinfo