1a8003a70SNiels Sascha Reedijk /*
2a8003a70SNiels Sascha Reedijk * Copyright 2022 Haiku Inc. All rights reserved.
3a8003a70SNiels Sascha Reedijk * Distributed under the terms of the MIT License.
4a8003a70SNiels Sascha Reedijk *
5a8003a70SNiels Sascha Reedijk * Authors:
6a8003a70SNiels Sascha Reedijk * Niels Sascha Reedijk, niels.reedijk@gmail.com
7a8003a70SNiels Sascha Reedijk */
8a8003a70SNiels Sascha Reedijk
9a8003a70SNiels Sascha Reedijk #include <HttpFields.h>
10a8003a70SNiels Sascha Reedijk
11a8003a70SNiels Sascha Reedijk #include <algorithm>
12a8003a70SNiels Sascha Reedijk #include <ctype.h>
13a8003a70SNiels Sascha Reedijk #include <utility>
14a8003a70SNiels Sascha Reedijk
15cb67e348SNiels Sascha Reedijk #include "HttpPrivate.h"
16cb67e348SNiels Sascha Reedijk
17a8003a70SNiels Sascha Reedijk using namespace BPrivate::Network;
18a8003a70SNiels Sascha Reedijk
19a8003a70SNiels Sascha Reedijk
20a8003a70SNiels Sascha Reedijk // #pragma mark -- utilities
21a8003a70SNiels Sascha Reedijk
22a8003a70SNiels Sascha Reedijk
23a8003a70SNiels Sascha Reedijk /*!
24a8003a70SNiels Sascha Reedijk \brief Validate whether the string is a valid HTTP header value
25a8003a70SNiels Sascha Reedijk
26a8003a70SNiels Sascha Reedijk RFC 7230 section 3.2.6 determines that valid tokens for the header are:
27a8003a70SNiels Sascha Reedijk HTAB ('\t'), SP (32), all visible ASCII characters (33-126), and all characters that
28a8003a70SNiels Sascha Reedijk not control characters (in the case of a char, any value < 0)
29a8003a70SNiels Sascha Reedijk
30a8003a70SNiels Sascha Reedijk \note When printing out the HTTP header, sometimes the string needs to be quoted and some
31a8003a70SNiels Sascha Reedijk characters need to be escaped. This function is not checking for whether the string can
32a8003a70SNiels Sascha Reedijk be transmitted as is.
33a8003a70SNiels Sascha Reedijk
34a8003a70SNiels Sascha Reedijk \returns \c true if the string is valid, or \c false if it is not.
35a8003a70SNiels Sascha Reedijk */
36a8003a70SNiels Sascha Reedijk static inline bool
validate_value_string(const std::string_view & string)37a8003a70SNiels Sascha Reedijk validate_value_string(const std::string_view& string)
38a8003a70SNiels Sascha Reedijk {
39a8003a70SNiels Sascha Reedijk for (auto it = string.cbegin(); it < string.cend(); it++) {
40a8003a70SNiels Sascha Reedijk if ((*it >= 0 && *it < 32) || *it == 127 || *it == '\t')
41a8003a70SNiels Sascha Reedijk return false;
42a8003a70SNiels Sascha Reedijk }
43a8003a70SNiels Sascha Reedijk return true;
44a8003a70SNiels Sascha Reedijk }
45a8003a70SNiels Sascha Reedijk
46a8003a70SNiels Sascha Reedijk
478ccf8fb4SNiels Sascha Reedijk /*!
48a8003a70SNiels Sascha Reedijk \brief Case insensitively compare two string_views.
49a8003a70SNiels Sascha Reedijk
50a8003a70SNiels Sascha Reedijk Inspired by https://stackoverflow.com/a/4119881
51a8003a70SNiels Sascha Reedijk */
52a8003a70SNiels Sascha Reedijk static inline bool
iequals(const std::string_view & a,const std::string_view & b)53a8003a70SNiels Sascha Reedijk iequals(const std::string_view& a, const std::string_view& b)
54a8003a70SNiels Sascha Reedijk {
55*71e29bbeSNiels Sascha Reedijk return std::equal(a.begin(), a.end(), b.begin(), b.end(),
56*71e29bbeSNiels Sascha Reedijk [](char a, char b) { return tolower(a) == tolower(b); });
57a8003a70SNiels Sascha Reedijk }
58a8003a70SNiels Sascha Reedijk
59a8003a70SNiels Sascha Reedijk
608ccf8fb4SNiels Sascha Reedijk /*!
618ccf8fb4SNiels Sascha Reedijk \brief Trim whitespace from the beginning and end of a string_view
628ccf8fb4SNiels Sascha Reedijk
638ccf8fb4SNiels Sascha Reedijk Inspired by:
648ccf8fb4SNiels Sascha Reedijk https://terrislinenbach.medium.com/trimming-whitespace-from-a-string-view-6795e18b108f
658ccf8fb4SNiels Sascha Reedijk */
668ccf8fb4SNiels Sascha Reedijk static inline std::string_view
trim(std::string_view in)678ccf8fb4SNiels Sascha Reedijk trim(std::string_view in)
688ccf8fb4SNiels Sascha Reedijk {
698ccf8fb4SNiels Sascha Reedijk auto left = in.begin();
708ccf8fb4SNiels Sascha Reedijk for (;; ++left) {
718ccf8fb4SNiels Sascha Reedijk if (left == in.end())
728ccf8fb4SNiels Sascha Reedijk return std::string_view();
738ccf8fb4SNiels Sascha Reedijk if (!isspace(*left))
748ccf8fb4SNiels Sascha Reedijk break;
758ccf8fb4SNiels Sascha Reedijk }
768ccf8fb4SNiels Sascha Reedijk
778ccf8fb4SNiels Sascha Reedijk auto right = in.end() - 1;
78*71e29bbeSNiels Sascha Reedijk for (; right > left && isspace(*right); --right)
79*71e29bbeSNiels Sascha Reedijk ;
808ccf8fb4SNiels Sascha Reedijk
818ccf8fb4SNiels Sascha Reedijk return std::string_view(left, std::distance(left, right) + 1);
828ccf8fb4SNiels Sascha Reedijk }
838ccf8fb4SNiels Sascha Reedijk
848ccf8fb4SNiels Sascha Reedijk
85a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields::InvalidHeader
86a8003a70SNiels Sascha Reedijk
87a8003a70SNiels Sascha Reedijk
InvalidInput(const char * origin,BString input)88a8003a70SNiels Sascha Reedijk BHttpFields::InvalidInput::InvalidInput(const char* origin, BString input)
89a8003a70SNiels Sascha Reedijk :
90a8003a70SNiels Sascha Reedijk BError(origin),
91a8003a70SNiels Sascha Reedijk input(std::move(input))
92a8003a70SNiels Sascha Reedijk {
93a8003a70SNiels Sascha Reedijk }
94a8003a70SNiels Sascha Reedijk
95a8003a70SNiels Sascha Reedijk
96a8003a70SNiels Sascha Reedijk const char*
Message() const97a8003a70SNiels Sascha Reedijk BHttpFields::InvalidInput::Message() const noexcept
98a8003a70SNiels Sascha Reedijk {
99a8003a70SNiels Sascha Reedijk return "Invalid format or unsupported characters in input";
100a8003a70SNiels Sascha Reedijk }
101a8003a70SNiels Sascha Reedijk
102a8003a70SNiels Sascha Reedijk
103a8003a70SNiels Sascha Reedijk BString
DebugMessage() const104a8003a70SNiels Sascha Reedijk BHttpFields::InvalidInput::DebugMessage() const
105a8003a70SNiels Sascha Reedijk {
106a8003a70SNiels Sascha Reedijk BString output = BError::DebugMessage();
107a8003a70SNiels Sascha Reedijk output << "\t " << input << "\n";
108a8003a70SNiels Sascha Reedijk return output;
109a8003a70SNiels Sascha Reedijk }
110a8003a70SNiels Sascha Reedijk
111a8003a70SNiels Sascha Reedijk
112a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields::Name
113a8003a70SNiels Sascha Reedijk
114a8003a70SNiels Sascha Reedijk
FieldName()1158ccf8fb4SNiels Sascha Reedijk BHttpFields::FieldName::FieldName() noexcept
116*71e29bbeSNiels Sascha Reedijk :
117*71e29bbeSNiels Sascha Reedijk fName(std::string_view())
1188ccf8fb4SNiels Sascha Reedijk {
1198ccf8fb4SNiels Sascha Reedijk }
1208ccf8fb4SNiels Sascha Reedijk
1218ccf8fb4SNiels Sascha Reedijk
FieldName(const std::string_view & name)1228ccf8fb4SNiels Sascha Reedijk BHttpFields::FieldName::FieldName(const std::string_view& name) noexcept
123*71e29bbeSNiels Sascha Reedijk :
124*71e29bbeSNiels Sascha Reedijk fName(name)
125a8003a70SNiels Sascha Reedijk {
126a8003a70SNiels Sascha Reedijk }
127a8003a70SNiels Sascha Reedijk
128a8003a70SNiels Sascha Reedijk
129a8003a70SNiels Sascha Reedijk /*!
1308ccf8fb4SNiels Sascha Reedijk \brief Copy constructor;
131a8003a70SNiels Sascha Reedijk */
1328ccf8fb4SNiels Sascha Reedijk BHttpFields::FieldName::FieldName(const FieldName& other) noexcept = default;
133a8003a70SNiels Sascha Reedijk
134a8003a70SNiels Sascha Reedijk
135a8003a70SNiels Sascha Reedijk /*!
136a8003a70SNiels Sascha Reedijk \brief Move constructor
137a8003a70SNiels Sascha Reedijk
138a8003a70SNiels Sascha Reedijk Moving leaves the other object in the empty state. It is implemented to satisfy the internal
139a8003a70SNiels Sascha Reedijk requirements of BHttpFields and std::list<Field>. Once an object is moved from it must no
140a8003a70SNiels Sascha Reedijk longer be used as an entry in a BHttpFields object.
141a8003a70SNiels Sascha Reedijk */
FieldName(FieldName && other)142a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::FieldName(FieldName&& other) noexcept
143*71e29bbeSNiels Sascha Reedijk :
144*71e29bbeSNiels Sascha Reedijk fName(std::move(other.fName))
145a8003a70SNiels Sascha Reedijk {
146a8003a70SNiels Sascha Reedijk other.fName = std::string_view();
147a8003a70SNiels Sascha Reedijk }
148a8003a70SNiels Sascha Reedijk
149a8003a70SNiels Sascha Reedijk
150a8003a70SNiels Sascha Reedijk /*!
1518ccf8fb4SNiels Sascha Reedijk \brief Copy assignment;
152a8003a70SNiels Sascha Reedijk */
153*71e29bbeSNiels Sascha Reedijk BHttpFields::FieldName& BHttpFields::FieldName::operator=(
154*71e29bbeSNiels Sascha Reedijk const BHttpFields::FieldName& other) noexcept = default;
155a8003a70SNiels Sascha Reedijk
156a8003a70SNiels Sascha Reedijk
157a8003a70SNiels Sascha Reedijk /*!
158a8003a70SNiels Sascha Reedijk \brief Move assignment
159a8003a70SNiels Sascha Reedijk
160a8003a70SNiels Sascha Reedijk Moving leaves the other object in the empty state. It is implemented to satisfy the internal
161a8003a70SNiels Sascha Reedijk requirements of BHttpFields and std::list<Field>. Once an object is moved from it must no
162a8003a70SNiels Sascha Reedijk longer be used as an entry in a BHttpFields object.
163a8003a70SNiels Sascha Reedijk */
164a8003a70SNiels Sascha Reedijk BHttpFields::FieldName&
operator =(BHttpFields::FieldName && other)165a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator=(BHttpFields::FieldName&& other) noexcept
166a8003a70SNiels Sascha Reedijk {
167a8003a70SNiels Sascha Reedijk fName = std::move(other.fName);
168a8003a70SNiels Sascha Reedijk other.fName = std::string_view();
169a8003a70SNiels Sascha Reedijk return *this;
170a8003a70SNiels Sascha Reedijk }
171a8003a70SNiels Sascha Reedijk
172a8003a70SNiels Sascha Reedijk
173a8003a70SNiels Sascha Reedijk bool
operator ==(const BString & other) const174a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator==(const BString& other) const noexcept
175a8003a70SNiels Sascha Reedijk {
1768ccf8fb4SNiels Sascha Reedijk return iequals(fName, std::string_view(other.String()));
177a8003a70SNiels Sascha Reedijk }
178a8003a70SNiels Sascha Reedijk
179a8003a70SNiels Sascha Reedijk
180a8003a70SNiels Sascha Reedijk bool
operator ==(const std::string_view & other) const181a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator==(const std::string_view& other) const noexcept
182a8003a70SNiels Sascha Reedijk {
1838ccf8fb4SNiels Sascha Reedijk return iequals(fName, other);
184a8003a70SNiels Sascha Reedijk }
185a8003a70SNiels Sascha Reedijk
186a8003a70SNiels Sascha Reedijk
187a8003a70SNiels Sascha Reedijk bool
operator ==(const BHttpFields::FieldName & other) const188a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator==(const BHttpFields::FieldName& other) const noexcept
189a8003a70SNiels Sascha Reedijk {
1908ccf8fb4SNiels Sascha Reedijk return iequals(fName, other.fName);
191a8003a70SNiels Sascha Reedijk }
192a8003a70SNiels Sascha Reedijk
193a8003a70SNiels Sascha Reedijk
operator std::string_view() const194a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator std::string_view() const
195a8003a70SNiels Sascha Reedijk {
1968ccf8fb4SNiels Sascha Reedijk return fName;
197a8003a70SNiels Sascha Reedijk }
198a8003a70SNiels Sascha Reedijk
199a8003a70SNiels Sascha Reedijk
200a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields::Field
201a8003a70SNiels Sascha Reedijk
202a8003a70SNiels Sascha Reedijk
Field()203a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field() noexcept
204*71e29bbeSNiels Sascha Reedijk :
205*71e29bbeSNiels Sascha Reedijk fName(std::string_view()),
206*71e29bbeSNiels Sascha Reedijk fValue(std::string_view())
207a8003a70SNiels Sascha Reedijk {
208a8003a70SNiels Sascha Reedijk }
209a8003a70SNiels Sascha Reedijk
210a8003a70SNiels Sascha Reedijk
Field(const std::string_view & name,const std::string_view & value)211a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field(const std::string_view& name, const std::string_view& value)
212a8003a70SNiels Sascha Reedijk {
213cb67e348SNiels Sascha Reedijk if (name.length() == 0 || !validate_http_token_string(name))
2148ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(name.data(), name.size()));
215a8003a70SNiels Sascha Reedijk if (value.length() == 0 || !validate_value_string(value))
216a8003a70SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(value.data(), value.length()));
217a8003a70SNiels Sascha Reedijk
2188ccf8fb4SNiels Sascha Reedijk BString rawField(name.data(), name.size());
2198ccf8fb4SNiels Sascha Reedijk rawField << ": ";
2208ccf8fb4SNiels Sascha Reedijk rawField.Append(value.data(), value.size());
2218ccf8fb4SNiels Sascha Reedijk
2228ccf8fb4SNiels Sascha Reedijk fName = std::string_view(rawField.String(), name.size());
2238ccf8fb4SNiels Sascha Reedijk fValue = std::string_view(rawField.String() + name.size() + 2, value.size());
2248ccf8fb4SNiels Sascha Reedijk fRawField = std::move(rawField);
225a8003a70SNiels Sascha Reedijk }
2268ccf8fb4SNiels Sascha Reedijk
2278ccf8fb4SNiels Sascha Reedijk
Field(BString & field)2288ccf8fb4SNiels Sascha Reedijk BHttpFields::Field::Field(BString& field)
2298ccf8fb4SNiels Sascha Reedijk {
2308ccf8fb4SNiels Sascha Reedijk // Check if the input contains a key, a separator and a value.
2318ccf8fb4SNiels Sascha Reedijk auto separatorIndex = field.FindFirst(':');
2328ccf8fb4SNiels Sascha Reedijk if (separatorIndex <= 0)
2338ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, field);
2348ccf8fb4SNiels Sascha Reedijk
2358ccf8fb4SNiels Sascha Reedijk // Get the name and the value. Remove whitespace around the value.
2368ccf8fb4SNiels Sascha Reedijk auto name = std::string_view(field.String(), separatorIndex);
2378ccf8fb4SNiels Sascha Reedijk auto value = trim(std::string_view(field.String() + separatorIndex + 1));
2388ccf8fb4SNiels Sascha Reedijk
2398ccf8fb4SNiels Sascha Reedijk if (name.length() == 0 || !validate_http_token_string(name))
2408ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(name.data(), name.size()));
2418ccf8fb4SNiels Sascha Reedijk if (value.length() == 0 || !validate_value_string(value))
2428ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(value.data(), value.length()));
2438ccf8fb4SNiels Sascha Reedijk
2448ccf8fb4SNiels Sascha Reedijk fRawField = std::move(field);
2458ccf8fb4SNiels Sascha Reedijk fName = name;
2468ccf8fb4SNiels Sascha Reedijk fValue = value;
247a8003a70SNiels Sascha Reedijk }
248a8003a70SNiels Sascha Reedijk
249a8003a70SNiels Sascha Reedijk
Field(const BHttpFields::Field & other)250a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field(const BHttpFields::Field& other)
251*71e29bbeSNiels Sascha Reedijk :
252*71e29bbeSNiels Sascha Reedijk fName(std::string_view()),
253*71e29bbeSNiels Sascha Reedijk fValue(std::string_view())
254a8003a70SNiels Sascha Reedijk {
2558ccf8fb4SNiels Sascha Reedijk if (other.IsEmpty()) {
2568ccf8fb4SNiels Sascha Reedijk fRawField = BString();
2578ccf8fb4SNiels Sascha Reedijk fName = std::string_view();
2588ccf8fb4SNiels Sascha Reedijk fValue = std::string_view();
2598ccf8fb4SNiels Sascha Reedijk } else {
2608ccf8fb4SNiels Sascha Reedijk fRawField = other.fRawField;
2618ccf8fb4SNiels Sascha Reedijk auto nameSize = other.Name().fName.size();
2628ccf8fb4SNiels Sascha Reedijk auto valueOffset = other.fValue.data() - other.fRawField.value().String();
2638ccf8fb4SNiels Sascha Reedijk fName = std::string_view((*fRawField).String(), nameSize);
2648ccf8fb4SNiels Sascha Reedijk fValue = std::string_view((*fRawField).String() + valueOffset, other.fValue.size());
265a8003a70SNiels Sascha Reedijk }
266a8003a70SNiels Sascha Reedijk }
267a8003a70SNiels Sascha Reedijk
268a8003a70SNiels Sascha Reedijk
Field(BHttpFields::Field && other)269a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field(BHttpFields::Field&& other) noexcept
270*71e29bbeSNiels Sascha Reedijk :
271*71e29bbeSNiels Sascha Reedijk fRawField(std::move(other.fRawField)),
272*71e29bbeSNiels Sascha Reedijk fName(std::move(other.fName)),
273*71e29bbeSNiels Sascha Reedijk fValue(std::move(other.fValue))
274a8003a70SNiels Sascha Reedijk {
275a8003a70SNiels Sascha Reedijk other.fName.fName = std::string_view();
276a8003a70SNiels Sascha Reedijk other.fValue = std::string_view();
277a8003a70SNiels Sascha Reedijk }
278a8003a70SNiels Sascha Reedijk
279a8003a70SNiels Sascha Reedijk
280a8003a70SNiels Sascha Reedijk BHttpFields::Field&
operator =(const BHttpFields::Field & other)281a8003a70SNiels Sascha Reedijk BHttpFields::Field::operator=(const BHttpFields::Field& other)
282a8003a70SNiels Sascha Reedijk {
283a8003a70SNiels Sascha Reedijk if (other.IsEmpty()) {
2848ccf8fb4SNiels Sascha Reedijk fRawField = BString();
285a8003a70SNiels Sascha Reedijk fName = std::string_view();
286a8003a70SNiels Sascha Reedijk fValue = std::string_view();
287a8003a70SNiels Sascha Reedijk } else {
2888ccf8fb4SNiels Sascha Reedijk fRawField = other.fRawField;
2898ccf8fb4SNiels Sascha Reedijk auto nameSize = other.Name().fName.size();
2908ccf8fb4SNiels Sascha Reedijk auto valueOffset = other.fValue.data() - other.fRawField.value().String();
2918ccf8fb4SNiels Sascha Reedijk fName = std::string_view((*fRawField).String(), nameSize);
2928ccf8fb4SNiels Sascha Reedijk fValue = std::string_view((*fRawField).String() + valueOffset, other.fValue.size());
293a8003a70SNiels Sascha Reedijk }
294a8003a70SNiels Sascha Reedijk return *this;
295a8003a70SNiels Sascha Reedijk }
296a8003a70SNiels Sascha Reedijk
297a8003a70SNiels Sascha Reedijk
298a8003a70SNiels Sascha Reedijk BHttpFields::Field&
operator =(BHttpFields::Field && other)299a8003a70SNiels Sascha Reedijk BHttpFields::Field::operator=(BHttpFields::Field&& other) noexcept
300a8003a70SNiels Sascha Reedijk {
3018ccf8fb4SNiels Sascha Reedijk fRawField = std::move(other.fRawField);
302a8003a70SNiels Sascha Reedijk fName = std::move(other.fName);
303a8003a70SNiels Sascha Reedijk other.fName.fName = std::string_view();
304a8003a70SNiels Sascha Reedijk fValue = std::move(other.fValue);
305a8003a70SNiels Sascha Reedijk fValue = std::string_view();
306a8003a70SNiels Sascha Reedijk return *this;
307a8003a70SNiels Sascha Reedijk }
308a8003a70SNiels Sascha Reedijk
309a8003a70SNiels Sascha Reedijk
310a8003a70SNiels Sascha Reedijk const BHttpFields::FieldName&
Name() const311a8003a70SNiels Sascha Reedijk BHttpFields::Field::Name() const noexcept
312a8003a70SNiels Sascha Reedijk {
313a8003a70SNiels Sascha Reedijk return fName;
314a8003a70SNiels Sascha Reedijk }
315a8003a70SNiels Sascha Reedijk
316a8003a70SNiels Sascha Reedijk
317a8003a70SNiels Sascha Reedijk std::string_view
Value() const318a8003a70SNiels Sascha Reedijk BHttpFields::Field::Value() const noexcept
319a8003a70SNiels Sascha Reedijk {
3208ccf8fb4SNiels Sascha Reedijk return fValue;
321a8003a70SNiels Sascha Reedijk }
3228ccf8fb4SNiels Sascha Reedijk
3238ccf8fb4SNiels Sascha Reedijk
3248ccf8fb4SNiels Sascha Reedijk std::string_view
RawField() const3258ccf8fb4SNiels Sascha Reedijk BHttpFields::Field::RawField() const noexcept
3268ccf8fb4SNiels Sascha Reedijk {
3278ccf8fb4SNiels Sascha Reedijk if (fRawField)
3288ccf8fb4SNiels Sascha Reedijk return std::string_view((*fRawField).String(), (*fRawField).Length());
3298ccf8fb4SNiels Sascha Reedijk else
3308ccf8fb4SNiels Sascha Reedijk return std::string_view();
331a8003a70SNiels Sascha Reedijk }
332a8003a70SNiels Sascha Reedijk
333a8003a70SNiels Sascha Reedijk
334a8003a70SNiels Sascha Reedijk bool
IsEmpty() const335a8003a70SNiels Sascha Reedijk BHttpFields::Field::IsEmpty() const noexcept
336a8003a70SNiels Sascha Reedijk {
337a8003a70SNiels Sascha Reedijk // The object is either fully empty, or it has data, so we only have to check fValue.
3388ccf8fb4SNiels Sascha Reedijk return !fRawField.has_value();
339a8003a70SNiels Sascha Reedijk }
340a8003a70SNiels Sascha Reedijk
341a8003a70SNiels Sascha Reedijk
342a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields
343a8003a70SNiels Sascha Reedijk
344a8003a70SNiels Sascha Reedijk
BHttpFields()345a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields()
346a8003a70SNiels Sascha Reedijk {
347a8003a70SNiels Sascha Reedijk }
348a8003a70SNiels Sascha Reedijk
349a8003a70SNiels Sascha Reedijk
BHttpFields(std::initializer_list<BHttpFields::Field> fields)350a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields(std::initializer_list<BHttpFields::Field> fields)
351a8003a70SNiels Sascha Reedijk {
3528ccf8fb4SNiels Sascha Reedijk AddFields(fields);
353a8003a70SNiels Sascha Reedijk }
354a8003a70SNiels Sascha Reedijk
355a8003a70SNiels Sascha Reedijk
356a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields(const BHttpFields& other) = default;
357a8003a70SNiels Sascha Reedijk
358a8003a70SNiels Sascha Reedijk
BHttpFields(BHttpFields && other)359a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields(BHttpFields&& other)
360*71e29bbeSNiels Sascha Reedijk :
361*71e29bbeSNiels Sascha Reedijk fFields(std::move(other.fFields))
362a8003a70SNiels Sascha Reedijk {
363a8003a70SNiels Sascha Reedijk // Explicitly clear the other list, as the C++ standard does not specify that the other list
364a8003a70SNiels Sascha Reedijk // will be empty.
365a8003a70SNiels Sascha Reedijk other.fFields.clear();
366a8003a70SNiels Sascha Reedijk }
367a8003a70SNiels Sascha Reedijk
368a8003a70SNiels Sascha Reedijk
~BHttpFields()369a8003a70SNiels Sascha Reedijk BHttpFields::~BHttpFields() noexcept
370a8003a70SNiels Sascha Reedijk {
371a8003a70SNiels Sascha Reedijk }
372a8003a70SNiels Sascha Reedijk
373a8003a70SNiels Sascha Reedijk
374*71e29bbeSNiels Sascha Reedijk BHttpFields& BHttpFields::operator=(const BHttpFields& other) = default;
375a8003a70SNiels Sascha Reedijk
376a8003a70SNiels Sascha Reedijk
377a8003a70SNiels Sascha Reedijk BHttpFields&
operator =(BHttpFields && other)378a8003a70SNiels Sascha Reedijk BHttpFields::operator=(BHttpFields&& other) noexcept
379a8003a70SNiels Sascha Reedijk {
380a8003a70SNiels Sascha Reedijk fFields = std::move(other.fFields);
381a8003a70SNiels Sascha Reedijk
382a8003a70SNiels Sascha Reedijk // Explicitly clear the other list, as the C++ standard does not specify that the other list
383a8003a70SNiels Sascha Reedijk // will be empty.
384a8003a70SNiels Sascha Reedijk other.fFields.clear();
385a8003a70SNiels Sascha Reedijk return *this;
386a8003a70SNiels Sascha Reedijk }
387a8003a70SNiels Sascha Reedijk
388a8003a70SNiels Sascha Reedijk
389a8003a70SNiels Sascha Reedijk const BHttpFields::Field&
operator [](size_t index) const390a8003a70SNiels Sascha Reedijk BHttpFields::operator[](size_t index) const
391a8003a70SNiels Sascha Reedijk {
392a8003a70SNiels Sascha Reedijk if (index >= fFields.size())
393a8003a70SNiels Sascha Reedijk throw BRuntimeError(__PRETTY_FUNCTION__, "Index out of bounds");
394a8003a70SNiels Sascha Reedijk auto it = fFields.cbegin();
395a8003a70SNiels Sascha Reedijk std::advance(it, index);
396a8003a70SNiels Sascha Reedijk return *it;
397a8003a70SNiels Sascha Reedijk }
398a8003a70SNiels Sascha Reedijk
399a8003a70SNiels Sascha Reedijk
400a8003a70SNiels Sascha Reedijk void
AddField(const std::string_view & name,const std::string_view & value)401a8003a70SNiels Sascha Reedijk BHttpFields::AddField(const std::string_view& name, const std::string_view& value)
402a8003a70SNiels Sascha Reedijk {
4038ccf8fb4SNiels Sascha Reedijk fFields.emplace_back(name, value);
4048ccf8fb4SNiels Sascha Reedijk }
4058ccf8fb4SNiels Sascha Reedijk
4068ccf8fb4SNiels Sascha Reedijk
4078ccf8fb4SNiels Sascha Reedijk void
AddField(BString & field)4088ccf8fb4SNiels Sascha Reedijk BHttpFields::AddField(BString& field)
4098ccf8fb4SNiels Sascha Reedijk {
4108ccf8fb4SNiels Sascha Reedijk fFields.emplace_back(field);
411a8003a70SNiels Sascha Reedijk }
412a8003a70SNiels Sascha Reedijk
413a8003a70SNiels Sascha Reedijk
414a8003a70SNiels Sascha Reedijk void
AddFields(std::initializer_list<Field> fields)415d9a4c607SNiels Sascha Reedijk BHttpFields::AddFields(std::initializer_list<Field> fields)
416d9a4c607SNiels Sascha Reedijk {
417d9a4c607SNiels Sascha Reedijk for (auto& field: fields) {
418d9a4c607SNiels Sascha Reedijk if (!field.IsEmpty())
4198ccf8fb4SNiels Sascha Reedijk fFields.push_back(std::move(field));
420d9a4c607SNiels Sascha Reedijk }
421d9a4c607SNiels Sascha Reedijk }
422d9a4c607SNiels Sascha Reedijk
423d9a4c607SNiels Sascha Reedijk
424d9a4c607SNiels Sascha Reedijk void
RemoveField(const std::string_view & name)425a8003a70SNiels Sascha Reedijk BHttpFields::RemoveField(const std::string_view& name) noexcept
426a8003a70SNiels Sascha Reedijk {
427a8003a70SNiels Sascha Reedijk for (auto it = FindField(name); it != end(); it = FindField(name)) {
428a8003a70SNiels Sascha Reedijk fFields.erase(it);
429a8003a70SNiels Sascha Reedijk }
430a8003a70SNiels Sascha Reedijk }
431a8003a70SNiels Sascha Reedijk
432a8003a70SNiels Sascha Reedijk
433a8003a70SNiels Sascha Reedijk void
RemoveField(ConstIterator it)434a8003a70SNiels Sascha Reedijk BHttpFields::RemoveField(ConstIterator it) noexcept
435a8003a70SNiels Sascha Reedijk {
436a8003a70SNiels Sascha Reedijk fFields.erase(it);
437a8003a70SNiels Sascha Reedijk }
438a8003a70SNiels Sascha Reedijk
439a8003a70SNiels Sascha Reedijk
440a8003a70SNiels Sascha Reedijk void
MakeEmpty()441a8003a70SNiels Sascha Reedijk BHttpFields::MakeEmpty() noexcept
442a8003a70SNiels Sascha Reedijk {
443a8003a70SNiels Sascha Reedijk fFields.clear();
444a8003a70SNiels Sascha Reedijk }
445a8003a70SNiels Sascha Reedijk
446a8003a70SNiels Sascha Reedijk
447a8003a70SNiels Sascha Reedijk BHttpFields::ConstIterator
FindField(const std::string_view & name) const448a8003a70SNiels Sascha Reedijk BHttpFields::FindField(const std::string_view& name) const noexcept
449a8003a70SNiels Sascha Reedijk {
450a8003a70SNiels Sascha Reedijk for (auto it = fFields.cbegin(); it != fFields.cend(); it++) {
451a8003a70SNiels Sascha Reedijk if ((*it).Name() == name)
452a8003a70SNiels Sascha Reedijk return it;
453a8003a70SNiels Sascha Reedijk }
454a8003a70SNiels Sascha Reedijk return fFields.cend();
455a8003a70SNiels Sascha Reedijk }
456a8003a70SNiels Sascha Reedijk
457a8003a70SNiels Sascha Reedijk
458a8003a70SNiels Sascha Reedijk size_t
CountFields() const459a8003a70SNiels Sascha Reedijk BHttpFields::CountFields() const noexcept
460a8003a70SNiels Sascha Reedijk {
461a8003a70SNiels Sascha Reedijk return fFields.size();
462a8003a70SNiels Sascha Reedijk }
463a8003a70SNiels Sascha Reedijk
464a8003a70SNiels Sascha Reedijk
4657b1d966cSNiels Sascha Reedijk size_t
CountFields(const std::string_view & name) const4667b1d966cSNiels Sascha Reedijk BHttpFields::CountFields(const std::string_view& name) const noexcept
4677b1d966cSNiels Sascha Reedijk {
4687b1d966cSNiels Sascha Reedijk size_t count = 0;
4697b1d966cSNiels Sascha Reedijk for (auto it = fFields.cbegin(); it != fFields.cend(); it++) {
4707b1d966cSNiels Sascha Reedijk if ((*it).Name() == name)
4717b1d966cSNiels Sascha Reedijk count += 1;
4727b1d966cSNiels Sascha Reedijk }
4737b1d966cSNiels Sascha Reedijk return count;
4747b1d966cSNiels Sascha Reedijk }
4757b1d966cSNiels Sascha Reedijk
4767b1d966cSNiels Sascha Reedijk
477a8003a70SNiels Sascha Reedijk BHttpFields::ConstIterator
begin() const478a8003a70SNiels Sascha Reedijk BHttpFields::begin() const noexcept
479a8003a70SNiels Sascha Reedijk {
480a8003a70SNiels Sascha Reedijk return fFields.cbegin();
481a8003a70SNiels Sascha Reedijk }
482a8003a70SNiels Sascha Reedijk
483a8003a70SNiels Sascha Reedijk
484a8003a70SNiels Sascha Reedijk BHttpFields::ConstIterator
end() const485a8003a70SNiels Sascha Reedijk BHttpFields::end() const noexcept
486a8003a70SNiels Sascha Reedijk {
487a8003a70SNiels Sascha Reedijk return fFields.cend();
488a8003a70SNiels Sascha Reedijk }
489