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
17#include <restinio/impl/include_fmtlib.hpp>
18
19#include <restinio/asio_include.hpp>
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
64 class sendfile_chunk_size_guarded_value_t
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 )
76 return sendfile_default_chunk_size;
77
78 if( sendfile_max_chunk_size < chunk_size_value )
79 return sendfile_max_chunk_size;
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:
95 const file_size_t m_chunk_size;
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*/
108 class file_descriptor_holder_t
109{
110 public:
112 friend void
113 swap( file_descriptor_holder_t & left, file_descriptor_holder_t & right ) noexcept
114 {
115 using std::swap;
116 swap( left.m_file_descriptor, right.m_file_descriptor );
117 }
118
120 file_descriptor_holder_t( file_descriptor_t fd ) noexcept
121 : m_file_descriptor{ fd }
122 {}
123
128 file_descriptor_holder_t( const file_descriptor_holder_t & ) = delete;
129 file_descriptor_holder_t & operator = ( const file_descriptor_holder_t & ) = delete;
131
132 file_descriptor_holder_t( file_descriptor_holder_t && fdh ) noexcept
133 : m_file_descriptor{ fdh.m_file_descriptor }
134 {
135 fdh.release();
136 }
137
138 file_descriptor_holder_t & operator = ( file_descriptor_holder_t && fdh ) noexcept
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
148 ~file_descriptor_holder_t() noexcept
149 {
150 if( is_valid() )
151 close_file( m_file_descriptor );
152 }
153
155 bool is_valid() const noexcept
156 {
157 return null_file_descriptor() != m_file_descriptor;
158 }
159
160 //Get file descriptor.
161 file_descriptor_t fd() const noexcept
162 {
163 return m_file_descriptor;
164 }
165
166 // Release stored descriptor.
167 void release() noexcept
168 {
169 m_file_descriptor = null_file_descriptor();
170 }
171
172 private:
174 file_descriptor_t m_file_descriptor;
175};
176
177//
178// file_meta_t
179//
180
182 class file_meta_t
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
195 file_meta_t(
196 file_size_t file_total_size,
197 std::chrono::system_clock::time_point last_modified_at ) noexcept
198 : m_file_total_size{ file_total_size }
199 , m_last_modified_at{ last_modified_at }
200 {}
201
202 file_size_t file_total_size() const noexcept { return m_file_total_size; }
203
204 auto last_modified_at() const noexcept { return m_last_modified_at; }
205
206 private:
208 file_size_t m_file_total_size{ 0 };
209
211 std::chrono::system_clock::time_point m_last_modified_at{};
212};
213
214//
215// sendfile_t
216//
217
219
225 class sendfile_t
226{
227 friend sendfile_t sendfile(
228 file_descriptor_holder_t ,
229 file_meta_t ,
230 file_size_t ) noexcept;
231
232 sendfile_t(
234 file_descriptor_holder_t fdh,
236 file_meta_t meta,
238 sendfile_chunk_size_guarded_value_t chunk ) noexcept
239 : m_file_descriptor{ std::move( fdh ) }
240 , m_meta{ meta }
241 , m_offset{ 0 }
242 , m_size{ m_meta.file_total_size() }
243 , m_chunk_size{ chunk.value() }
244 , m_timelimit{ std::chrono::steady_clock::duration::zero() }
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
264 sendfile_t( const sendfile_t & ) = delete;
265 sendfile_t & operator = ( const sendfile_t & ) = delete;
267
272 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
318 sendfile_t &
319 offset_and_size(
320 file_offset_t offset_value,
321 file_size_t size_value = std::numeric_limits< file_size_t >::max() ) &
322 {
323 check_file_is_valid();
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 &&
344 offset_and_size(
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
359 sendfile_t &
360 chunk_size( sendfile_chunk_size_guarded_value_t chunk ) &
361 {
362 check_file_is_valid();
363
364 m_chunk_size = chunk.value();
365 return *this;
366 }
367
369 sendfile_t &&
370 chunk_size( sendfile_chunk_size_guarded_value_t chunk ) &&
371 {
372 return std::move( this->chunk_size( chunk ) );
373 }
375
376 auto timelimit() const noexcept { return m_timelimit; }
377
383 sendfile_t &
384 timelimit( std::chrono::steady_clock::duration timelimit_value ) &
385 {
386 check_file_is_valid();
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
400 file_descriptor_t
401 file_descriptor() const noexcept
402 {
403 return m_file_descriptor.fd();
404 }
405
407
419 friend file_descriptor_holder_t
420 takeaway_file_descriptor( sendfile_t & target )
421 {
422 return std::move(target.m_file_descriptor);
423 }
424
425 private:
427 void
428 check_file_is_valid() const
429 {
430 if( !is_valid() )
431 {
432 throw exception_t{ "invalid file descriptor" };
433 }
434 }
435
437 file_descriptor_holder_t m_file_descriptor;
438
440 file_meta_t m_meta;
441
443 file_offset_t m_offset;
445 file_size_t m_size;
446
448 file_size_t m_chunk_size;
449
451
454 std::chrono::steady_clock::duration m_timelimit{ std::chrono::steady_clock::duration::zero() };
455};
456
457//
458// sendfile()
459//
460
467 inline sendfile_t
468 sendfile(
470 file_descriptor_holder_t fd,
472 file_meta_t meta,
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
480 sendfile(
482 const char * file_path,
484 file_size_t chunk_size = sendfile_default_chunk_size )
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
494 sendfile(
496 const std::string & file_path,
498 file_size_t chunk_size = sendfile_default_chunk_size )
499{
500 return sendfile( file_path.c_str(), chunk_size );
501}
502
503 inline sendfile_t
504 sendfile(
506 string_view_t file_path,
508 file_size_t chunk_size = sendfile_default_chunk_size )
509{
510 return
511 sendfile(
512 std::string{ file_path.data(), file_path.size() },
513 chunk_size );
514}
516
517} /* namespace restinio */
asio_include.hpp
restinio::exception_t
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
restinio::file_descriptor_holder_t
Wrapper class for working with native file handler.
Definition: sendfile.hpp:109
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::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::file_descriptor_holder_t::m_file_descriptor
file_descriptor_t m_file_descriptor
Target file descriptor.
Definition: sendfile.hpp:174
restinio::file_descriptor_holder_t::is_valid
bool is_valid() const noexcept
Check if file descriptor is valid.
Definition: sendfile.hpp:155
restinio::file_descriptor_holder_t::file_descriptor_holder_t
file_descriptor_holder_t(const file_descriptor_holder_t &)=delete
restinio::file_descriptor_holder_t::release
void release() noexcept
Definition: sendfile.hpp:167
restinio::file_descriptor_holder_t::fd
file_descriptor_t fd() const noexcept
Definition: sendfile.hpp:161
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::file_meta_t
Meta data of the file.
Definition: sendfile.hpp:183
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
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::file_meta_t::last_modified_at
auto last_modified_at() const noexcept
Definition: sendfile.hpp:204
restinio::file_meta_t::file_total_size
file_size_t file_total_size() const noexcept
Definition: sendfile.hpp:202
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::m_file_total_size
file_size_t m_file_total_size
Total file size.
Definition: sendfile.hpp:208
restinio::file_meta_t::file_meta_t
file_meta_t() noexcept
Definition: sendfile.hpp:192
restinio::sendfile_chunk_size_guarded_value_t
A guard class for setting chunk size.
Definition: sendfile.hpp:65
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_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::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_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::sendfile_t
Send file write operation description.
Definition: sendfile.hpp:226
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::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::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::sendfile_t::m_meta
file_meta_t m_meta
File meta data.
Definition: sendfile.hpp:440
restinio::sendfile_t::m_file_descriptor
file_descriptor_holder_t m_file_descriptor
Native file descriptor.
Definition: sendfile.hpp:437
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::sendfile_t::timelimit
sendfile_t & timelimit(std::chrono::steady_clock::duration timelimit_value) &
Definition: sendfile.hpp:384
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
restinio::sendfile_t::timelimit
sendfile_t && timelimit(std::chrono::steady_clock::duration timelimit_value) &&
Definition: sendfile.hpp:393
restinio::sendfile_t::chunk_size
sendfile_t & chunk_size(sendfile_chunk_size_guarded_value_t chunk) &
Definition: sendfile.hpp:360
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
restinio::sendfile_t::size
auto size() const noexcept
Get size of data to write.
Definition: sendfile.hpp:306
restinio::sendfile_t::swap
friend void swap(sendfile_t &left, sendfile_t &right) noexcept
Definition: sendfile.hpp:249
restinio::sendfile_t::chunk_size
auto chunk_size() const noexcept
Definition: sendfile.hpp:352
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::timelimit
auto timelimit() const noexcept
Definition: sendfile.hpp:376
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::sendfile_t::is_valid
bool is_valid() const noexcept
Check if file is valid.
Definition: sendfile.hpp:294
restinio::sendfile_t::sendfile_t
sendfile_t(const sendfile_t &)=delete
restinio::sendfile_t::operator=
sendfile_t & operator=(const sendfile_t &)=delete
restinio::sendfile_t::sendfile_t
sendfile_t(sendfile_t &&sf) noexcept
Definition: sendfile.hpp:272
restinio::sendfile_t::m_offset
file_offset_t m_offset
Data offset within the file.
Definition: sendfile.hpp:443
restinio::sendfile_t::meta
const file_meta_t & meta() const
Get file meta data.
Definition: sendfile.hpp:297
restinio::sendfile_t::offset
auto offset() const noexcept
Get offset of data to write.
Definition: sendfile.hpp:303
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_t::m_timelimit
std::chrono::steady_clock::duration m_timelimit
Timelimit for writing all the given data.
Definition: sendfile.hpp:454
restinio::sendfile_t::m_size
file_size_t m_size
The size of data portion in file.
Definition: sendfile.hpp:445
exception.hpp
include_fmtlib.hpp
A special wrapper around fmtlib include files.
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:465
nonstd::optional_lite::swap
void swap(optional< T > &x, optional< T > &y)
Definition: optional.hpp:1705
restinio::http_field_parsers::qvalue_details::zero
constexpr underlying_uint_t zero
The minimal allowed value for a qvalue.
Definition: basics.hpp:41
restinio::utils::metaprogramming
Definition: metaprogramming.hpp:24
restinio
Definition: asio_include.hpp:21
restinio::sendfile_max_chunk_size
constexpr file_size_t sendfile_max_chunk_size
Maximum size of a chunk.
Definition: sendfile.hpp:51
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::null_file_descriptor
constexpr file_descriptor_t null_file_descriptor()
Get file descriptor which stands for null.
Definition: sendfile_defs_default.hpp:36
restinio::file_size_t
std::uint64_t file_size_t
Definition: sendfile_defs_default.hpp:23
restinio::string_view_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
restinio::close_file
void close_file(file_descriptor_t fd)
Close file by its descriptor.
Definition: sendfile_defs_default.hpp:89
restinio::file_offset_t
std::int64_t file_offset_t
Definition: sendfile_defs_default.hpp:22
restinio::file_descriptor_t
std::FILE * file_descriptor_t
Definition: sendfile_defs_default.hpp:21
restinio::open_file
file_descriptor_t open_file(const char *file_path)
Open file.
Definition: sendfile_defs_default.hpp:40
restinio::sendfile_default_chunk_size
constexpr file_size_t sendfile_default_chunk_size
Default chunk size for sendfile operation.
Definition: sendfile.hpp:47
sendfile_defs_default.hpp
sendfile_defs_posix.hpp
sendfile_defs_win.hpp
string_view.hpp
const
#define const
Definition: zconf.h:230