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