aboutsummaryrefslogtreecommitdiffstats
path: root/swarm/api/http/middleware.go
diff options
context:
space:
mode:
Diffstat (limited to 'swarm/api/http/middleware.go')
-rw-r--r--swarm/api/http/middleware.go95
1 files changed, 95 insertions, 0 deletions
diff --git a/swarm/api/http/middleware.go b/swarm/api/http/middleware.go
new file mode 100644
index 000000000..d338a782c
--- /dev/null
+++ b/swarm/api/http/middleware.go
@@ -0,0 +1,95 @@
+package http
+
+import (
+ "fmt"
+ "net/http"
+ "runtime/debug"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/metrics"
+ "github.com/ethereum/go-ethereum/swarm/api"
+ "github.com/ethereum/go-ethereum/swarm/log"
+ "github.com/ethereum/go-ethereum/swarm/spancontext"
+ "github.com/pborman/uuid"
+)
+
+// Adapt chains h (main request handler) main handler to adapters (middleware handlers)
+// Please note that the order of execution for `adapters` is FIFO (adapters[0] will be executed first)
+func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
+ for i := range adapters {
+ adapter := adapters[len(adapters)-1-i]
+ h = adapter(h)
+ }
+ return h
+}
+
+type Adapter func(http.Handler) http.Handler
+
+func SetRequestID(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ r = r.WithContext(SetRUID(r.Context(), uuid.New()[:8]))
+ metrics.GetOrRegisterCounter(fmt.Sprintf("http.request.%s", r.Method), nil).Inc(1)
+ log.Info("created ruid for request", "ruid", GetRUID(r.Context()), "method", r.Method, "url", r.RequestURI)
+
+ h.ServeHTTP(w, r)
+ })
+}
+
+func ParseURI(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ uri, err := api.Parse(strings.TrimLeft(r.URL.Path, "/"))
+ if err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ RespondError(w, r, fmt.Sprintf("invalid URI %q", r.URL.Path), http.StatusBadRequest)
+ return
+ }
+ if uri.Addr != "" && strings.HasPrefix(uri.Addr, "0x") {
+ uri.Addr = strings.TrimPrefix(uri.Addr, "0x")
+
+ msg := fmt.Sprintf(`The requested hash seems to be prefixed with '0x'. You will be redirected to the correct URL within 5 seconds.<br/>
+ Please click <a href='%[1]s'>here</a> if your browser does not redirect you within 5 seconds.<script>setTimeout("location.href='%[1]s';",5000);</script>`, "/"+uri.String())
+ w.WriteHeader(http.StatusNotFound)
+ w.Write([]byte(msg))
+ return
+ }
+
+ ctx := r.Context()
+ r = r.WithContext(SetURI(ctx, uri))
+ log.Debug("parsed request path", "ruid", GetRUID(r.Context()), "method", r.Method, "uri.Addr", uri.Addr, "uri.Path", uri.Path, "uri.Scheme", uri.Scheme)
+
+ h.ServeHTTP(w, r)
+ })
+}
+
+func InitLoggingResponseWriter(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ writer := newLoggingResponseWriter(w)
+
+ h.ServeHTTP(writer, r)
+ })
+}
+
+func InstrumentOpenTracing(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ uri := GetURI(r.Context())
+ if uri == nil || r.Method == "" || (uri != nil && uri.Scheme == "") {
+ h.ServeHTTP(w, r) // soft fail
+ return
+ }
+ spanName := fmt.Sprintf("http.%s.%s", r.Method, uri.Scheme)
+ ctx, sp := spancontext.StartSpan(r.Context(), spanName)
+ defer sp.Finish()
+ h.ServeHTTP(w, r.WithContext(ctx))
+ })
+}
+
+func RecoverPanic(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ defer func() {
+ if err := recover(); err != nil {
+ log.Error("panic recovery!", "stack trace", debug.Stack(), "url", r.URL.String(), "headers", r.Header)
+ }
+ }()
+ h.ServeHTTP(w, r)
+ })
+}