Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,130 @@ const (
MIMEYAML2 = binding.MIMEYAML2
MIMETOML = binding.MIMETOML
MIMEPROTOBUF = binding.MIMEPROTOBUF

HeaderAuthorization string = "Authorization"
HeaderProxyAuthenticate string = "Proxy-Authenticate"
HeaderProxyAuthorization string = "Proxy-Authorization"
HeaderWWWAuthenticate string = "WWW-Authenticate"
HeaderAge string = "Age"
HeaderCacheControl string = "Cache-Control"
HeaderClearSiteData string = "Clear-Site-Data"
HeaderExpires string = "Expires"
HeaderPragma string = "Pragma"
HeaderWarning string = "Warning"
HeaderAcceptCH string = "Accept-CH"
HeaderAcceptCHLifetime string = "Accept-CH-Lifetime"
HeaderContentDPR string = "Content-DPR"
HeaderDPR string = "DPR"
HeaderEarlyData string = "Early-Data"
HeaderSaveData string = "Save-Data"
HeaderViewportWidth string = "Viewport-Width"
HeaderWidth string = "Width"
HeaderETag string = "ETag"
HeaderIfMatch string = "If-Match"
HeaderIfModifiedSince string = "If-Modified-Since"
HeaderIfNoneMatch string = "If-None-Match"
HeaderIfUnmodifiedSince string = "If-Unmodified-Since"
HeaderLastModified string = "Last-Modified"
HeaderVary string = "Vary"
HeaderConnection string = "Connection"
HeaderKeepAlive string = "Keep-Alive"
HeaderAccept string = "Accept"
HeaderAcceptCharset string = "Accept-Charset"
HeaderAcceptEncoding string = "Accept-Encoding"
HeaderAcceptLanguage string = "Accept-Language"
HeaderCookie string = "Cookie"
HeaderExpect string = "Expect"
HeaderMaxForwards string = "Max-Forwards"
HeaderSetCookie string = "Set-Cookie"
HeaderAccessControlAllowCredentials string = "Access-Control-Allow-Credentials"
HeaderAccessControlAllowHeaders string = "Access-Control-Allow-Headers"
HeaderAccessControlAllowMethods string = "Access-Control-Allow-Methods"
HeaderAccessControlAllowOrigin string = "Access-Control-Allow-Origin"
HeaderAccessControlExposeHeaders string = "Access-Control-Expose-Headers"
HeaderAccessControlMaxAge string = "Access-Control-Max-Age"
HeaderAccessControlRequestHeaders string = "Access-Control-Request-Headers"
HeaderAccessControlRequestMethod string = "Access-Control-Request-Method"
HeaderOrigin string = "Origin"
HeaderTimingAllowOrigin string = "Timing-Allow-Origin"
HeaderXPermittedCrossDomainPolicies string = "X-Permitted-Cross-Domain-Policies"
HeaderDNT string = "DNT"
HeaderTk string = "Tk"
HeaderContentDisposition string = "Content-Disposition"
HeaderContentEncoding string = "Content-Encoding"
HeaderContentLanguage string = "Content-Language"
HeaderContentLength string = "Content-Length"
HeaderContentLocation string = "Content-Location"
HeaderContentType string = "Content-Type"
HeaderForwarded string = "Forwarded"
HeaderVia string = "Via"
HeaderXForwardedFor string = "X-Forwarded-For"
HeaderXForwardedHost string = "X-Forwarded-Host"
HeaderXForwardedProto string = "X-Forwarded-Proto"
HeaderXForwardedProtocol string = "X-Forwarded-Protocol"
HeaderXForwardedSsl string = "X-Forwarded-Ssl"
HeaderXUrlScheme string = "X-Url-Scheme"
HeaderRealIp string = "X-Real-IP"
HeaderLocation string = "Location"
HeaderFrom string = "From"
HeaderHost string = "Host"
HeaderReferer string = "Referer"
HeaderReferrerPolicy string = "Referrer-Policy"
HeaderUserAgent string = "User-Agent"
HeaderAllow string = "Allow"
HeaderServer string = "Server"
HeaderAcceptRanges string = "Accept-Ranges"
HeaderContentRange string = "Content-Range"
HeaderIfRange string = "If-Range"
HeaderRange string = "Range"
HeaderContentSecurityPolicy string = "Content-Security-Policy"
HeaderContentSecurityPolicyReportOnly string = "Content-Security-Policy-Report-Only"
HeaderCrossOriginResourcePolicy string = "Cross-Origin-Resource-Policy"
HeaderExpectCT string = "Expect-CT"
HeaderFeaturePolicy string = "Feature-Policy"
HeaderPublicKeyPins string = "Public-Key-Pins"
HeaderPublicKeyPinsReportOnly string = "Public-Key-Pins-Report-Only"
HeaderStrictTransportSecurity string = "Strict-Transport-Security"
HeaderUpgradeInsecureRequests string = "Upgrade-Insecure-Requests"
HeaderXContentTypeOptions string = "X-Content-Type-Options"
HeaderXDownloadOptions string = "X-Download-Options"
HeaderXFrameOptions string = "X-Frame-Options"
HeaderXPoweredBy string = "X-Powered-By"
HeaderXXSSProtection string = "X-XSS-Protection"
HeaderLastEventID string = "Last-Event-ID"
HeaderNEL string = "NEL"
HeaderPingFrom string = "Ping-From"
HeaderPingTo string = "Ping-To"
HeaderReportTo string = "Report-To"
HeaderTE string = "TE"
HeaderTrailer string = "Trailer"
HeaderTransferEncoding string = "Transfer-Encoding"
HeaderSecWebSocketAccept string = "Sec-WebSocket-Accept"
HeaderSecWebSocketExtensions string = "Sec-WebSocket-Extensions"
HeaderSecWebSocketKey string = "Sec-WebSocket-Key"
HeaderSecWebSocketProtocol string = "Sec-WebSocket-Protocol"
HeaderSecWebSocketVersion string = "Sec-WebSocket-Version"
HeaderAcceptPatch string = "Accept-Patch"
HeaderAcceptPushPolicy string = "Accept-Push-Policy"
HeaderAcceptSignature string = "Accept-Signature"
HeaderAltSvc string = "Alt-Svc"
HeaderDate string = "Date"
HeaderIndex string = "Index"
HeaderLargeAllocation string = "Large-Allocation"
HeaderLink string = "Link"
HeaderPushPolicy string = "Push-Policy"
HeaderRetryAfter string = "Retry-After"
HeaderServerTiming string = "Server-Timing"
HeaderSignature string = "Signature"
HeaderSignedHeaders string = "Signed-Headers"
HeaderSourceMap string = "SourceMap"
HeaderUpgrade string = "Upgrade"
HeaderXDNSPrefetchControl string = "X-DNS-Prefetch-Control"
HeaderXPingback string = "X-Pingback"
HeaderXRequestID string = "X-Request-ID"
HeaderXRequestedWith string = "X-Requested-With"
HeaderXRobotsTag string = "X-Robots-Tag"
HeaderXUACompatible string = "X-UA-Compatible"
)

