github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/pkg/publicapi/handlerwrapper/http_handler.go (about)

     1  package handlerwrapper
     2  
     3  import (
     4  	"net/http"
     5  	"strings"
     6  
     7  	"github.com/felixge/httpsnoop"
     8  )
     9  
    10  type HTTPHandlerWrapper struct {
    11  	nodeID             string
    12  	httpHandler        http.Handler
    13  	requestInfoHandler RequestInfoHandler
    14  }
    15  
    16  func NewHTTPHandlerWrapper(
    17  	nodeID string,
    18  	httpHandler http.Handler,
    19  	requestInfoHandler RequestInfoHandler) *HTTPHandlerWrapper {
    20  	return &HTTPHandlerWrapper{
    21  		nodeID:             nodeID,
    22  		httpHandler:        httpHandler,
    23  		requestInfoHandler: requestInfoHandler,
    24  	}
    25  }
    26  
    27  // An HTTP handler that triggers another handler, capturs info about the request and calls request info handler.
    28  func (wrapper *HTTPHandlerWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    29  	ri := &HTTPRequestInfo{
    30  		Method:    r.Method,
    31  		URI:       r.URL.String(),
    32  		Referer:   r.Header.Get("Referer"),
    33  		UserAgent: r.Header.Get("User-Agent"),
    34  		NodeID:    wrapper.nodeID,
    35  	}
    36  
    37  	ri.Ipaddr = requestGetRemoteAddress(r)
    38  
    39  	// this runs http handler and captures information about HTTP request
    40  	m := httpsnoop.CaptureMetrics(wrapper.httpHandler, w, r)
    41  
    42  	ri.StatusCode = m.Code
    43  	ri.Size = m.Written
    44  	ri.Duration = m.Duration.Milliseconds()
    45  	ri.ClientID = w.Header().Get(HTTPHeaderClientID)
    46  	ri.JobID = w.Header().Get(HTTPHeaderJobID)
    47  	wrapper.requestInfoHandler.Handle(r.Context(), ri)
    48  }
    49  
    50  // Request.RemoteAddress contains port, which we want to remove i.e.:
    51  // "[::1]:58292" => "[::1]"
    52  func ipAddrFromRemoteAddr(s string) string {
    53  	idx := strings.LastIndex(s, ":")
    54  	if idx == -1 {
    55  		return s
    56  	}
    57  	return s[:idx]
    58  }
    59  
    60  // requestGetRemoteAddress returns ip address of the client making the request,
    61  // taking into account http proxies
    62  func requestGetRemoteAddress(r *http.Request) string {
    63  	hdr := r.Header
    64  	hdrRealIP := hdr.Get("X-Real-Ip")
    65  	hdrForwardedFor := hdr.Get("X-Forwarded-For")
    66  	if hdrRealIP == "" && hdrForwardedFor == "" {
    67  		return ipAddrFromRemoteAddr(r.RemoteAddr)
    68  	}
    69  	if hdrForwardedFor != "" {
    70  		// X-Forwarded-For is potentially a list of addresses separated with ","
    71  		parts := strings.Split(hdrForwardedFor, ",")
    72  		for i, p := range parts {
    73  			parts[i] = strings.TrimSpace(p)
    74  		}
    75  		// TODO: should return first non-local address
    76  		return parts[0]
    77  	}
    78  	return hdrRealIP
    79  }