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