14 #include <restinio/helpers/string_algo.hpp> 15 #include <restinio/helpers/easy_parser.hpp> 16 #include <restinio/helpers/http_field_parsers/basics.hpp> 17 #include <restinio/helpers/http_field_parsers/content-type.hpp> 19 #include <restinio/http_headers.hpp> 20 #include <restinio/request_handler.hpp> 21 #include <restinio/expected.hpp> 23 #include <restinio/impl/string_caseless_compare.hpp> 25 #include <restinio/utils/metaprogramming.hpp> 76 using namespace restinio::string_algo;
78 std::vector< string_view_t > result;
79 std::vector< string_view_t > tmp_result;
81 const string_view_t eol{
"\r\n" };
82 const string_view_t last_separator{
"--\r\n" };
85 auto boundary_pos = body.find( boundary );
86 if( string_view_t::npos == boundary_pos )
92 if( boundary_pos != 0u &&
93 (boundary_pos < eol.size() ||
94 body.substr( boundary_pos - eol.size(), eol.size() ) != eol) )
97 auto remaining_body = body.substr( boundary_pos + boundary.size() );
98 if( starts_with( remaining_body, last_separator ) )
102 while( starts_with( remaining_body, eol ) )
104 remaining_body = remaining_body.substr( eol.size() );
106 boundary_pos = remaining_body.find( boundary );
107 if( string_view_t::npos == boundary_pos )
111 if( boundary_pos < eol.size() ||
112 remaining_body.substr( boundary_pos - eol.size(), eol.size() ) != eol )
115 tmp_result.push_back(
116 remaining_body.substr( 0u, boundary_pos - eol.size() ) );
118 remaining_body = remaining_body.substr( boundary_pos + boundary.size() );
120 if( starts_with( remaining_body, last_separator ) )
123 swap( tmp_result, result );
165 constexpr char CR =
'\r';
166 constexpr char LF =
'\n';
191 return from.fragment( from.current_position() );
214 std::string accumulator;
215 auto ch = from.getch();
216 while( !ch.m_eof && ch.m_ch != CR && ch.m_ch != LF )
218 accumulator += ch.m_ch;
223 return make_unexpected( easy_parser::parse_error_t{
224 from.current_position(),
225 easy_parser::error_reason_t::unexpected_eof
231 return { std::move(accumulator) };
258 return produce< parsed_part_t >(
259 produce< http_header_fields_t >(
261 produce< http_header_field_t >(
262 token_p() >> to_lower() >> custom_consumer(
263 [](
auto & f, std::string && v) {
264 f.name(std::move(v));
268 field_value_producer_t{} >> custom_consumer(
269 [](
auto & f, std::string && v) {
270 f.value(std::move(v));
272 symbol(CR), symbol(LF)
273 ) >> custom_consumer(
274 [](
auto & to, http_header_field_t && v) {
275 to.add_field( std::move(v) );
278 ) >> &parsed_part_t::fields,
279 symbol(CR), symbol(LF),
280 body_producer_t{} >> &parsed_part_t::body );
317 namespace easy_parser = restinio::easy_parser;
319 easy_parser::impl::source_t source{ part };
321 auto actual_producer = impl::make_parser();
323 return easy_parser::impl::top_level_clause_t<
decltype(actual_producer) >{
324 std::move(actual_producer)
325 }.try_process( source );
405 return (ch >=
'0' && ch <=
'9')
406 || ((ch >=
'A' && ch <=
'Z') || (ch >=
'a' && ch <=
'z'))
461 if( value.size() >= 1u && value.size() <= 70u )
463 const std::size_t last_index = value.size() - 1u;
464 for( std::size_t i = 0u; i != last_index; ++i )
465 if( !is_bchar( value[i] ) )
466 return enumeration_error_t::illegal_boundary_value;
468 if( !is_bcharnospace( value[ last_index ] ) )
469 return enumeration_error_t::illegal_boundary_value;
472 return enumeration_error_t::illegal_boundary_value;
494 template<
typename Extra_Data >
567 template<
typename Handler >
609 template<
typename T >
683 template<
typename User_Type,
typename Handler >
708 "Handler should be callable object, " 709 "should accept parsed_part_t by value, const or rvalue reference, " 710 "and should return handling_result_t" );
constexpr bool is_bcharnospace(char ch)
expected_t< std::string, easy_parser::parse_error_t > try_parse(easy_parser::impl::source_t &from) const
Enumeration of parts should be ignored. All remaining parts of multipart body will be skipped and the...
A special producer that consumes the whole remaining content from the input stream.
A description of parsed content of one part of a multipart body.
std::vector< string_view_t > split_multipart_body(string_view_t body, string_view_t boundary)
Helper function for spliting a multipart body into a serie of separate parts.
Value of 'boundary' parameter is invalid (for example it contains some illegal characters).
std::optional< enumeration_error_t > check_boundary_value(string_view_t value)
A helper function for checking the validity of 'boundary' value.
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container ¶ms, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
A special producer that consumes the rest of the current line in the input stream until CR/LF will be...
expected_t< std::string, enumeration_error_t > detect_boundary_for_multipart_body(const generic_request_t< Extra_Data > &req, string_view_t expected_media_type, std::optional< string_view_t > expected_media_subtype)
Helper function for parsing Content-Type field and extracting the value of 'boundary' parameter...
Unable to parse Content-Type field value.
expected_t< parsed_part_t, restinio::easy_parser::parse_error_t > try_parse_part(string_view_t part)
Helper function for parsing content of one part of a multipart body.
expected_t< std::size_t, enumeration_error_t > enumerate_parts_of_request_body(const std::vector< string_view_t > &parts, Handler &&handler)
A function that parses every part of a multipart body and calls a user-provided handler for every par...
Content-Type field is not found. If Content-Type is absent there is no way to detect 'boundary' param...
enumeration_error_t
The result of an attempt to enumerate parts of a multipart body.
string_view_t body
The body of that part.
No parts of a multipart body actually found.
Enumeration of parts was aborted by user-provided handler. This code is returned when user-provided h...
constexpr bool is_bchar(char ch)
auto make_parser()
A factory function for a parser of a part of multipart message.
Content-Type field value parsed but doesn't contain an appropriate value. For example there can be me...
http_header_fields_t fields
HTTP-fields local for that part.
expected_t< std::size_t, enumeration_error_t > enumerate_parts(const generic_request_t< User_Type > &req, Handler &&handler, string_view_t expected_media_type=string_view_t{ "multipart" }, std::optional< string_view_t > expected_media_subtype=std::nullopt)
A helper function for enumeration of parts of a multipart body.
Enumeration of parts should be continued. If there is another part the user-provided handler will be ...
expected_t< string_view_t, easy_parser::parse_error_t > try_parse(easy_parser::impl::source_t &from) const noexcept
Some unexpected error encountered during the enumeration.
Enumeration of parts should be stopped. All remaining parts of multipart body will be skipped...
handling_result_t
The result to be returned from user-provided handler of parts of multipart body.