file_upload.hpp
Go to the documentation of this file.
/*
* RESTinio
*/
#pragma once
#include <restinio/helpers/http_field_parsers/content-type.hpp>
#include <restinio/helpers/http_field_parsers/content-disposition.hpp>
#include <restinio/helpers/multipart_body.hpp>
#include <restinio/http_headers.hpp>
#include <restinio/request_handler.hpp>
#include <restinio/expected.hpp>
#include <iostream>
namespace restinio
{
namespace file_upload
{
//
// enumeration_error_t
//
enum class enumeration_error_t
{
content_type_field_not_found,
content_type_field_parse_error,
content_type_field_inappropriate_value,
illegal_boundary_value,
content_disposition_field_parse_error,
content_disposition_field_inappropriate_value,
no_parts_found,
no_files_found,
terminated_by_handler,
unexpected_error
};
namespace impl
{
RESTINIO_NODISCARD
constexpr enumeration_error_t
translate_enumeration_error(
restinio::multipart_body::enumeration_error_t original )
{
using source = restinio::multipart_body::enumeration_error_t;
using dest = enumeration_error_t;
dest result = dest::unexpected_error;
switch( original )
{
case source::content_type_field_not_found:
result = dest::content_type_field_not_found; break;
case source::content_type_field_parse_error:
result = dest::content_type_field_parse_error; break;
case source::content_type_field_inappropriate_value:
result = dest::content_type_field_inappropriate_value; break;
case source::illegal_boundary_value:
result = dest::illegal_boundary_value; break;
case source::no_parts_found:
result = dest::no_parts_found; break;
case source::terminated_by_handler:
result = dest::terminated_by_handler; break;
case source::unexpected_error:
/* nothing to do */ break;
}
return result;
}
} /* namespace impl */
//
// handling_result_t
//
using handling_result_t = restinio::multipart_body::handling_result_t;
//
// part_description_t
//
struct part_description_t
{
http_header_fields_t fields;
string_view_t body;
std::string name;
optional_t< std::string > filename_star;
optional_t< std::string > filename;
};
//
// analyze_part
//
RESTINIO_NODISCARD
inline expected_t< part_description_t, enumeration_error_t >
analyze_part( restinio::multipart_body::parsed_part_t parsed_part )
{
namespace hfp = restinio::http_field_parsers;
// Content-Disposition field should be present.
const auto disposition_field = parsed_part.fields.opt_value_of(
restinio::http_field::content_disposition );
if( !disposition_field )
return make_unexpected( enumeration_error_t::no_files_found );
// Content-Disposition should have value `form-data` with
// `name` and `filename*`/`filename` parameters.
const auto parsed_disposition = hfp::content_disposition_value_t::
try_parse( *disposition_field );
if( !parsed_disposition )
return make_unexpected(
enumeration_error_t::content_disposition_field_parse_error );
if( "form-data" != parsed_disposition->value )
return make_unexpected( enumeration_error_t::no_files_found );
const auto name = hfp::find_first(
parsed_disposition->parameters, "name" );
if( !name )
return make_unexpected(
enumeration_error_t::content_disposition_field_inappropriate_value );
const auto expected_to_optional = []( auto expected ) {
return expected ?
optional_t< std::string >{ std::string{
expected->data(),
expected->size()
} }
: optional_t< std::string >{};
};
auto filename_star = expected_to_optional( hfp::find_first(
parsed_disposition->parameters, "filename*" ) );
auto filename = expected_to_optional( hfp::find_first(
parsed_disposition->parameters, "filename" ) );
// If there is no `filename*` nor `filename` then there is no file.
if( !filename_star && !filename )
return make_unexpected( enumeration_error_t::no_files_found );
return part_description_t{
std::move( parsed_part.fields ),
parsed_part.body,
std::string{ name->data(), name->size() },
std::move(filename_star),
std::move(filename)
};
}
namespace impl
{
//
// valid_handler_type
//
template< typename, typename = restinio::utils::metaprogramming::void_t<> >
struct valid_handler_type : public std::false_type {};
template< typename T >
struct valid_handler_type<
T,
restinio::utils::metaprogramming::void_t<
std::enable_if_t<
std::is_same<
handling_result_t,
decltype(std::declval<T>()(std::declval<part_description_t>()))
>::value,
bool
>
>
> : public std::true_type
{};
} /* namespace impl */
template< typename Extra_Data, typename Handler >
expected_t< std::size_t, enumeration_error_t >
enumerate_parts_with_files(
const generic_request_t< Extra_Data > & req,
Handler && handler,
string_view_t expected_media_type = string_view_t{"multipart"},
string_view_t expected_media_subtype = string_view_t{"form-data"} )
{
static_assert(
impl::valid_handler_type< std::decay_t<Handler> >::value,
"Handler should be callable object, "
"should accept part_description_t by value, const or rvalue reference, "
"and should return handling_result_t" );
std::size_t files_found{ 0u };
optional_t< enumeration_error_t > error;
const auto result = restinio::multipart_body::enumerate_parts( req,
[&handler, &files_found, &error]
( restinio::multipart_body::parsed_part_t part )
{
auto part_description = analyze_part( std::move(part) );
if( part_description )
{
++files_found;
return handler( std::move(*part_description) );
}
else if( enumeration_error_t::no_files_found ==
part_description.error() )
{
return handling_result_t::continue_enumeration;
}
else
{
error = part_description.error();
return handling_result_t::terminate_enumeration;
}
},
expected_media_type,
expected_media_subtype );
if( error )
return make_unexpected( *error );
else if( !result )
return make_unexpected(
impl::translate_enumeration_error( result.error() ) );
else
return files_found;
}
} /* namespace file_upload */
} /* namespace restinio */
nonstd::optional_lite::optional
class optional
Definition: optional.hpp:919
restinio::generic_request_t
HTTP Request data.
Definition: request_handler.hpp:201
restinio::http_header_fields_t
Header fields map.
Definition: http_headers.hpp:703
restinio::http_header_fields_t::opt_value_of
optional_t< string_view_t > opt_value_of(string_view_t name) const noexcept
Get optional value of a field.
Definition: http_headers.hpp:1300
RESTINIO_NODISCARD
#define RESTINIO_NODISCARD
Definition: compiler_features.hpp:33
content-disposition.hpp
Stuff related to value of Content-Disposition HTTP-field.
content-type.hpp
Stuff related to value of Content-Type HTTP-field.
expected.hpp
http_headers.hpp
multipart_body.hpp
Various tools for working with multipart bodies.
nonstd::optional_lite::std11::false_type
bool_constant< false > false_type
Definition: optional.hpp:460
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:465
nonstd::optional_lite::std11::true_type
bool_constant< true > true_type
Definition: optional.hpp:459
restinio::easy_parser::try_parse
RESTINIO_NODISCARD expected_t< typename Producer::result_type, parse_error_t > try_parse(string_view_t from, Producer producer)
Perform the parsing of the specified content by using specified value producer.
Definition: easy_parser.hpp:5042
restinio::file_upload::impl::translate_enumeration_error
RESTINIO_NODISCARD constexpr enumeration_error_t translate_enumeration_error(restinio::multipart_body::enumeration_error_t original)
Helper function for conversion from one enumeration_error to another.
Definition: file_upload.hpp:85
restinio::file_upload::analyze_part
RESTINIO_NODISCARD expected_t< part_description_t, enumeration_error_t > analyze_part(restinio::multipart_body::parsed_part_t parsed_part)
Helper function for analyzing an already parsed part of a multipart body for presence of an uploaded ...
Definition: file_upload.hpp:221
restinio::file_upload::enumerate_parts_with_files
expected_t< std::size_t, enumeration_error_t > enumerate_parts_with_files(const generic_request_t< Extra_Data > &req, Handler &&handler, string_view_t expected_media_type=string_view_t{"multipart"}, string_view_t expected_media_subtype=string_view_t{"form-data"})
A helper function for enumeration of parts of a multipart body those contain uploaded files.
Definition: file_upload.hpp:360
restinio::file_upload::enumeration_error_t
enumeration_error_t
The result of an attempt to enumerate parts of a multipart body that contains uploaded file.
Definition: file_upload.hpp:40
restinio::file_upload::enumeration_error_t::content_type_field_inappropriate_value
@ content_type_field_inappropriate_value
Content-Type field value parsed but doesn't contain an appropriate value. For example there can be me...
restinio::file_upload::enumeration_error_t::no_files_found
@ no_files_found
No files found in the current part. For example, there is no Content-Disposition field for that part,...
restinio::file_upload::enumeration_error_t::no_parts_found
@ no_parts_found
No parts of a multipart body actually found.
restinio::file_upload::enumeration_error_t::illegal_boundary_value
@ illegal_boundary_value
Value of 'boundary' parameter is invalid (for example it contains some illegal characters).
restinio::file_upload::enumeration_error_t::content_type_field_not_found
@ content_type_field_not_found
Content-Type field is not found. If Content-Type is absent there is no way to detect 'boundary' param...
restinio::file_upload::enumeration_error_t::terminated_by_handler
@ terminated_by_handler
Enumeration of parts was aborted by user-provided handler. This code is returned when user-provided h...
restinio::file_upload::enumeration_error_t::content_type_field_parse_error
@ content_type_field_parse_error
Unable to parse Content-Type field value.
restinio::file_upload::enumeration_error_t::content_disposition_field_inappropriate_value
@ content_disposition_field_inappropriate_value
Content-Disposition field value parsed but doesn't contain an appropriate value. For example,...
restinio::file_upload::enumeration_error_t::unexpected_error
@ unexpected_error
Some unexpected error encountered during the enumeration.
restinio::file_upload::enumeration_error_t::content_disposition_field_parse_error
@ content_disposition_field_parse_error
Unable to parse Content-Disposition field.
restinio::http_field_parsers
Definition: accept-charset.hpp:20
restinio::http_field_parsers::find_first
RESTINIO_NODISCARD expected_t< string_view_t, not_found_t > find_first(const parameter_with_mandatory_value_container_t &where, string_view_t what)
A helper function to find the first occurence of a parameter with the specified value.
Definition: basics.hpp:1568
restinio::multipart_body::handling_result_t
handling_result_t
The result to be returned from user-provided handler of parts of multipart body.
Definition: multipart_body.hpp:338
restinio::multipart_body::handling_result_t::continue_enumeration
@ continue_enumeration
Enumeration of parts should be continued. If there is another part the user-provided handler will be ...
restinio::multipart_body::enumerate_parts
RESTINIO_NODISCARD 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" }, optional_t< string_view_t > expected_media_subtype=nullopt)
A helper function for enumeration of parts of a multipart body.
Definition: multipart_body.hpp:686
restinio::multipart_body::enumeration_error_t
enumeration_error_t
The result of an attempt to enumerate parts of a multipart body.
Definition: multipart_body.hpp:362
restinio::utils::metaprogramming::void_t
typename make_void< Ts... >::type void_t
Definition: metaprogramming.hpp:28
restinio
Definition: asio_include.hpp:21
restinio::string_view_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
restinio::expected_t
nonstd::expected< T, E > expected_t
Definition: expected.hpp:22
request_handler.hpp
restinio::file_upload::impl::valid_handler_type
Definition: file_upload.hpp:280
restinio::file_upload::part_description_t
A description of one part with an uploaded file.
Definition: file_upload.hpp:147
restinio::file_upload::part_description_t::fields
http_header_fields_t fields
HTTP-fields local for that part.
Definition: file_upload.hpp:153
restinio::file_upload::part_description_t::filename
optional_t< std::string > filename
The value of Content-Disposition's 'filename' parameter.
Definition: file_upload.hpp:175
restinio::file_upload::part_description_t::name
std::string name
The value of Content-Disposition's 'name' parameter.
Definition: file_upload.hpp:157
restinio::file_upload::part_description_t::filename_star
optional_t< std::string > filename_star
The value of Content-Disposition's 'filename*' parameter.
Definition: file_upload.hpp:169
restinio::file_upload::part_description_t::body
string_view_t body
The body of that part.
Definition: file_upload.hpp:155
restinio::multipart_body::parsed_part_t
A description of parsed content of one part of a multipart body.
Definition: multipart_body.hpp:144
restinio::multipart_body::parsed_part_t::fields
http_header_fields_t fields
HTTP-fields local for that part.
Definition: multipart_body.hpp:150
restinio::multipart_body::parsed_part_t::body
string_view_t body
The body of that part.
Definition: multipart_body.hpp:152