RESTinio
file_upload.hpp
Go to the documentation of this file.
1/*
2 * RESTinio
3 */
4
12#pragma once
13
17
20#include <restinio/expected.hpp>
21
22#include <iostream>
23
24namespace restinio
25{
26
27namespace file_upload
28{
29
30//
31// enumeration_error_t
32//
40{
72};
73
74namespace impl
75{
76
84constexpr enumeration_error_t
87{
89 using dest = enumeration_error_t;
90
91 dest result = dest::unexpected_error;
92
93 switch( original )
94 {
95 case source::content_type_field_not_found:
96 result = dest::content_type_field_not_found; break;
97
98 case source::content_type_field_parse_error:
99 result = dest::content_type_field_parse_error; break;
100
101 case source::content_type_field_inappropriate_value:
102 result = dest::content_type_field_inappropriate_value; break;
103
104 case source::illegal_boundary_value:
105 result = dest::illegal_boundary_value; break;
106
107 case source::no_parts_found:
108 result = dest::no_parts_found; break;
109
110 case source::terminated_by_handler:
111 result = dest::terminated_by_handler; break;
112
113 case source::unexpected_error:
114 /* nothing to do */ break;
115 }
116
117 return result;
118}
119
120} /* namespace impl */
121
122//
123// handling_result_t
124//
132
133//
134// part_description_t
135//
147{
149
157 std::string name;
159
171
176};
177
178//
179// analyze_part
180//
222{
223 namespace hfp = restinio::http_field_parsers;
224
225 // Content-Disposition field should be present.
226 const auto disposition_field = parsed_part.fields.opt_value_of(
227 restinio::http_field::content_disposition );
228 if( !disposition_field )
229 return make_unexpected( enumeration_error_t::no_files_found );
230
231 // Content-Disposition should have value `form-data` with
232 // `name` and `filename*`/`filename` parameters.
233 const auto parsed_disposition = hfp::content_disposition_value_t::
234 try_parse( *disposition_field );
235 if( !parsed_disposition )
236 return make_unexpected(
238 if( "form-data" != parsed_disposition->value )
239 return make_unexpected( enumeration_error_t::no_files_found );
240
241 const auto name = hfp::find_first(
242 parsed_disposition->parameters, "name" );
243 if( !name )
244 return make_unexpected(
246 const auto expected_to_optional = []( auto expected ) {
247 return expected ?
248 optional_t< std::string >{ std::string{
249 expected->data(),
250 expected->size()
251 } }
253 };
254
255 auto filename_star = expected_to_optional( hfp::find_first(
256 parsed_disposition->parameters, "filename*" ) );
257 auto filename = expected_to_optional( hfp::find_first(
258 parsed_disposition->parameters, "filename" ) );
259
260 // If there is no `filename*` nor `filename` then there is no file.
261 if( !filename_star && !filename )
262 return make_unexpected( enumeration_error_t::no_files_found );
263
264 return part_description_t{
265 std::move( parsed_part.fields ),
266 parsed_part.body,
267 std::string{ name->data(), name->size() },
268 std::move(filename_star),
269 std::move(filename)
270 };
271}
272
273namespace impl
274{
275
276//
277// valid_handler_type
278//
279template< typename, typename = restinio::utils::metaprogramming::void_t<> >
281
282template< typename T >
284 T,
286 std::enable_if_t<
287 std::is_same<
288 handling_result_t,
289 decltype(std::declval<T>()(std::declval<part_description_t>()))
290 >::value,
291 bool
292 >
293 >
294 > : public std::true_type
295{};
296
297} /* namespace impl */
298
358template< typename Extra_Data, typename Handler >
364 Handler && handler,
367 string_view_t expected_media_type = string_view_t{"multipart"},
369 string_view_t expected_media_subtype = string_view_t{"form-data"} )
370{
371 static_assert(
372 impl::valid_handler_type< std::decay_t<Handler> >::value,
373 "Handler should be callable object, "
374 "should accept part_description_t by value, const or rvalue reference, "
375 "and should return handling_result_t" );
376
377 std::size_t files_found{ 0u };
378 optional_t< enumeration_error_t > error;
379
380 const auto result = restinio::multipart_body::enumerate_parts( req,
381 [&handler, &files_found, &error]
383 {
384 auto part_description = analyze_part( std::move(part) );
385 if( part_description )
386 {
387 ++files_found;
388
389 return handler( std::move(*part_description) );
390 }
392 part_description.error() )
393 {
395 }
396 else
397 {
398 error = part_description.error();
399 return handling_result_t::terminate_enumeration;
400 }
401 },
402 expected_media_type,
403 expected_media_subtype );
404
405 if( error )
406 return make_unexpected( *error );
407 else if( !result )
408 return make_unexpected(
409 impl::translate_enumeration_error( result.error() ) );
410 else
411 return files_found;
412}
413
414} /* namespace file_upload */
415
416} /* namespace restinio */
417
optional_t< string_view_t > opt_value_of(string_view_t name) const noexcept
Get optional value of a field.
#define RESTINIO_NODISCARD
Stuff related to value of Content-Disposition HTTP-field.
Stuff related to value of Content-Type HTTP-field.
Various tools for working with multipart bodies.
bool_constant< false > false_type
Definition: optional.hpp:460
bool_constant< true > true_type
Definition: optional.hpp:459
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.
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_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 ...
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.
enumeration_error_t
The result of an attempt to enumerate parts of a multipart body that contains uploaded file.
Definition: file_upload.hpp:40
@ content_type_field_inappropriate_value
Content-Type field value parsed but doesn't contain an appropriate value. For example there can be me...
@ no_files_found
No files found in the current part. For example, there is no Content-Disposition field for that part,...
@ no_parts_found
No parts of a multipart body actually found.
@ illegal_boundary_value
Value of 'boundary' parameter is invalid (for example it contains some illegal characters).
@ content_type_field_not_found
Content-Type field is not found. If Content-Type is absent there is no way to detect 'boundary' param...
@ terminated_by_handler
Enumeration of parts was aborted by user-provided handler. This code is returned when user-provided h...
@ content_type_field_parse_error
Unable to parse Content-Type field value.
@ content_disposition_field_inappropriate_value
Content-Disposition field value parsed but doesn't contain an appropriate value. For example,...
@ unexpected_error
Some unexpected error encountered during the enumeration.
@ content_disposition_field_parse_error
Unable to parse Content-Disposition field.
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
handling_result_t
The result to be returned from user-provided handler of parts of multipart body.
@ continue_enumeration
Enumeration of parts should be continued. If there is another part the user-provided handler will be ...
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.
enumeration_error_t
The result of an attempt to enumerate parts of a multipart body.
typename make_void< Ts... >::type void_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
nonstd::expected< T, E > expected_t
Definition: expected.hpp:22
A description of one part with an uploaded file.
http_header_fields_t fields
HTTP-fields local for that part.
optional_t< std::string > filename
The value of Content-Disposition's 'filename' parameter.
std::string name
The value of Content-Disposition's 'name' parameter.
optional_t< std::string > filename_star
The value of Content-Disposition's 'filename*' parameter.
string_view_t body
The body of that part.
A description of parsed content of one part of a multipart body.
http_header_fields_t fields
HTTP-fields local for that part.
string_view_t body
The body of that part.