rippled
rfc2616.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of Beast: https://github.com/vinniefalco/Beast
4  Copyright 2014, Vinnie Falco <vinnie.falco@gmail.com>
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef BEAST_RFC2616_HPP
21 #define BEAST_RFC2616_HPP
22 
23 // TODO: This include <cstdint> is a workaround for beast compilation bug.
24 // Remove when fix https://github.com/boostorg/beast/pull/2682/ is available.
25 #include <cstdint>
26 
27 #include <boost/beast/http/message.hpp>
28 #include <boost/beast/http/rfc7230.hpp>
29 #include <boost/range/algorithm/equal.hpp>
30 #include <boost/range/iterator_range.hpp>
31 #include <boost/utility/string_ref.hpp>
32 
33 #include <algorithm>
34 #include <cctype>
35 #include <iterator>
36 #include <string>
37 #include <utility>
38 #include <vector>
39 
40 namespace beast {
41 namespace rfc2616 {
42 
43 namespace detail {
44 
46 {
47  explicit ci_equal_pred() = default;
48 
49  bool
50  operator()(char c1, char c2)
51  {
52  // VFALCO TODO Use a table lookup here
53  return std::tolower(static_cast<unsigned char>(c1)) ==
54  std::tolower(static_cast<unsigned char>(c2));
55  }
56 };
57 
62 inline bool
63 is_lws(char c)
64 {
65  return c == ' ' || c == '\t';
66 }
67 
69 inline bool
70 is_white(char c)
71 {
72  switch (c)
73  {
74  case ' ':
75  case '\f':
76  case '\n':
77  case '\r':
78  case '\t':
79  case '\v':
80  return true;
81  };
82  return false;
83 }
84 
85 template <class FwdIter>
86 FwdIter
87 trim_right(FwdIter first, FwdIter last)
88 {
89  if (first == last)
90  return last;
91  do
92  {
93  --last;
94  if (!is_white(*last))
95  return ++last;
96  } while (last != first);
97  return first;
98 }
99 
100 template <class String>
101 String
102 trim_right(String const& s)
103 {
104  using std::begin;
105  using std::end;
106  auto first(begin(s));
107  auto last(end(s));
108  last = trim_right(first, last);
109  return {first, last};
110 }
111 
112 } // namespace detail
113 
122 template <
123  class FwdIt,
124  class Result = std::vector<
126  class Char>
127 Result
128 split(FwdIt first, FwdIt last, Char delim)
129 {
130  using namespace detail;
131  using string = typename Result::value_type;
132 
133  Result result;
134 
135  FwdIt iter = first;
136  string e;
137  while (iter != last)
138  {
139  if (*iter == '"')
140  {
141  // quoted-string
142  ++iter;
143  while (iter != last)
144  {
145  if (*iter == '"')
146  {
147  ++iter;
148  break;
149  }
150 
151  if (*iter == '\\')
152  {
153  // quoted-pair
154  ++iter;
155  if (iter != last)
156  e.append(1, *iter++);
157  }
158  else
159  {
160  // qdtext
161  e.append(1, *iter++);
162  }
163  }
164  if (!e.empty())
165  {
166  result.emplace_back(std::move(e));
167  e.clear();
168  }
169  }
170  else if (*iter == delim)
171  {
172  e = trim_right(e);
173  if (!e.empty())
174  {
175  result.emplace_back(std::move(e));
176  e.clear();
177  }
178  ++iter;
179  }
180  else if (is_lws(*iter))
181  {
182  ++iter;
183  }
184  else
185  {
186  e.append(1, *iter++);
187  }
188  }
189 
190  if (!e.empty())
191  {
192  e = trim_right(e);
193  if (!e.empty())
194  result.emplace_back(std::move(e));
195  }
196  return result;
197 }
198 
199 template <
200  class FwdIt,
201  class Result = std::vector<
203 Result
204 split_commas(FwdIt first, FwdIt last)
205 {
206  return split(first, last, ',');
207 }
208 
209 template <class Result = std::vector<std::string>>
210 Result
211 split_commas(boost::beast::string_view const& s)
212 {
213  return split_commas(s.begin(), s.end());
214 }
215 
216 //------------------------------------------------------------------------------
217 
227 {
228  using iter_type = boost::string_ref::const_iterator;
229 
232  boost::string_ref value_;
233 
234 public:
235  using value_type = boost::string_ref;
236  using pointer = value_type const*;
237  using reference = value_type const&;
240 
241  list_iterator(iter_type begin, iter_type end) : it_(begin), end_(end)
242  {
243  if (it_ != end_)
244  increment();
245  }
246 
247  bool
248  operator==(list_iterator const& other) const
249  {
250  return other.it_ == it_ && other.end_ == end_ &&
251  other.value_.size() == value_.size();
252  }
253 
254  bool
255  operator!=(list_iterator const& other) const
256  {
257  return !(*this == other);
258  }
259 
260  reference
261  operator*() const
262  {
263  return value_;
264  }
265 
266  pointer
267  operator->() const
268  {
269  return &*(*this);
270  }
271 
274  {
275  increment();
276  return *this;
277  }
278 
281  {
282  auto temp = *this;
283  ++(*this);
284  return temp;
285  }
286 
287 private:
288  template <class = void>
289  void
290  increment();
291 };
292 
293 template <class>
294 void
296 {
297  using namespace detail;
298  value_.clear();
299  while (it_ != end_)
300  {
301  if (*it_ == '"')
302  {
303  // quoted-string
304  ++it_;
305  if (it_ == end_)
306  return;
307  if (*it_ != '"')
308  {
309  auto start = it_;
310  for (;;)
311  {
312  ++it_;
313  if (it_ == end_)
314  {
315  value_ = boost::string_ref(
316  &*start, std::distance(start, it_));
317  return;
318  }
319  if (*it_ == '"')
320  {
321  value_ = boost::string_ref(
322  &*start, std::distance(start, it_));
323  ++it_;
324  return;
325  }
326  }
327  }
328  ++it_;
329  }
330  else if (*it_ == ',')
331  {
332  it_++;
333  continue;
334  }
335  else if (is_lws(*it_))
336  {
337  ++it_;
338  continue;
339  }
340  else
341  {
342  auto start = it_;
343  for (;;)
344  {
345  ++it_;
346  if (it_ == end_ || *it_ == ',' || is_lws(*it_))
347  {
348  value_ =
349  boost::string_ref(&*start, std::distance(start, it_));
350  return;
351  }
352  }
353  }
354  }
355 }
360 inline bool
361 ci_equal(boost::string_ref s1, boost::string_ref s2)
362 {
363  return boost::range::equal(s1, s2, detail::ci_equal_pred{});
364 }
365 
367 inline boost::iterator_range<list_iterator>
368 make_list(boost::string_ref const& field)
369 {
370  return boost::iterator_range<list_iterator>{
371  list_iterator{field.begin(), field.end()},
372  list_iterator{field.end(), field.end()}};
373 }
374 
379 template <class = void>
380 bool
381 token_in_list(boost::string_ref const& value, boost::string_ref const& token)
382 {
383  for (auto const& item : make_list(value))
384  if (ci_equal(item, token))
385  return true;
386  return false;
387 }
388 
389 template <bool isRequest, class Body, class Fields>
390 bool
391 is_keep_alive(boost::beast::http::message<isRequest, Body, Fields> const& m)
392 {
393  if (m.version() <= 10)
394  return boost::beast::http::token_list{
395  m[boost::beast::http::field::connection]}
396  .exists("keep-alive");
397  return !boost::beast::http::token_list{
398  m[boost::beast::http::field::connection]}
399  .exists("close");
400 }
401 
402 } // namespace rfc2616
403 } // namespace beast
404 
405 #endif
beast::rfc2616::list_iterator::value_type
boost::string_ref value_type
Definition: rfc2616.h:235
beast::rfc2616::list_iterator::it_
iter_type it_
Definition: rfc2616.h:230
std::basic_string
STL class.
beast::rfc2616::list_iterator::reference
value_type const & reference
Definition: rfc2616.h:237
beast::rfc2616::list_iterator::pointer
value_type const * pointer
Definition: rfc2616.h:236
utility
beast::rfc2616::list_iterator::operator==
bool operator==(list_iterator const &other) const
Definition: rfc2616.h:248
vector
beast::rfc2616::split
Result split(FwdIt first, FwdIt last, Char delim)
Parse a character sequence of values separated by commas.
Definition: rfc2616.h:128
beast::rfc2616::detail::ci_equal_pred::ci_equal_pred
ci_equal_pred()=default
iterator
std::forward_iterator_tag
std::distance
T distance(T... args)
beast::rfc2616::list_iterator::increment
void increment()
Definition: rfc2616.h:295
algorithm
beast::rfc2616::make_list
boost::iterator_range< list_iterator > make_list(boost::string_ref const &field)
Returns a range representing the list.
Definition: rfc2616.h:368
beast::rfc2616::detail::ci_equal_pred::operator()
bool operator()(char c1, char c2)
Definition: rfc2616.h:50
beast::rfc2616::is_keep_alive
bool is_keep_alive(boost::beast::http::message< isRequest, Body, Fields > const &m)
Definition: rfc2616.h:391
beast::rfc2616::list_iterator::list_iterator
list_iterator(iter_type begin, iter_type end)
Definition: rfc2616.h:241
beast::rfc2616::list_iterator::operator->
pointer operator->() const
Definition: rfc2616.h:267
beast::rfc2616::list_iterator
Iterates through a comma separated list.
Definition: rfc2616.h:226
beast::rfc2616::detail::is_lws
bool is_lws(char c)
Returns true if c is linear white space.
Definition: rfc2616.h:63
cstdint
beast::rfc2616::list_iterator::value_
boost::string_ref value_
Definition: rfc2616.h:232
beast::rfc2616::split_commas
Result split_commas(FwdIt first, FwdIt last)
Definition: rfc2616.h:204
beast::rfc2616::ci_equal
bool ci_equal(boost::string_ref s1, boost::string_ref s2)
Returns true if two strings are equal.
Definition: rfc2616.h:361
beast::rfc2616::list_iterator::operator*
reference operator*() const
Definition: rfc2616.h:261
beast::field
field_t< CharT, Traits, Allocator > field(std::basic_string< CharT, Traits, Allocator > const &text, int width=8, int pad=0, bool right=false)
Definition: iosformat.h:162
beast::rfc2616::detail::ci_equal_pred
Definition: rfc2616.h:45
beast::rfc2616::token_in_list
bool token_in_list(boost::string_ref const &value, boost::string_ref const &token)
Returns true if the specified token exists in the list.
Definition: rfc2616.h:381
beast::rfc2616::detail::trim_right
FwdIter trim_right(FwdIter first, FwdIter last)
Definition: rfc2616.h:87
beast::rfc2616::list_iterator::operator++
list_iterator operator++(int)
Definition: rfc2616.h:280
beast::rfc2616::list_iterator::iter_type
boost::string_ref::const_iterator iter_type
Definition: rfc2616.h:228
std::begin
T begin(T... args)
beast::rfc2616::list_iterator::end_
iter_type end_
Definition: rfc2616.h:231
std::ptrdiff_t
cctype
std::end
T end(T... args)
beast::rfc2616::detail::is_white
bool is_white(char c)
Returns true if c is any whitespace character.
Definition: rfc2616.h:70
beast::rfc2616::list_iterator::operator++
list_iterator & operator++()
Definition: rfc2616.h:273
beast::rfc2616::list_iterator::operator!=
bool operator!=(list_iterator const &other) const
Definition: rfc2616.h:255
beast
Definition: base_uint.h:641
string