package httpheaders import ( "net/http" "net/textproto" "github.com/yusing/go-proxy/internal/utils/strutils" "golang.org/x/net/http/httpguts" ) const ( HeaderXForwardedMethod = "X-Forwarded-Method" HeaderXForwardedFor = "X-Forwarded-For" HeaderXForwardedProto = "X-Forwarded-Proto" HeaderXForwardedHost = "X-Forwarded-Host" HeaderXForwardedPort = "X-Forwarded-Port" HeaderXForwardedURI = "X-Forwarded-Uri" HeaderXRealIP = "X-Real-IP" HeaderContentType = "Content-Type" HeaderContentLength = "Content-Length" HeaderGoDoxyCheckRedirect = "X-Godoxy-Check-Redirect" ) // Hop-by-hop headers. These are removed when sent to the backend. // As of RFC 7230, hop-by-hop headers are required to appear in the // Connection header field. These are the headers defined by the // obsoleted RFC 2616 (section 13.5.1) and are used for backward // compatibility. var hopHeaders = []string{ "Connection", "Proxy-Connection", // non-standard but still sent by libcurl and rejected by e.g. google "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "Te", // canonicalized version of "TE" "Trailer", // not Trailers per URL above; https://www.rfc-editor.org/errata_search.php?eid=4522 "Transfer-Encoding", "Upgrade", } func UpgradeType(h http.Header) string { if !httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade") { return "" } return h.Get("Upgrade") } // RemoveHopByHopHeaders removes hop-by-hop headers. func RemoveHopByHopHeaders(h http.Header) { // RFC 7230, section 6.1: Remove headers listed in the "Connection" header. for _, f := range h["Connection"] { for _, sf := range strutils.SplitComma(f) { if sf = textproto.TrimString(sf); sf != "" { h.Del(sf) } } } // RFC 2616, section 13.5.1: Remove a set of known hop-by-hop headers. // This behavior is superseded by the RFC 7230 Connection header, but // preserve it for backwards compatibility. for _, f := range hopHeaders { h.Del(f) } } func RemoveHop(h http.Header) { reqUpType := UpgradeType(h) RemoveHopByHopHeaders(h) if reqUpType != "" { h.Set("Connection", "Upgrade") h.Set("Upgrade", reqUpType) } else { h.Del("Connection") } } func RemoveServiceHeaders(h http.Header) { h.Del("X-Powered-By") h.Del("Server") } func CopyHeader(dst, src http.Header) { for k, vv := range src { for _, v := range vv { dst.Add(k, v) } } } func FilterHeaders(h http.Header, allowed []string) http.Header { if len(allowed) == 0 { return h } filtered := make(http.Header) for i, header := range allowed { values := h.Values(header) if len(values) == 0 { continue } filtered[http.CanonicalHeaderKey(allowed[i])] = append([]string(nil), values...) } return filtered } func HeaderToMap(h http.Header) map[string]string { result := make(map[string]string) for k, v := range h { if len(v) > 0 { result[k] = v[0] // Take the first value } } return result }