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 #include <boost/beast/http/message.hpp>
24 #include <boost/beast/http/rfc7230.hpp>
25 #include <boost/range/algorithm/equal.hpp>
26 #include <boost/range/iterator_range.hpp>
27 #include <boost/utility/string_ref.hpp>
28 #include <algorithm>
29 #include <cctype>
30 #include <iterator>
31 #include <string>
32 #include <tuple> // for std::tie, remove ASAP
33 #include <utility>
34 #include <vector>
35 
36 namespace beast {
37 namespace rfc2616 {
38 
39 namespace detail {
40 
41 /* Routines for performing RFC2616 compliance.
42  RFC2616:
43  Hypertext Transfer Protocol -- HTTP/1.1
44  http://www.w3.org/Protocols/rfc2616/rfc2616
45 */
46 
48 {
49  explicit ci_equal_pred() = default;
50 
51  bool
52  operator()(char c1, char c2)
53  {
54  // VFALCO TODO Use a table lookup here
55  return std::tolower(static_cast<unsigned char>(c1)) ==
56  std::tolower(static_cast<unsigned char>(c2));
57  }
58 };
59 
60 } // namespace detail
61 
66 inline bool
67 is_lws(char c)
68 {
69  return c == ' ' || c == '\t';
70 }
71 
73 inline bool
74 is_white(char c)
75 {
76  switch (c)
77  {
78  case ' ':
79  case '\f':
80  case '\n':
81  case '\r':
82  case '\t':
83  case '\v':
84  return true;
85  };
86  return false;
87 }
88 
90 inline bool
91 is_control(char c)
92 {
93  return c <= 31 || c >= 127;
94 }
95 
97 inline bool
98 is_separator(char c)
99 {
100  // VFALCO Could use a static table
101  switch (c)
102  {
103  case '(':
104  case ')':
105  case '<':
106  case '>':
107  case '@':
108  case ',':
109  case ';':
110  case ':':
111  case '\\':
112  case '"':
113  case '{':
114  case '}':
115  case ' ':
116  case '\t':
117  return true;
118  };
119  return false;
120 }
121 
123 inline bool
124 is_char(char c)
125 {
126 #ifdef __CHAR_UNSIGNED__ /* -funsigned-char */
127  return c >= 0 && c <= 127;
128 #else
129  return c >= 0;
130 #endif
131 }
132 
133 template <class FwdIter>
134 FwdIter
135 trim_left(FwdIter first, FwdIter last)
136 {
137  return std::find_if_not(first, last, is_white);
138 }
139 
140 template <class FwdIter>
141 FwdIter
142 trim_right(FwdIter first, FwdIter last)
143 {
144  if (first == last)
145  return last;
146  do
147  {
148  --last;
149  if (!is_white(*last))
150  return ++last;
151  } while (last != first);
152  return first;
153 }
154 
155 template <class CharT, class Traits, class Allocator>
156 void
158 {
159  s.resize(std::distance(s.begin(), trim_right(s.begin(), s.end())));
160 }
161 
162 template <class FwdIter>
164 trim(FwdIter first, FwdIter last)
165 {
166  first = trim_left(first, last);
167  last = trim_right(first, last);
168  return std::make_pair(first, last);
169 }
170 
171 template <class String>
172 String
173 trim(String const& s)
174 {
175  using std::begin;
176  using std::end;
177  auto first = begin(s);
178  auto last = end(s);
179  std::tie(first, last) = trim(first, last);
180  return {first, last};
181 }
182 
183 template <class String>
184 String
185 trim_right(String const& s)
186 {
187  using std::begin;
188  using std::end;
189  auto first(begin(s));
190  auto last(end(s));
191  last = trim_right(first, last);
192  return {first, last};
193 }
194 
195 inline std::string
196 trim(std::string const& s)
197 {
198  return trim<std::string>(s);
199 }
200 
209 template <
210  class FwdIt,
211  class Result = std::vector<
213  class Char>
214 Result
215 split(FwdIt first, FwdIt last, Char delim)
216 {
217  Result result;
218  using string = typename Result::value_type;
219  FwdIt iter = first;
220  string e;
221  while (iter != last)
222  {
223  if (*iter == '"')
224  {
225  // quoted-string
226  ++iter;
227  while (iter != last)
228  {
229  if (*iter == '"')
230  {
231  ++iter;
232  break;
233  }
234 
235  if (*iter == '\\')
236  {
237  // quoted-pair
238  ++iter;
239  if (iter != last)
240  e.append(1, *iter++);
241  }
242  else
243  {
244  // qdtext
245  e.append(1, *iter++);
246  }
247  }
248  if (!e.empty())
249  {
250  result.emplace_back(std::move(e));
251  e.clear();
252  }
253  }
254  else if (*iter == delim)
255  {
256  e = trim_right(e);
257  if (!e.empty())
258  {
259  result.emplace_back(std::move(e));
260  e.clear();
261  }
262  ++iter;
263  }
264  else if (is_lws(*iter))
265  {
266  ++iter;
267  }
268  else
269  {
270  e.append(1, *iter++);
271  }
272  }
273 
274  if (!e.empty())
275  {
276  e = trim_right(e);
277  if (!e.empty())
278  result.emplace_back(std::move(e));
279  }
280  return result;
281 }
282 
283 template <
284  class FwdIt,
285  class Result = std::vector<
287 Result
288 split_commas(FwdIt first, FwdIt last)
289 {
290  return split(first, last, ',');
291 }
292 
293 template <class Result = std::vector<std::string>>
294 Result
295 split_commas(boost::beast::string_view const& s)
296 {
297  return split_commas(s.begin(), s.end());
298 }
299 
300 //------------------------------------------------------------------------------
301 
311 {
312  using iter_type = boost::string_ref::const_iterator;
313 
316  boost::string_ref value_;
317 
318 public:
319  using value_type = boost::string_ref;
320  using pointer = value_type const*;
321  using reference = value_type const&;
324 
325  list_iterator(iter_type begin, iter_type end) : it_(begin), end_(end)
326  {
327  if (it_ != end_)
328  increment();
329  }
330 
331  bool
332  operator==(list_iterator const& other) const
333  {
334  return other.it_ == it_ && other.end_ == end_ &&
335  other.value_.size() == value_.size();
336  }
337 
338  bool
339  operator!=(list_iterator const& other) const
340  {
341  return !(*this == other);
342  }
343 
344  reference
345  operator*() const
346  {
347  return value_;
348  }
349 
350  pointer
351  operator->() const
352  {
353  return &*(*this);
354  }
355 
358  {
359  increment();
360  return *this;
361  }
362 
365  {
366  auto temp = *this;
367  ++(*this);
368  return temp;
369  }
370 
371 private:
372  template <class = void>
373  void
374  increment();
375 };
376 
377 template <class>
378 void
380 {
381  value_.clear();
382  while (it_ != end_)
383  {
384  if (*it_ == '"')
385  {
386  // quoted-string
387  ++it_;
388  if (it_ == end_)
389  return;
390  if (*it_ != '"')
391  {
392  auto start = it_;
393  for (;;)
394  {
395  ++it_;
396  if (it_ == end_)
397  {
398  value_ = boost::string_ref(
399  &*start, std::distance(start, it_));
400  return;
401  }
402  if (*it_ == '"')
403  {
404  value_ = boost::string_ref(
405  &*start, std::distance(start, it_));
406  ++it_;
407  return;
408  }
409  }
410  }
411  ++it_;
412  }
413  else if (*it_ == ',')
414  {
415  it_++;
416  continue;
417  }
418  else if (is_lws(*it_))
419  {
420  ++it_;
421  continue;
422  }
423  else
424  {
425  auto start = it_;
426  for (;;)
427  {
428  ++it_;
429  if (it_ == end_ || *it_ == ',' || is_lws(*it_))
430  {
431  value_ =
432  boost::string_ref(&*start, std::distance(start, it_));
433  return;
434  }
435  }
436  }
437  }
438 }
439 
444 inline bool
445 ci_equal(boost::string_ref s1, boost::string_ref s2)
446 {
447  return boost::range::equal(s1, s2, detail::ci_equal_pred{});
448 }
449 
451 inline boost::iterator_range<list_iterator>
452 make_list(boost::string_ref const& field)
453 {
454  return boost::iterator_range<list_iterator>{
455  list_iterator{field.begin(), field.end()},
456  list_iterator{field.end(), field.end()}};
457 }
458 
463 template <class = void>
464 bool
465 token_in_list(boost::string_ref const& value, boost::string_ref const& token)
466 {
467  for (auto const& item : make_list(value))
468  if (ci_equal(item, token))
469  return true;
470  return false;
471 }
472 
473 template <bool isRequest, class Body, class Fields>
474 bool
475 is_keep_alive(boost::beast::http::message<isRequest, Body, Fields> const& m)
476 {
477  if (m.version() <= 10)
478  return boost::beast::http::token_list{
479  m[boost::beast::http::field::connection]}
480  .exists("keep-alive");
481  return !boost::beast::http::token_list{
482  m[boost::beast::http::field::connection]}
483  .exists("close");
484 }
485 
486 } // namespace rfc2616
487 } // namespace beast
488 
489 #endif
beast::rfc2616::list_iterator::value_type
boost::string_ref value_type
Definition: rfc2616.h:319
std::basic_string::resize
T resize(T... args)
beast::rfc2616::list_iterator::it_
iter_type it_
Definition: rfc2616.h:314
std::basic_string
STL class.
beast::rfc2616::list_iterator::reference
value_type const & reference
Definition: rfc2616.h:321
beast::rfc2616::list_iterator::pointer
value_type const * pointer
Definition: rfc2616.h:320
utility
beast::rfc2616::trim_right_in_place
void trim_right_in_place(std::basic_string< CharT, Traits, Allocator > &s)
Definition: rfc2616.h:157
beast::rfc2616::is_char
bool is_char(char c)
Returns true if c is a character.
Definition: rfc2616.h:124
std::pair
beast::rfc2616::list_iterator::operator==
bool operator==(list_iterator const &other) const
Definition: rfc2616.h:332
vector
beast::rfc2616::split
Result split(FwdIt first, FwdIt last, Char delim)
Parse a character sequence of values separated by commas.
Definition: rfc2616.h:215
std::find_if_not
T find_if_not(T... args)
beast::rfc2616::detail::ci_equal_pred::ci_equal_pred
ci_equal_pred()=default
iterator
std::forward_iterator_tag
std::distance
T distance(T... args)
tuple
beast::rfc2616::list_iterator::increment
void increment()
Definition: rfc2616.h:379
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:452
beast::rfc2616::detail::ci_equal_pred::operator()
bool operator()(char c1, char c2)
Definition: rfc2616.h:52
std::tie
T tie(T... args)
beast::rfc2616::trim_right
FwdIter trim_right(FwdIter first, FwdIter last)
Definition: rfc2616.h:142
beast::rfc2616::trim
std::pair< FwdIter, FwdIter > trim(FwdIter first, FwdIter last)
Definition: rfc2616.h:164
beast::rfc2616::is_keep_alive
bool is_keep_alive(boost::beast::http::message< isRequest, Body, Fields > const &m)
Definition: rfc2616.h:475
beast::rfc2616::list_iterator::list_iterator
list_iterator(iter_type begin, iter_type end)
Definition: rfc2616.h:325
beast::rfc2616::list_iterator::operator->
pointer operator->() const
Definition: rfc2616.h:351
beast::rfc2616::trim_left
FwdIter trim_left(FwdIter first, FwdIter last)
Definition: rfc2616.h:135
beast::rfc2616::list_iterator
Iterates through a comma separated list.
Definition: rfc2616.h:310
beast::rfc2616::is_lws
bool is_lws(char c)
Returns true if c is linear white space.
Definition: rfc2616.h:67
beast::rfc2616::list_iterator::value_
boost::string_ref value_
Definition: rfc2616.h:316
beast::rfc2616::split_commas
Result split_commas(FwdIt first, FwdIt last)
Definition: rfc2616.h:288
beast::rfc2616::is_separator
bool is_separator(char c)
Returns true if c is a separator.
Definition: rfc2616.h:98
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:445
beast::rfc2616::list_iterator::operator*
reference operator*() const
Definition: rfc2616.h:345
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:47
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:465
beast::rfc2616::list_iterator::operator++
list_iterator operator++(int)
Definition: rfc2616.h:364
beast::rfc2616::list_iterator::iter_type
boost::string_ref::const_iterator iter_type
Definition: rfc2616.h:312
std::basic_string::begin
T begin(T... args)
beast::rfc2616::list_iterator::end_
iter_type end_
Definition: rfc2616.h:315
std::ptrdiff_t
cctype
beast::rfc2616::is_white
bool is_white(char c)
Returns true if c is any whitespace character.
Definition: rfc2616.h:74
beast::rfc2616::is_control
bool is_control(char c)
Returns true if c is a control character.
Definition: rfc2616.h:91
std::make_pair
T make_pair(T... args)
std::basic_string::end
T end(T... args)
beast::rfc2616::list_iterator::operator++
list_iterator & operator++()
Definition: rfc2616.h:357
beast::rfc2616::list_iterator::operator!=
bool operator!=(list_iterator const &other) const
Definition: rfc2616.h:339
beast
Definition: base_uint.h:646
string