cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2024.2.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

connection/header_test.go

113lines · modecode

1package connection
2
3import (
4 "fmt"
5 "net/http"
6 "reflect"
7 "sort"
8 "testing"
9
10 "github.com/stretchr/testify/assert"
11)
12
13func TestSerializeHeaders(t *testing.T) {
14 request, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
15 assert.NoError(t, err)
16
17 mockHeaders := http.Header{
18 "Mock-Header-One": {"Mock header one value", "three"},
19 "Mock-Header-Two-Long": {"Mock header two value\nlong"},
20 ":;": {":;", ";:"},
21 ":": {":"},
22 ";": {";"},
23 ";;": {";;"},
24 "Empty values": {"", ""},
25 "": {"Empty key"},
26 "control\tcharacter\b\n": {"value\n\b\t"},
27 ";\v:": {":\v;"},
28 }
29
30 for header, values := range mockHeaders {
31 for _, value := range values {
32 // Note that Golang's http library is opinionated;
33 // at this point every header name will be title-cased in order to comply with the HTTP RFC
34 // This means our proxy is not completely transparent when it comes to proxying headers
35 request.Header.Add(header, value)
36 }
37 }
38
39 serializedHeaders := SerializeHeaders(request.Header)
40
41 // Sanity check: the headers serialized to something that's not an empty string
42 assert.NotEqual(t, "", serializedHeaders)
43
44 // Deserialize back, and ensure we get the same set of headers
45 deserializedHeaders, err := DeserializeHeaders(serializedHeaders)
46 assert.NoError(t, err)
47
48 assert.Equal(t, 13, len(deserializedHeaders))
49 h2muxExpectedHeaders := stdlibHeaderToH2muxHeader(mockHeaders)
50
51 sort.Sort(ByName(deserializedHeaders))
52 sort.Sort(ByName(h2muxExpectedHeaders))
53
54 assert.True(
55 t,
56 reflect.DeepEqual(h2muxExpectedHeaders, deserializedHeaders),
57 fmt.Sprintf("got = %#v, want = %#v\n", deserializedHeaders, h2muxExpectedHeaders),
58 )
59}
60
61func TestSerializeNoHeaders(t *testing.T) {
62 request, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
63 assert.NoError(t, err)
64
65 serializedHeaders := SerializeHeaders(request.Header)
66 deserializedHeaders, err := DeserializeHeaders(serializedHeaders)
67 assert.NoError(t, err)
68 assert.Equal(t, 0, len(deserializedHeaders))
69}
70
71func TestDeserializeMalformed(t *testing.T) {
72 var err error
73
74 malformedData := []string{
75 "malformed data",
76 "bW9jawo=", // "mock"
77 "bW9jawo=:ZGF0YQo=:bW9jawo=", // "mock:data:mock"
78 "::",
79 }
80
81 for _, malformedValue := range malformedData {
82 _, err = DeserializeHeaders(malformedValue)
83 assert.Error(t, err)
84 }
85}
86
87func TestIsControlResponseHeader(t *testing.T) {
88 controlResponseHeaders := []string{
89 // Anything that begins with cf-int- or cf-cloudflared-
90 "cf-int-sample-header",
91 "cf-cloudflared-sample-header",
92 // Any http2 pseudoheader
93 ":sample-pseudo-header",
94 }
95
96 for _, header := range controlResponseHeaders {
97 assert.True(t, IsControlResponseHeader(header))
98 }
99}
100
101func TestIsNotControlResponseHeader(t *testing.T) {
102 notControlResponseHeaders := []string{
103 "mock-header",
104 "another-sample-header",
105 "upgrade",
106 "connection",
107 "cf-whatever", // On the response path, we only want to filter cf-int- and cf-cloudflared-
108 }
109
110 for _, header := range notControlResponseHeaders {
111 assert.False(t, IsControlResponseHeader(header))
112 }
113}