2021-03-26 04:04:56 +00:00
|
|
|
package connection
|
2019-11-13 15:11:35 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"reflect"
|
2020-02-21 02:51:46 +00:00
|
|
|
"sort"
|
2019-11-13 15:11:35 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
2020-02-09 02:07:07 +00:00
|
|
|
func TestSerializeHeaders(t *testing.T) {
|
|
|
|
request, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2020-02-21 02:51:46 +00:00
|
|
|
mockHeaders := http.Header{
|
2020-02-09 02:07:07 +00:00
|
|
|
"Mock-Header-One": {"Mock header one value", "three"},
|
|
|
|
"Mock-Header-Two-Long": {"Mock header two value\nlong"},
|
|
|
|
":;": {":;", ";:"},
|
|
|
|
":": {":"},
|
|
|
|
";": {";"},
|
|
|
|
";;": {";;"},
|
|
|
|
"Empty values": {"", ""},
|
|
|
|
"": {"Empty key"},
|
|
|
|
"control\tcharacter\b\n": {"value\n\b\t"},
|
|
|
|
";\v:": {":\v;"},
|
|
|
|
}
|
|
|
|
|
|
|
|
for header, values := range mockHeaders {
|
|
|
|
for _, value := range values {
|
|
|
|
// Note that Golang's http library is opinionated;
|
|
|
|
// at this point every header name will be title-cased in order to comply with the HTTP RFC
|
|
|
|
// This means our proxy is not completely transparent when it comes to proxying headers
|
|
|
|
request.Header.Add(header, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 02:51:46 +00:00
|
|
|
serializedHeaders := SerializeHeaders(request.Header)
|
2020-02-09 02:07:07 +00:00
|
|
|
|
|
|
|
// Sanity check: the headers serialized to something that's not an empty string
|
|
|
|
assert.NotEqual(t, "", serializedHeaders)
|
|
|
|
|
|
|
|
// Deserialize back, and ensure we get the same set of headers
|
|
|
|
deserializedHeaders, err := DeserializeHeaders(serializedHeaders)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2020-02-21 02:51:46 +00:00
|
|
|
assert.Equal(t, 13, len(deserializedHeaders))
|
|
|
|
h2muxExpectedHeaders := stdlibHeaderToH2muxHeader(mockHeaders)
|
|
|
|
|
|
|
|
sort.Sort(ByName(deserializedHeaders))
|
|
|
|
sort.Sort(ByName(h2muxExpectedHeaders))
|
|
|
|
|
|
|
|
assert.True(
|
|
|
|
t,
|
|
|
|
reflect.DeepEqual(h2muxExpectedHeaders, deserializedHeaders),
|
|
|
|
fmt.Sprintf("got = %#v, want = %#v\n", deserializedHeaders, h2muxExpectedHeaders),
|
|
|
|
)
|
2020-02-09 02:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSerializeNoHeaders(t *testing.T) {
|
|
|
|
request, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2020-02-21 02:51:46 +00:00
|
|
|
serializedHeaders := SerializeHeaders(request.Header)
|
2020-02-09 02:07:07 +00:00
|
|
|
deserializedHeaders, err := DeserializeHeaders(serializedHeaders)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 0, len(deserializedHeaders))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeserializeMalformed(t *testing.T) {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
malformedData := []string{
|
|
|
|
"malformed data",
|
|
|
|
"bW9jawo=", // "mock"
|
|
|
|
"bW9jawo=:ZGF0YQo=:bW9jawo=", // "mock:data:mock"
|
|
|
|
"::",
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, malformedValue := range malformedData {
|
2020-02-21 02:51:46 +00:00
|
|
|
_, err = DeserializeHeaders(malformedValue)
|
2020-02-09 02:07:07 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
}
|
|
|
|
}
|
2020-02-21 02:51:46 +00:00
|
|
|
|
2021-08-31 16:33:10 +00:00
|
|
|
func TestIsControlResponseHeader(t *testing.T) {
|
|
|
|
controlResponseHeaders := []string{
|
|
|
|
// Anything that begins with cf-int- or cf-cloudflared-
|
|
|
|
"cf-int-sample-header",
|
|
|
|
"cf-cloudflared-sample-header",
|
|
|
|
// Any http2 pseudoheader
|
|
|
|
":sample-pseudo-header",
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, header := range controlResponseHeaders {
|
|
|
|
assert.True(t, IsControlResponseHeader(header))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIsNotControlResponseHeader(t *testing.T) {
|
|
|
|
notControlResponseHeaders := []string{
|
2020-07-25 04:23:00 +00:00
|
|
|
"mock-header",
|
|
|
|
"another-sample-header",
|
2021-08-31 16:33:10 +00:00
|
|
|
"upgrade",
|
|
|
|
"connection",
|
|
|
|
"cf-whatever", // On the response path, we only want to filter cf-int- and cf-cloudflared-
|
2020-02-21 02:51:46 +00:00
|
|
|
}
|
|
|
|
|
2021-08-31 16:33:10 +00:00
|
|
|
for _, header := range notControlResponseHeaders {
|
|
|
|
assert.False(t, IsControlResponseHeader(header))
|
2020-02-21 02:51:46 +00:00
|
|
|
}
|
|
|
|
}
|