// BodyBytesKey indicates a default body bytes key.
Expand Down
147 changes: 147 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,22 @@ func TestContextHeaders(t *testing.T) {
assert.False(t, exist)
}

func TestContextHeadersConstants(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Header(HeaderContentType, "text/plain")
c.Header("X-Custom", "value")

assert.Equal(t, "text/plain", c.Writer.Header().Get(HeaderContentType))
assert.Equal(t, "value", c.Writer.Header().Get("X-Custom"))

c.Header(HeaderContentType, "text/html")
c.Header("X-Custom", "")

assert.Equal(t, "text/html", c.Writer.Header().Get(HeaderContentType))
_, exist := c.Writer.Header()["X-Custom"]
assert.False(t, exist)
}

// TODO
func TestContextRenderRedirectWithRelativePath(t *testing.T) {
w := httptest.NewRecorder()
Expand Down Expand Up @@ -2009,6 +2025,137 @@ func TestContextClientIP(t *testing.T) {
assert.Empty(t, c.ClientIP())
}

func TestContextClientIPConstants(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodPost, "/", nil)
c.engine.trustedCIDRs, _ = c.engine.prepareTrustedCIDRs()
resetContextForClientIPTests(c)

// Legacy tests (validating that the defaults don't break the
// (insecure!) old behaviour)
assert.Equal(t, "20.20.20.20", c.ClientIP())

c.Request.Header.Del(HeaderXForwardedFor)
assert.Equal(t, "10.10.10.10", c.ClientIP())

c.Request.Header.Set(HeaderXForwardedFor, "30.30.30.30 ")
assert.Equal(t, "30.30.30.30", c.ClientIP())

c.Request.Header.Del(HeaderXForwardedFor)
c.Request.Header.Del(HeaderRealIp)
c.engine.TrustedPlatform = PlatformGoogleAppEngine
assert.Equal(t, "50.50.50.50", c.ClientIP())

c.Request.Header.Del("X-Appengine-Remote-Addr")
assert.Equal(t, "40.40.40.40", c.ClientIP())

// no port
c.Request.RemoteAddr = "50.50.50.50"
assert.Empty(t, c.ClientIP())

// Tests exercising the TrustedProxies functionality
resetContextForClientIPTests(c)

// IPv6 support
c.Request.RemoteAddr = "[::1]:12345"
assert.Equal(t, "20.20.20.20", c.ClientIP())

resetContextForClientIPTests(c)
// No trusted proxies
_ = c.engine.SetTrustedProxies([]string{})
c.engine.RemoteIPHeaders = []string{HeaderXForwardedFor}
assert.Equal(t, "40.40.40.40", c.ClientIP())

// Disabled TrustedProxies feature
_ = c.engine.SetTrustedProxies(nil)
assert.Equal(t, "40.40.40.40", c.ClientIP())

// Last proxy is trusted, but the RemoteAddr is not
_ = c.engine.SetTrustedProxies([]string{"30.30.30.30"})
assert.Equal(t, "40.40.40.40", c.ClientIP())

// Only trust RemoteAddr
_ = c.engine.SetTrustedProxies([]string{"40.40.40.40"})
assert.Equal(t, "30.30.30.30", c.ClientIP())

// All steps are trusted
_ = c.engine.SetTrustedProxies([]string{"40.40.40.40", "30.30.30.30", "20.20.20.20"})
assert.Equal(t, "20.20.20.20", c.ClientIP())

// Use CIDR
_ = c.engine.SetTrustedProxies([]string{"40.40.25.25/16", "30.30.30.30"})
assert.Equal(t, "20.20.20.20", c.ClientIP())

// Use hostname that resolves to all the proxies
_ = c.engine.SetTrustedProxies([]string{"foo"})
assert.Equal(t, "40.40.40.40", c.ClientIP())

// Use hostname that returns an error
_ = c.engine.SetTrustedProxies([]string{"bar"})
assert.Equal(t, "40.40.40.40", c.ClientIP())

// X-Forwarded-For has a non-IP element
_ = c.engine.SetTrustedProxies([]string{"40.40.40.40"})
c.Request.Header.Set("X-Forwarded-For", " blah ")
assert.Equal(t, "40.40.40.40", c.ClientIP())

// Result from LookupHost has non-IP element. This should never
// happen, but we should test it to make sure we handle it
// gracefully.
_ = c.engine.SetTrustedProxies([]string{"baz"})
c.Request.Header.Set("X-Forwarded-For", " 30.30.30.30 ")
assert.Equal(t, "40.40.40.40", c.ClientIP())

_ = c.engine.SetTrustedProxies([]string{"40.40.40.40"})
c.Request.Header.Del("X-Forwarded-For")
c.engine.RemoteIPHeaders = []string{HeaderXForwardedFor, HeaderRealIp}
assert.Equal(t, "10.10.10.10", c.ClientIP())

c.engine.RemoteIPHeaders = []string{}
c.engine.TrustedPlatform = PlatformGoogleAppEngine
assert.Equal(t, "50.50.50.50", c.ClientIP())

// Use custom TrustedPlatform header
c.engine.TrustedPlatform = "X-CDN-IP"
c.Request.Header.Set("X-CDN-IP", "80.80.80.80")
assert.Equal(t, "80.80.80.80", c.ClientIP())
// wrong header
c.engine.TrustedPlatform = "X-Wrong-Header"
assert.Equal(t, "40.40.40.40", c.ClientIP())

c.Request.Header.Del("X-CDN-IP")
// TrustedPlatform is empty
c.engine.TrustedPlatform = ""
assert.Equal(t, "40.40.40.40", c.ClientIP())

// Test the legacy flag
c.engine.AppEngine = true
assert.Equal(t, "50.50.50.50", c.ClientIP())
c.engine.AppEngine = false
c.engine.TrustedPlatform = PlatformGoogleAppEngine

c.Request.Header.Del("X-Appengine-Remote-Addr")
assert.Equal(t, "40.40.40.40", c.ClientIP())

c.engine.TrustedPlatform = PlatformCloudflare
assert.Equal(t, "60.60.60.60", c.ClientIP())

c.Request.Header.Del("CF-Connecting-IP")
assert.Equal(t, "40.40.40.40", c.ClientIP())

c.engine.TrustedPlatform = PlatformFlyIO
assert.Equal(t, "70.70.70.70", c.ClientIP())

c.Request.Header.Del("Fly-Client-IP")
assert.Equal(t, "40.40.40.40", c.ClientIP())

c.engine.TrustedPlatform = ""

// no port
c.Request.RemoteAddr = "50.50.50.50"
assert.Empty(t, c.ClientIP())
}

func resetContextForClientIPTests(c *Context) {
c.Request.Header.Set("X-Real-IP", " 10.10.10.10 ")
c.Request.Header.Set("X-Forwarded-For", " 20.20.20.20, 30.30.30.30")
Expand Down
Loading