distribution/registry/api/v2/headerparser_test.go
Michal Minář 1b43e1e30d
Honor X-Forwarded-Port and Forwarded headers
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>
2016-11-02 16:49:42 +01:00

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)
}
}
}