mirror of
https://github.com/distribution/distribution
synced 2024-11-12 05:45:51 +01:00
1b43e1e30d
Prefer non-standard headers like X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Port over the standard Forwarded header to maintain backwards compatibility. If a port is not specified neither in Host nor in forwarded headers but it is specified just with X-Forwarded-Port, use its value in base urls for redirects. Forwarded header is defined in rfc7239. X-Forwarded-Port is a non-standard header. Here's a description copied from "HTTP Headers and Elastic Load Balancing" of AWS ELB docs: > The X-Forwarded-Port request header helps you identify the port that > an HTTP or HTTPS load balancer uses to connect to the client. Signed-off-by: Michal Minář <miminar@redhat.com>
162 lines
3.8 KiB
Go
162 lines
3.8 KiB
Go
package v2
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestParseForwardedHeader(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
raw string
|
|
expected map[string]string
|
|
expectedRest string
|
|
expectedError bool
|
|
}{
|
|
{
|
|
name: "empty",
|
|
raw: "",
|
|
},
|
|
{
|
|
name: "one pair",
|
|
raw: " key = value ",
|
|
expected: map[string]string{"key": "value"},
|
|
},
|
|
{
|
|
name: "two pairs",
|
|
raw: " key1 = value1; key2=value2",
|
|
expected: map[string]string{"key1": "value1", "key2": "value2"},
|
|
},
|
|
{
|
|
name: "uppercase parameter",
|
|
raw: "KeY=VaL",
|
|
expected: map[string]string{"key": "VaL"},
|
|
},
|
|
{
|
|
name: "missing key=value pair - be tolerant",
|
|
raw: "key=val;",
|
|
expected: map[string]string{"key": "val"},
|
|
},
|
|
{
|
|
name: "quoted values",
|
|
raw: `key="val";param = "[[ $((1 + 1)) == 3 ]] && echo panic!;" ; p=" abcd "`,
|
|
expected: map[string]string{"key": "val", "param": "[[ $((1 + 1)) == 3 ]] && echo panic!;", "p": " abcd "},
|
|
},
|
|
{
|
|
name: "empty quoted value",
|
|
raw: `key=""`,
|
|
expected: map[string]string{"key": ""},
|
|
},
|
|
{
|
|
name: "quoted double quotes",
|
|
raw: `key="\"value\""`,
|
|
expected: map[string]string{"key": `"value"`},
|
|
},
|
|
{
|
|
name: "quoted backslash",
|
|
raw: `key="\"\\\""`,
|
|
expected: map[string]string{"key": `"\"`},
|
|
},
|
|
{
|
|
name: "ignore subsequent elements",
|
|
raw: "key=a, param= b",
|
|
expected: map[string]string{"key": "a"},
|
|
expectedRest: " param= b",
|
|
},
|
|
{
|
|
name: "empty element - be tolerant",
|
|
raw: " , key=val",
|
|
expectedRest: " key=val",
|
|
},
|
|
{
|
|
name: "obscure key",
|
|
raw: `ob₷C&r€ = value`,
|
|
expected: map[string]string{`ob₷c&r€`: "value"},
|
|
},
|
|
{
|
|
name: "duplicate parameter",
|
|
raw: "key=a; p=b; key=c",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "empty parameter",
|
|
raw: "=value",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "empty value",
|
|
raw: "key= ",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "empty value before a new element ",
|
|
raw: "key=,",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "empty value before a new pair",
|
|
raw: "key=;",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "just parameter",
|
|
raw: "key",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "missing key-value",
|
|
raw: "a=b;;",
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "unclosed quoted value",
|
|
raw: `key="value`,
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "escaped terminating dquote",
|
|
raw: `key="value\"`,
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "just a quoted value",
|
|
raw: `"key=val"`,
|
|
expectedError: true,
|
|
},
|
|
{
|
|
name: "quoted key",
|
|
raw: `"key"=val`,
|
|
expectedError: true,
|
|
},
|
|
} {
|
|
parsed, rest, err := parseForwardedHeader(tc.raw)
|
|
if err != nil && !tc.expectedError {
|
|
t.Errorf("[%s] got unexpected error: %v", tc.name, err)
|
|
}
|
|
if err == nil && tc.expectedError {
|
|
t.Errorf("[%s] got unexpected non-error", tc.name)
|
|
}
|
|
if err != nil || tc.expectedError {
|
|
continue
|
|
}
|
|
for key, value := range tc.expected {
|
|
v, exists := parsed[key]
|
|
if !exists {
|
|
t.Errorf("[%s] missing expected parameter %q", tc.name, key)
|
|
continue
|
|
}
|
|
if v != value {
|
|
t.Errorf("[%s] got unexpected value for parameter %q: %q != %q", tc.name, key, v, value)
|
|
}
|
|
}
|
|
for key, value := range parsed {
|
|
if _, exists := tc.expected[key]; !exists {
|
|
t.Errorf("[%s] got unexpected key/value pair: %q=%q", tc.name, key, value)
|
|
}
|
|
}
|
|
|
|
if rest != tc.expectedRest {
|
|
t.Errorf("[%s] got unexpected unparsed string: %q != %q", tc.name, rest, tc.expectedRest)
|
|
}
|
|
}
|
|
}
|