Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't add dbl headers for X-Forwarded-Proto and X-Forwarded-Port #175

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions app/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ func (h *Http) proxyHandler() http.HandlerFunc {
keepHost := ctx.Value(ctxKeepHost).(bool)
r.Header.Add("X-Forwarded-Host", r.Host)
if h.SSLConfig.SSLMode == SSLAuto || h.SSLConfig.SSLMode == SSLStatic {
r.Header.Add("X-Forwarded-Proto", "https")
r.Header.Add("X-Forwarded-Port", "443")
h.setHeaderIfNotExists(r, "X-Forwarded-Proto", "https")
h.setHeaderIfNotExists(r, "X-Forwarded-Port", "443")
}
r.URL.Path = uu.Path
r.URL.Host = uu.Host
Expand Down Expand Up @@ -466,3 +466,9 @@ func (h *Http) discoveredServers(ctx context.Context, interval time.Duration) (s
}
return servers
}

func (h *Http) setHeaderIfNotExists(r *http.Request, key, value string) {
if _, ok := r.Header[key]; !ok {
r.Header.Set(key, value)
}
}
107 changes: 107 additions & 0 deletions app/proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package proxy
import (
"bytes"
"context"
"crypto/tls"
"fmt"
"io"
"math/rand"
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"strings"
"sync/atomic"
"testing"
"time"
Expand Down Expand Up @@ -120,6 +122,111 @@ func TestHttp_Do(t *testing.T) {
})
}

func TestHttp_DoWithSSL(t *testing.T) {
port := rand.Intn(10000) + 40000
h := Http{Timeouts: Timeouts{ResponseHeader: 200 * time.Millisecond}, Address: fmt.Sprintf("localhost:%d", port),
AccessLog: io.Discard, Signature: true, ProxyHeaders: []string{"hh1:vv1", "hh2:vv2"}, StdOutEnabled: true,
Reporter: &ErrorReporter{Nice: true},
SSLConfig: SSLConfig{SSLMode: SSLStatic, Cert: "testdata/localhost.crt", Key: "testdata/localhost.key"}, Insecure: true,
}
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()

ds := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Logf("req: %v", r)
w.Header().Add("h1", "v1")
require.Equal(t, "127.0.0.1", r.Header.Get("X-Real-IP"))
require.Equal(t, "127.0.0.1", r.Header.Get("X-Forwarded-For"))
require.Equal(t, "https", r.Header.Get("X-Forwarded-Proto")) // ssl auto only
require.Equal(t, "443", r.Header.Get("X-Forwarded-Port"))
fmt.Fprintf(w, "response %s", r.URL.String())
}))

svc := discovery.NewService([]discovery.Provider{
&provider.Static{Rules: []string{
"localhost,^/api/(.*)," + strings.Replace(ds.URL, "127.0.0.1", "localhost", 1) + "/123/$1,",
"127.0.0.1,^/api/(.*)," + strings.Replace(ds.URL, "127.0.0.1", "localhost", 1) + "/567/$1,",
},
}}, time.Millisecond*10)

go func() {
_ = svc.Run(context.Background())
}()

time.Sleep(50 * time.Millisecond)
h.Matcher = svc
h.Metrics = mgmt.NewMetrics()

go func() {
_ = h.Run(ctx)
}()
time.Sleep(10 * time.Millisecond)

client := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}

t.Run("to localhost, good", func(t *testing.T) {
req, err := http.NewRequest("GET", "https://localhost:"+strconv.Itoa(port)+"/api/something", http.NoBody)
require.NoError(t, err)
resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
t.Logf("%+v", resp.Header)

body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, "response /123/something", string(body))
assert.Equal(t, "reproxy", resp.Header.Get("App-Name"))
assert.Equal(t, "v1", resp.Header.Get("h1"))
assert.Equal(t, "vv1", resp.Header.Get("hh1"))
assert.Equal(t, "vv2", resp.Header.Get("hh2"))
})

t.Run("to localhost, request with X-Forwarded-Proto and X-Forwarded-Port", func(t *testing.T) {
req, err := http.NewRequest("GET", "https://localhost:"+strconv.Itoa(port)+"/api/something", http.NoBody)
req.Header.Set("X-Forwarded-Proto", "https")
req.Header.Set("X-Forwarded-Port", "443")
require.NoError(t, err)
resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
t.Logf("%+v", resp.Header)

body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, "response /123/something", string(body))
assert.Equal(t, "reproxy", resp.Header.Get("App-Name"))
assert.Equal(t, "v1", resp.Header.Get("h1"))
assert.Equal(t, "vv1", resp.Header.Get("hh1"))
assert.Equal(t, "vv2", resp.Header.Get("hh2"))
})

