Skip to content

Commit b2b7746

Browse files
authored
httpheaders: use cow types (#48276)
1 parent e6bc6e9 commit b2b7746

29 files changed

+214
-166
lines changed

src/core/cors.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2015 Fanout, Inc.
3+
* Copyright (C) 2025 Fastly, Inc.
34
*
45
* This file is part of Pushpin.
56
*
@@ -57,7 +58,7 @@ void applyCorsHeaders(const HttpHeaders &requestHeaders, HttpHeaders *responseHe
5758
{
5859
if(!responseHeaders->contains("Access-Control-Allow-Methods"))
5960
{
60-
QByteArray method = requestHeaders.get("Access-Control-Request-Method");
61+
QByteArray method = requestHeaders.get("Access-Control-Request-Method").asQByteArray();
6162

6263
if(!method.isEmpty())
6364
*responseHeaders += HttpHeader("Access-Control-Allow-Methods", method);
@@ -67,8 +68,10 @@ void applyCorsHeaders(const HttpHeaders &requestHeaders, HttpHeaders *responseHe
6768

6869
if(!responseHeaders->contains("Access-Control-Allow-Headers"))
6970
{
70-
QList<QByteArray> allowHeaders;
71-
foreach(const QByteArray &h, requestHeaders.getAll("Access-Control-Request-Headers", true))
71+
CowByteArrayList allowHeaders;
72+
73+
CowByteArrayList l = requestHeaders.getAll("Access-Control-Request-Headers", true);
74+
for(CowByteArrayConstRef h : std::as_const(l))
7275
{
7376
if(!h.isEmpty())
7477
allowHeaders += h;
@@ -83,8 +86,8 @@ void applyCorsHeaders(const HttpHeaders &requestHeaders, HttpHeaders *responseHe
8386
QList<QByteArray> exposeHeaders;
8487
foreach(const HttpHeader &h, *responseHeaders)
8588
{
86-
if(!isSimpleHeader(h.first) && !headerNameStartsWith(h.first, "Access-Control-") && !headerNameStartsWith(h.first, "Grip-") && !headerNamesContains(exposeHeaders, h.first))
87-
exposeHeaders += h.first;
89+
if(!isSimpleHeader(h.first.asQByteArray()) && !headerNameStartsWith(h.first.asQByteArray(), "Access-Control-") && !headerNameStartsWith(h.first.asQByteArray(), "Grip-") && !headerNamesContains(exposeHeaders, h.first.asQByteArray()))
90+
exposeHeaders += h.first.asQByteArray();
8891
}
8992

9093
if(!exposeHeaders.isEmpty())
@@ -96,7 +99,7 @@ void applyCorsHeaders(const HttpHeaders &requestHeaders, HttpHeaders *responseHe
9699

97100
if(!responseHeaders->contains("Access-Control-Allow-Origin"))
98101
{
99-
QByteArray origin = requestHeaders.get("Origin");
102+
CowByteArray origin = requestHeaders.get("Origin");
100103

101104
if(origin.isEmpty())
102105
origin = "*";

src/core/cowbytearray.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,23 @@ class CowByteArray
9797

9898
ssize_t indexOf(char ch, ssize_t from = 0) const { return inner_.indexOf(ch, from); }
9999
CowByteArray mid(ssize_t pos, ssize_t len = -1) const { return inner_.mid(pos, len); }
100+
CowByteArray trimmed() const { return inner_.trimmed(); }
100101

101102
void clear() { inner_.clear(); }
102103
void resize(ssize_t size) { inner_.resize(size); }
103104

104105
char operator[](ssize_t i) const { return inner_[(qsizetype)i]; }
105106
char & operator[](ssize_t i) { return inner_[(qsizetype)i]; }
107+
CowByteArray & operator+=(const CowByteArray &other) { inner_ += other.inner_; return *this; }
108+
CowByteArray & operator+=(char ch) { inner_ += ch; return *this; }
109+
CowByteArray & operator+=(const char *str) { inner_ += str; return *this; }
106110

107111
const QByteArray & asQByteArray() const { return inner_; }
108112

113+
friend CowByteArray operator+(const CowByteArray &lhs, const CowByteArray &rhs);
114+
friend CowByteArray operator+(const CowByteArray &lhs, const char *rhs);
115+
friend CowByteArray operator+(const char *lhs, const CowByteArray &rhs);
116+
109117
friend bool operator==(const CowByteArray &lhs, const CowByteArray &rhs);
110118
friend bool operator==(const CowByteArray &lhs, const char *const &rhs);
111119
friend bool operator==(const char *const &lhs, const CowByteArray &rhs);
@@ -116,6 +124,10 @@ class CowByteArray
116124
QByteArray inner_;
117125
};
118126

127+
inline CowByteArray operator+(const CowByteArray &lhs, const CowByteArray &rhs) { return lhs.inner_ + rhs.inner_; }
128+
inline CowByteArray operator+(const CowByteArray &lhs, const char *rhs) { return lhs.inner_ + rhs; }
129+
inline CowByteArray operator+(const char *lhs, const CowByteArray &rhs) { return lhs + rhs.inner_; }
130+
119131
inline bool operator==(const CowByteArray &lhs, const CowByteArray &rhs) { return lhs.inner_ == rhs.inner_; }
120132
inline bool operator==(const CowByteArray &lhs, const char *const &rhs) { return lhs.inner_ == rhs; }
121133
inline bool operator==(const char *const &lhs, const CowByteArray &rhs) { return lhs == rhs.inner_; }
@@ -185,6 +197,7 @@ class CowByteArrayList
185197

186198
bool isEmpty() const { return inner_.isEmpty(); }
187199
ssize_t count() const { return inner_.count(); }
200+
bool contains(const CowByteArray &a) const { return inner_.contains(a.asQByteArray()); }
188201

189202
iterator begin() { return inner_.begin(); }
190203
const_iterator begin() const { return inner_.begin(); }

src/core/cowbytearraytest.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ static void methods()
9494
TEST_ASSERT_EQ(b, "hel");
9595
TEST_ASSERT_EQ(c, "lo");
9696

97+
// trimmed
98+
TEST_ASSERT_EQ(CowByteArray(" hel lo ").trimmed(), "hel lo");
99+
97100
// clear
98101
CowByteArray d("hello");
99102
TEST_ASSERT(!d.isEmpty());
@@ -111,20 +114,39 @@ static void methods()
111114

112115
static void operators()
113116
{
117+
// operator=
114118
CowByteArray a;
115119
a = CowByteArray("hello");
116120
TEST_ASSERT_EQ(a, "hello");
117121

122+
// operator[] (const)
118123
TEST_ASSERT_EQ(std::as_const(a)[1], 'e');
119124
TEST_ASSERT_EQ(a[1], 'e');
120125

126+
// operator[] (non-const)
121127
a[1] = 'a';
122128
TEST_ASSERT_EQ(a, "hallo");
123129

130+
// operator+
131+
TEST_ASSERT_EQ(CowByteArray("hello") + CowByteArray(" world"), "hello world");
132+
TEST_ASSERT_EQ(CowByteArray("hello") + " world", "hello world");
133+
TEST_ASSERT_EQ("hello" + CowByteArray(" world"), "hello world");
134+
135+
// operator+=
136+
a += CowByteArray(" world");
137+
TEST_ASSERT_EQ(a, "hallo world");
138+
a += '!';
139+
TEST_ASSERT_EQ(a, "hallo world!");
140+
a += "11";
141+
TEST_ASSERT_EQ(a, "hallo world!11");
142+
143+
// operator==
144+
a = "hello";
124145
TEST_ASSERT(CowByteArray("hello") == CowByteArray("hello"));
125146
TEST_ASSERT(CowByteArray("hello") == "hello");
126147
TEST_ASSERT("hello" == CowByteArray("hello"));
127148

149+
// operator!=
128150
TEST_ASSERT(CowByteArray("hello") != CowByteArray("world"));
129151
TEST_ASSERT(CowByteArray("hello") != "world");
130152
TEST_ASSERT("hello" != CowByteArray("world"));
@@ -163,6 +185,10 @@ static void listMethods()
163185
a += CowByteArray("world");
164186
TEST_ASSERT_EQ(a.count(), 2);
165187

188+
// contains
189+
TEST_ASSERT(a.contains("world"));
190+
TEST_ASSERT(!a.contains("foo"));
191+
166192
// begin/end (const)
167193
CowByteArrayList::const_iterator cit = std::as_const(a).begin();
168194
TEST_ASSERT_EQ(*cit, "hello");

src/core/cowstringtest.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,17 @@ static void methods()
6363

6464
static void operators()
6565
{
66+
// operator=
6667
CowString a;
6768
a = CowString("hello");
6869
TEST_ASSERT_EQ(a, "hello");
6970

71+
// operator==
7072
TEST_ASSERT(CowString("hello") == CowString("hello"));
7173
TEST_ASSERT(CowString("hello") == "hello");
7274
TEST_ASSERT("hello" == CowString("hello"));
7375

76+
// operator!=
7477
TEST_ASSERT(CowString("hello") != CowString("world"));
7578
TEST_ASSERT(CowString("hello") != "world");
7679
TEST_ASSERT("hello" != CowString("world"));

src/core/httpheaders.cpp

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2012-2017 Fanout, Inc.
3+
* Copyright (C) 2025 Fastly, Inc.
34
*
45
* $FANOUT_BEGIN_LICENSE:APACHE2$
56
*
@@ -21,7 +22,7 @@
2122
#include "httpheaders.h"
2223

2324
// return position, end of string if not found, -1 on error
24-
static int findNonQuoted(const QByteArray &in, char c, int offset = 0)
25+
static int findNonQuoted(const CowByteArray &in, char c, int offset = 0)
2526
{
2627
bool inQuote = false;
2728

@@ -67,7 +68,7 @@ static int findNonQuoted(const QByteArray &in, char c, int offset = 0)
6768
}
6869

6970
// search for one of many chars
70-
static int findNext(const QByteArray &in, const char *charList, int offset = 0)
71+
static int findNext(const CowByteArray &in, const char *charList, int offset = 0)
7172
{
7273
int len = qstrlen(charList);
7374
for(int n = offset; n < in.size(); ++n)
@@ -83,9 +84,9 @@ static int findNext(const QByteArray &in, const char *charList, int offset = 0)
8384
return -1;
8485
}
8586

86-
static QList<QByteArray> headerSplit(const QByteArray &in)
87+
static CowByteArrayList headerSplit(const CowByteArray &in)
8788
{
88-
QList<QByteArray> parts;
89+
CowByteArrayList parts;
8990
int pos = 0;
9091
while(pos < in.size())
9192
{
@@ -109,7 +110,7 @@ static QList<QByteArray> headerSplit(const QByteArray &in)
109110
return parts;
110111
}
111112

112-
bool HttpHeaderParameters::contains(const QByteArray &key) const
113+
bool HttpHeaderParameters::contains(const CowByteArray &key) const
113114
{
114115
for(int n = 0; n < count(); ++n)
115116
{
@@ -120,7 +121,7 @@ bool HttpHeaderParameters::contains(const QByteArray &key) const
120121
return false;
121122
}
122123

123-
QByteArray HttpHeaderParameters::get(const QByteArray &key) const
124+
CowByteArray HttpHeaderParameters::get(const CowByteArray &key) const
124125
{
125126
for(int n = 0; n < count(); ++n)
126127
{
@@ -129,10 +130,10 @@ QByteArray HttpHeaderParameters::get(const QByteArray &key) const
129130
return h.second;
130131
}
131132

132-
return QByteArray();
133+
return CowByteArray();
133134
}
134135

135-
bool HttpHeaders::contains(const QByteArray &key) const
136+
bool HttpHeaders::contains(const CowByteArray &key) const
136137
{
137138
for(int n = 0; n < count(); ++n)
138139
{
@@ -143,7 +144,7 @@ bool HttpHeaders::contains(const QByteArray &key) const
143144
return false;
144145
}
145146

146-
QByteArray HttpHeaders::get(const QByteArray &key) const
147+
CowByteArray HttpHeaders::get(const CowByteArray &key) const
147148
{
148149
for(int n = 0; n < count(); ++n)
149150
{
@@ -152,30 +153,30 @@ QByteArray HttpHeaders::get(const QByteArray &key) const
152153
return h.second;
153154
}
154155

155-
return QByteArray();
156+
return CowByteArray();
156157
}
157158

158-
HttpHeaderParameters HttpHeaders::getAsParameters(const QByteArray &key, ParseMode mode) const
159+
HttpHeaderParameters HttpHeaders::getAsParameters(const CowByteArray &key, ParseMode mode) const
159160
{
160-
QByteArray h = get(key);
161+
CowByteArray h = get(key);
161162
if(h.isEmpty())
162163
return HttpHeaderParameters();
163164

164165
return parseParameters(h, mode);
165166
}
166167

167-
QByteArray HttpHeaders::getAsFirstParameter(const QByteArray &key) const
168+
CowByteArray HttpHeaders::getAsFirstParameter(const CowByteArray &key) const
168169
{
169170
HttpHeaderParameters p = getAsParameters(key);
170171
if(p.isEmpty())
171-
return QByteArray();
172+
return CowByteArray();
172173

173174
return p[0].first;
174175
}
175176

176-
QList<QByteArray> HttpHeaders::getAll(const QByteArray &key, bool split) const
177+
CowByteArrayList HttpHeaders::getAll(const CowByteArray &key, bool split) const
177178
{
178-
QList<QByteArray> out;
179+
CowByteArrayList out;
179180

180181
for(int n = 0; n < count(); ++n)
181182
{
@@ -192,11 +193,12 @@ QList<QByteArray> HttpHeaders::getAll(const QByteArray &key, bool split) const
192193
return out;
193194
}
194195

195-
QList<HttpHeaderParameters> HttpHeaders::getAllAsParameters(const QByteArray &key, ParseMode mode, bool split) const
196+
QList<HttpHeaderParameters> HttpHeaders::getAllAsParameters(const CowByteArray &key, ParseMode mode, bool split) const
196197
{
197198
QList<HttpHeaderParameters> out;
198199

199-
foreach(const QByteArray &h, getAll(key, split))
200+
CowByteArrayList l = getAll(key, split);
201+
for(CowByteArrayConstRef h : std::as_const(l))
200202
{
201203
bool ok;
202204
HttpHeaderParameters params = parseParameters(h, mode, &ok);
@@ -207,9 +209,9 @@ QList<HttpHeaderParameters> HttpHeaders::getAllAsParameters(const QByteArray &ke
207209
return out;
208210
}
209211

210-
QList<QByteArray> HttpHeaders::takeAll(const QByteArray &key, bool split)
212+
CowByteArrayList HttpHeaders::takeAll(const CowByteArray &key, bool split)
211213
{
212-
QList<QByteArray> out;
214+
CowByteArrayList out;
213215

214216
for(int n = 0; n < count(); ++n)
215217
{
@@ -229,7 +231,7 @@ QList<QByteArray> HttpHeaders::takeAll(const QByteArray &key, bool split)
229231
return out;
230232
}
231233

232-
void HttpHeaders::removeAll(const QByteArray &key)
234+
void HttpHeaders::removeAll(const CowByteArray &key)
233235
{
234236
for(int n = 0; n < count(); ++n)
235237
{
@@ -241,12 +243,12 @@ void HttpHeaders::removeAll(const QByteArray &key)
241243
}
242244
}
243245

244-
QByteArray HttpHeaders::join(const QList<QByteArray> &values)
246+
CowByteArray HttpHeaders::join(const CowByteArrayList &values)
245247
{
246-
QByteArray out;
248+
CowByteArray out;
247249

248250
bool first = true;
249-
foreach(const QByteArray &val, values)
251+
for(CowByteArrayConstRef val : std::as_const(values))
250252
{
251253
if(!first)
252254
out += ", ";
@@ -258,7 +260,7 @@ QByteArray HttpHeaders::join(const QList<QByteArray> &values)
258260
return out;
259261
}
260262

261-
HttpHeaderParameters HttpHeaders::parseParameters(const QByteArray &in, ParseMode mode, bool *ok)
263+
HttpHeaderParameters HttpHeaders::parseParameters(const CowByteArray &in, ParseMode mode, bool *ok)
262264
{
263265
HttpHeaderParameters out;
264266

@@ -268,20 +270,20 @@ HttpHeaderParameters HttpHeaders::parseParameters(const QByteArray &in, ParseMod
268270
int at = in.indexOf(';');
269271
if(at != -1)
270272
{
271-
out += HttpHeaderParameter(in.mid(0, at).trimmed(), QByteArray());
273+
out += HttpHeaderParameter(in.mid(0, at).trimmed(), CowByteArray());
272274
start = at + 1;
273275
}
274276
else
275277
{
276-
out += HttpHeaderParameter(in.trimmed(), QByteArray());
278+
out += HttpHeaderParameter(in.trimmed(), CowByteArray());
277279
start = in.size();
278280
}
279281
}
280282

281283
while(start < in.size())
282284
{
283-
QByteArray var;
284-
QByteArray val;
285+
CowByteArray var;
286+
CowByteArray val;
285287

286288
int at = findNext(in, "=;", start);
287289
if(at != -1)

0 commit comments

Comments
 (0)