diff --git a/modules/context/context.go b/modules/context/context.go index 64f8b12084576..1a82358951895 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -511,9 +511,19 @@ func (ctx *Context) GetCookieFloat64(name string) float64 { return v } -// RemoteAddr returns the client machie ip address +// RemoteAddr returns the client machine ip address. It respects the X-Real-IP (preferred) or X-Forwarded-For header. func (ctx *Context) RemoteAddr() string { - return ctx.Req.RemoteAddr + addr := ctx.Req.Header.Get("X-Real-IP") + if len(addr) == 0 { + addr = ctx.Req.Header.Get("X-Forwarded-For") + if addr == "" { + addr = ctx.Req.RemoteAddr + if i := strings.LastIndex(addr, ":"); i > -1 { + addr = addr[:i] + } + } + } + return addr } // Params returns the param on route diff --git a/modules/context/context_test.go b/modules/context/context_test.go new file mode 100644 index 0000000000000..858e0fd1e4da1 --- /dev/null +++ b/modules/context/context_test.go @@ -0,0 +1,42 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package context + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRemoteAddrNoHeader(t *testing.T) { + expected := "123.456.78.9" + req, _ := http.NewRequest(http.MethodGet, "url", nil) + req.RemoteAddr = expected + + ctx := context.Context{Req: req} + + assert.Equal(t, expected, ctx.RemoteAddr(), "RemoteAddr should match the expected response") +} + +func TestRemoteAddrXRealIpHeader(t *testing.T) { + expected := "123.456.78.9" + req, _ := http.NewRequest(http.MethodGet, "url", nil) + req.Header.Add("X-Real-IP", expected) + + ctx := context.Context{Req: req} + + assert.Equal(t, expected, ctx.RemoteAddr(), "RemoteAddr should match the expected response") +} + +func TestRemoteAddrXForwardedForHeader(t *testing.T) { + expected := "123.456.78.9" + req, _ := http.NewRequest(http.MethodGet, "url", nil) + req.Header.Add("X-Forwarded-For", expected) + + ctx := context.Context{Req: req} + + assert.Equal(t, expected, ctx.RemoteAddr(), "RemoteAddr should match the expected response") +}