Repository: gofiber/fiber (Go)

Issue:
🧹 [v3 Maintenance]: GetReqHeaders and GetRespHeaders are missing from the main branch but still documented
### Maintenance Task Description

GetReqHeaders and GetRespHeaders are missing from the main branch but still documented in a handful of places. If this was by mistake, they'll need to be pulled back in. If it was intentional, we should update the docs.  I can help with this, but I just need clarification what the intent was.

### Impact on the Project

_No response_

### Additional Context (optional)

_No response_

### Checklist:

- [X] I have confirmed that this maintenance task is currently not being addressed.
- [X] I understand that this task will be evaluated by the maintainers and prioritized accordingly.
- [X] I am available to provide further information if needed.


Discussion:
@efectn do you recall if this was intentional? thx
@nickajacks1 Not all the latest changes have been migrated to v3 yet
I want to bring both methods from v2. I will start a PR =) Can I work on this issue?
@gaby I opened the PR #2831 bringing both functions to v3 =)



Patch:
diff --git a/ctx.go b/ctx.go
index b292ea7b42..9257825e7b 100644
--- a/ctx.go
+++ b/ctx.go
@@ -560,6 +560,30 @@ func (c *DefaultCtx) GetRespHeader(key string, defaultValue ...string) string {
 	return defaultString(c.app.getString(c.fasthttp.Response.Header.Peek(key)), defaultValue)
 }
 
+// GetRespHeaders returns the HTTP response headers.
+// Returned value is only valid within the handler. Do not store any references.
+// Make copies or use the Immutable setting instead.
+func (c *DefaultCtx) GetRespHeaders() map[string][]string {
+	headers := make(map[string][]string)
+	c.Response().Header.VisitAll(func(k, v []byte) {
+		key := c.app.getString(k)
+		headers[key] = append(headers[key], c.app.getString(v))
+	})
+	return headers
+}
+
+// GetReqHeaders returns the HTTP request headers.
+// Returned value is only valid within the handler. Do not store any references.
+// Make copies or use the Immutable setting instead.
+func (c *DefaultCtx) GetReqHeaders() map[string][]string {
+	headers := make(map[string][]string)
+	c.Request().Header.VisitAll(func(k, v []byte) {
+		key := c.app.getString(k)
+		headers[key] = append(headers[key], c.app.getString(v))
+	})
+	return headers
+}
+
 // 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.
diff --git a/ctx_interface.go b/ctx_interface.go
index ae8b171238..799be5601f 100644
--- a/ctx_interface.go
+++ b/ctx_interface.go
@@ -134,6 +134,16 @@ type Ctx interface {
 	// Make copies or use the Immutable setting instead.
 	GetRespHeader(key string, defaultValue ...string) string
 
+	// GetRespHeaders returns the HTTP response headers.
+	// Returned value is only valid within the handler. Do not store any references.
+	// Make copies or use the Immutable setting instead.
+	GetRespHeaders() map[string][]string
+
+	// GetReqHeaders returns the HTTP request headers.
+	// Returned value is only valid within the handler. Do not store any references.
+	// Make copies or use the Immutable setting instead.
+	GetReqHeaders() map[string][]string
+
 	// 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.


Test patch:
diff --git a/ctx_test.go b/ctx_test.go
index eb66dfae96..df896920e3 100644
--- a/ctx_test.go
+++ b/ctx_test.go
@@ -4853,3 +4853,89 @@ func Test_Ctx_extractIPsFromHeader_EnableValidateIp(t *testing.T) {
 	res := ips[len(ips)-2]
 	require.Equal(t, "42.118.81.169", res)
 }
+
+// go test -run Test_Ctx_GetRespHeaders
+func Test_Ctx_GetRespHeaders(t *testing.T) {
+	t.Parallel()
+	app := New()
+	c := app.NewCtx(&fasthttp.RequestCtx{})
+
+	c.Set("test", "Hello, World 👋!")
+	c.Set("foo", "bar")
+	c.Response().Header.Set("multi", "one")
+	c.Response().Header.Add("multi", "two")
+	c.Response().Header.Set(HeaderContentType, "application/json")
+
+	require.Equal(t, map[string][]string{
+		"Content-Type": {"application/json"},
+		"Foo":          {"bar"},
+		"Multi":        {"one", "two"},
+		"Test":         {"Hello, World 👋!"},
+	}, c.GetRespHeaders())
+}
+
+func Benchmark_Ctx_GetRespHeaders(b *testing.B) {
+	app := New()
+	c := app.NewCtx(&fasthttp.RequestCtx{})
+
+	c.Response().Header.Set("test", "Hello, World 👋!")
+	c.Response().Header.Set("foo", "bar")
+	c.Response().Header.Set(HeaderContentType, "application/json")
+
+	b.ReportAllocs()
+	b.ResetTimer()
+
+	var headers map[string][]string
+	for n := 0; n < b.N; n++ {
+		headers = c.GetRespHeaders()
+	}
+
+	require.Equal(b, map[string][]string{
+		"Content-Type": {"application/json"},
+		"Foo":          {"bar"},
+		"Test":         {"Hello, World 👋!"},
+	}, headers)
+}
+
+// go test -run Test_Ctx_GetReqHeaders
+func Test_Ctx_GetReqHeaders(t *testing.T) {
+	t.Parallel()
+	app := New()
+	c := app.NewCtx(&fasthttp.RequestCtx{})
+
+	c.Request().Header.Set("test", "Hello, World 👋!")
+	c.Request().Header.Set("foo", "bar")
+	c.Request().Header.Set("multi", "one")
+	c.Request().Header.Add("multi", "two")
+	c.Request().Header.Set(HeaderContentType, "application/json")
+
+	require.Equal(t, map[string][]string{
+		"Content-Type": {"application/json"},
+		"Foo":          {"bar"},
+		"Test":         {"Hello, World 👋!"},
+		"Multi":        {"one", "two"},
+	}, c.GetReqHeaders())
+}
+
+func Benchmark_Ctx_GetReqHeaders(b *testing.B) {
+	app := New()
+	c := app.NewCtx(&fasthttp.RequestCtx{})
+
+	c.Request().Header.Set("test", "Hello, World 👋!")
+	c.Request().Header.Set("foo", "bar")
+	c.Request().Header.Set(HeaderContentType, "application/json")
+
+	b.ReportAllocs()
+	b.ResetTimer()
+
+	var headers map[string][]string
+	for n := 0; n < b.N; n++ {
+		headers = c.GetReqHeaders()
+	}
+
+	require.Equal(b, map[string][]string{
+		"Content-Type": {"application/json"},
+		"Foo":          {"bar"},
+		"Test":         {"Hello, World 👋!"},
+	}, headers)
+}