RESTinio
host.hpp
Go to the documentation of this file.
1 /*
2  * RESTinio
3  */
4 
5 /*!
6  * @file
7  * @brief Stuff related to value of Host HTTP-field.
8  *
9  * @since v.0.6.9
10  */
11 
12 #pragma once
13 
14 #include <restinio/helpers/http_field_parsers/basics.hpp>
15 
16 #include <restinio/helpers/http_field_parsers/details/pct_encoded_symbols.hpp>
17 
18 #include <restinio/variant.hpp>
19 
20 namespace restinio
21 {
22 
23 namespace http_field_parsers
24 {
25 
26 namespace host_details
27 {
28 
29 namespace ep_impl = restinio::easy_parser::impl;
32 
33 //
34 // unreserved_predicate_t
35 //
36 /*!
37  * @brief A preducate for symbol_producer_template that checks that
38  * a symbol is unreserved symbol from RCF3986.
39  *
40  * See: https://tools.ietf.org/html/rfc3986#appendix-A
41  *
42  * @since v.0.6.9
43  */
45 {
47  bool
48  operator()( const char actual ) const noexcept
49  {
50  return hfp_impl::is_alpha(actual)
52  || '-' == actual
53  || '.' == actual
54  || '_' == actual
55  || '~' == actual
56  ;
57  }
58 };
59 
60 //
61 // unreserved_symbol_producer
62 //
63 /*!
64  * @brief A factory for producer that extracts unreserved symbols.
65  *
66  * See: https://tools.ietf.org/html/rfc3986#appendix-A
67  *
68  * @since v.0.6.9
69  */
71 inline auto
73 {
75 }
76 
77 //
78 // sub_delims_predicate_t
79 //
80 /*!
81  * @brief A preducate for symbol_producer_template that checks that
82  * a symbol is sub-delims symbol from RCF3986.
83  *
84  * See: https://tools.ietf.org/html/rfc3986#appendix-A
85  *
86  * @since v.0.6.9
87  */
89 {
91  bool
92  operator()( const char actual ) const noexcept
93  {
94  return '!' == actual
95  || '$' == actual
96  || '&' == actual
97  || '\'' == actual
98  || '(' == actual
99  || ')' == actual
100  || '*' == actual
101  || '+' == actual
102  || ',' == actual
103  || ';' == actual
104  || '=' == actual
105  ;
106  }
107 };
108 
109 //
110 // sub_delims_symbol_producer
111 //
112 /*!
113  * @brief A factory for producer that extracts sub-delims symbols.
114  *
115  * See: https://tools.ietf.org/html/rfc3986#appendix-A
116  *
117  * @since v.0.6.9
118  */
120 inline auto
122 {
124 }
125 
126 //
127 // ipv4_address_producer
128 //
129 /*!
130  * @brief A factory for producer of IPv4address value.
131  *
132  * Produces `std::string`.
133  *
134  * Uses the following grammar (see https://tools.ietf.org/html/rfc3986#appendix-A):
135 @verbatim
136 IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
137 
138 dec-octet = DIGIT ; 0-9
139  / %x31-39 DIGIT ; 10-99
140  / "1" 2DIGIT ; 100-199
141  / "2" %x30-34 DIGIT ; 200-249
142  / "25" %x30-35 ; 250-255
143 @endverbatim
144  *
145  * @since v.0.6.9
146  */
148 inline auto
150 {
151  const auto dec_octet = produce< std::string >(
152  alternatives(
153  sequence(
154  symbol_p('2') >> to_container(),
155  symbol_p('5') >> to_container(),
156  symbol_from_range_p('0', '5') >> to_container()
157  ),
158  sequence(
159  symbol_p('2') >> to_container(),
160  symbol_from_range_p('0', '4') >> to_container(),
161  digit_p() >> to_container()
162  ),
163  sequence(
164  symbol_p('1') >> to_container(),
165  digit_p() >> to_container(),
166  digit_p() >> to_container()
167  ),
168  sequence(
169  symbol_from_range_p('1', '9') >> to_container(),
170  digit_p() >> to_container()
171  ),
172  digit_p() >> to_container()
173  )
174  );
175 
176  return produce< std::string >(
177  dec_octet >> to_container(),
178  symbol_p('.') >> to_container(),
179  dec_octet >> to_container(),
180  symbol_p('.') >> to_container(),
181  dec_octet >> to_container(),
182  symbol_p('.') >> to_container(),
184  );
185 }
186 
187 //FIXME: maybe this should be a part of easy_parser?
188 #if 0
189 struct debug_printer : public ep_impl::clause_tag
190 {
191  std::string m_tag;
192 
193  debug_printer( std::string v ) noexcept : m_tag{ std::move(v) } {}
194 
195  template< typename Target_Type >
198  try_process( ep_impl::source_t & from, Target_Type & /*target*/ )
199  {
200  std::cout << "*** debug_print: " << m_tag << std::endl;
201 
202  return nullopt;
203  }
204 };
205 #endif
206 
207 //
208 // ipv6_address_producer
209 //
210 /*!
211  * @brief A factory for producer of ipv6_address value.
212  *
213  * Produces `std::string`.
214  *
215  * Uses the following grammar (see https://tools.ietf.org/html/rfc3986#appendix-A):
216 @verbatim
217  IPv6address = 6( h16 ":" ) ls32
218  / "::" 5( h16 ":" ) ls32
219  / [ h16 ] "::" 4( h16 ":" ) ls32
220  / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
221  / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
222  / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
223  / [ *4( h16 ":" ) h16 ] "::" ls32
224  / [ *5( h16 ":" ) h16 ] "::" h16
225  / [ *6( h16 ":" ) h16 ] "::"
226 
227  h16 = 1*4HEXDIG
228  ls32 = ( h16 ":" h16 ) / IPv4address
229 @endverbatim
230  *
231  * @since v.0.6.9
232  */
234 inline auto
236 {
237  const auto h16 = produce< std::string >(
238  repeat( 1u, 4u, hexdigit_p() >> to_container() )
239  );
240  const auto h16_with_colon = sequence(
241  h16 >> to_container(),
242  symbol_p(':') >> to_container(),
243  not_clause( symbol(':') )
244  );
245  const auto ls32 = produce< std::string >(
246  alternatives(
247  sequence(
248  h16 >> to_container(),
249  symbol_p(':') >> to_container(),
250  h16 >> to_container()
251  ),
253  )
254  );
255  const auto double_colon =
256  exact_p( "::" ) >> just( std::string{ "::" } ) >> to_container()
257  ;
258 
259  return produce< std::string >(
260  alternatives(
261  sequence(
262  repeat( 6u, 6u, h16_with_colon ),
263  ls32 >> to_container()
264  ),
265  sequence(
266  double_colon,
267  repeat( 5u, 5u, h16_with_colon ),
268  ls32 >> to_container()
269  ),
270  sequence(
271  maybe( h16 >> to_container() ),
272  double_colon,
273  repeat( 4u, 4u, h16_with_colon ),
274  ls32 >> to_container()
275  ),
276  sequence(
277  maybe(
278  repeat( 0u, 1u, h16_with_colon ),
279  h16 >> to_container()
280  ),
281  double_colon,
282  repeat( 3u, 3u, h16_with_colon ),
283  ls32 >> to_container()
284  ),
285  sequence(
286  maybe(
287  repeat( 0u, 2u, h16_with_colon ),
288  h16 >> to_container()
289  ),
290  double_colon,
291  repeat( 2u, 2u, h16_with_colon ),
292  ls32 >> to_container()
293  ),
294  sequence(
295  maybe(
296  repeat( 0u, 3u, h16_with_colon ),
297  h16 >> to_container()
298  ),
299  double_colon,
301  ls32 >> to_container()
302  ),
303  sequence(
304  maybe(
305  repeat( 0u, 4u, h16_with_colon ),
306  h16 >> to_container()
307  ),
308  double_colon,
309  ls32 >> to_container()
310  ),
311  sequence(
312  maybe(
313  repeat( 0u, 5u, h16_with_colon ),
314  h16 >> to_container()
315  ),
316  double_colon,
317  h16 >> to_container()
318  ),
319  sequence(
320  maybe(
321  repeat( 0u, 6u, h16_with_colon ),
322  h16 >> to_container()
323  ),
325  )
326  )
327  );
328 }
329 
330 //
331 // reg_name_producer
332 //
333 /*!
334  * @brief A factory for producer of reg-name value.
335  *
336  * Produces `std::string`.
337  *
338  * @note
339  * reg-name is defined in RFC3986 as:
340 @verbatim
341 reg-name = *( unreserved / pct-encoded / sub-delims )
342 @endverbatim
343  * but this producer uses more strict grammar (because empty reg-name
344  * in Host HTTP-field has no sense):
345 @verbatim
346 reg-name = 1*( unreserved / pct-encoded / sub-delims )
347 @endverbatim
348  *
349  * @since v.0.6.9
350  */
352 inline auto
354 {
355  return produce< std::string >(
356  repeat( 1, N,
357  alternatives(
362  )
363  )
364  );
365 }
366 
367 } /* namespace host_details */
368 
369 //
370 // raw_host_value_t
371 //
372 /*!
373  * @brief Tools for working with the raw value of Host HTTP-field.
374  *
375  * This struct represents parsed value of HTTP-field Host with out
376  * advanced processing of parsed value (like decoding percent-encoded
377  * symbols into UTF-8 byte sequences and transforming string representation
378  * of IP addresses into internal form).
379  *
380  * See https://tools.ietf.org/html/rfc3986#appendix-A.
381  *
382  * @note
383  * Value of 'host' is converted to lower case.
384  *
385  * @since v.0.6.9
386  */
388 {
389  struct reg_name_t
390  {
392 
393  reg_name_t() = default;
394  explicit reg_name_t( std::string val ) noexcept : v{ std::move(val) } {}
395 
396  friend bool
397  operator==( const reg_name_t & a, const reg_name_t & b ) noexcept
398  {
399  return a.v == b.v;
400  }
401 
402  friend bool
403  operator!=( const reg_name_t & a, const reg_name_t & b ) noexcept
404  {
405  return a.v != b.v;
406  }
407 
408  friend bool
409  operator<( const reg_name_t & a, const reg_name_t & b ) noexcept
410  {
411  return a.v < b.v;
412  }
413 
415  static reg_name_t
416  from_string( std::string v ) noexcept
417  {
418  return reg_name_t{ std::move(v) };
419  }
420  };
421 
423  {
425 
426  ipv4_address_t() = default;
427  explicit ipv4_address_t( std::string val ) noexcept : v{ std::move(val) } {}
428 
429  friend bool
430  operator==( const ipv4_address_t & a, const ipv4_address_t & b ) noexcept
431  {
432  return a.v == b.v;
433  }
434 
435  friend bool
436  operator!=( const ipv4_address_t & a, const ipv4_address_t & b ) noexcept
437  {
438  return a.v != b.v;
439  }
440 
441  friend bool
442  operator<( const ipv4_address_t & a, const ipv4_address_t & b ) noexcept
443  {
444  return a.v < b.v;
445  }
446 
448  static ipv4_address_t
449  from_string( std::string v ) noexcept
450  {
451  return ipv4_address_t{ std::move(v) };
452  }
453  };
454 
456  {
458 
459  ipv6_address_t() = default;
460  explicit ipv6_address_t( std::string val ) noexcept : v{ std::move(val) } {}
461 
462  friend bool
463  operator==( const ipv6_address_t & a, const ipv6_address_t & b ) noexcept
464  {
465  return a.v == b.v;
466  }
467 
468  friend bool
469  operator!=( const ipv6_address_t & a, const ipv6_address_t & b ) noexcept
470  {
471  return a.v != b.v;
472  }
473 
474  friend bool
475  operator<( const ipv6_address_t & a, const ipv6_address_t & b ) noexcept
476  {
477  return a.v < b.v;
478  }
479 
481  static ipv6_address_t
482  from_string( std::string v ) noexcept
483  {
484  return ipv6_address_t{ std::move(v) };
485  }
486  };
487 
489 
491 
492  //! Optional port value.
493  /*!
494  * Will be empty if there is no 'port' in the value of Host HTTP-field.
495  */
497 
498  /*!
499  * @brief A factory function for a parser of Host value.
500  *
501  * @since v.0.6.9
502  */
504  static auto
506  {
507  using namespace host_details;
508 
509  return produce< raw_host_value_t >(
511  alternatives(
512 
514  symbol('['),
516  >> to_lower()
518  >> as_result(),
519  symbol(']')
520  ) >> as_result(),
521 
525  >> as_result()
526  ) >> as_result(),
527 
528  produce< reg_name_t >(
529  reg_name_p() >> to_lower()
531  >> as_result()
532  ) >> as_result()
533  )
534  ) >> &raw_host_value_t::host,
535  maybe(
536  symbol(':'),
539  )
540  );
541  }
542 
543  /*!
544  * @brief An attempt to parse Host HTTP-field.
545  *
546  * @since v.0.6.9
547  */
551  {
553  }
554 };
555 
556 inline std::ostream &
558 {
559  struct host_dumper_t
560  {
561  std::ostream & m_to;
562 
563  void operator()( const raw_host_value_t::reg_name_t & n ) const
564  {
565  m_to << n.v;
566  }
567 
568  void operator()( const raw_host_value_t::ipv4_address_t & n ) const
569  {
570  m_to << n.v;
571  }
572 
573  void operator()( const raw_host_value_t::ipv6_address_t & n ) const
574  {
575  m_to << '[' << n.v << ']';
576  }
577  };
578 
579  visit( host_dumper_t{ to }, rhv.host );
580 
581  if( rhv.port )
582  to << ':' << *(rhv.port) << std::endl;
583 
584  return to;
585 }
586 
587 } /* namespace http_field_parsers */
588 
589 } /* namespace restinio */
static RESTINIO_NODISCARD ipv6_address_t from_string(std::string v) noexcept
Definition: host.hpp:482
friend bool operator!=(const ipv6_address_t &a, const ipv6_address_t &b) noexcept
Definition: host.hpp:469
friend bool operator<(const ipv6_address_t &a, const ipv6_address_t &b) noexcept
Definition: host.hpp:475
std::ostream & operator<<(std::ostream &to, const raw_host_value_t &rhv)
Definition: host.hpp:557
friend bool operator==(const ipv4_address_t &a, const ipv4_address_t &b) noexcept
Definition: host.hpp:430
friend bool operator==(const reg_name_t &a, const reg_name_t &b) noexcept
Definition: host.hpp:397
friend bool operator!=(const reg_name_t &a, const reg_name_t &b) noexcept
Definition: host.hpp:403
optional_t< std::uint16_t > port
Optional port value.
Definition: host.hpp:496
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
Definition: host.hpp:92
static RESTINIO_NODISCARD ipv4_address_t from_string(std::string v) noexcept
Definition: host.hpp:449
RESTINIO_NODISCARD bool operator()(const char actual) const noexcept
Definition: host.hpp:48
RESTINIO_NODISCARD auto reg_name_p()
A factory for producer of reg-name value.
Definition: host.hpp:353
friend bool operator==(const ipv6_address_t &a, const ipv6_address_t &b) noexcept
Definition: host.hpp:463
friend bool operator<(const ipv4_address_t &a, const ipv4_address_t &b) noexcept
Definition: host.hpp:442
RESTINIO_NODISCARD auto try_parse_field(const generic_request_t< Extra_Data > &req, http_field_t field_id, string_view_t default_value=string_view_t{})
A helper function for extraction and parsing a value of HTTP-field.
static RESTINIO_NODISCARD expected_t< raw_host_value_t, restinio::easy_parser::parse_error_t > try_parse(string_view_t what)
An attempt to parse Host HTTP-field.
Definition: host.hpp:550
friend bool operator<(const reg_name_t &a, const reg_name_t &b) noexcept
Definition: host.hpp:409
static RESTINIO_NODISCARD reg_name_t from_string(std::string v) noexcept
Definition: host.hpp:416
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, optional_t< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...
Definition: value_or.hpp:64
friend bool operator!=(const ipv4_address_t &a, const ipv4_address_t &b) noexcept
Definition: host.hpp:436