sendfile.hpp
Go to the documentation of this file.
/*
restinio
*/
#pragma once
#include <string>
#include <chrono>
#include <array>
#include <restinio/impl/include_fmtlib.hpp>
#include <restinio/asio_include.hpp>
#include <restinio/string_view.hpp>
#include <restinio/exception.hpp>
/*
Defenitions for:
file_descriptor_t
file_offset_t
file_size_t
*/
#if defined( _MSC_VER ) || defined(__MINGW32__)
#include "sendfile_defs_win.hpp"
#elif (defined( __clang__ ) || defined( __GNUC__ )) && !defined(__WIN32__)
#include "sendfile_defs_posix.hpp"
#else
#if defined (RESTINIO_ENABLE_SENDFILE_DEFAULT_IMPL)
#include "sendfile_defs_default.hpp"
#else
#error "Sendfile not supported, to enable default implementation define RESTINIO_ENABLE_SENDFILE_DEFAULT_IMPL macro"
#endif
#endif
namespace restinio
{
constexpr file_size_t sendfile_default_chunk_size = 1024 * 1024;
constexpr file_size_t sendfile_max_chunk_size = 1024 * 1024 * 1024;
//
// sendfile_chunk_size_guarded_value_t
//
class sendfile_chunk_size_guarded_value_t
{
/*
- If chunk_size_value is zero returns 1.
- If chunk_size_value is greater than sendfile_max_chunk_size returns sendfile_max_chunk_size.
- Otherwise returns chunk_size_value itself.
*/
static constexpr file_size_t
clarify_chunk_size( file_size_t chunk_size_value ) noexcept
{
if( 0 == chunk_size_value )
return sendfile_default_chunk_size;
if( sendfile_max_chunk_size < chunk_size_value )
return sendfile_max_chunk_size;
return chunk_size_value;
}
public:
constexpr sendfile_chunk_size_guarded_value_t( file_size_t chunk_size_value ) noexcept
: m_chunk_size{ clarify_chunk_size( chunk_size_value ) }
{}
constexpr auto value() const noexcept { return m_chunk_size; }
private:
const file_size_t m_chunk_size;
};
//
// file_descriptor_holder_t
//
/*
Class is responsible for managing file descriptor as resource.
@since v.0.4.3
*/
class file_descriptor_holder_t
{
public:
friend void
swap( file_descriptor_holder_t & left, file_descriptor_holder_t & right ) noexcept
{
using std::swap;
swap( left.m_file_descriptor, right.m_file_descriptor );
}
file_descriptor_holder_t( file_descriptor_t fd ) noexcept
: m_file_descriptor{ fd }
{}
file_descriptor_holder_t( const file_descriptor_holder_t & ) = delete;
file_descriptor_holder_t & operator = ( const file_descriptor_holder_t & ) = delete;
file_descriptor_holder_t( file_descriptor_holder_t && fdh ) noexcept
: m_file_descriptor{ fdh.m_file_descriptor }
{
fdh.release();
}
file_descriptor_holder_t & operator = ( file_descriptor_holder_t && fdh ) noexcept
{
if( this != &fdh )
{
file_descriptor_holder_t tmp{ std::move( fdh ) };
swap( *this, tmp );
}
return *this;
}
~file_descriptor_holder_t() noexcept
{
if( is_valid() )
close_file( m_file_descriptor );
}
bool is_valid() const noexcept
{
return null_file_descriptor() != m_file_descriptor;
}
//Get file descriptor.
file_descriptor_t fd() const noexcept
{
return m_file_descriptor;
}
// Release stored descriptor.
void release() noexcept
{
m_file_descriptor = null_file_descriptor();
}
private:
file_descriptor_t m_file_descriptor;
};
//
// file_meta_t
//
class file_meta_t
{
public:
friend void
swap( file_meta_t & r, file_meta_t & l ) noexcept
{
std::swap( r.m_file_total_size, l.m_file_total_size );
std::swap( r.m_last_modified_at, l.m_last_modified_at );
}
file_meta_t() noexcept
{}
file_meta_t(
file_size_t file_total_size,
std::chrono::system_clock::time_point last_modified_at ) noexcept
: m_file_total_size{ file_total_size }
, m_last_modified_at{ last_modified_at }
{}
file_size_t file_total_size() const noexcept { return m_file_total_size; }
auto last_modified_at() const noexcept { return m_last_modified_at; }
private:
file_size_t m_file_total_size{ 0 };
std::chrono::system_clock::time_point m_last_modified_at{};
};
//
// sendfile_t
//
class sendfile_t
{
friend sendfile_t sendfile(
file_descriptor_holder_t ,
file_meta_t ,
file_size_t ) noexcept;
sendfile_t(
file_descriptor_holder_t fdh,
file_meta_t meta,
sendfile_chunk_size_guarded_value_t chunk ) noexcept
: m_file_descriptor{ std::move( fdh ) }
, m_meta{ meta }
, m_offset{ 0 }
, m_size{ m_meta.file_total_size() }
, m_chunk_size{ chunk.value() }
, m_timelimit{ std::chrono::steady_clock::duration::zero() }
{}
public:
friend void
swap( sendfile_t & left, sendfile_t & right ) noexcept
{
using std::swap;
swap( left.m_file_descriptor, right.m_file_descriptor );
swap( left.m_meta, right.m_meta );
swap( left.m_offset, right.m_offset );
swap( left.m_size, right.m_size );
swap( left.m_chunk_size, right.m_chunk_size );
swap( left.m_timelimit, right.m_timelimit );
}
sendfile_t( const sendfile_t & ) = delete;
sendfile_t & operator = ( const sendfile_t & ) = delete;
sendfile_t( sendfile_t && sf ) noexcept
: m_file_descriptor{ std::move( sf.m_file_descriptor ) }
, m_meta{ sf.m_meta }
, m_offset{ sf.m_offset }
, m_size{ sf.m_size }
, m_chunk_size{ sf.m_chunk_size }
, m_timelimit{ sf.m_timelimit }
{}
sendfile_t & operator = ( sendfile_t && sf ) noexcept
{
if( this != &sf )
{
sendfile_t tmp{ std::move( sf ) };
swap( *this, tmp );
}
return *this;
}
bool is_valid() const noexcept { return m_file_descriptor.is_valid(); }
const file_meta_t & meta() const
{
return m_meta;
}
auto offset() const noexcept { return m_offset; }
auto size() const noexcept { return m_size; }
sendfile_t &
offset_and_size(
file_offset_t offset_value,
file_size_t size_value = std::numeric_limits< file_size_t >::max() ) &
{
check_file_is_valid();
if( static_cast< file_size_t >( offset_value ) > m_meta.file_total_size() )
{
throw exception_t{
fmt::format(
"invalid file offset: {}, while file size is {}",
offset_value,
m_meta.file_total_size() ) };
}
m_offset = offset_value;
m_size =
std::min< file_size_t >(
m_meta.file_total_size() - static_cast< file_size_t >( offset_value ),
size_value );
return *this;
}
sendfile_t &&
offset_and_size(
file_offset_t offset_value,
file_size_t size_value = std::numeric_limits< file_size_t >::max() ) &&
{
return std::move( this->offset_and_size( offset_value, size_value ) );
}
auto chunk_size() const noexcept { return m_chunk_size; }
sendfile_t &
chunk_size( sendfile_chunk_size_guarded_value_t chunk ) &
{
check_file_is_valid();
m_chunk_size = chunk.value();
return *this;
}
sendfile_t &&
chunk_size( sendfile_chunk_size_guarded_value_t chunk ) &&
{
return std::move( this->chunk_size( chunk ) );
}
auto timelimit() const noexcept { return m_timelimit; }
sendfile_t &
timelimit( std::chrono::steady_clock::duration timelimit_value ) &
{
check_file_is_valid();
m_timelimit = std::max( timelimit_value, std::chrono::steady_clock::duration::zero() );
return *this;
}
sendfile_t &&
timelimit( std::chrono::steady_clock::duration timelimit_value ) &&
{
return std::move( this->timelimit( timelimit_value ) );
}
file_descriptor_t
file_descriptor() const noexcept
{
return m_file_descriptor.fd();
}
friend file_descriptor_holder_t
takeaway_file_descriptor( sendfile_t & target )
{
return std::move(target.m_file_descriptor);
}
private:
void
check_file_is_valid() const
{
if( !is_valid() )
{
throw exception_t{ "invalid file descriptor" };
}
}
file_descriptor_holder_t m_file_descriptor;
file_meta_t m_meta;
file_offset_t m_offset;
file_size_t m_size;
file_size_t m_chunk_size;
std::chrono::steady_clock::duration m_timelimit{ std::chrono::steady_clock::duration::zero() };
};
//
// sendfile()
//
inline sendfile_t
sendfile(
file_descriptor_holder_t fd,
file_meta_t meta,
file_size_t chunk_size = sendfile_default_chunk_size ) noexcept
{
return sendfile_t{ std::move( fd ), meta, chunk_size };
}
inline sendfile_t
sendfile(
const char * file_path,
file_size_t chunk_size = sendfile_default_chunk_size )
{
file_descriptor_holder_t fd{ open_file( file_path ) };
auto meta = get_file_meta< file_meta_t >( fd.fd() );
return sendfile( std::move( fd ), meta, chunk_size );
}
inline sendfile_t
sendfile(
const std::string & file_path,
file_size_t chunk_size = sendfile_default_chunk_size )
{
return sendfile( file_path.c_str(), chunk_size );
}
inline sendfile_t
sendfile(
string_view_t file_path,
file_size_t chunk_size = sendfile_default_chunk_size )
{
return
sendfile(
std::string{ file_path.data(), file_path.size() },
chunk_size );
}
} /* 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