github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/api/http/middleware.go (about)

     1  package http
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"runtime/debug"
     7  	"strings"
     8  
     9  	"github.com/FusionFoundation/efsn/metrics"
    10  	"github.com/FusionFoundation/efsn/swarm/api"
    11  	"github.com/FusionFoundation/efsn/swarm/log"
    12  	"github.com/FusionFoundation/efsn/swarm/sctx"
    13  	"github.com/FusionFoundation/efsn/swarm/spancontext"
    14  	"github.com/pborman/uuid"
    15  )
    16  
    17  // Adapt chains h (main request handler) main handler to adapters (middleware handlers)
    18  // Please note that the order of execution for `adapters` is FIFO (adapters[0] will be executed first)
    19  func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
    20  	for i := range adapters {
    21  		adapter := adapters[len(adapters)-1-i]
    22  		h = adapter(h)
    23  	}
    24  	return h
    25  }
    26  
    27  type Adapter func(http.Handler) http.Handler
    28  
    29  func SetRequestID(h http.Handler) http.Handler {
    30  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    31  		r = r.WithContext(SetRUID(r.Context(), uuid.New()[:8]))
    32  		metrics.GetOrRegisterCounter(fmt.Sprintf("http.request.%s", r.Method), nil).Inc(1)
    33  		log.Info("created ruid for request", "ruid", GetRUID(r.Context()), "method", r.Method, "url", r.RequestURI)
    34  
    35  		h.ServeHTTP(w, r)
    36  	})
    37  }
    38  
    39  func SetRequestHost(h http.Handler) http.Handler {
    40  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    41  		r = r.WithContext(sctx.SetHost(r.Context(), r.Host))
    42  		log.Info("setting request host", "ruid", GetRUID(r.Context()), "host", sctx.GetHost(r.Context()))
    43  
    44  		h.ServeHTTP(w, r)
    45  	})
    46  }
    47  
    48  func ParseURI(h http.Handler) http.Handler {
    49  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    50  		uri, err := api.Parse(strings.TrimLeft(r.URL.Path, "/"))
    51  		if err != nil {
    52  			w.WriteHeader(http.StatusBadRequest)
    53  			RespondError(w, r, fmt.Sprintf("invalid URI %q", r.URL.Path), http.StatusBadRequest)
    54  			return
    55  		}
    56  		if uri.Addr != "" && strings.HasPrefix(uri.Addr, "0x") {
    57  			uri.Addr = strings.TrimPrefix(uri.Addr, "0x")
    58  
    59  			msg := fmt.Sprintf(`The requested hash seems to be prefixed with '0x'. You will be redirected to the correct URL within 5 seconds.<br/>
    60  			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())
    61  			w.WriteHeader(http.StatusNotFound)
    62  			w.Write([]byte(msg))
    63  			return
    64  		}
    65  
    66  		ctx := r.Context()
    67  		r = r.WithContext(SetURI(ctx, uri))
    68  		log.Debug("parsed request path", "ruid", GetRUID(r.Context()), "method", r.Method, "uri.Addr", uri.Addr, "uri.Path", uri.Path, "uri.Scheme", uri.Scheme)
    69  
    70  		h.ServeHTTP(w, r)
    71  	})
    72  }
    73  
    74  func InitLoggingResponseWriter(h http.Handler) http.Handler {
    75  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    76  		writer := newLoggingResponseWriter(w)
    77  		h.ServeHTTP(writer, r)
    78  		log.Debug("request served", "ruid", GetRUID(r.Context()), "code", writer.statusCode)
    79  	})
    80  }
    81  
    82  func InstrumentOpenTracing(h http.Handler) http.Handler {
    83  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    84  		uri := GetURI(r.Context())
    85  		if uri == nil || r.Method == "" || (uri != nil && uri.Scheme == "") {
    86  			h.ServeHTTP(w, r) // soft fail
    87  			return
    88  		}
    89  		spanName := fmt.Sprintf("http.%s.%s", r.Method, uri.Scheme)
    90  		ctx, sp := spancontext.StartSpan(r.Context(), spanName)
    91  		defer sp.Finish()
    92  		h.ServeHTTP(w, r.WithContext(ctx))
    93  	})
    94  }
    95  
    96  func RecoverPanic(h http.Handler) http.Handler {
    97  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    98  		defer func() {
    99  			if err := recover(); err != nil {
   100  				log.Error("panic recovery!", "stack trace", string(debug.Stack()), "url", r.URL.String(), "headers", r.Header)
   101  			}
   102  		}()
   103  		h.ServeHTTP(w, r)
   104  	})
   105  }