RESTinio
uri_helpers.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
9 #pragma once
10 
11 #include <string>
12 #include <unordered_map>
13 
15 
16 #include <restinio/exception.hpp>
18 #include <restinio/optional.hpp>
19 
20 namespace restinio
21 {
22 
23 namespace impl
24 {
25 
26 inline const char *
27 modified_memchr( int chr , const char * from, const char * to )
28 {
29  const char * result = static_cast< const char * >(
30  std::memchr( from, chr, static_cast<std::size_t>(to - from) ) );
31 
32  return result ? result : to;
33 }
34 
35 } /* namespace impl */
36 
37 //
38 // query_string_params_t
39 //
40 
43 {
44  public:
45  using parameters_container_t = std::vector< std::pair< string_view_t, string_view_t > >;
46 
50  std::unique_ptr< char[] > data_buffer,
51  parameters_container_t parameters )
52  : m_data_buffer{ std::move( data_buffer ) }
53  , m_parameters{ std::move( parameters ) }
54  {}
55 
59  std::unique_ptr< char[] > data_buffer,
61  : m_data_buffer{ std::move( data_buffer ) }
62  , m_tag{ tag }
63  {}
64 
67 
70 
74  {
75  return find_parameter_with_check( key ).second;
76  }
77 
79  bool
80  has( string_view_t key ) const noexcept
81  {
82  return m_parameters.end() != find_parameter( key );
83  }
84 
88  get_param( string_view_t key ) const noexcept
89  {
90  const auto it = find_parameter( key );
91 
92  return m_parameters.end() != it ?
93  optional_t< string_view_t >{ it->second } :
95  }
96 
98  auto size() const noexcept { return m_parameters.size(); }
99 
102  bool empty() const noexcept { return m_parameters.empty(); }
103 
106  parameters_container_t::const_iterator
107  begin() const noexcept
108  {
109  return m_parameters.begin();
110  }
111 
112  parameters_container_t::const_iterator
113  end() const noexcept
114  {
115  return m_parameters.end();
116  }
118 
120 
131  auto tag() const noexcept { return m_tag; }
132 
133  private:
134  parameters_container_t::const_iterator
135  find_parameter( string_view_t key ) const noexcept
136  {
137  return
138  std::find_if(
139  m_parameters.begin(),
140  m_parameters.end(),
141  [&]( const auto p ){
142  return key == p.first;
143  } );
144  }
145 
146  parameters_container_t::const_reference
148  {
149  auto it = find_parameter( key );
150 
151  if( m_parameters.end() == it )
152  {
153  throw exception_t{
154  fmt::format(
155  "unable to find parameter \"{}\"",
156  std::string{ key.data(), key.size() } ) };
157  }
158 
159  return *it;
160  }
161 
163  std::unique_ptr< char[] > m_data_buffer;
165 
167 
169 };
170 
172 template < typename Value_Type >
173 Value_Type
175 {
176  return get< Value_Type >( params[ key ] );
177 }
178 
179 namespace parse_query_traits
180 {
181 
182 namespace details
183 {
184 
195 {
196  static string_view_t::size_type
198  string_view_t where,
199  string_view_t::size_type start_from ) noexcept
200  {
201  return where.find_first_of( "&;", start_from );
202  }
203 };
204 
215 {
216  static string_view_t::size_type
218  string_view_t where,
219  string_view_t::size_type start_from ) noexcept
220  {
221  return where.find_first_of( '&', start_from );
222  }
223 };
224 
225 } /* namespace details */
226 
247 {};
248 
265 {};
266 
292 {};
293 
325 struct relaxed
328 {};
329 
330 } /* namespace parse_query_traits */
331 
338 {
340  std::string m_description;
341 
342 public:
345  {}
348  : m_description{ failure.giveout_description() }
349  {}
350 
353  const std::string &
354  description() const noexcept { return m_description; }
355 
357 
363  std::string
364  giveout_description() noexcept { return m_description; }
365 };
366 
395 template< typename Parse_Traits >
397 expected_t< query_string_params_t, parse_query_failure_t >
400  string_view_t original_query_string )
401 {
402  std::unique_ptr< char[] > data_buffer;
404 
405  if( !original_query_string.empty() )
406  {
407  // Because query string is not empty a new buffer should be
408  // allocated and query string should be copied to it.
409  data_buffer.reset( new char[ original_query_string.size() ] );
410  std::memcpy(
411  data_buffer.get(),
412  original_query_string.data(),
413  original_query_string.size() );
414 
415  // Work with created buffer:
416  string_view_t work_query_string{
417  data_buffer.get(),
418  original_query_string.size()
419  };
420  string_view_t::size_type pos{ 0 };
421  const string_view_t::size_type end_pos = work_query_string.size();
422 
423  while( pos < end_pos )
424  {
425  const auto eq_pos = work_query_string.find_first_of( '=', pos );
426 
427  if( string_view_t::npos == eq_pos )
428  {
429  // Since v.0.4.9 we should check the presence of tag (web beacon)
430  // in query string.
431  // Tag can be the only item in query string.
432  if( pos != 0u )
433  // The query string has illegal format.
434  return make_unexpected( parse_query_failure_t{
435  fmt::format(
436  "invalid format of key-value pairs in query_string, "
437  "no '=' symbol starting from position {}",
438  pos )
439  } );
440  else
441  {
442  // Query string contains only tag (web beacon).
443  auto tag_unescape_result =
444  utils::try_inplace_unescape_percent_encoding< Parse_Traits >(
445  &data_buffer[ pos ],
446  end_pos - pos );
447  if( !tag_unescape_result )
448  return make_unexpected( parse_query_failure_t{
449  std::move(tag_unescape_result.error())
450  } );
451 
452  const string_view_t tag = work_query_string.substr(
453  pos, *tag_unescape_result );
454 
455  return query_string_params_t{ std::move( data_buffer ), tag };
456  }
457  }
458 
459  const auto eq_pos_next = eq_pos + 1u;
460  auto separator_pos = Parse_Traits::find_next_separator(
461  work_query_string, eq_pos_next );
462  if( string_view_t::npos == separator_pos )
463  separator_pos = work_query_string.size();
464 
465  // Handle next pair of parameters found.
466  auto key_unescape_result =
467  utils::try_inplace_unescape_percent_encoding< Parse_Traits >(
468  &data_buffer[ pos ],
469  eq_pos - pos );
470  if( !key_unescape_result )
471  return make_unexpected( parse_query_failure_t{
472  std::move(key_unescape_result.error())
473  } );
474 
475  auto value_unescape_result =
476  utils::try_inplace_unescape_percent_encoding< Parse_Traits >(
477  &data_buffer[ eq_pos_next ],
478  separator_pos - eq_pos_next );
479  if( !value_unescape_result )
480  return make_unexpected( parse_query_failure_t{
481  std::move(value_unescape_result.error())
482  } );
483 
484  parameters.emplace_back(
485  string_view_t{ &data_buffer[ pos ], *key_unescape_result },
486  string_view_t{ &data_buffer[ eq_pos_next ], *value_unescape_result } );
487 
488  pos = separator_pos + 1u;
489  }
490  }
491 
492  return query_string_params_t{
493  std::move( data_buffer ),
494  std::move( parameters )
495  };
496 }
497 
499 
515 template< typename Parse_Traits = parse_query_traits::restinio_defaults >
517 query_string_params_t
520  string_view_t original_query_string )
521 {
522  auto r = try_parse_query< Parse_Traits >( original_query_string );
523  if( !r )
524  throw exception_t{ std::move(r.error().giveout_description()) };
525 
526  return std::move(*r);
527 }
528 
529 } /* namespace restinio */
restinio::exception_t
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
RESTINIO_NODISCARD
#define RESTINIO_NODISCARD
Definition: compiler_features.hpp:33
restinio::parse_query_traits::details::ampersand_and_semicolon_as_separators::find_next_separator
static string_view_t::size_type find_next_separator(string_view_t where, string_view_t::size_type start_from) noexcept
Definition: uri_helpers.hpp:197
restinio::query_string_params_t::m_parameters
parameters_container_t m_parameters
Definition: uri_helpers.hpp:164
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
restinio::parse_query_traits::details::ampersand_only_as_separators::find_next_separator
static string_view_t::size_type find_next_separator(string_view_t where, string_view_t::size_type start_from) noexcept
Definition: uri_helpers.hpp:217
restinio::query_string_params_t::query_string_params_t
query_string_params_t(std::unique_ptr< char[] > data_buffer, optional_t< string_view_t > tag)
Constructor for the case when query string contains only tag (web beacon).
Definition: uri_helpers.hpp:58
restinio::utils::x_www_form_urlencoded_unescape_traits
Traits for escaping and unexcaping symbols in a query string in correspondence with application/x-www...
Definition: percent_encoding.hpp:61
restinio::parse_query_failure_t::m_description
std::string m_description
Description of a failure.
Definition: uri_helpers.hpp:340
restinio::parse_query_traits::restinio_defaults
Traits for the default RESTinio parser for query string.
Definition: uri_helpers.hpp:247
restinio::string_view_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
restinio::query_string_params_t::begin
parameters_container_t::const_iterator begin() const noexcept
Definition: uri_helpers.hpp:107
restinio::query_string_params_t::get_param
optional_t< string_view_t > get_param(string_view_t key) const noexcept
Get the value of a parameter if it exists.
Definition: uri_helpers.hpp:88
restinio::parse_query_traits::details::ampersand_and_semicolon_as_separators
Helper class to be reused in implementation of query-string parsing traits.
Definition: uri_helpers.hpp:195
restinio::query_string_params_t::operator=
query_string_params_t & operator=(query_string_params_t &&)=default
restinio::query_string_params_t::operator[]
string_view_t operator[](string_view_t key) const
Get parameter.
Definition: uri_helpers.hpp:73
restinio::query_string_params_t::query_string_params_t
query_string_params_t(std::unique_ptr< char[] > data_buffer, parameters_container_t parameters)
Constructor for the case when query string empty of contains a set of key-value pairs.
Definition: uri_helpers.hpp:49
restinio::query_string_params_t::find_parameter
parameters_container_t::const_iterator find_parameter(string_view_t key) const noexcept
Definition: uri_helpers.hpp:135
restinio::parse_query_failure_t::description
RESTINIO_NODISCARD const std::string & description() const noexcept
Get a reference to the description of the failure.
Definition: uri_helpers.hpp:354
restinio::query_string_params_t::empty
bool empty() const noexcept
Is there any parameters?
Definition: uri_helpers.hpp:102
restinio::utils::unescape_percent_encoding_failure_t
Type that indicates a failure of unescaping of percent-encoded symbols.
Definition: percent_encoding.hpp:160
restinio::parse_query_traits::details::ampersand_only_as_separators
Helper class to be reused in implementation of query-string parsing traits.
Definition: uri_helpers.hpp:215
restinio::parse_query_traits::javascript_compatible
Traits for parsing a query string in JavaScript-compatible mode.
Definition: uri_helpers.hpp:265
restinio::utils::restinio_default_unescape_traits
The default traits for escaping and unexcaping symbols in a query string.
Definition: percent_encoding.hpp:36
restinio::try_parse_query
RESTINIO_NODISCARD expected_t< query_string_params_t, parse_query_failure_t > try_parse_query(string_view_t original_query_string)
Helper function for parsing query string.
Definition: uri_helpers.hpp:398
restinio::parse_query_failure_t::giveout_description
RESTINIO_NODISCARD std::string giveout_description() noexcept
Get out the value of the description of the failure.
Definition: uri_helpers.hpp:364
restinio::utils::relaxed_unescape_traits
Traits for escaping and unescaping symbols in a query string in very relaxed mode.
Definition: percent_encoding.hpp:97
restinio::impl::modified_memchr
const char * modified_memchr(int chr, const char *from, const char *to)
Definition: uri_helpers.hpp:27
restinio::query_string_params_t::query_string_params_t
query_string_params_t(query_string_params_t &&)=default
restinio::parse_query_failure_t::parse_query_failure_t
parse_query_failure_t(std::string description)
Definition: uri_helpers.hpp:343
nonstd::optional_lite::optional
class optional
Definition: optional.hpp:839
restinio::parse_query
RESTINIO_NODISCARD query_string_params_t parse_query(string_view_t original_query_string)
Parse query key-value parts.
Definition: uri_helpers.hpp:518
restinio::query_string_params_t::parameters_container_t
std::vector< std::pair< string_view_t, string_view_t > > parameters_container_t
Definition: uri_helpers.hpp:45
restinio::query_string_params_t::tag
auto tag() const noexcept
Get the tag (web beacon) part.
Definition: uri_helpers.hpp:131
include_fmtlib.hpp
A special wrapper around fmtlib include files.
restinio::utils::javascript_compatible_unescape_traits
The traits for escaping and unexcaping symbols in JavaScript-compatible mode.
Definition: percent_encoding.hpp:125
nonstd::optional_lite::nullopt
const nullopt_t nullopt((nullopt_t::init()))
restinio::parse_query_failure_t::parse_query_failure_t
parse_query_failure_t(utils::unescape_percent_encoding_failure_t &&failure)
Definition: uri_helpers.hpp:346
restinio::parse_query_traits::x_www_form_urlencoded
Traits for parsing a query string in application/x-www-form-urlencoded mode.
Definition: uri_helpers.hpp:292
restinio::query_string_params_t::size
auto size() const noexcept
Get the size of parameters.
Definition: uri_helpers.hpp:98
restinio::query_string_params_t::end
parameters_container_t::const_iterator end() const noexcept
Definition: uri_helpers.hpp:113
restinio::query_string_params_t::has
bool has(string_view_t key) const noexcept
Check parameter.
Definition: uri_helpers.hpp:80
restinio::query_string_params_t
Parameters container for query strings parameters.
Definition: uri_helpers.hpp:43
restinio
Definition: asio_include.hpp:21
exception.hpp
restinio::query_string_params_t::find_parameter_with_check
parameters_container_t::const_reference find_parameter_with_check(string_view_t key) const
Definition: uri_helpers.hpp:147
percent_encoding.hpp
restinio::query_string_params_t::m_data_buffer
std::unique_ptr< char[] > m_data_buffer
Shared buffer for string_view of named parameterts names.
Definition: uri_helpers.hpp:163
restinio::parse_query_traits::relaxed
Traits for parsing a query string in a very relaxed mode.
Definition: uri_helpers.hpp:328
restinio::query_string_params_t::m_tag
optional_t< string_view_t > m_tag
Tag (or web beacon) part.
Definition: uri_helpers.hpp:168
restinio::parse_query_failure_t
Type that indicates a failure of an attempt of query-string parsing.
Definition: uri_helpers.hpp:338
restinio::get
Value_Type get(const router::route_params_t &params, string_view_t key)
Cast named parameter value to a given type.
Definition: express.hpp:743
restinio::query_string_params_t::query_string_params_t
query_string_params_t(const query_string_params_t &)=delete
const
#define const
Definition: zconf.h:230
optional.hpp