Extract request utilities into its own package

The RemoteAddr and RemoteIP functions operate on *http.Request values,
not contexts. They have very low cohesion with the rest of the package.

Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
Cory Snider
2023-10-24 13:39:55 -04:00
parent d0f5aa670b
commit 9157226e7b
6 changed files with 134 additions and 119 deletions

View File

@@ -3,15 +3,14 @@ package dcontext
import (
"context"
"errors"
"net"
"net/http"
"strings"
"sync"
"time"
"github.com/distribution/distribution/v3/internal/requestutil"
"github.com/google/uuid"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
)
// Common errors used with this package.
@@ -20,48 +19,6 @@ var (
ErrNoResponseWriterContext = errors.New("no http response in context")
)
func parseIP(ipStr string) net.IP {
ip := net.ParseIP(ipStr)
if ip == nil {
log.Warnf("invalid remote IP address: %q", ipStr)
}
return ip
}
// RemoteAddr extracts the remote address of the request, taking into
// account proxy headers.
func RemoteAddr(r *http.Request) string {
if prior := r.Header.Get("X-Forwarded-For"); prior != "" {
remoteAddr, _, _ := strings.Cut(prior, ",")
remoteAddr = strings.Trim(remoteAddr, " ")
if parseIP(remoteAddr) != nil {
return remoteAddr
}
}
// X-Real-Ip is less supported, but worth checking in the
// absence of X-Forwarded-For
if realIP := r.Header.Get("X-Real-Ip"); realIP != "" {
if parseIP(realIP) != nil {
return realIP
}
}
return r.RemoteAddr
}
// RemoteIP extracts the remote IP of the request, taking into
// account proxy headers.
func RemoteIP(r *http.Request) string {
addr := RemoteAddr(r)
// Try parsing it as "IP:port"
if ip, _, err := net.SplitHostPort(addr); err == nil {
return ip
}
return addr
}
// WithRequest places the request on the context. The context of the request
// is assigned a unique id, available at "http.request.id". The request itself
// is available at "http.request". Other common attributes are available under
@@ -193,7 +150,7 @@ func (ctx *httpRequestContext) Value(key interface{}) interface{} {
case "http.request.uri":
return ctx.r.RequestURI
case "http.request.remoteaddr":
return RemoteAddr(ctx.r)
return requestutil.RemoteAddr(ctx.r)
case "http.request.method":
return ctx.r.Method
case "http.request.host":