forked from TrueCloudLab/frostfs-s3-gw
Refactoring request info
- simplify - more usable Signed-off-by: Evgeniy Kulikov <kim@nspcc.ru>
This commit is contained in:
parent
93e54bc681
commit
26f1df2721
1 changed files with 106 additions and 17 deletions
123
api/reqinfo.go
123
api/reqinfo.go
|
@ -2,7 +2,14 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -25,6 +32,12 @@ type (
|
||||||
ObjectName string // Object name
|
ObjectName string // Object name
|
||||||
tags []KeyVal // Any additional info not accommodated by above fields
|
tags []KeyVal // Any additional info not accommodated by above fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectRequest struct {
|
||||||
|
Bucket string
|
||||||
|
Object string
|
||||||
|
Method string
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Key used for Get/SetReqInfo
|
// Key used for Get/SetReqInfo
|
||||||
|
@ -32,17 +45,97 @@ type contextKeyType string
|
||||||
|
|
||||||
const ctxRequestInfo = contextKeyType("NeoFS-S3-Gate")
|
const ctxRequestInfo = contextKeyType("NeoFS-S3-Gate")
|
||||||
|
|
||||||
|
var (
|
||||||
|
// De-facto standard header keys.
|
||||||
|
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
|
||||||
|
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// RFC7239 defines a new "Forwarded: " header designed to replace the
|
||||||
|
// existing use of X-Forwarded-* headers.
|
||||||
|
// e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43
|
||||||
|
forwarded = http.CanonicalHeaderKey("Forwarded")
|
||||||
|
// Allows for a sub-match of the first value after 'for=' to the next
|
||||||
|
// comma, semi-colon or space. The match is case-insensitive.
|
||||||
|
forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|, )]+)(.*)`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetSourceIP retrieves the IP from the X-Forwarded-For, X-Real-IP and RFC7239
|
||||||
|
// Forwarded headers (in that order), falls back to r.RemoteAddr when all
|
||||||
|
// else fails.
|
||||||
|
func GetSourceIP(r *http.Request) string {
|
||||||
|
var addr string
|
||||||
|
|
||||||
|
if fwd := r.Header.Get(xForwardedFor); fwd != "" {
|
||||||
|
// Only grab the first (client) address. Note that '192.168.0.1,
|
||||||
|
// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
|
||||||
|
// the first may represent forwarding proxies earlier in the chain.
|
||||||
|
s := strings.Index(fwd, ", ")
|
||||||
|
if s == -1 {
|
||||||
|
s = len(fwd)
|
||||||
|
}
|
||||||
|
addr = fwd[:s]
|
||||||
|
} else if fwd := r.Header.Get(xRealIP); fwd != "" {
|
||||||
|
// X-Real-IP should only contain one IP address (the client making the
|
||||||
|
// request).
|
||||||
|
addr = fwd
|
||||||
|
} else if fwd := r.Header.Get(forwarded); fwd != "" {
|
||||||
|
// match should contain at least two elements if the protocol was
|
||||||
|
// specified in the Forwarded header. The first element will always be
|
||||||
|
// the 'for=' capture, which we ignore. In the case of multiple IP
|
||||||
|
// addresses (for=8.8.8.8, 8.8.4.4, 172.16.1.20 is valid) we only
|
||||||
|
// extract the first, which should be the client IP.
|
||||||
|
if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 {
|
||||||
|
// IPv6 addresses in Forwarded headers are quoted-strings. We strip
|
||||||
|
// these quotes.
|
||||||
|
addr = strings.Trim(match[1], `"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr != "" {
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to remote address if headers not set.
|
||||||
|
addr, _, _ = net.SplitHostPort(r.RemoteAddr)
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareContext(w http.ResponseWriter, r *http.Request) context.Context {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
bucket := vars["bucket"]
|
||||||
|
object, err := url.PathUnescape(vars["object"])
|
||||||
|
if err != nil {
|
||||||
|
object = vars["object"]
|
||||||
|
}
|
||||||
|
prefix, err := url.QueryUnescape(vars["prefix"])
|
||||||
|
if err != nil {
|
||||||
|
prefix = vars["prefix"]
|
||||||
|
}
|
||||||
|
if prefix != "" {
|
||||||
|
object = prefix
|
||||||
|
}
|
||||||
|
return SetReqInfo(r.Context(),
|
||||||
|
// prepare request info
|
||||||
|
NewReqInfo(w, r, ObjectRequest{
|
||||||
|
Bucket: bucket,
|
||||||
|
Object: object,
|
||||||
|
Method: mux.CurrentRoute(r).GetName(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
// NewReqInfo :
|
// NewReqInfo :
|
||||||
func NewReqInfo(remoteHost, userAgent, deploymentID, requestID, api, bucket, object string) *ReqInfo {
|
func NewReqInfo(w http.ResponseWriter, r *http.Request, req ObjectRequest) *ReqInfo {
|
||||||
req := ReqInfo{}
|
return &ReqInfo{
|
||||||
req.RemoteHost = remoteHost
|
API: req.Method,
|
||||||
req.UserAgent = userAgent
|
BucketName: req.Bucket,
|
||||||
req.API = api
|
ObjectName: req.Object,
|
||||||
req.DeploymentID = deploymentID
|
UserAgent: r.UserAgent(),
|
||||||
req.RequestID = requestID
|
RemoteHost: GetSourceIP(r),
|
||||||
req.BucketName = bucket
|
RequestID: GetRequestID(w),
|
||||||
req.ObjectName = object
|
DeploymentID: deploymentID.String(),
|
||||||
return &req
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendTags - appends key/val to ReqInfo.tags
|
// AppendTags - appends key/val to ReqInfo.tags
|
||||||
|
@ -99,13 +192,9 @@ func SetReqInfo(ctx context.Context, req *ReqInfo) context.Context {
|
||||||
|
|
||||||
// GetReqInfo returns ReqInfo if set.
|
// GetReqInfo returns ReqInfo if set.
|
||||||
func GetReqInfo(ctx context.Context) *ReqInfo {
|
func GetReqInfo(ctx context.Context) *ReqInfo {
|
||||||
if ctx != nil {
|
if ctx == nil {
|
||||||
r, ok := ctx.Value(ctxRequestInfo).(*ReqInfo)
|
return nil
|
||||||
if ok {
|
} else if r, ok := ctx.Value(ctxRequestInfo).(*ReqInfo); ok {
|
||||||
return r
|
|
||||||
}
|
|
||||||
r = &ReqInfo{}
|
|
||||||
SetReqInfo(ctx, r)
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in a new issue