1 /*!
2 * @file
3 * @brief Helpers for parsing IP-addresses.
4 */
5
6 #pragma once
7
8 #include <restinio/helpers/easy_parser.hpp>
9
10 #include <asio/ip/address.hpp>
11
12 namespace arataga::utils::parsers
13 {
14
15 //
16 // is_ip_address_char_predicate_t
17 //
18 /*!
19 * @brief A predicate for easy_parser that detects symbols enabled
20 * to be used in IP-addresses.
21 */
22 struct is_ip_address_char_predicate_t
23 {
24 [[nodiscard]]
25 bool
operator ()arataga::utils::parsers::is_ip_address_char_predicate_t26 operator()( char ch ) const noexcept
27 {
28 return restinio::easy_parser::impl::is_hexdigit(ch)
29 || '.' == ch
30 || ':' == ch
31 ;
32 }
33 };
34
35 //
36 // ip_address_char_p
37 //
38 /*!
39 * @brief A producer for easy_parser that extracts symbols enabled
40 * to be used in IP-addresses.
41 */
42 [[nodiscard]]
43 inline auto
ip_address_char_p()44 ip_address_char_p() noexcept
45 {
46 return restinio::easy_parser::impl::symbol_producer_template_t<
47 is_ip_address_char_predicate_t >{};
48 }
49
50 //
51 // ip_address_char_seq_p
52 //
53 /*!
54 * @brief A producer for easy_parser that extracts a sequence of
55 * symbols enabled to be used in IP-addresses.
56 *
57 * Produces an instance of std::string.
58 */
59 [[nodiscard]]
60 inline auto
ip_address_char_seq_p()61 ip_address_char_seq_p() noexcept
62 {
63 using namespace restinio::easy_parser;
64
65 return produce< std::string >(
66 repeat( 1, N, ip_address_char_p() >> to_container() )
67 );
68 }
69
70 //
71 // ipv4_address_p
72 //
73 /*!
74 * @brief A procuder for easy_parser that extracts IPv4-address.
75 *
76 * Produces an instance of asio::ip::address_v4.
77 */
78 [[nodiscard]]
79 inline auto
ipv4_address_p()80 ipv4_address_p() noexcept
81 {
82 using namespace restinio::easy_parser;
83
84 using byte_t = asio::ip::address_v4::bytes_type::value_type;
85 const auto one_group = non_negative_decimal_number_p< byte_t >();
86
87 return produce< asio::ip::address_v4 >(
88 produce< asio::ip::address_v4::bytes_type >(
89 repeat( 3u, 3u, one_group >> to_container(), symbol('.') ),
90 one_group >> to_container()
91 )
92 >> convert( []( const auto & arr ) {
93 return asio::ip::make_address_v4( arr );
94 } )
95 >> as_result()
96 );
97 }
98
99 //
100 // ip_address_p
101 //
102 /*!
103 * @brief A producer for easy_parser that extracts IP-address regardless of
104 * its version.
105 *
106 * Produces an instance of asio::ip::address.
107 *
108 * Can handle IPv4 and IPv6 addresses.
109 */
110 [[nodiscard]]
111 inline auto
ip_address_p()112 ip_address_p() noexcept
113 {
114 using namespace restinio::easy_parser;
115
116 const auto try_extract_ip_address =
117 []( const std::string & ip_as_string ) ->
118 restinio::expected_t< asio::ip::address, error_reason_t >
119 {
120 asio::error_code ec;
121 auto addr = asio::ip::make_address( ip_as_string, ec );
122 if( ec )
123 return restinio::make_unexpected(
124 error_reason_t::illegal_value_found );
125
126 return { addr };
127 };
128
129 return produce< asio::ip::address >(
130 produce< std::string >(
131 repeat( 1u, N, ip_address_char_p() >> to_container() )
132 )
133 >> convert( try_extract_ip_address )
134 >> as_result()
135 );
136 }
137
138 } /* namespace arataga::utils::parsers */
139
140