Repository: nginx/nginx-gateway-fabric (go)

Issue:
HTTPRoute filters need to apply the user provided value for the existing headers 
**Describe the bug**
HTTPRoute filters does not honor the user provided value for already existing headers. 

**To Reproduce**
Steps to reproduce the behavior:

Apply the [gateway.yaml](https://github.com/nginx/nginx-gateway-fabric/blob/main/examples/http-request-header-filter/gateway.yaml) and [headers](https://github.com/nginx/nginx-gateway-fabric/blob/main/examples/http-request-header-filter/headers.yaml) application 

use the following HTTPRoute 

```
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: headers
spec:
  parentRefs:
  - name: gateway
    sectionName: http
  hostnames:
  - "echo.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /headers
    filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        set:
        - name: X-Forwarded-Proto
          value: https
    backendRefs:
    - name: headers
      port: 80
```

The header `X-Forwarded-Proto` 

Nginx Config

```
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-Proto "https";
        proxy_set_header Host "$gw_api_compliant_host";
        proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
        proxy_set_header X-Real-IP "$remote_addr";
        proxy_set_header X-Forwarded-Proto "$scheme";
        proxy_set_header X-Forwarded-Host "$host";
        proxy_set_header X-Forwarded-Port "$server_port";
        proxy_set_header Upgrade "$http_upgrade";
        proxy_set_header Connection "$connection_upgrade";
        proxy_pass http://default_headers_80$request_uri;
```

The header is `X-Forwarded-Proto` set twice.

**Expected behavior**
We need to set the header `X-Forwarded-Proto` once to `https` (user provided value).  

**Your environment**
* Version of the NGINX Gateway Fabric - release version or a specific commit. The first line of the nginx-gateway container logs includes the commit info. -- edge
* Version of Kubernetes 
* Kubernetes platform (e.g. Mini-kube or GCP)
* Details on how you expose the NGINX Gateway Fabric Pod (e.g. Service of type LoadBalancer or port-forward)
* Logs of NGINX container: `kubectl -n nginx-gateway logs -l app=nginx-gateway -c nginx`
* NGINX Configuration: `kubectl -n nginx-gateway exec <gateway-pod> -c nginx -- nginx -T`

**Additional context**
Add any other context about the problem here. Any log files you want to share.


Pull request:
De-duplicate base headers if specified by user
Problem: If a user set a header in a header filter that had a default value set by NGF, both values would end up being set.

Solution: If provided by a user, don't set the default header value.

Testing: Unit test and manual verification of header de-duplication.

Closes #3192

### Checklist

Before creating a PR, run through this checklist and mark each as complete.

- [ ] I have read the [CONTRIBUTING](https://github.com/nginx/nginx-gateway-fabric/blob/main/CONTRIBUTING.md) doc
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] I have checked that all unit tests pass after adding my changes
- [ ] I have updated necessary documentation
- [ ] I have rebased my branch onto main
- [ ] I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

### Release notes

If this PR introduces a change that affects users and needs to be mentioned in the [release notes](../blob/main/CHANGELOG.md),
please add a brief note that summarizes the change.

<!-- If this PR does not require a release note, you can just write NONE in the release-note block below. -->

```release-note
Fix an issue where default headers were still being set when overwritten by a user.
```


Patch:
diff --git a/internal/mode/static/nginx/config/servers.go b/internal/mode/static/nginx/config/servers.go
index 0e2c58f1..f7d76e2e 100644
--- a/internal/mode/static/nginx/config/servers.go
+++ b/internal/mode/static/nginx/config/servers.go
@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"maps"
+	"slices"
 	"strconv"
 	"strings"
 	gotemplate "text/template"
@@ -812,7 +813,15 @@ func generateProxySetHeaders(
 		})
 	}
 
-	return append(proxySetHeaders, baseHeaders...)
+	for _, header := range baseHeaders {
+		if !slices.ContainsFunc(proxySetHeaders, func(h http.Header) bool {
+			return header.Name == h.Name
+		}) {
+			proxySetHeaders = append(proxySetHeaders, header)
+		}
+	}
+
+	return proxySetHeaders
 }
 
 func generateResponseHeaders(filters *dataplane.HTTPFilters) http.ResponseHeaders {


Test patch:
diff --git a/internal/mode/static/nginx/config/servers_test.go b/internal/mode/static/nginx/config/servers_test.go
index 29d84d0c..56da44f1 100644
--- a/internal/mode/static/nginx/config/servers_test.go
+++ b/internal/mode/static/nginx/config/servers_test.go
@@ -3146,6 +3146,54 @@ func TestGenerateProxySetHeaders(t *testing.T) {
 			}, httpBaseHeaders...),
 			baseHeaders: httpBaseHeaders,
 		},
+		{
+			msg: "header filter overwrite base header",
+			filters: &dataplane.HTTPFilters{
+				RequestHeaderModifiers: &dataplane.HTTPHeaderFilter{
+					Set: []dataplane.HTTPHeader{
+						{
+							Name:  "X-Forwarded-Proto",
+							Value: "new-proto",
+						},
+					},
+				},
+			},
+			expectedHeaders: []http.Header{
+				{
+					Name:  "X-Forwarded-Proto",
+					Value: "new-proto",
+				},
+				{
+					Name:  "Host",
+					Value: "$gw_api_compliant_host",
+				},
+				{
+					Name:  "X-Forwarded-For",
+					Value: "$proxy_add_x_forwarded_for",
+				},
+				{
+					Name:  "X-Real-IP",
+					Value: "$remote_addr",
+				},
+				{
+					Name:  "X-Forwarded-Host",
+					Value: "$host",
+				},
+				{
+					Name:  "X-Forwarded-Port",
+					Value: "$server_port",
+				},
+				{
+					Name:  "Upgrade",
+					Value: "$http_upgrade",
+				},
+				{
+					Name:  "Connection",
+					Value: "$connection_upgrade",
+				},
+			},
+			baseHeaders: httpBaseHeaders,
+		},
 		{
 			msg: "with url rewrite hostname",
 			filters: &dataplane.HTTPFilters{