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 
24 namespace restinio
25 {
26 
27 namespace file_upload
28 {
29 
30 //
31 // enumeration_error_t
32 //
40 {
44  content_type_field_not_found,
46  content_type_field_parse_error,
50  content_type_field_inappropriate_value,
53  illegal_boundary_value,
55  content_disposition_field_parse_error,
58  content_disposition_field_inappropriate_value,
60  no_parts_found,
65  no_files_found,
69  terminated_by_handler,
72 };
73 
74 namespace impl
75 {
76 
84 constexpr 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(
237  enumeration_error_t::content_disposition_field_parse_error );
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(
245  enumeration_error_t::content_disposition_field_inappropriate_value );
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 
273 namespace impl
274 {
275 
276 //
277 // valid_handler_type
278 //
279 template< typename, typename = restinio::utils::metaprogramming::void_t<> >
280 struct valid_handler_type : public std::false_type {};
281 
282 template< 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 
358 template< typename Handler >
362  const request_t & req,
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  }
391  else if( enumeration_error_t::no_files_found ==
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 
restinio::file_upload::part_description_t::fields
http_header_fields_t fields
HTTP-fields local for that part.
Definition: file_upload.hpp:153
RESTINIO_NODISCARD
#define RESTINIO_NODISCARD
Definition: compiler_features.hpp:33
restinio::file_upload::enumerate_parts_with_files
expected_t< std::size_t, enumeration_error_t > enumerate_parts_with_files(const request_t &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
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
restinio::file_upload::impl::translate_enumeration_error
constexpr RESTINIO_NODISCARD 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
request_handler.hpp
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::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::string_view_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
restinio::file_upload::part_description_t
A description of one part with an uploaded file.
Definition: file_upload.hpp:147
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::http_field_parsers
Definition: accept-charset.hpp:20
restinio::http_header_fields_t
Header fields map.
Definition: http_headers.hpp:703
restinio::multipart_body::parsed_part_t
A description of parsed content of one part of a multipart body.
Definition: multipart_body.hpp:144
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::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
content-disposition.hpp
Stuff related to value of Content-Disposition HTTP-field.
nonstd::optional_lite::optional
class optional
Definition: optional.hpp:839
restinio::multipart_body::enumerate_parts
RESTINIO_NODISCARD expected_t< std::size_t, enumeration_error_t > enumerate_parts(const request_t &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:685
restinio::utils::metaprogramming::void_t
typename make_void< Ts... >::type void_t
Definition: metaprogramming.hpp:28
restinio::expected_t
nonstd::expected< T, E > expected_t
Definition: expected.hpp:22
restinio::file_upload::part_description_t::name
std::string name
The value of Content-Disposition's 'name' parameter.
Definition: file_upload.hpp:157
restinio::multipart_body::parsed_part_t::body
string_view_t body
The body of that part.
Definition: multipart_body.hpp:152
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::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::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
Definition: asio_include.hpp:21
restinio::file_upload::part_description_t::body
string_view_t body
The body of that part.
Definition: file_upload.hpp:155
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::file_upload::part_description_t::filename
optional_t< std::string > filename
The value of Content-Disposition's 'filename' parameter.
Definition: file_upload.hpp:175
expected.hpp
restinio::file_upload::impl::valid_handler_type
Definition: file_upload.hpp:280
content-type.hpp
Stuff related to value of Content-Type HTTP-field.
multipart_body.hpp
Various tools for working with multipart bodies.
http_headers.hpp
restinio::multipart_body::parsed_part_t::fields
http_header_fields_t fields
HTTP-fields local for that part.
Definition: multipart_body.hpp:150
restinio::request_t
HTTP Request data.
Definition: request_handler.hpp:44