t.Run("to 127.0.0.1", func(t *testing.T) {
req, err := http.NewRequest("GET", "https://127.0.0.1:"+strconv.Itoa(port)+"/api/something", http.NoBody)
req.Header.Set("X-Forwarded-Proto", "https")
req.Header.Set("X-Forwarded-Port", "443")
require.NoError(t, err)
resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
t.Logf("%+v", resp.Header)

body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, "response /567/something", string(body))
assert.Equal(t, "reproxy", resp.Header.Get("App-Name"))
assert.Equal(t, "v1", resp.Header.Get("h1"))
assert.Equal(t, "vv1", resp.Header.Get("hh1"))
assert.Equal(t, "vv2", resp.Header.Get("hh2"))
})
}

func TestHttp_DoWithAssets(t *testing.T) {
port := rand.Intn(10000) + 40000
cc := NewCacheControl(time.Hour * 12)
Expand Down
37 changes: 20 additions & 17 deletions app/proxy/testdata/localhost.crt
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIC5TCCAc2gAwIBAgIJALiRj0+veRc9MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0yMTA0MjcwNzQ1MzlaFw0yMTA1MjcwNzQ1MzlaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKku5qZGexf0uvgVY+u8DOSnq8W10w+yQ1wSkMR5T0ag3hyimIDmDhNB3dI0
5/B9IsIC9ZwUxOGHVCjP+TODXAGYIGYRx3BQb8si2369UXTQYNvVNQzPFdThjdcN
gXUmLN08a3ZMdXDC62DcOcVv1+oHd1qbuugkHqwA9CEn/aMJeYPso/4cfbgXX0WD
LEYkzgYwkyVf4JxyDWjm5d5fh/Tgpuu3lgH8qgKi51BmuSdiMiWsZ+AZykjpwAY6
FsNHHmi1NZ1gLj/bzXNjziK50SIgIBiqTIxYdQBrYliRYC3RD252M4Sjk+WAOkVs
RvLDvYLcl0kqclayzBr2qI/2RkECAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B
AQsFAAOCAQEARvUEtFQC/l73/cTyEy24Om3t7uwHWzYRBQDz2dkj2V+OHuXaXKQW
9ucv9DupNYxuXLVg93IPZgDGlFUZMlNnTvP5APBdQZyuoyZER7pqlJg8Sfo1BO5P
KUqaspgdIzd8BmIYMkOaDgd/kOgqjGKjXJwHVvSl7oBcZ8WrxDBMuopXuFosYHVK
z9ZsknqbxibgWBhwLKgDSOwLwVRIPIXlgJpSIyfDpQt0D3PbiFfcXYHqZ09ocZ/b
mIRqF7/OpWW/15Zdo3+gqohWr5qoDZIH8gtBWRs6Ai3cbE/D5jSNdfDrrjRs0HkN
GHmkcX4ABMze6SN7cWFpgeIvy1mxKfMoZw==
-----END CERTIFICATE-----
MIIDhzCCAm+gAwIBAgIUKMrw5NqY2c4v/ziNzA+JGC7keMgwDQYJKoZIhvcNAQEL
BQAwUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGljYWdv
MRAwDgYDVQQKDAdyZXByb3h5MRIwEAYDVQQDDAlsb2NhbGhvc3QwIBcNMjQwMjA2
MDQ1NDIxWhgPMjA1MTA2MjQwNDU0MjFaMFIxCzAJBgNVBAYTAlVTMQswCQYDVQQI
DAJJTDEQMA4GA1UEBwwHQ2hpY2FnbzEQMA4GA1UECgwHcmVwcm94eTESMBAGA1UE
AwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxvql
fklS0YOZhy2KmP+LlGvYpt2j5GgUr7FWXS/nUdYPtT8GhTzhP6AuVO5a63vmUuoY
XP61DtnirC571eIpgxNiZSUzRYn/IFR75BT025hZ6hwpAU+6ccpJjbQs48O74cgS
xL+QML2/zqgWIvT9hZg5+/fi8gO76Gcwyi/r1pwk4Gac1HJTdicQes5AewUuFQt+
AdN/VSklzDmQAn+mgWmXqxnTMgccGBlsiiYTjKkBSIrUB5TEXIpASzU12EzF8LCU
mG2g4/wUGgKAXEUXI/KGdhm83XR7a0vWRsKNZDokNIeFfohr0JI1h1uJNM+2bfN5
bTaLEjnxxwnw7j+ApwIDAQABo1MwUTAdBgNVHQ4EFgQUYiSDgICi9jUqX3K5hDXz
sZlksBswHwYDVR0jBBgwFoAUYiSDgICi9jUqX3K5hDXzsZlksBswDwYDVR0TAQH/
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEArSpccPKHbnS4Xc0SUdqhBiEpM49v
u3yVXvUFaFq6drIJNeAjmMundw4qPuSl8w56YVwzHwmv8OSAyb15RUl+1mSpT//i
sIqn3Ph3y6AcnyrkobCYOPho4dZMTsuSPfa9WRuFdvpUuZcn9JlvzlPZeYs6ba32
wZfGBu6We26u89dcUKstKLEWZOI6rvTwViDiNafpnQc2JmP8U27wkyQe0uRuwUUY
nLlB44QmWWHgct2YJz7wIJ0R9LQB32rhvLvkDnpl2VRA87xl8Q4z6yGfZVSzkRtq
2K8HX+VuCB3NB61tC+eYbNEehkcdfJmuXzO/fLcoMWKEH5Q1ExmPMn+BKQ==
-----END CERTIFICATE-----
54 changes: 27 additions & 27 deletions app/proxy/testdata/localhost.key
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCpLuamRnsX9Lr4
FWPrvAzkp6vFtdMPskNcEpDEeU9GoN4copiA5g4TQd3SNOfwfSLCAvWcFMThh1Qo
z/kzg1wBmCBmEcdwUG/LItt+vVF00GDb1TUMzxXU4Y3XDYF1JizdPGt2THVwwutg
3DnFb9fqB3dam7roJB6sAPQhJ/2jCXmD7KP+HH24F19FgyxGJM4GMJMlX+Cccg1o
5uXeX4f04Kbrt5YB/KoCoudQZrknYjIlrGfgGcpI6cAGOhbDRx5otTWdYC4/281z
Y84iudEiICAYqkyMWHUAa2JYkWAt0Q9udjOEo5PlgDpFbEbyw72C3JdJKnJWsswa
9qiP9kZBAgMBAAECggEAcCZ7F3ZZWwQMfTAQ0NAT6++KWsGxbBJLvNlBxjx0ZOl2
05ylY60dX36mQRZ5Ol55kArOLe1GpgpDq9pR4+gMMbJap87ZWoa31P0Ca/2r5bfM
vW2UgS0116y9jfWR/8qSqwXGZuFAaMONrOPQGCWQB79zS0k4mXJ4MqVfMCuGY3Bs
IkeyT96/pcYg36KeTGfvZOrX1GvH3udht5x2BxwuWdNjLEqL391OetnZe1H3NArs
fklboxgc/G0kRfx6X9/pqB+zytqeYec1nqc13I+3z6xjD1a2dK7rldY6CAp0IhwU
54hmu8MO/Laq3159xbB0BR48ClIwox+4z0pT5hDtEQKBgQDbfVMOma9TYmWGd7Or
/iuOVS64Jm2vrGySg/JlSBFskogy1vTtzwuAWe/3NLy5FVt1W7WC2Wt8OM1LIsh1
lBiWM4Fz2bqLAgu1Y48Y0DsNVtckgo1jmwT4i1Ub664NMVvsaXLNtiSWzf53Jmh9
J5zyg9ZiLXA7q+P5QDpZdskmowKBgQDFU1jC0LoaQaw+vH06eIoXVWYYwU+xpAK+
AXZv7N3nBafhYTaTfWT/j54xoJr4kCnavXADMZq3oeHzR20B9oc4F1qT/6rEzYlu
pi7EtxXHf406Huf1uLOU8VckYEZd31i9dM0By7RD+EopYcI1TEIN1UR5XYv/bwHa
tZHjAFoBywKBgQCjnrZG4QxRFb3nUt6OrYgcr6WHQ6Zq2heJ1XDiTaonjMiZVaL6
kGjbgrAfUaIKO0CVqQsTgy7cSJ/JjiFvfToi5jxvd3TXYWwHCTPIZJpQ5Fa3cdci
1JINEhkdGkECtrP29djOPyThgqhafDhSbDBUnTE4uPS8lvP4gAe/X4yuDwKBgQC6
AGaavMWwGleSi3o/s3/3nrgufYnxmPg8woQx3MUPD3XALTKUtI6Pl4E2pn1t7/aE
Ci2b1RZSInYqLBnEz+2GIf1vpIAEIvp5IozTQQF2m/Uz5A4iwYgFzbimwVmTAwVT
ENZt6uZxa4n8l/nI46kgAPgaruNYU/sbfiuWHq65IQKBgCMYfLML4oeRt+Xm5wcy
T+PrP0qKt20wW/nqn4TVjuO606ywD2aLS/AJ96k04maEEAebahy6ODoEjNb3erQW
VGsMydDBZ0QlMs6x7LDh3JLP0+JNETCezd1Nl20ykjpaoZ8Unzf/gpgaVjZON+wF
ON1xMW7NBrs9xvcjhBVgtn6r
-----END PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDG+qV+SVLRg5mH
LYqY/4uUa9im3aPkaBSvsVZdL+dR1g+1PwaFPOE/oC5U7lrre+ZS6hhc/rUO2eKs
LnvV4imDE2JlJTNFif8gVHvkFPTbmFnqHCkBT7pxykmNtCzjw7vhyBLEv5Awvb/O
qBYi9P2FmDn79+LyA7voZzDKL+vWnCTgZpzUclN2JxB6zkB7BS4VC34B039VKSXM
OZACf6aBaZerGdMyBxwYGWyKJhOMqQFIitQHlMRcikBLNTXYTMXwsJSYbaDj/BQa
AoBcRRcj8oZ2GbzddHtrS9ZGwo1kOiQ0h4V+iGvQkjWHW4k0z7Zt83ltNosSOfHH
CfDuP4CnAgMBAAECggEAVx8xzOyf5XqAg26OS9VAMTlTQCS1ePGVdSPpk53A49Ud
RZeV7EquuWQSRT+j8Y1rWIyFJFqlvh3qoMctk4WV9X1MTMsP+vekDGzRXhlK6Md5
PwcbcSaOlPokYHYuXX+7SO2IQjs6EA1U6VAxeRbZ1l/Dq65q4Np/sQ9VjoGS+oDX
ApTYm5lKiKjBzf4xJ9jE61YaC9phxE099Tl8CEDRUUCEFL7fd6I+cPpCZE6094P5
OHjMJYXAONclhXCXmPeGjtio9VnGgrGaclnBzjHs94XcW+slXBZdzDubXsi5Uhb3
6P+GVpuyhpgFLEqtAbl6HUcGtS/Gbq4uYW+2FhlpWQKBgQD5pmKiJ7P2W2a3gZto
/Rb9r6Q2YnbtAPigKCaN6Ntzahrej1we7Qqi4lYS1z9YmRaXxyvySdNiTbYo/qLm
XEK2F8AnJUpaEK0+QJ7EQbTww8bElhPnpG9246+qMTbUwSgf6sRZ+RToGMQ5EBTY
deFgz4H0qXrDj2RQkOC1ayvDRQKBgQDMClBjsZa+FKoTWBGnHFlBzQQ9X0jAaSno
sPPsd9N8pcHZ2P3NehSEGeCeRc8xcZZib4TK1APnRGg+56tX+QSvwGT4P8C5GHvM
S3T8xojgpFK6JGai/jrcBWqOCa3xXrP3miiF8Es01Q2Wy3EuMffkBlUBgsW66PPU
A3W4UwWc+wKBgGtz4iBJVnxC+wMhFfMqfCrU3qlJ2EZKlLjajz2lbE9Q7B+/NLda
76kMImAZpXpM6hyJ7bBrdkBpkm4yq4rbSxt1PY+bzVTWuLqCtdNjNK4slfEnZ4nc
jN1vQrzOUftg6BRUyA6x1v3PKyYkddR1aHxy1EyqZdyma1cCBLYRWtTBAoGAUpD5
5t2+OjzyddF1k0INfGsSBCPCtNnZc6fnjREQK6iHwTflvHhiRPKTynhFV6S3Ti4C
dnFFAxjTdmEZHQhPtS8NrMdfnYci0ZDXTlKooP7d2yVPwzVNbCtk6wVPthS0jsV7
EHgkdsSgMx0wN5lQzp0hWPMqQHBz+p9Ly8MMynECgYEAr+zCEd1v3n6okfaZKFV9
czy1jigLgXOdDSzqAe8FE53hFQiCkYn5fj7byNRYrCmUb1dtoQJsM7AmN1LkWVv3
5hC8FKHS78SBkeCRplWIr329z+xoBrV+9b4DubUQXACW7zQh911404TdbZMjGohW
oJdJyZA2raAm/gaOyTIqDz0=
-----END PRIVATE KEY-----
Loading