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
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__)
34#else
35 #if defined (RESTINIO_ENABLE_SENDFILE_DEFAULT_IMPL)
37 #else
38 #error "Sendfile not supported, to enable default implementation define RESTINIO_ENABLE_SENDFILE_DEFAULT_IMPL macro"
39 #endif
40#endif
41
42namespace restinio
43{
44
48
51constexpr 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
122 {}
123
131
133 : m_file_descriptor{ fdh.m_file_descriptor }
134 {
135 fdh.release();
136 }
137
139 {
140 if( this != &fdh )
141 {
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(
230 file_size_t ) noexcept;
231
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
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
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 &
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,
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
359 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
383 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
467inline 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
479inline 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
493inline sendfile_t
496 const std::string & file_path,
499{
500 return sendfile( file_path.c_str(), chunk_size );
501}
502
503inline 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 */
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
Wrapper class for working with native file handler.
Definition: sendfile.hpp:109
file_descriptor_holder_t & operator=(const file_descriptor_holder_t &)=delete
file_descriptor_holder_t(file_descriptor_holder_t &&fdh) noexcept
Definition: sendfile.hpp:132
friend void swap(file_descriptor_holder_t &left, file_descriptor_holder_t &right) noexcept
Swap two descriptors.
Definition: sendfile.hpp:113
file_descriptor_t m_file_descriptor
Target file descriptor.
Definition: sendfile.hpp:174
bool is_valid() const noexcept
Check if file descriptor is valid.
Definition: sendfile.hpp:155
file_descriptor_holder_t(const file_descriptor_holder_t &)=delete
file_descriptor_t fd() const noexcept
Definition: sendfile.hpp:161
file_descriptor_holder_t(file_descriptor_t fd) noexcept
Init constructor.
Definition: sendfile.hpp:120
Meta data of the file.
Definition: sendfile.hpp:183
std::chrono::system_clock::time_point m_last_modified_at
Last modification date.
Definition: sendfile.hpp:211
file_meta_t(file_size_t file_total_size, std::chrono::system_clock::time_point last_modified_at) noexcept
Definition: sendfile.hpp:195
auto last_modified_at() const noexcept
Definition: sendfile.hpp:204
file_size_t file_total_size() const noexcept
Definition: sendfile.hpp:202
friend void swap(file_meta_t &r, file_meta_t &l) noexcept
Definition: sendfile.hpp:186
file_size_t m_file_total_size
Total file size.
Definition: sendfile.hpp:208
file_meta_t() noexcept
Definition: sendfile.hpp:192
A guard class for setting chunk size.
Definition: sendfile.hpp:65
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
constexpr sendfile_chunk_size_guarded_value_t(file_size_t chunk_size_value) noexcept
Definition: sendfile.hpp:86
constexpr auto value() const noexcept
Get the valid value of a chunk size.
Definition: sendfile.hpp:91
const file_size_t m_chunk_size
Valid value of the chunk size.
Definition: sendfile.hpp:95
Send file write operation description.
Definition: sendfile.hpp:226
friend file_descriptor_holder_t takeaway_file_descriptor(sendfile_t &target)
Take away the file description form sendfile object.
Definition: sendfile.hpp:420
sendfile_t && chunk_size(sendfile_chunk_size_guarded_value_t chunk) &&
Set prefered chunk size to use in write operation.
Definition: sendfile.hpp:370
void check_file_is_valid() const
Check if stored file descriptor is valid, and throws if it is not.
Definition: sendfile.hpp:428
file_meta_t m_meta
File meta data.
Definition: sendfile.hpp:440
file_descriptor_holder_t m_file_descriptor
Native file descriptor.
Definition: sendfile.hpp:437
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
sendfile_t & timelimit(std::chrono::steady_clock::duration timelimit_value) &
Definition: sendfile.hpp:384
file_descriptor_t file_descriptor() const noexcept
Get the file descriptor of a given sendfile operation.
Definition: sendfile.hpp:401
sendfile_t && timelimit(std::chrono::steady_clock::duration timelimit_value) &&
Definition: sendfile.hpp:393
sendfile_t & chunk_size(sendfile_chunk_size_guarded_value_t chunk) &
Definition: sendfile.hpp:360
file_size_t m_chunk_size
A prefered chunk size for a single write call.
Definition: sendfile.hpp:448
auto size() const noexcept
Get size of data to write.
Definition: sendfile.hpp:306
friend void swap(sendfile_t &left, sendfile_t &right) noexcept
Definition: sendfile.hpp:249
auto chunk_size() const noexcept
Definition: sendfile.hpp:352
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
auto timelimit() const noexcept
Definition: sendfile.hpp:376
sendfile_t(file_descriptor_holder_t fdh, file_meta_t meta, sendfile_chunk_size_guarded_value_t chunk) noexcept
Definition: sendfile.hpp:232
bool is_valid() const noexcept
Check if file is valid.
Definition: sendfile.hpp:294
sendfile_t(const sendfile_t &)=delete
sendfile_t & operator=(const sendfile_t &)=delete
sendfile_t(sendfile_t &&sf) noexcept
Definition: sendfile.hpp:272
file_offset_t m_offset
Data offset within the file.
Definition: sendfile.hpp:443
const file_meta_t & meta() const
Get file meta data.
Definition: sendfile.hpp:297
auto offset() const noexcept
Get offset of data to write.
Definition: sendfile.hpp:303
friend sendfile_t sendfile(file_descriptor_holder_t, file_meta_t, file_size_t) noexcept
Definition: sendfile.hpp:468
std::chrono::steady_clock::duration m_timelimit
Timelimit for writing all the given data.
Definition: sendfile.hpp:454
file_size_t m_size
The size of data portion in file.
Definition: sendfile.hpp:445
A special wrapper around fmtlib include files.
void swap(optional< T > &x, optional< T > &y)
Definition: optional.hpp:1705
constexpr underlying_uint_t zero
The minimal allowed value for a qvalue.
Definition: basics.hpp:41
constexpr file_size_t sendfile_max_chunk_size
Maximum size of a chunk.
Definition: sendfile.hpp:51
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
constexpr file_descriptor_t null_file_descriptor()
Get file descriptor which stands for null.
std::uint64_t file_size_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
void close_file(file_descriptor_t fd)
Close file by its descriptor.
std::int64_t file_offset_t
std::FILE * file_descriptor_t
file_descriptor_t open_file(const char *file_path)
Open file.
constexpr file_size_t sendfile_default_chunk_size
Default chunk size for sendfile operation.
Definition: sendfile.hpp:47
#define const
Definition: zconf.h:230