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