RESTinio
Loading...
Searching...
No Matches
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
18#include <restinio/optional.hpp>
19
20namespace restinio
21{
22
23namespace impl
24{
25
26inline const char *
27modified_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(
156 "unable to find parameter \"{}\"" ),
157 std::string{ key.data(), key.size() } ) };
158 }
159
160 return *it;
161 }
162
164 std::unique_ptr< char[] > m_data_buffer;
166
168
170};
171
173template < typename Value_Type >
174Value_Type
176{
177 return get< Value_Type >( params[ key ] );
178}
179
180namespace parse_query_traits
181{
182
183namespace details
184{
185
196{
197 static string_view_t::size_type
199 string_view_t where,
200 string_view_t::size_type start_from ) noexcept
201 {
202 return where.find_first_of( "&;", start_from );
203 }
204};
205
216{
217 static string_view_t::size_type
219 string_view_t where,
220 string_view_t::size_type start_from ) noexcept
221 {
222 return where.find_first_of( '&', start_from );
223 }
224};
225
226} /* namespace details */
227
248{};
249
266{};
267
293{};
294
329{};
330
331} /* namespace parse_query_traits */
332
339{
341 std::string m_description;
342
343public:
345 : m_description{ std::move(description) }
346 {}
350 {}
351
354 const std::string &
355 description() const noexcept { return m_description; }
356
358
364 std::string
365 giveout_description() noexcept { return m_description; }
366};
367
396template< typename Parse_Traits >
398expected_t< query_string_params_t, parse_query_failure_t >
401 string_view_t original_query_string )
402{
403 std::unique_ptr< char[] > data_buffer;
405
406 if( !original_query_string.empty() )
407 {
408 // Because query string is not empty a new buffer should be
409 // allocated and query string should be copied to it.
410 data_buffer.reset( new char[ original_query_string.size() ] );
411 std::memcpy(
412 data_buffer.get(),
413 original_query_string.data(),
414 original_query_string.size() );
415
416 // Work with created buffer:
417 string_view_t work_query_string{
418 data_buffer.get(),
419 original_query_string.size()
420 };
421 string_view_t::size_type pos{ 0 };
422 const string_view_t::size_type end_pos = work_query_string.size();
423
424 while( pos < end_pos )
425 {
426 const auto eq_pos = work_query_string.find_first_of( '=', pos );
427
428 if( string_view_t::npos == eq_pos )
429 {
430 // Since v.0.4.9 we should check the presence of tag (web beacon)
431 // in query string.
432 // Tag can be the only item in query string.
433 if( pos != 0u )
434 // The query string has illegal format.
435 return make_unexpected( parse_query_failure_t{
436 fmt::format(
438 "invalid format of key-value pairs in query_string, "
439 "no '=' symbol starting from position {}" ),
440 pos )
441 } );
442 else
443 {
444 // Query string contains only tag (web beacon).
445 auto tag_unescape_result =
446 utils::try_inplace_unescape_percent_encoding< Parse_Traits >(
447 &data_buffer[ pos ],
448 end_pos - pos );
449 if( !tag_unescape_result )
450 return make_unexpected( parse_query_failure_t{
451 std::move(tag_unescape_result.error())
452 } );
453
454 const string_view_t tag = work_query_string.substr(
455 pos, *tag_unescape_result );
456
457 return query_string_params_t{ std::move( data_buffer ), tag };
458 }
459 }
460
461 const auto eq_pos_next = eq_pos + 1u;
462 auto separator_pos = Parse_Traits::find_next_separator(
463 work_query_string, eq_pos_next );
464 if( string_view_t::npos == separator_pos )
465 separator_pos = work_query_string.size();
466
467 // Handle next pair of parameters found.
468 auto key_unescape_result =
469 utils::try_inplace_unescape_percent_encoding< Parse_Traits >(
470 &data_buffer[ pos ],
471 eq_pos - pos );
472 if( !key_unescape_result )
473 return make_unexpected( parse_query_failure_t{
474 std::move(key_unescape_result.error())
475 } );
476
477 auto value_unescape_result =
478 utils::try_inplace_unescape_percent_encoding< Parse_Traits >(
479 &data_buffer[ eq_pos_next ],
480 separator_pos - eq_pos_next );
481 if( !value_unescape_result )
482 return make_unexpected( parse_query_failure_t{
483 std::move(value_unescape_result.error())
484 } );
485
486 parameters.emplace_back(
487 string_view_t{ &data_buffer[ pos ], *key_unescape_result },
488 string_view_t{ &data_buffer[ eq_pos_next ], *value_unescape_result } );
489
490 pos = separator_pos + 1u;
491 }
492 }
493
495 std::move( data_buffer ),
496 std::move( parameters )
497 };
498}
499
501
517template< typename Parse_Traits = parse_query_traits::restinio_defaults >
519query_string_params_t
522 string_view_t original_query_string )
523{
524 auto r = try_parse_query< Parse_Traits >( original_query_string );
525 if( !r )
526 throw exception_t{ std::move(r.error().giveout_description()) };
527
528 return std::move(*r);
529}
530
531} /* namespace restinio */
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
Type that indicates a failure of an attempt of query-string parsing.
RESTINIO_NODISCARD const std::string & description() const noexcept
Get a reference to the description of the failure.
RESTINIO_NODISCARD std::string giveout_description() noexcept
Get out the value of the description of the failure.
std::string m_description
Description of a failure.
parse_query_failure_t(std::string description)
parse_query_failure_t(utils::unescape_percent_encoding_failure_t &&failure)
Parameters container for query strings parameters.
Definition: uri_helpers.hpp:43
std::unique_ptr< char[] > m_data_buffer
Shared buffer for string_view of named parameterts names.
query_string_params_t(query_string_params_t &&)=default
auto tag() const noexcept
Get the tag (web beacon) part.
bool empty() const noexcept
Is there any parameters?
auto size() const noexcept
Get the size of parameters.
Definition: uri_helpers.hpp:98
parameters_container_t::const_iterator begin() const noexcept
query_string_params_t & operator=(query_string_params_t &&)=default
string_view_t operator[](string_view_t key) const
Get parameter.
Definition: uri_helpers.hpp:73
parameters_container_t m_parameters
std::vector< std::pair< string_view_t, string_view_t > > parameters_container_t
Definition: uri_helpers.hpp:45
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
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
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
parameters_container_t::const_iterator find_parameter(string_view_t key) const noexcept
optional_t< string_view_t > m_tag
Tag (or web beacon) part.
parameters_container_t::const_reference find_parameter_with_check(string_view_t key) const
parameters_container_t::const_iterator end() const noexcept
bool has(string_view_t key) const noexcept
Check parameter.
Definition: uri_helpers.hpp:80
query_string_params_t(const query_string_params_t &)=delete
Type that indicates a failure of unescaping of percent-encoded symbols.
#define RESTINIO_NODISCARD
A special wrapper around fmtlib include files.
#define RESTINIO_FMT_FORMAT_STRING(s)
const char * modified_memchr(int chr, const char *from, const char *to)
Definition: uri_helpers.hpp:27
nonstd::string_view string_view_t
Definition: string_view.hpp:19
RESTINIO_NODISCARD query_string_params_t parse_query(string_view_t original_query_string)
Parse query key-value parts.
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.
Value_Type get(const router::route_params_t &params, string_view_t key)
Cast named parameter value to a given type.
Definition: express.hpp:854
STL namespace.
Helper class to be reused in implementation of query-string parsing traits.
static string_view_t::size_type find_next_separator(string_view_t where, string_view_t::size_type start_from) noexcept
Helper class to be reused in implementation of query-string parsing traits.
static string_view_t::size_type find_next_separator(string_view_t where, string_view_t::size_type start_from) noexcept
Traits for parsing a query string in JavaScript-compatible mode.
Traits for parsing a query string in a very relaxed mode.
Traits for the default RESTinio parser for query string.
Traits for parsing a query string in application/x-www-form-urlencoded mode.
The traits for escaping and unexcaping symbols in JavaScript-compatible mode.
Traits for escaping and unescaping symbols in a query string in very relaxed mode.
The default traits for escaping and unexcaping symbols in a query string.
Traits for escaping and unexcaping symbols in a query string in correspondence with application/x-www...
#define const
Definition: zconf.h:230