From e3282f64085423e48cf5424910fb0652d80e198c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Efe=20=C3=87etin?= Date: Tue, 6 Sep 2022 18:43:06 +0300 Subject: [PATCH] :recycle: v3 (enhancement): replace `c.Hostname()` -> `c.Host()` & add `c.Hostname()` that returns host without port --- app.go | 4 +- client_test.go | 6 +-- ctx.go | 18 +++++-- ctx_interface.go | 8 +++- ctx_test.go | 73 ++++++++++++++++++++++------- middleware/adaptor/adopter_test.go | 4 +- middleware/logger/default_logger.go | 2 +- 7 files changed, 86 insertions(+), 29 deletions(-) diff --git a/app.go b/app.go index 2b416c17..7740d3ab 100644 --- a/app.go +++ b/app.go @@ -349,12 +349,12 @@ type Config struct { // If request ip in TrustedProxies whitelist then: // 1. c.Scheme() get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header // 2. c.IP() get value from ProxyHeader header. - // 3. c.Hostname() get value from X-Forwarded-Host header + // 3. c.Host() and c.Hostname() get value from X-Forwarded-Host header // But if request ip NOT in Trusted Proxies whitelist then: // 1. c.Scheme() WON't get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header, // will return https in case when tls connection is handled by the app, of http otherwise // 2. c.IP() WON'T get value from ProxyHeader header, will return RemoteIP() from fasthttp context - // 3. c.Hostname() WON'T get value from X-Forwarded-Host header, fasthttp.Request.URI().Host() + // 3. c.Host() and c.Hostname() WON'T get value from X-Forwarded-Host header, fasthttp.Request.URI().Host() // will be used to get the hostname. // // Default: false diff --git a/client_test.go b/client_test.go index ad5eecc1..9b866dc0 100644 --- a/client_test.go +++ b/client_test.go @@ -31,7 +31,7 @@ func Test_Client_Invalid_URL(t *testing.T) { app := New(Config{DisableStartupMessage: true}) app.Get("/", func(c Ctx) error { - return c.SendString(c.Hostname()) + return c.SendString(c.Host()) }) go func() { require.Nil(t, app.Listener(ln)) }() @@ -69,7 +69,7 @@ func Test_Client_Get(t *testing.T) { app := New(Config{DisableStartupMessage: true}) app.Get("/", func(c Ctx) error { - return c.SendString(c.Hostname()) + return c.SendString(c.Host()) }) go func() { require.Nil(t, app.Listener(ln)) }() @@ -394,7 +394,7 @@ func Test_Client_Agent_Host(t *testing.T) { app := New(Config{DisableStartupMessage: true}) app.Get("/", func(c Ctx) error { - return c.SendString(c.Hostname()) + return c.SendString(c.Host()) }) go func() { require.Nil(t, app.Listener(ln)) }() diff --git a/ctx.go b/ctx.go index 43f9835e..5d6c57df 100644 --- a/ctx.go +++ b/ctx.go @@ -210,7 +210,7 @@ func (c *DefaultCtx) BaseURL() string { if c.baseURI != "" { return c.baseURI } - c.baseURI = c.Scheme() + "://" + c.Hostname() + c.baseURI = c.Scheme() + "://" + c.Host() return c.baseURI } @@ -468,11 +468,11 @@ func (c *DefaultCtx) GetRespHeader(key string, defaultValue ...string) string { return defaultString(c.app.getString(c.fasthttp.Response.Header.Peek(key)), defaultValue) } -// Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header. +// Host contains the host derived from the X-Forwarded-Host or Host HTTP header. // Returned value is only valid within the handler. Do not store any references. // Make copies or use the Immutable setting instead. // Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. -func (c *DefaultCtx) Hostname() string { +func (c *DefaultCtx) Host() string { if c.IsProxyTrusted() { if host := c.Get(HeaderXForwardedHost); len(host) > 0 { return host @@ -481,6 +481,16 @@ func (c *DefaultCtx) Hostname() string { return c.app.getString(c.fasthttp.Request.URI().Host()) } +// Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header using the c.Host() method. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting instead. +// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +func (c *DefaultCtx) Hostname() string { + addr, _ := parseAddr(c.Host()) + + return addr +} + // Port returns the remote port of the request. func (c *DefaultCtx) Port() string { port := c.fasthttp.RemoteAddr().(*net.TCPAddr).Port @@ -1238,7 +1248,7 @@ func (c *DefaultCtx) Subdomains(offset ...int) []string { if len(offset) > 0 { o = offset[0] } - subdomains := strings.Split(c.Hostname(), ".") + subdomains := strings.Split(c.Host(), ".") l := len(subdomains) - o // Check index to avoid slice bounds out of range panic if l < 0 { diff --git a/ctx_interface.go b/ctx_interface.go index 9f24a4c4..3adcea49 100644 --- a/ctx_interface.go +++ b/ctx_interface.go @@ -123,7 +123,13 @@ type Ctx interface { // Make copies or use the Immutable setting instead. GetRespHeader(key string, defaultValue ...string) string - // Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header. + // Host contains the host derived from the X-Forwarded-Host or Host HTTP header. + // Returned value is only valid within the handler. Do not store any references. + // Make copies or use the Immutable setting instead. + // Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. + Host() string + + // Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header using the c.Host() method. // Returned value is only valid within the handler. Do not store any references. // Make copies or use the Immutable setting instead. // Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. diff --git a/ctx_test.go b/ctx_test.go index 7372c297..82e21d39 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -772,18 +772,18 @@ func Test_Ctx_Get(t *testing.T) { require.Equal(t, "default", c.Get("unknown", "default")) } -// go test -run Test_Ctx_Hostname -func Test_Ctx_Hostname(t *testing.T) { +// go test -run Test_Ctx_Host +func Test_Ctx_Host(t *testing.T) { t.Parallel() app := New() c := app.NewCtx(&fasthttp.RequestCtx{}) c.Request().SetRequestURI("http://google.com/test") - require.Equal(t, "google.com", c.Hostname()) + require.Equal(t, "google.com", c.Host()) } -// go test -run Test_Ctx_Hostname_Untrusted -func Test_Ctx_Hostname_UntrustedProxy(t *testing.T) { +// go test -run Test_Ctx_Host_UntrustedProxy +func Test_Ctx_Host_UntrustedProxy(t *testing.T) { t.Parallel() // Don't trust any proxy { @@ -791,7 +791,7 @@ func Test_Ctx_Hostname_UntrustedProxy(t *testing.T) { c := app.NewCtx(&fasthttp.RequestCtx{}) c.Request().SetRequestURI("http://google.com/test") c.Request().Header.Set(HeaderXForwardedHost, "google1.com") - require.Equal(t, "google.com", c.Hostname()) + require.Equal(t, "google.com", c.Host()) app.ReleaseCtx(c) } // Trust to specific proxy list @@ -800,48 +800,89 @@ func Test_Ctx_Hostname_UntrustedProxy(t *testing.T) { c := app.NewCtx(&fasthttp.RequestCtx{}) c.Request().SetRequestURI("http://google.com/test") c.Request().Header.Set(HeaderXForwardedHost, "google1.com") - require.Equal(t, "google.com", c.Hostname()) + require.Equal(t, "google.com", c.Host()) app.ReleaseCtx(c) } } -// go test -run Test_Ctx_Hostname_Trusted -func Test_Ctx_Hostname_TrustedProxy(t *testing.T) { +// go test -run Test_Ctx_Host_TrustedProxy +func Test_Ctx_Host_TrustedProxy(t *testing.T) { t.Parallel() { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0", "0.8.0.1"}}) c := app.NewCtx(&fasthttp.RequestCtx{}) c.Request().SetRequestURI("http://google.com/test") c.Request().Header.Set(HeaderXForwardedHost, "google1.com") - require.Equal(t, "google1.com", c.Hostname()) + require.Equal(t, "google1.com", c.Host()) app.ReleaseCtx(c) } } -// go test -run Test_Ctx_Hostname_UntrustedProxyRange -func Test_Ctx_Hostname_TrustedProxyRange(t *testing.T) { +// go test -run Test_Ctx_Host_TrustedProxyRange +func Test_Ctx_Host_TrustedProxyRange(t *testing.T) { t.Parallel() app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0/30"}}) c := app.NewCtx(&fasthttp.RequestCtx{}) c.Request().SetRequestURI("http://google.com/test") c.Request().Header.Set(HeaderXForwardedHost, "google1.com") - require.Equal(t, "google1.com", c.Hostname()) + require.Equal(t, "google1.com", c.Host()) app.ReleaseCtx(c) } -// go test -run Test_Ctx_Hostname_UntrustedProxyRange -func Test_Ctx_Hostname_UntrustedProxyRange(t *testing.T) { +// go test -run Test_Ctx_Host_UntrustedProxyRange +func Test_Ctx_Host_UntrustedProxyRange(t *testing.T) { t.Parallel() app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"1.0.0.0/30"}}) c := app.NewCtx(&fasthttp.RequestCtx{}) c.Request().SetRequestURI("http://google.com/test") c.Request().Header.Set(HeaderXForwardedHost, "google1.com") - require.Equal(t, "google.com", c.Hostname()) + require.Equal(t, "google.com", c.Host()) app.ReleaseCtx(c) } +// go test -v -run=^$ -bench=Benchmark_Ctx_Host -benchmem -count=4 +func Benchmark_Ctx_Host(b *testing.B) { + app := New() + c := app.NewCtx(&fasthttp.RequestCtx{}) + c.Request().SetRequestURI("http://google.com/test") + var host string + b.ReportAllocs() + b.ResetTimer() + for n := 0; n < b.N; n++ { + host = c.Host() + } + require.Equal(b, "google.com", host) +} + +// go test -run Test_Ctx_Hostname +func Test_Ctx_Hostname(t *testing.T) { + t.Parallel() + app := New() + c := app.NewCtx(&fasthttp.RequestCtx{}) + + c.Request().SetRequestURI("http://google.com/test") + require.Equal(t, "google.com", c.Hostname()) + + c.Request().SetRequestURI("http://google.com:8080/test") + require.Equal(t, "google.com", c.Hostname()) +} + +// go test -v -run=^$ -bench=Benchmark_Ctx_Hostname -benchmem -count=4 +func Benchmark_Ctx_Hostname(b *testing.B) { + app := New() + c := app.NewCtx(&fasthttp.RequestCtx{}) + c.Request().SetRequestURI("http://google.com:8080/test") + var hostname string + b.ReportAllocs() + b.ResetTimer() + for n := 0; n < b.N; n++ { + hostname = c.Hostname() + } + require.Equal(b, "google.com", hostname) +} + // go test -run Test_Ctx_Port func Test_Ctx_Port(t *testing.T) { t.Parallel() diff --git a/middleware/adaptor/adopter_test.go b/middleware/adaptor/adopter_test.go index 6480bff8..8e9531e7 100644 --- a/middleware/adaptor/adopter_test.go +++ b/middleware/adaptor/adopter_test.go @@ -245,8 +245,8 @@ func testFiberToHandlerFunc(t *testing.T, checkDefaultPort bool, app ...*fiber.A if contentLength != expectedContentLength { t.Fatalf("unexpected contentLength %d. Expecting %d", contentLength, expectedContentLength) } - if c.Hostname() != expectedHost { - t.Fatalf("unexpected host %q. Expecting %q", c.Hostname(), expectedHost) + if c.Host() != expectedHost { + t.Fatalf("unexpected host %q. Expecting %q", c.Host(), expectedHost) } remoteAddr := c.Context().RemoteAddr().String() if remoteAddr != expectedRemoteAddr { diff --git a/middleware/logger/default_logger.go b/middleware/logger/default_logger.go index 822cb676..41442f78 100644 --- a/middleware/logger/default_logger.go +++ b/middleware/logger/default_logger.go @@ -88,7 +88,7 @@ func defaultLogger(c fiber.Ctx, data LoggerData, cfg Config) error { case TagIPs: return buf.WriteString(c.Get(fiber.HeaderXForwardedFor)) case TagHost: - return buf.WriteString(c.Hostname()) + return buf.WriteString(c.Host()) case TagPath: return buf.WriteString(c.Path()) case TagURL: