From 00c016208e3aedfbc8860db2eeab435420e3c37a Mon Sep 17 00:00:00 2001 From: Mark van der Velden Date: Wed, 26 Apr 2017 09:55:48 +0200 Subject: [PATCH 1/3] Adding a path-strip feature, strip the first part of a requested path --- README.md | 2 ++ handlers/pathstrip.go | 22 +++++++++++++++ main.go | 63 ++++++++++++++++++++++++++++--------------- 3 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 handlers/pathstrip.go diff --git a/README.md b/README.md index e69de29..ed09113 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,2 @@ +# Introduction +Proxima is a small reverse-proxy intended to guard the popular [Imaginary](https://github.com/h2non/imaginary) service. It's intended as a public facing frontend for Imaginary. \ No newline at end of file diff --git a/handlers/pathstrip.go b/handlers/pathstrip.go new file mode 100644 index 0000000..a30e4b7 --- /dev/null +++ b/handlers/pathstrip.go @@ -0,0 +1,22 @@ +package handlers + +import ( + "net/http" + + "strings" + + "github.com/go-kit/kit/log" +) + +// NewPathStrip strips the path from the request URL, paths always start with a /. +func NewPathStrip(_ log.Logger, path string) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, path) { + r.URL.Path = strings.TrimPrefix(r.URL.Path, path) + } + + h.ServeHTTP(w, r) + }) + } +} diff --git a/main.go b/main.go index cfd4275..f2a1d28 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,8 @@ import ( "fmt" + stdlog "log" + "github.com/Dynom/proxima/handlers" "github.com/go-kit/kit/log" "github.com/juju/ratelimit" @@ -23,16 +25,12 @@ var ( allowedImaginaryParams string allowedImaginaryActions string imaginaryURL string + pathSegmentToStrip string listenPort int64 bucketRate float64 bucketSize int64 Version = "dev" - logger = log.With( - log.NewLogfmtLogger(os.Stderr), - "ts", log.DefaultTimestampUTC, - "caller", log.DefaultCaller, - ) ) type argumentList []string @@ -54,12 +52,18 @@ func init() { flag.Int64Var(&bucketSize, "bucket-size", 500, "Rate limiter bucket size (burst capacity)") flag.StringVar(&allowedImaginaryParams, "allowed-params", "", "A comma seperated list of parameters allows to be sent upstream. If empty, everything is allowed.") flag.StringVar(&allowedImaginaryActions, "allowed-actions", "", "A comma seperated list of actions allows to be sent upstream. If empty, everything is allowed.") - + flag.StringVar(&pathSegmentToStrip, "root-path-strip", "", "A section of the (left most) path to strip (e.g.: \"/static\"). Start with a /.") } func main() { flag.Parse() + logger := log.With( + log.NewLogfmtLogger(os.Stderr), + "ts", log.DefaultTimestampUTC, + "caller", log.DefaultCaller, + ) + logger.Log( "msg", "Starting.", "version", Version, @@ -73,20 +77,11 @@ func main() { } rlBucket := ratelimit.NewBucketWithRate(bucketRate, bucketSize) - - proxy := httputil.NewSingleHostReverseProxy(rURL) - proxy.Transport = &http.Transport{ - DisableCompression: true, - DisableKeepAlives: false, - IdleConnTimeout: 5 * time.Minute, - MaxIdleConns: 10000, - MaxIdleConnsPerHost: 10000, - ResponseHeaderTimeout: 10 * time.Second, - } + proxy := newProxy(rURL, logger) s := &http.Server{ Addr: fmt.Sprintf(":%d", listenPort), - Handler: decorateHandler(proxy, rlBucket), + Handler: decorateHandler(proxy, rlBucket, logger), ReadHeaderTimeout: 2 * time.Second, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, @@ -97,18 +92,33 @@ func main() { s.ListenAndServe() } +func newProxy(backend *url.URL, l log.Logger) *httputil.ReverseProxy { + proxy := httputil.NewSingleHostReverseProxy(backend) + proxy.ErrorLog = stdlog.New(log.NewStdlibAdapter(l), "", stdlog.LstdFlags) + proxy.Transport = &http.Transport{ + DisableCompression: true, + DisableKeepAlives: false, + IdleConnTimeout: 5 * time.Minute, + MaxIdleConns: 10000, + MaxIdleConnsPerHost: 10000, + ResponseHeaderTimeout: 10 * time.Second, + } + + return proxy +} + type httpHandler func(h http.Handler) http.Handler -func decorateHandler(h http.Handler, b *ratelimit.Bucket) http.Handler { +func decorateHandler(h http.Handler, b *ratelimit.Bucket, l log.Logger) http.Handler { decorators := []httpHandler{ - handlers.NewValidateURLParameter(logger, allowedHosts), + handlers.NewValidateURLParameter(l, allowedHosts), } if allowedImaginaryParams != "" { decorators = append( decorators, handlers.NewAllowedParams( - logger, + l, strings.Split(allowedImaginaryParams, ","), )) } @@ -117,16 +127,25 @@ func decorateHandler(h http.Handler, b *ratelimit.Bucket) http.Handler { decorators = append( decorators, handlers.NewAllowedActions( - logger, + l, strings.Split(allowedImaginaryActions, ","), )) } + if pathSegmentToStrip != "" { + decorators = append( + decorators, + handlers.NewPathStrip( + l, + pathSegmentToStrip, + )) + } + // Defining early needed handlers last decorators = append( decorators, handlers.NewIgnoreFaviconRequests(), - handlers.NewRateLimitHandler(b, logger), + handlers.NewRateLimitHandler(b, l), ) var handler http.Handler = h From eb297167a05f0e130aca0d636c4eed4e7018f67e Mon Sep 17 00:00:00 2001 From: Mark van der Velden Date: Wed, 26 Apr 2017 12:32:54 +0200 Subject: [PATCH 2/3] PR feedback --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 33c8681..c6c1ab8 100644 --- a/main.go +++ b/main.go @@ -67,7 +67,7 @@ func main() { } rlBucket := ratelimit.NewBucketWithRate(bucketRate, bucketSize) - proxy := newProxy(rURL, logger) + proxy := newProxy(logger, rURL) s := &http.Server{ Addr: fmt.Sprintf(":%d", listenPort), @@ -82,7 +82,7 @@ func main() { s.ListenAndServe() } -func newProxy(backend *url.URL, l log.Logger) *httputil.ReverseProxy { +func newProxy(l log.Logger, backend *url.URL) *httputil.ReverseProxy { proxy := httputil.NewSingleHostReverseProxy(backend) proxy.ErrorLog = stdlog.New(log.NewStdlibAdapter(l), "", stdlog.LstdFlags) proxy.Transport = &http.Transport{ From eb1a02db9838bcc3af02eabf539b3addd0dd6386 Mon Sep 17 00:00:00 2001 From: Mark van der Velden Date: Wed, 26 Apr 2017 12:39:26 +0200 Subject: [PATCH 3/3] Consistency, logger as first argument on all the things --- handlers/ratelimiter.go | 2 +- main.go | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/handlers/ratelimiter.go b/handlers/ratelimiter.go index 4147985..735c394 100644 --- a/handlers/ratelimiter.go +++ b/handlers/ratelimiter.go @@ -8,7 +8,7 @@ import ( "github.com/juju/ratelimit" ) -func NewRateLimitHandler(b *ratelimit.Bucket, l log.Logger) func(h http.Handler) http.Handler { +func NewRateLimitHandler(l log.Logger, b *ratelimit.Bucket) func(h http.Handler) http.Handler { return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { d := b.Take(1) diff --git a/main.go b/main.go index c6c1ab8..20dd3de 100644 --- a/main.go +++ b/main.go @@ -58,6 +58,7 @@ func main() { "allowed_hosts", allowedHosts.String(), "allowed_params", allowedImaginaryParams.String(), "allowed_actions", allowedImaginaryActions.String(), + "path_to_strip", pathSegmentToStrip, "imaginary_backend", imaginaryURL, ) @@ -71,7 +72,7 @@ func main() { s := &http.Server{ Addr: fmt.Sprintf(":%d", listenPort), - Handler: decorateHandler(proxy, rlBucket, logger), + Handler: decorateHandler(logger, proxy, rlBucket), ReadHeaderTimeout: 2 * time.Second, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, @@ -99,7 +100,7 @@ func newProxy(l log.Logger, backend *url.URL) *httputil.ReverseProxy { type httpHandler func(h http.Handler) http.Handler -func decorateHandler(h http.Handler, b *ratelimit.Bucket, l log.Logger) http.Handler { +func decorateHandler(l log.Logger, h http.Handler, b *ratelimit.Bucket) http.Handler { decorators := []httpHandler{ handlers.NewValidateURLParameter(l, allowedHosts), } @@ -135,7 +136,7 @@ func decorateHandler(h http.Handler, b *ratelimit.Bucket, l log.Logger) http.Han decorators = append( decorators, handlers.NewIgnoreFaviconRequests(), - handlers.NewRateLimitHandler(b, l), + handlers.NewRateLimitHandler(l, b), ) var handler http.Handler = h