cloudflare/cloudflared

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2025.2.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

connection/header_test.go

135lines · 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 expectedHeaders := headerToReqHeader(mockHeaders)
50
51 sort.Sort(ByName(deserializedHeaders))
52 sort.Sort(ByName(expectedHeaders))
53
54 assert.True(
55 t,
56 reflect.DeepEqual(expectedHeaders, deserializedHeaders),
57 fmt.Sprintf("got = %#v, want = %#v\n", deserializedHeaders, expectedHeaders),
58 )
59}
60
61type ByName []HTTPHeader
62
63func (a ByName) Len() int { return len(a) }
64func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
65func (a ByName) Less(i, j int) bool {
66 if a[i].Name == a[j].Name {
67 return a[i].Value < a[j].Value
68 }
69
70 return a[i].Name < a[j].Name
71}
72
73func headerToReqHeader(headers http.Header) (reqHeaders []HTTPHeader) {
74 for name, values := range headers {
75 for _, value := range values {
76 reqHeaders = append(reqHeaders, HTTPHeader{Name: name, Value: value})
77 }
78 }
79
80 return reqHeaders
81}
82
83func TestSerializeNoHeaders(t *testing.T) {
84 request, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
85 assert.NoError(t, err)
86
87 serializedHeaders := SerializeHeaders(request.Header)
88 deserializedHeaders, err := DeserializeHeaders(serializedHeaders)
89 assert.NoError(t, err)
90 assert.Equal(t, 0, len(deserializedHeaders))
91}
92
93func TestDeserializeMalformed(t *testing.T) {
94 var err error
95
96 malformedData := []string{
97 "malformed data",
98 "bW9jawo=", // "mock"
99 "bW9jawo=:ZGF0YQo=:bW9jawo=", // "mock:data:mock"
100 "::",
101 }
102
103 for _, malformedValue := range malformedData {
104 _, err = DeserializeHeaders(malformedValue)
105 assert.Error(t, err)
106 }
107}
108
109func TestIsControlResponseHeader(t *testing.T) {
110 controlResponseHeaders := []string{
111 // Anything that begins with cf-int- or cf-cloudflared-
112 "cf-int-sample-header",
113 "cf-cloudflared-sample-header",
114 // Any http2 pseudoheader
115 ":sample-pseudo-header",
116 }
117
118 for _, header := range controlResponseHeaders {
119 assert.True(t, IsControlResponseHeader(header))
120 }
121}
122
123func TestIsNotControlResponseHeader(t *testing.T) {
124 notControlResponseHeaders := []string{
125 "mock-header",
126 "another-sample-header",
127 "upgrade",
128 "connection",
129 "cf-whatever", // On the response path, we only want to filter cf-int- and cf-cloudflared-
130 }
131
132 for _, header := range notControlResponseHeaders {
133 assert.False(t, IsControlResponseHeader(header))
134 }
135}
136