xrpld
Loading...
Searching...
No Matches
rfc2616.h
1#pragma once
2
3#include <boost/beast/http/message.hpp>
4#include <boost/beast/http/rfc7230.hpp>
5#include <boost/range/algorithm/equal.hpp>
6#include <boost/range/iterator_range.hpp>
7#include <boost/utility/string_ref.hpp>
8
9#include <algorithm>
10#include <cctype>
11#include <cstddef>
12#include <iterator>
13#include <string>
14#include <vector>
15
16namespace beast::rfc2616 {
17
18namespace detail {
19
21{
22 explicit CiEqualPred() = default;
23
24 bool
25 operator()(char c1, char c2)
26 {
27 // VFALCO TODO Use a table lookup here
28 return std::tolower(static_cast<unsigned char>(c1)) ==
29 std::tolower(static_cast<unsigned char>(c2));
30 }
31};
32
38inline bool
39isLws(char c)
40{
41 return c == ' ' || c == '\t';
42}
43
47inline bool
48isWhite(char c)
49{
50 switch (c)
51 {
52 case ' ':
53 case '\f':
54 case '\n':
55 case '\r':
56 case '\t':
57 case '\v':
58 return true;
59 default:
60 return false;
61 };
62}
63
64template <class FwdIter>
65FwdIter
66trimRight(FwdIter first, FwdIter last)
67{
68 if (first == last)
69 return last;
70 do
71 {
72 --last;
73 if (!isWhite(*last))
74 return ++last;
75 } while (last != first);
76 return first;
77}
78
79template <class String>
80String
81trimRight(String const& s)
82{
83 using std::begin;
84 using std::end;
85 auto first(begin(s));
86 auto last(end(s));
87 last = trimRight(first, last);
88 return {first, last};
89}
90
91} // namespace detail
92
102template <
103 class FwdIt,
105 class Char>
106Result
107split(FwdIt first, FwdIt last, Char delim)
108{
109 using namespace detail;
110 using string = Result::value_type;
111
112 Result result;
113
114 FwdIt iter = first;
115 string e;
116 while (iter != last)
117 {
118 if (*iter == '"')
119 {
120 // quoted-string
121 ++iter;
122 while (iter != last)
123 {
124 if (*iter == '"')
125 {
126 ++iter;
127 break;
128 }
129
130 if (*iter == '\\')
131 {
132 // quoted-pair
133 ++iter;
134 if (iter != last)
135 e.append(1, *iter++);
136 }
137 else
138 {
139 // qdtext
140 e.append(1, *iter++);
141 }
142 }
143 if (!e.empty())
144 {
145 result.emplace_back(std::move(e));
146 e.clear();
147 }
148 }
149 else if (*iter == delim)
150 {
151 e = trimRight(e);
152 if (!e.empty())
153 {
154 result.emplace_back(std::move(e));
155 e.clear();
156 }
157 ++iter;
158 }
159 else if (isLws(*iter))
160 {
161 ++iter;
162 }
163 else
164 {
165 e.append(1, *iter++);
166 }
167 }
168
169 if (!e.empty())
170 {
171 e = trimRight(e);
172 if (!e.empty())
173 result.emplace_back(std::move(e));
174 }
175 return result;
176}
177
178template <
179 class FwdIt,
181Result
182splitCommas(FwdIt first, FwdIt last)
183{
184 return split(first, last, ',');
185}
186
187template <class Result = std::vector<std::string>>
188Result
189splitCommas(boost::beast::string_view const& s)
190{
191 return splitCommas(s.begin(), s.end());
192}
193
194//------------------------------------------------------------------------------
195
206{
207 using iter_type = boost::string_ref::const_iterator;
208
211 boost::string_ref value_;
212
213public:
214 using value_type = boost::string_ref;
215 using pointer = value_type const*;
216 using reference = value_type const&;
219
220 ListIterator(iter_type begin, iter_type end) : it_(begin), end_(end)
221 {
222 if (it_ != end_)
223 increment();
224 }
225
226 bool
227 operator==(ListIterator const& other) const
228 {
229 return other.it_ == it_ && other.end_ == end_ && other.value_.size() == value_.size();
230 }
231
233 operator*() const
234 {
235 return value_;
236 }
237
238 pointer
240 {
241 return &*(*this);
242 }
243
246 {
247 increment();
248 return *this;
249 }
250
253 {
254 auto temp = *this;
255 ++(*this);
256 return temp;
257 }
258
259private:
260 template <class = void>
261 void
262 increment();
263};
264
265template <class>
266void
268{
269 using namespace detail;
270 value_.clear();
271 while (it_ != end_)
272 {
273 if (*it_ == '"')
274 {
275 // quoted-string
276 ++it_;
277 if (it_ == end_)
278 return;
279 if (*it_ != '"')
280 {
281 auto start = it_;
282 for (;;)
283 {
284 ++it_;
285 if (it_ == end_)
286 {
287 value_ = boost::string_ref(&*start, std::distance(start, it_));
288 return;
289 }
290 if (*it_ == '"')
291 {
292 value_ = boost::string_ref(&*start, std::distance(start, it_));
293 ++it_;
294 return;
295 }
296 }
297 }
298 ++it_;
299 }
300 else if (*it_ == ',')
301 {
302 it_++;
303 continue;
304 }
305 else if (isLws(*it_))
306 {
307 ++it_;
308 continue;
309 }
310 else
311 {
312 auto start = it_;
313 for (;;)
314 {
315 ++it_;
316 if (it_ == end_ || *it_ == ',' || isLws(*it_))
317 {
318 value_ = boost::string_ref(&*start, std::distance(start, it_));
319 return;
320 }
321 }
322 }
323 }
324}
325
330inline bool
331ciEqual(boost::string_ref s1, boost::string_ref s2)
332{
333 return boost::range::equal(s1, s2, detail::CiEqualPred{});
334}
335
339inline boost::iterator_range<ListIterator>
340makeList(boost::string_ref const& field)
341{
342 return boost::iterator_range<ListIterator>{
343 ListIterator{field.begin(), field.end()}, ListIterator{field.end(), field.end()}};
344}
345
351template <class = void>
352bool
353tokenInList(boost::string_ref const& value, boost::string_ref const& token)
354{
355 auto const list = makeList(value);
356 // ListIterator is not default-constructible, so it does not model a std::ranges
357 // sentinel/range; the classic std::any_of (which only needs an input iterator)
358 // is used instead.
359 // NOLINTNEXTLINE(modernize-use-ranges)
360 return std::any_of(
361 list.begin(), list.end(), [&token](auto const& item) { return ciEqual(item, token); });
362}
363
364template <bool IsRequest, class Body, class Fields>
365bool
366isKeepAlive(boost::beast::http::message<IsRequest, Body, Fields> const& m)
367{
368 if (m.version() <= 10)
369 {
370 return boost::beast::http::token_list{m[boost::beast::http::field::connection]}.exists(
371 "keep-alive");
372 }
373 return !boost::beast::http::token_list{m[boost::beast::http::field::connection]}.exists(
374 "close");
375}
376
377} // namespace beast::rfc2616
T any_of(T... args)
T begin(T... args)
Iterates through a comma separated list.
Definition rfc2616.h:206
ListIterator operator++(int)
Definition rfc2616.h:252
pointer operator->() const
Definition rfc2616.h:239
reference operator*() const
Definition rfc2616.h:233
bool operator==(ListIterator const &other) const
Definition rfc2616.h:227
ListIterator(iter_type begin, iter_type end)
Definition rfc2616.h:220
value_type const & reference
Definition rfc2616.h:216
std::forward_iterator_tag iterator_category
Definition rfc2616.h:218
ListIterator & operator++()
Definition rfc2616.h:245
boost::string_ref::const_iterator iter_type
Definition rfc2616.h:207
value_type const * pointer
Definition rfc2616.h:215
std::ptrdiff_t difference_type
Definition rfc2616.h:217
boost::string_ref value_type
Definition rfc2616.h:214
boost::string_ref value_
Definition rfc2616.h:211
T distance(T... args)
T end(T... args)
FwdIter trimRight(FwdIter first, FwdIter last)
Definition rfc2616.h:66
bool isLws(char c)
Returns true if c is linear white space.
Definition rfc2616.h:39
bool isWhite(char c)
Returns true if c is any whitespace character.
Definition rfc2616.h:48
bool isKeepAlive(boost::beast::http::message< IsRequest, Body, Fields > const &m)
Definition rfc2616.h:366
boost::iterator_range< ListIterator > makeList(boost::string_ref const &field)
Returns a range representing the list.
Definition rfc2616.h:340
Result split(FwdIt first, FwdIt last, Char delim)
Parse a character sequence of values separated by commas.
Definition rfc2616.h:107
Result splitCommas(FwdIt first, FwdIt last)
Definition rfc2616.h:182
bool ciEqual(boost::string_ref s1, boost::string_ref s2)
Returns true if two strings are equal.
Definition rfc2616.h:331
bool tokenInList(boost::string_ref const &value, boost::string_ref const &token)
Returns true if the specified token exists in the list.
Definition rfc2616.h:353
bool operator()(char c1, char c2)
Definition rfc2616.h:25