RESTinio
Loading...
Searching...
No Matches
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 <variant>
19
20namespace restinio
21{
22
23namespace http_field_parsers
24{
25
26namespace host_details
27{
28
29namespace ep_impl = restinio::easy_parser::impl;
30namespace hfp_impl = restinio::http_field_parsers::impl;
31namespace hfp_details = restinio::http_field_parsers::details;
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{
46 [[nodiscard]]
47 bool
48 operator()( const char actual ) const noexcept
49 {
50 return hfp_impl::is_alpha(actual)
51 || hfp_impl::is_digit(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 */
70[[nodiscard]]
71inline auto
73{
74 return ep_impl::symbol_producer_template_t< unreserved_predicate_t >{};
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{
90 [[nodiscard]]
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 */
119[[nodiscard]]
120inline auto
122{
123 return ep_impl::symbol_producer_template_t< sub_delims_predicate_t >{};
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
136IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
137
138dec-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 */
147[[nodiscard]]
148inline auto
150{
151 const auto dec_octet = produce< std::string >(
152 alternatives(
153 sequence(
157 ),
158 sequence(
162 ),
163 sequence(
167 ),
168 sequence(
171 ),
173 )
174 );
175
176 return produce< std::string >(
177 dec_octet >> to_container(),
179 dec_octet >> to_container(),
181 dec_octet >> to_container(),
183 dec_octet >> to_container()
184 );
185}
186
187//FIXME: maybe this should be a part of easy_parser?
188#if 0
189struct debug_printer : public ep_impl::clause_tag
190{
192
193 debug_printer( std::string v ) noexcept : m_tag{ std::move(v) } {}
194
195 template< typename Target_Type >
196 [[nodiscard]]
198 try_process( ep_impl::source_t & from, Target_Type & /*target*/ )
199 {
200 std::cout << "*** debug_print: " << m_tag << std::endl;
201
202 return std::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 */
233[[nodiscard]]
234inline 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 ),
252 ipv4_address_p() >> as_result()
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,
300 h16_with_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 ),
324 double_colon
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
341reg-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
346reg-name = 1*( unreserved / pct-encoded / sub-delims )
347@endverbatim
348 *
349 * @since v.0.6.9
350 */
351[[nodiscard]]
352inline auto
354{
355 return produce< std::string >(
356 repeat( 1, N,
357 alternatives(
358 unreserved_symbol_p() >> to_container(),
359 hfp_details::pct_encoded_symbols_p()
360 >> hfp_details::pct_encoded_symbols_consumer_t{},
361 sub_delims_symbol_p() >> to_container()
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{
390 {
391 std::string v;
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
414 [[nodiscard]]
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 {
424 std::string v;
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
447 [[nodiscard]]
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 {
457 std::string v;
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
480 [[nodiscard]]
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 */
503 [[nodiscard]]
504 static auto
506 {
507 using namespace host_details;
508
509 return produce< raw_host_value_t >(
510 produce< host_value_t >(
511 alternatives(
512
513 produce< ipv6_address_t >(
514 symbol('['),
515 ipv6_address_p()
516 >> to_lower()
517 >> convert( ipv6_address_t::from_string )
518 >> as_result(),
519 symbol(']')
520 ) >> as_result(),
521
522 produce< ipv4_address_t >(
523 ipv4_address_p()
524 >> convert( ipv4_address_t::from_string )
525 >> as_result()
526 ) >> as_result(),
527
528 produce< reg_name_t >(
529 reg_name_p() >> to_lower()
530 >> convert( reg_name_t::from_string )
531 >> as_result()
532 ) >> as_result()
533 )
534 ) >> &raw_host_value_t::host,
535 maybe(
536 symbol(':'),
537 non_negative_decimal_number_p< std::uint16_t >()
538 >> &raw_host_value_t::port
539 )
540 );
541 }
542
543 /*!
544 * @brief An attempt to parse Host HTTP-field.
545 *
546 * @since v.0.6.9
547 */
548 [[nodiscard]]
550 try_parse( string_view_t what )
551 {
552 return restinio::easy_parser::try_parse( what, make_parser() );
553 }
554};
555
556inline std::ostream &
557operator<<( std::ostream & to, const raw_host_value_t & rhv )
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 */
constexpr bool is_digit(const char ch) noexcept
Is a character a decimal digit?
auto digit_p() noexcept
A factory function to create a digit_producer.
auto to_container()
A factory function to create a to_container_consumer.
auto symbol_p(char expected) noexcept
A factory function to create a symbol_producer.
auto symbol_from_range_p(char left, char right) noexcept
A factory function to create a symbol_from_range_producer.
auto hexdigit_p() noexcept
A factory function to create a hexdigit_producer.
auto reg_name_p()
A factory for producer of reg-name value.
Definition host.hpp:353
auto ipv4_address_p()
A factory for producer of IPv4address value.
Definition host.hpp:149
auto sub_delims_symbol_p()
A factory for producer that extracts sub-delims symbols.
Definition host.hpp:121
auto ipv6_address_p()
A factory for producer of ipv6_address value.
Definition host.hpp:235
auto unreserved_symbol_p()
A factory for producer that extracts unreserved symbols.
Definition host.hpp:72
constexpr bool is_alpha(const char ch) noexcept
Is a character an ALPHA?
Definition basics.hpp:265
A preducate for symbol_producer_template that checks that a symbol is sub-delims symbol from RCF3986.
Definition host.hpp:89
bool operator()(const char actual) const noexcept
Definition host.hpp:92
A preducate for symbol_producer_template that checks that a symbol is unreserved symbol from RCF3986.
Definition host.hpp:45
bool operator()(const char actual) const noexcept
Definition host.hpp:48
friend bool operator==(const ipv4_address_t &a, const ipv4_address_t &b) noexcept
Definition host.hpp:430
static ipv4_address_t from_string(std::string v) noexcept
Definition host.hpp:449
friend bool operator!=(const ipv4_address_t &a, const ipv4_address_t &b) noexcept
Definition host.hpp:436
friend bool operator<(const ipv4_address_t &a, const ipv4_address_t &b) noexcept
Definition host.hpp:442
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:463
friend bool operator<(const ipv6_address_t &a, const ipv6_address_t &b) noexcept
Definition host.hpp:475
static ipv6_address_t from_string(std::string v) noexcept
Definition host.hpp:482
friend bool operator<(const reg_name_t &a, const reg_name_t &b) noexcept
Definition host.hpp:409
static reg_name_t from_string(std::string v) noexcept
Definition host.hpp:416
friend bool operator!=(const reg_name_t &a, const reg_name_t &b) noexcept
Definition host.hpp:403
friend bool operator==(const reg_name_t &a, const reg_name_t &b) noexcept
Definition host.hpp:397
Tools for working with the raw value of Host HTTP-field.
Definition host.hpp:388
std::optional< std::uint16_t > port
Optional port value.
Definition host.hpp:496
std::variant< reg_name_t, ipv4_address_t, ipv6_address_t > host_value_t
Definition host.hpp:488
static auto make_parser()
A factory function for a parser of Host value.
Definition host.hpp:505
static 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