RESTinio
sendfile.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
11 #pragma once
12 
13 #include <string>
14 #include <chrono>
15 #include <array>
16 
18 
20 #include <restinio/string_view.hpp>
21 #include <restinio/exception.hpp>
22 
23 /*
24  Defenitions for:
25  file_descriptor_t
26  file_offset_t
27  file_size_t
28 */
29 
30 #if defined( _MSC_VER ) || defined(__MINGW32__)
31  #include "sendfile_defs_win.hpp"
32 #elif (defined( __clang__ ) || defined( __GNUC__ )) && !defined(__WIN32__)
33  #include "sendfile_defs_posix.hpp"
34 #else
35  #if defined (RESTINIO_ENABLE_SENDFILE_DEFAULT_IMPL)
36  #include "sendfile_defs_default.hpp"
37  #else
38  #error "Sendfile not supported, to enable default implementation define RESTINIO_ENABLE_SENDFILE_DEFAULT_IMPL macro"
39  #endif
40 #endif
41 
42 namespace restinio
43 {
44 
47 constexpr file_size_t sendfile_default_chunk_size = 1024 * 1024;
48 
51 constexpr file_size_t sendfile_max_chunk_size = 1024 * 1024 * 1024;
52 
53 //
54 // sendfile_chunk_size_guarded_value_t
55 //
56 
58 
65 {
67  /*
68  - If chunk_size_value is zero returns 1.
69  - If chunk_size_value is greater than sendfile_max_chunk_size returns sendfile_max_chunk_size.
70  - Otherwise returns chunk_size_value itself.
71  */
72  static constexpr file_size_t
73  clarify_chunk_size( file_size_t chunk_size_value ) noexcept
74  {
75  if( 0 == chunk_size_value )
77 
78  if( sendfile_max_chunk_size < chunk_size_value )
80 
81  return chunk_size_value;
82  }
83 
84  public:
85 
86  constexpr sendfile_chunk_size_guarded_value_t( file_size_t chunk_size_value ) noexcept
87  : m_chunk_size{ clarify_chunk_size( chunk_size_value ) }
88  {}
89 
91  constexpr auto value() const noexcept { return m_chunk_size; }
92 
93  private:
96 };
97 
98 //
99 // file_descriptor_holder_t
100 //
101 
103 /*
104  Class is responsible for managing file descriptor as resource.
105 
106  @since v.0.4.3
107 */
109 {
110  public:
112  friend void
114  {
115  using std::swap;
116  swap( left.m_file_descriptor, right.m_file_descriptor );
117  }
118 
121  : m_file_descriptor{ fd }
122  {}
123 
131 
133  : m_file_descriptor{ fdh.m_file_descriptor }
134  {
135  fdh.release();
136  }
137 
139  {
140  if( this != &fdh )
141  {
142  file_descriptor_holder_t tmp{ std::move( fdh ) };
143  swap( *this, tmp );
144  }
145  return *this;
146  }
147 
149  {
150  if( is_valid() )
152  }
153 
155  bool is_valid() const noexcept
156  {
158  }
159 
160  //Get file descriptor.
162  {
163  return m_file_descriptor;
164  }
165 
166  // Release stored descriptor.
167  void release() noexcept
168  {
170  }
171 
172  private:
175 };
176 
177 //
178 // file_meta_t
179 //
180 
183 {
184  public:
185  friend void
186  swap( file_meta_t & r, file_meta_t & l ) noexcept
187  {
188  std::swap( r.m_file_total_size, l.m_file_total_size );
189  std::swap( r.m_last_modified_at, l.m_last_modified_at );
190  }
191 
192  file_meta_t() noexcept
193  {}
194 
197  std::chrono::system_clock::time_point last_modified_at ) noexcept
200  {}
201 
203 
204  auto last_modified_at() const noexcept { return m_last_modified_at; }
205 
206  private:
209 
211  std::chrono::system_clock::time_point m_last_modified_at{};
212 };
213 
214 //
215 // sendfile_t
216 //
217 
219 
226 {
227  friend sendfile_t sendfile(
229  file_meta_t ,
230  file_size_t ) noexcept;
231 
238  sendfile_chunk_size_guarded_value_t chunk ) noexcept
239  : m_file_descriptor{ std::move( fdh ) }
240  , m_meta{ meta }
241  , m_offset{ 0 }
243  , m_chunk_size{ chunk.value() }
245  {}
246 
247  public:
248  friend void
249  swap( sendfile_t & left, sendfile_t & right ) noexcept
250  {
251  using std::swap;
252  swap( left.m_file_descriptor, right.m_file_descriptor );
253  swap( left.m_meta, right.m_meta );
254  swap( left.m_offset, right.m_offset );
255  swap( left.m_size, right.m_size );
256  swap( left.m_chunk_size, right.m_chunk_size );
257  swap( left.m_timelimit, right.m_timelimit );
258  }
259 
263  sendfile_t( const sendfile_t & ) = delete;
265  sendfile_t & operator = ( const sendfile_t & ) = delete;
267 
271  sendfile_t( sendfile_t && sf ) noexcept
273  : m_file_descriptor{ std::move( sf.m_file_descriptor ) }
274  , m_meta{ sf.m_meta }
275  , m_offset{ sf.m_offset }
276  , m_size{ sf.m_size }
277  , m_chunk_size{ sf.m_chunk_size }
278  , m_timelimit{ sf.m_timelimit }
279  {}
280 
281  sendfile_t & operator = ( sendfile_t && sf ) noexcept
282  {
283  if( this != &sf )
284  {
285  sendfile_t tmp{ std::move( sf ) };
286  swap( *this, tmp );
287  }
288 
289  return *this;
290  }
292 
294  bool is_valid() const noexcept { return m_file_descriptor.is_valid(); }
295 
297  const file_meta_t & meta() const
298  {
299  return m_meta;
300  }
301 
303  auto offset() const noexcept { return m_offset; }
304 
306  auto size() const noexcept { return m_size; }
307 
317  sendfile_t &
320  file_offset_t offset_value,
321  file_size_t size_value = std::numeric_limits< file_size_t >::max() ) &
322  {
324 
325  if( static_cast< file_size_t >( offset_value ) > m_meta.file_total_size() )
326  {
327  throw exception_t{
328  fmt::format(
329  "invalid file offset: {}, while file size is {}",
330  offset_value,
331  m_meta.file_total_size() ) };
332  }
333 
334  m_offset = offset_value;
335  m_size =
336  std::min< file_size_t >(
337  m_meta.file_total_size() - static_cast< file_size_t >( offset_value ),
338  size_value );
339 
340  return *this;
341  }
342 
343  sendfile_t &&
345  file_offset_t offset_value,
346  file_size_t size_value = std::numeric_limits< file_size_t >::max() ) &&
347  {
348  return std::move( this->offset_and_size( offset_value, size_value ) );
349  }
351 
352  auto chunk_size() const noexcept { return m_chunk_size; }
353 
358  sendfile_t &
361  {
363 
364  m_chunk_size = chunk.value();
365  return *this;
366  }
367 
369  sendfile_t &&
371  {
372  return std::move( this->chunk_size( chunk ) );
373  }
375 
376  auto timelimit() const noexcept { return m_timelimit; }
377 
382  sendfile_t &
384  timelimit( std::chrono::steady_clock::duration timelimit_value ) &
385  {
387 
388  m_timelimit = std::max( timelimit_value, std::chrono::steady_clock::duration::zero() );
389  return *this;
390  }
391 
392  sendfile_t &&
393  timelimit( std::chrono::steady_clock::duration timelimit_value ) &&
394  {
395  return std::move( this->timelimit( timelimit_value ) );
396  }
398 
402  {
403  return m_file_descriptor.fd();
404  }
405 
407 
421  {
422  return std::move(target.m_file_descriptor);
423  }
424 
425  private:
427  void
429  {
430  if( !is_valid() )
431  {
432  throw exception_t{ "invalid file descriptor" };
433  }
434  }
435 
438 
441 
446 
449 
451 
454  std::chrono::steady_clock::duration m_timelimit{ std::chrono::steady_clock::duration::zero() };
455 };
456 
457 //
458 // sendfile()
459 //
460 
466 inline sendfile_t
474  file_size_t chunk_size = sendfile_default_chunk_size ) noexcept
475 {
476  return sendfile_t{ std::move( fd ), meta, chunk_size };
477 }
478 
479 inline sendfile_t
482  const char * file_path,
485 {
486  file_descriptor_holder_t fd{ open_file( file_path ) };
487 
488  auto meta = get_file_meta< file_meta_t >( fd.fd() );
489 
490  return sendfile( std::move( fd ), meta, chunk_size );
491 }
492 
493 inline sendfile_t
496  const std::string & file_path,
499 {
500  return sendfile( file_path.c_str(), chunk_size );
501 }
502 
503 inline sendfile_t
506  string_view_t file_path,
509 {
510  return
511  sendfile(
512  std::string{ file_path.data(), file_path.size() },
513  chunk_size );
514 }
516 
517 } /* namespace restinio */
restinio::exception_t
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
restinio::sendfile_t::offset
auto offset() const noexcept
Get offset of data to write.
Definition: sendfile.hpp:303
restinio::sendfile_t::m_size
file_size_t m_size
The size of data portion in file.
Definition: sendfile.hpp:445
restinio::sendfile_t::operator=
sendfile_t & operator=(const sendfile_t &)=delete
restinio::sendfile_t::sendfile_t
sendfile_t(file_descriptor_holder_t fdh, file_meta_t meta, sendfile_chunk_size_guarded_value_t chunk) noexcept
Definition: sendfile.hpp:232
restinio::file_meta_t::m_last_modified_at
std::chrono::system_clock::time_point m_last_modified_at
Last modification date.
Definition: sendfile.hpp:211
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
restinio::file_size_t
std::uint64_t file_size_t
Definition: sendfile_defs_default.hpp:23
string_view.hpp
restinio::sendfile_t::swap
friend void swap(sendfile_t &left, sendfile_t &right) noexcept
Definition: sendfile.hpp:249
asio_include.hpp
restinio::sendfile_t::timelimit
sendfile_t && timelimit(std::chrono::steady_clock::duration timelimit_value) &&
Definition: sendfile.hpp:393
sendfile_defs_default.hpp
restinio::file_descriptor_t
std::FILE * file_descriptor_t
Definition: sendfile_defs_default.hpp:21
restinio::file_descriptor_holder_t
Wrapper class for working with native file handler.
Definition: sendfile.hpp:109
restinio::http_field_parsers::qvalue_details::zero
constexpr underlying_uint_t zero
The minimal allowed value for a qvalue.
Definition: basics.hpp:41
restinio::sendfile_chunk_size_guarded_value_t::m_chunk_size
const file_size_t m_chunk_size
Valid value of the chunk size.
Definition: sendfile.hpp:95
restinio::file_offset_t
std::int64_t file_offset_t
Definition: sendfile_defs_default.hpp:22
restinio::close_file
void close_file(file_descriptor_t fd)
Close file by its descriptor.
Definition: sendfile_defs_default.hpp:89
restinio::sendfile_t::m_timelimit
std::chrono::steady_clock::duration m_timelimit
Timelimit for writing all the given data.
Definition: sendfile.hpp:454
restinio::string_view_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
restinio::sendfile_t::sendfile
friend sendfile_t sendfile(file_descriptor_holder_t, file_meta_t, file_size_t) noexcept
Definition: sendfile.hpp:468
restinio::sendfile_max_chunk_size
constexpr file_size_t sendfile_max_chunk_size
Maximum size of a chunk.
Definition: sendfile.hpp:51
restinio::utils::metaprogramming
Definition: metaprogramming.hpp:24
restinio::file_meta_t::swap
friend void swap(file_meta_t &r, file_meta_t &l) noexcept
Definition: sendfile.hpp:186
restinio::file_meta_t::file_meta_t
file_meta_t(file_size_t file_total_size, std::chrono::system_clock::time_point last_modified_at) noexcept
Definition: sendfile.hpp:195
restinio::sendfile_t::chunk_size
sendfile_t && chunk_size(sendfile_chunk_size_guarded_value_t chunk) &&
Set prefered chunk size to use in write operation.
Definition: sendfile.hpp:370
restinio::file_descriptor_holder_t::is_valid
bool is_valid() const noexcept
Check if file descriptor is valid.
Definition: sendfile.hpp:155
restinio::file_meta_t::file_meta_t
file_meta_t() noexcept
Definition: sendfile.hpp:192
restinio::sendfile_t::meta
const file_meta_t & meta() const
Get file meta data.
Definition: sendfile.hpp:297
restinio::sendfile
sendfile_t sendfile(file_descriptor_holder_t fd, file_meta_t meta, file_size_t chunk_size=sendfile_default_chunk_size) noexcept
Definition: sendfile.hpp:468
restinio::sendfile_t::chunk_size
auto chunk_size() const noexcept
Definition: sendfile.hpp:352
restinio::open_file
file_descriptor_t open_file(const char *file_path)
Open file.
Definition: sendfile_defs_default.hpp:40
restinio::file_descriptor_holder_t::release
void release() noexcept
Definition: sendfile.hpp:167
restinio::sendfile_chunk_size_guarded_value_t::clarify_chunk_size
static constexpr file_size_t clarify_chunk_size(file_size_t chunk_size_value) noexcept
Checks chunk_size_value and returns a value in [1, sendfile_max_chunk_size].
Definition: sendfile.hpp:73
restinio::sendfile_default_chunk_size
constexpr file_size_t sendfile_default_chunk_size
Default chunk size for sendfile operation.
Definition: sendfile.hpp:47
restinio::sendfile_chunk_size_guarded_value_t::value
constexpr auto value() const noexcept
Get the valid value of a chunk size.
Definition: sendfile.hpp:91
restinio::sendfile_t::timelimit
sendfile_t & timelimit(std::chrono::steady_clock::duration timelimit_value) &
Definition: sendfile.hpp:384
restinio::file_meta_t::last_modified_at
auto last_modified_at() const noexcept
Definition: sendfile.hpp:204
restinio::sendfile_t::check_file_is_valid
void check_file_is_valid() const
Check if stored file descriptor is valid, and throws if it is not.
Definition: sendfile.hpp:428
restinio::file_descriptor_holder_t::fd
file_descriptor_t fd() const noexcept
Definition: sendfile.hpp:161
restinio::sendfile_t::m_file_descriptor
file_descriptor_holder_t m_file_descriptor
Native file descriptor.
Definition: sendfile.hpp:437
restinio::sendfile_t::takeaway_file_descriptor
friend file_descriptor_holder_t takeaway_file_descriptor(sendfile_t &target)
Take away the file description form sendfile object.
Definition: sendfile.hpp:420
restinio::sendfile_t::m_meta
file_meta_t m_meta
File meta data.
Definition: sendfile.hpp:440
restinio::file_meta_t::file_total_size
file_size_t file_total_size() const noexcept
Definition: sendfile.hpp:202
restinio::null_file_descriptor
constexpr file_descriptor_t null_file_descriptor()
Get file descriptor which stands for null.
Definition: sendfile_defs_default.hpp:36
include_fmtlib.hpp
A special wrapper around fmtlib include files.
restinio::file_meta_t::m_file_total_size
file_size_t m_file_total_size
Total file size.
Definition: sendfile.hpp:208
restinio::sendfile_chunk_size_guarded_value_t::sendfile_chunk_size_guarded_value_t
constexpr sendfile_chunk_size_guarded_value_t(file_size_t chunk_size_value) noexcept
Definition: sendfile.hpp:86
restinio::file_descriptor_holder_t::m_file_descriptor
file_descriptor_t m_file_descriptor
Target file descriptor.
Definition: sendfile.hpp:174
restinio::sendfile_t::chunk_size
sendfile_t & chunk_size(sendfile_chunk_size_guarded_value_t chunk) &
Definition: sendfile.hpp:360
restinio::sendfile_t::timelimit
auto timelimit() const noexcept
Definition: sendfile.hpp:376
restinio
Definition: asio_include.hpp:21
restinio::sendfile_t::offset_and_size
sendfile_t && offset_and_size(file_offset_t offset_value, file_size_t size_value=std::numeric_limits< file_size_t >::max()) &&
Definition: sendfile.hpp:344
restinio::sendfile_t::m_chunk_size
file_size_t m_chunk_size
A prefered chunk size for a single write call.
Definition: sendfile.hpp:448
exception.hpp
restinio::sendfile_t::is_valid
bool is_valid() const noexcept
Check if file is valid.
Definition: sendfile.hpp:294
sendfile_defs_posix.hpp
restinio::sendfile_t::size
auto size() const noexcept
Get size of data to write.
Definition: sendfile.hpp:306
restinio::sendfile_t::m_offset
file_offset_t m_offset
Data offset within the file.
Definition: sendfile.hpp:443
nonstd::optional_lite::swap
void swap(optional< T > &x, optional< T > &y)
Definition: optional.hpp:1619
restinio::file_meta_t
Meta data of the file.
Definition: sendfile.hpp:183
restinio::file_descriptor_holder_t::operator=
file_descriptor_holder_t & operator=(const file_descriptor_holder_t &)=delete
restinio::file_descriptor_holder_t::~file_descriptor_holder_t
~file_descriptor_holder_t() noexcept
Definition: sendfile.hpp:148
restinio::sendfile_t
Send file write operation description.
Definition: sendfile.hpp:226
restinio::sendfile_t::file_descriptor
file_descriptor_t file_descriptor() const noexcept
Get the file descriptor of a given sendfile operation.
Definition: sendfile.hpp:401
sendfile_defs_win.hpp
restinio::file_descriptor_holder_t::file_descriptor_holder_t
file_descriptor_holder_t(file_descriptor_t fd) noexcept
Init constructor.
Definition: sendfile.hpp:120
restinio::sendfile_t::offset_and_size
sendfile_t & offset_and_size(file_offset_t offset_value, file_size_t size_value=std::numeric_limits< file_size_t >::max()) &
Definition: sendfile.hpp:319
restinio::file_descriptor_holder_t::file_descriptor_holder_t
file_descriptor_holder_t(file_descriptor_holder_t &&fdh) noexcept
Definition: sendfile.hpp:132
restinio::file_descriptor_holder_t::swap
friend void swap(file_descriptor_holder_t &left, file_descriptor_holder_t &right) noexcept
Swap two descriptors.
Definition: sendfile.hpp:113
restinio::sendfile_chunk_size_guarded_value_t
A guard class for setting chunk size.
Definition: sendfile.hpp:65
const
#define const
Definition: zconf.h:230