Skip to content

Commit a3f0872

Browse files
Bisstocuzthinkerou
authored andcommitted
Provide custom options of TrustedPlatform for another CDN services (#2906)
* refine TrustedPlatform and docs * refactor for switch * refactor switch to if statement
1 parent b5ad462 commit a3f0872

File tree

4 files changed

+49
-12
lines changed

4 files changed

+49
-12
lines changed

README.md

+29
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
7777
- [http2 server push](#http2-server-push)
7878
- [Define format for the log of routes](#define-format-for-the-log-of-routes)
7979
- [Set and get a cookie](#set-and-get-a-cookie)
80+
- [Don't trust all proxies](#don't-trust-all-proxies)
8081
- [Testing](#testing)
8182
- [Users](#users)
8283

@@ -2164,6 +2165,34 @@ func main() {
21642165
}
21652166
```
21662167

2168+
**Notice:** If you are using a CDN service, you can set the `Engine.TrustedPlatform`
2169+
to skip TrustedProxies check, it has a higher priority than TrustedProxies.
2170+
Look at the example below:
2171+
```go
2172+
import (
2173+
"fmt"
2174+
2175+
"github.com/gin-gonic/gin"
2176+
)
2177+
2178+
func main() {
2179+
2180+
router := gin.Default()
2181+
// Use predefined header gin.PlatformXXX
2182+
router.TrustedPlatform = gin.PlatformGoogleAppEngine
2183+
// Or set your own trusted request header for another trusted proxy service
2184+
// Don't set it to any suspect request header, it's unsafe
2185+
router.TrustedPlatform = "X-CDN-IP"
2186+
2187+
router.GET("/", func(c *gin.Context) {
2188+
// If you set TrustedPlatform, ClientIP() will resolve the
2189+
// corresponding header and return IP directly
2190+
fmt.Printf("ClientIP: %s\n", c.ClientIP())
2191+
})
2192+
router.Run()
2193+
}
2194+
```
2195+
21672196
## Testing
21682197

21692198
The `net/http/httptest` package is preferable way for HTTP testing.

context.go

+5-9
Original file line numberDiff line numberDiff line change
@@ -728,20 +728,16 @@ func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (e
728728
return bb.BindBody(body, obj)
729729
}
730730

731-
// ClientIP implements a best effort algorithm to return the real client IP.
731+
// ClientIP implements one best effort algorithm to return the real client IP.
732732
// It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
733733
// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
734734
// If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy,
735735
// the remote IP (coming form Request.RemoteAddr) is returned.
736736
func (c *Context) ClientIP() string {
737-
// Check if we're running on a trusted platform
738-
switch c.engine.TrustedPlatform {
739-
case PlatformGoogleAppEngine:
740-
if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
741-
return addr
742-
}
743-
case PlatformCloudflare:
744-
if addr := c.requestHeader("CF-Connecting-IP"); addr != "" {
737+
// Check if we're running on a trusted platform, continue running backwards if error
738+
if c.engine.TrustedPlatform != "" {
739+
// Developers can define their own header of Trusted Platform or use predefined constants
740+
if addr := c.requestHeader(c.engine.TrustedPlatform); addr != "" {
745741
return addr
746742
}
747743
}

context_test.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -1460,8 +1460,20 @@ func TestContextClientIP(t *testing.T) {
14601460
c.engine.TrustedPlatform = PlatformGoogleAppEngine
14611461
assert.Equal(t, "50.50.50.50", c.ClientIP())
14621462

1463-
// Test the legacy flag
1463+
// Use custom TrustedPlatform header
1464+
c.engine.TrustedPlatform = "X-CDN-IP"
1465+
c.Request.Header.Set("X-CDN-IP", "80.80.80.80")
1466+
assert.Equal(t, "80.80.80.80", c.ClientIP())
1467+
// wrong header
1468+
c.engine.TrustedPlatform = "X-Wrong-Header"
1469+
assert.Equal(t, "40.40.40.40", c.ClientIP())
1470+
1471+
c.Request.Header.Del("X-CDN-IP")
1472+
// TrustedPlatform is empty
14641473
c.engine.TrustedPlatform = ""
1474+
assert.Equal(t, "40.40.40.40", c.ClientIP())
1475+
1476+
// Test the legacy flag
14651477
c.engine.AppEngine = true
14661478
assert.Equal(t, "50.50.50.50", c.ClientIP())
14671479
c.engine.AppEngine = false

gin.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ type RoutesInfo []RouteInfo
5959
const (
6060
// When running on Google App Engine. Trust X-Appengine-Remote-Addr
6161
// for determining the client's IP
62-
PlatformGoogleAppEngine = "google-app-engine"
62+
PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
6363
// When using Cloudflare's CDN. Trust CF-Connecting-IP for determining
6464
// the client's IP
65-
PlatformCloudflare = "cloudflare"
65+
PlatformCloudflare = "CF-Connecting-IP"
6666
)
6767

6868
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.

0 commit comments

Comments
 (0)