connection.hpp
Go to the documentation of this file.
/*
restinio
*/
#pragma once
#include <restinio/asio_include.hpp>
#include <http_parser.h>
#include <restinio/impl/include_fmtlib.hpp>
#include <restinio/exception.hpp>
#include <restinio/http_headers.hpp>
#include <restinio/request_handler.hpp>
#include <restinio/connection_count_limiter.hpp>
#include <restinio/impl/connection_base.hpp>
#include <restinio/impl/header_helpers.hpp>
#include <restinio/impl/response_coordinator.hpp>
#include <restinio/impl/connection_settings.hpp>
#include <restinio/impl/fixed_buffer.hpp>
#include <restinio/impl/write_group_output_ctx.hpp>
#include <restinio/impl/executor_wrapper.hpp>
#include <restinio/impl/sendfile_operation.hpp>
#include <restinio/utils/impl/safe_uint_truncate.hpp>
#include <restinio/utils/at_scope_exit.hpp>
namespace restinio
{
namespace impl
{
//
// http_parser_ctx_t
//
struct http_parser_ctx_t
{
http_request_header_t m_header;
std::string m_body;
std::string m_current_field_name;
std::size_t m_last_value_total_size{ 0u };
bool m_last_was_value{ true };
bool m_leading_headers_completed{ false };
chunked_input_info_block_t m_chunked_info_block;
bool m_message_complete{ false };
std::size_t m_total_field_count{ 0u };
const incoming_http_msg_limits_t m_limits;
http_parser_ctx_t(
incoming_http_msg_limits_t limits )
: m_limits{ limits }
{}
void
reset()
{
m_header = http_request_header_t{};
m_body.clear();
m_current_field_name.clear();
m_last_value_total_size = 0u;
m_last_was_value = true;
m_leading_headers_completed = false;
m_message_complete = false;
m_total_field_count = 0u;
}
RESTINIO_NODISCARD
chunked_input_info_unique_ptr_t
make_chunked_input_info_if_necessary()
{
chunked_input_info_unique_ptr_t result;
if( !m_chunked_info_block.m_chunks.empty() ||
0u != m_chunked_info_block.m_trailing_fields.fields_count() )
{
result = std::make_unique< chunked_input_info_t >(
std::move( m_chunked_info_block ) );
}
return result;
}
};
#include "parser_callbacks.ipp"
//
// create_parser_settings()
//
template< typename Http_Methods >
inline http_parser_settings
create_parser_settings() noexcept
{
http_parser_settings parser_settings;
http_parser_settings_init( &parser_settings );
parser_settings.on_url =
[]( http_parser * parser, const char * at, size_t length ) -> int {
return restinio_url_cb( parser, at, length );
};
parser_settings.on_header_field =
[]( http_parser * parser, const char * at, size_t length ) -> int {
return restinio_header_field_cb( parser, at, length );
};
parser_settings.on_header_value =
[]( http_parser * parser, const char * at, size_t length ) -> int {
return restinio_header_value_cb( parser, at, length );
};
parser_settings.on_headers_complete =
[]( http_parser * parser ) -> int {
return restinio_headers_complete_cb( parser );
};
parser_settings.on_body =
[]( http_parser * parser, const char * at, size_t length ) -> int {
return restinio_body_cb( parser, at, length );
};
parser_settings.on_chunk_header =
[]( http_parser * parser ) -> int {
return restinio_chunk_header_cb( parser );
};
parser_settings.on_chunk_complete =
[]( http_parser * parser ) -> int {
return restinio_chunk_complete_cb( parser );
};
parser_settings.on_message_complete =
[]( http_parser * parser ) -> int {
return restinio_message_complete_cb< Http_Methods >( parser );
};
return parser_settings;
}
//
// connection_upgrade_stage_t
//
enum class connection_upgrade_stage_t : std::uint8_t
{
none,
pending_upgrade_handling,
wait_for_upgrade_handling_result_or_nothing
};
//
// connection_input_t
//
struct connection_input_t
{
connection_input_t(
std::size_t buffer_size,
incoming_http_msg_limits_t limits )
: m_parser_ctx{ limits }
, m_buf{ buffer_size }
{}
http_parser m_parser;
http_parser_ctx_t m_parser_ctx;
fixed_buffer_t m_buf;
connection_upgrade_stage_t m_connection_upgrade_stage{
connection_upgrade_stage_t::none };
bool m_read_operation_is_running{ false };
void
reset_parser()
{
// Reinit parser.
http_parser_init( &m_parser, HTTP_REQUEST);
// Reset context and attach it to parser.
m_parser_ctx.reset();
m_parser.data = &m_parser_ctx;
}
};
template < typename Connection, typename Start_Read_CB, typename Failed_CB >
void
prepare_connection_and_start_read(
asio_ns::ip::tcp::socket & ,
Connection & ,
Start_Read_CB start_read_cb,
Failed_CB )
{
// No preparation is needed, start
start_read_cb();
}
// An overload for the case of non-TLS-connection.
inline tls_socket_t *
make_tls_socket_pointer_for_state_listener(
asio_ns::ip::tcp::socket & ) noexcept
{
return nullptr;
}
//
// connection_t
//
/*
Working circle consists of the following steps:
* wait for request -- reading from socket and parsing header and body;
* handling request -- once the request is completely obtained it's handling
is deligated to a handler chosen by handler factory;
* writing response -- writing response to socket;
* back to first step o close connection -- depending on keep-alive property
of the last response the connection goes back to first step or
shutdowns.
Each step is controlled by timer (\see schedule_operation_timeout_callback())
In case of errors connection closes itself.
*/
template < typename Traits >
class connection_t final
: public connection_base_t
, public executor_wrapper_t< typename Traits::strand_t >
{
using executor_wrapper_base_t = executor_wrapper_t< typename Traits::strand_t >;
public:
using timer_manager_t = typename Traits::timer_manager_t;
using timer_guard_t = typename timer_manager_t::timer_guard_t;
using request_handler_t = request_handler_type_from_traits_t< Traits >;
using generic_request_t = generic_request_type_from_traits_t< Traits >;
using logger_t = typename Traits::logger_t;
using strand_t = typename Traits::strand_t;
using stream_socket_t = typename Traits::stream_socket_t;
using lifetime_monitor_t =
typename connection_count_limit_types<Traits>::lifetime_monitor_t;
connection_t(
connection_id_t conn_id,
stream_socket_t && socket,
connection_settings_handle_t< Traits > settings,
endpoint_t remote_endpoint,
lifetime_monitor_t lifetime_monitor )
: connection_base_t{ conn_id }
, executor_wrapper_base_t{ socket.get_executor() }
, m_socket{ std::move( socket ) }
, m_settings{ std::move( settings ) }
, m_remote_endpoint{ std::move( remote_endpoint ) }
, m_input{
m_settings->m_buffer_size,
m_settings->m_incoming_http_msg_limits
}
, m_response_coordinator{ m_settings->m_max_pipelined_requests }
, m_timer_guard{ m_settings->create_timer_guard() }
, m_request_handler{ *( m_settings->m_request_handler ) }
, m_logger{ *( m_settings->m_logger ) }
, m_lifetime_monitor{ std::move(lifetime_monitor) }
{
// Notify of a new connection instance.
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] start connection with {}",
connection_id(),
m_remote_endpoint );
} );
}
// Disable copy/move.
connection_t( const connection_t & ) = delete;
connection_t( connection_t && ) = delete;
connection_t & operator = ( const connection_t & ) = delete;
connection_t & operator = ( connection_t && ) = delete;
~connection_t() override
{
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] destructor called",
connection_id() );
} );
}
void
init()
{
prepare_connection_and_start_read(
m_socket,
*this,
[ & ]{
// Inform state listener if it used.
m_settings->call_state_listener( [this]() noexcept {
return connection_state::notice_t{
this->connection_id(),
this->m_remote_endpoint,
connection_state::accepted_t{
make_tls_socket_pointer_for_state_listener(
m_socket )
}
};
} );
// Start timeout checking.
m_prepared_weak_ctx = shared_from_this();
init_next_timeout_checking();
// Start reading request.
wait_for_http_message();
},
[ & ]( const asio_ns::error_code & ec ){
trigger_error_and_close( [&]{
return fmt::format(
"[connection:{}] prepare connection error: {}",
connection_id(),
ec.message() );
} );
} );
}
void
wait_for_http_message()
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] start waiting for request",
connection_id() );
} );
// Prepare parser for consuming new request message.
m_input.reset_parser();
// Guard total time for a request to be read.
// guarding here makes the total read process
// to run in read_next_http_message_timelimit.
guard_read_operation();
if( 0 != m_input.m_buf.length() )
{
// If a pipeline requests were sent by client
// then the biginning (or even entire request) of it
// is in the buffer obtained from socket in previous
// read operation.
consume_data( m_input.m_buf.bytes(), m_input.m_buf.length() );
}
else
{
// Next request (if any) must be obtained from socket.
consume_message();
}
}
struct upgrade_internals_t
{
upgrade_internals_t(
upgrade_internals_t && ) = default;
upgrade_internals_t(
connection_settings_handle_t< Traits > settings,
stream_socket_t socket,
lifetime_monitor_t lifetime_monitor )
: m_settings{ std::move(settings) }
, m_socket{ std::move( socket ) }
, m_lifetime_monitor{ std::move(lifetime_monitor) }
{}
connection_settings_handle_t< Traits > m_settings;
stream_socket_t m_socket;
lifetime_monitor_t m_lifetime_monitor;
};
upgrade_internals_t
move_upgrade_internals()
{
return upgrade_internals_t{
m_settings,
std::move(m_socket),
std::move(m_lifetime_monitor)
};
}
private:
inline void
consume_message()
{
if( !m_input.m_read_operation_is_running )
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] continue reading request",
connection_id() );
} );
m_input.m_read_operation_is_running = true;
m_socket.async_read_some(
m_input.m_buf.make_asio_buffer(),
asio_ns::bind_executor(
this->get_executor(),
[this, ctx = shared_from_this()]
// NOTE: this lambda is noexcept since v.0.6.0.
( const asio_ns::error_code & ec,
std::size_t length ) noexcept {
m_input.m_read_operation_is_running = false;
RESTINIO_ENSURE_NOEXCEPT_CALL( after_read( ec, length ) );
} ) );
}
else
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] skip read operation: already running",
connection_id() );
} );
}
}
inline void
after_read( const asio_ns::error_code & ec, std::size_t length ) noexcept
{
if( !ec )
{
// Exceptions shouldn't go out of `after_read`.
// So intercept them and close the connection in the case
// of an exception.
try
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] received {} bytes",
this->connection_id(),
length );
} );
m_input.m_buf.obtained_bytes( length );
consume_data( m_input.m_buf.bytes(), length );
}
catch( const std::exception & x )
{
trigger_error_and_close( [&] {
return fmt::format(
"[connection:{}] unexpected exception during the "
"handling of incoming data: {}",
connection_id(),
x.what() );
} );
}
}
else
{
// Well, if it is actually an error
// then close connection.
if( !error_is_operation_aborted( ec ) )
{
if ( !error_is_eof( ec ) || 0 != m_input.m_parser.nread )
trigger_error_and_close( [&]{
return fmt::format(
"[connection:{}] read socket error: {}; "
"parsed bytes: {}",
connection_id(),
ec.message(),
m_input.m_parser.nread );
} );
else
{
// A case that is not such an error:
// on a connection (most probably keeped alive
// after previous request, but a new also applied)
// no bytes were consumed and remote peer closes connection.
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] EOF and no request, "
"close connection",
connection_id() );
} );
RESTINIO_ENSURE_NOEXCEPT_CALL( close() );
}
}
// else: read operation was cancelled.
}
}
void
consume_data( const char * data, std::size_t length )
{
auto & parser = m_input.m_parser;
const auto nparsed =
http_parser_execute(
&parser,
&( m_settings->m_parser_settings ),
data,
length );
// If entire http-message was obtained,
// parser is stopped and the might be a part of consecutive request
// left in buffer, so we mark how many bytes were obtained.
// and next message read (if any) will be started from already existing
// data left in buffer.
m_input.m_buf.consumed_bytes( nparsed );
if( HPE_OK != parser.http_errno &&
HPE_PAUSED != parser.http_errno )
{
// PARSE ERROR:
auto err = HTTP_PARSER_ERRNO( &parser );
// TODO: handle case when there are some request in process.
trigger_error_and_close( [&]{
return fmt::format(
"[connection:{}] parser error {}: {}",
connection_id(),
http_errno_name( err ),
http_errno_description( err ) );
} );
// nothing to do.
return;
}
if( m_input.m_parser_ctx.m_message_complete )
{
on_request_message_complete();
}
else
consume_message();
}
void
on_request_message_complete()
{
try
{
auto & parser = m_input.m_parser;
auto & parser_ctx = m_input.m_parser_ctx;
if( m_input.m_parser.upgrade )
{
// Start upgrade connection operation.
// The first thing is to make sure
// that upgrade request will be handled in
// a non pipelined fashion.
m_input.m_connection_upgrade_stage =
connection_upgrade_stage_t::pending_upgrade_handling;
}
if( connection_upgrade_stage_t::none ==
m_input.m_connection_upgrade_stage )
{
// Run ordinary HTTP logic.
const auto request_id = m_response_coordinator.register_new_request();
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] request received (#{}): {} {}",
connection_id(),
request_id,
http_method_str(
static_cast<http_method>( parser.method ) ),
parser_ctx.m_header.request_target() );
} );
// TODO: mb there is a way to
// track if response was emmited immediately in handler
// or it was delegated
// so it is possible to omit this timer scheduling.
guard_request_handling_operation();
const auto handling_result =
m_request_handler(
std::make_shared< generic_request_t >(
request_id,
std::move( parser_ctx.m_header ),
std::move( parser_ctx.m_body ),
parser_ctx.make_chunked_input_info_if_necessary(),
shared_from_concrete< connection_base_t >(),
m_remote_endpoint,
m_settings->extra_data_factory() ) );
switch( handling_result )
{
case request_handling_status_t::not_handled:
case request_handling_status_t::rejected:
// If handler refused request, say not implemented.
write_response_parts_impl(
request_id,
response_output_flags_t{
response_parts_attr_t::final_parts,
response_connection_attr_t::connection_close },
write_group_t{ create_not_implemented_resp() } );
break;
case request_handling_status_t::accepted:
if( m_response_coordinator.is_able_to_get_more_messages() )
{
// Request was accepted,
// didn't create immediate response that closes connection after,
// and it is possible to receive more requests
// then start consuming yet another request.
wait_for_http_message();
}
break;
}
}
else
{
m_logger.trace( [&]{
const std::string default_value{};
return fmt::format(
"[connection:{}] upgrade request received: {} {}; "
"Upgrade: '{}';",
connection_id(),
http_method_str(
static_cast<http_method>( parser.method ) ),
parser_ctx.m_header.request_target(),
parser_ctx.m_header.get_field_or(
http_field::upgrade, default_value ) );
} );
if( m_response_coordinator.empty() )
{
// There are no requests in handling
// So the current request with upgrade
// is the only one and can be handled directly.
// It is safe to call a handler for it.
handle_upgrade_request();
}
else
{
// There are pipelined request
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] upgrade request happened to be a pipelined one, "
"and will be handled after previous requests are handled",
connection_id() );
} );
}
// No further actions (like continue reading) in both cases are needed.
}
}
catch( const std::exception & ex )
{
trigger_error_and_close( [&]{
return fmt::format(
"[connection:{}] error while handling request: {}",
this->connection_id(),
ex.what() );
} );
}
}
void
handle_upgrade_request()
{
auto & parser = m_input.m_parser;
auto & parser_ctx = m_input.m_parser_ctx;
// If user responses with error
// then connection must be able to send
// (hence to receive) response.
const auto request_id = m_response_coordinator.register_new_request();
m_logger.info( [&]{
return fmt::format(
"[connection:{}] handle upgrade request (#{}): {} {}",
connection_id(),
request_id,
http_method_str(
static_cast<http_method>( parser.method ) ),
parser_ctx.m_header.request_target() );
} );
// Do not guard upgrade request.
cancel_timeout_checking();
// After calling handler we expect the results or
// no further operations with connection
m_input.m_connection_upgrade_stage =
connection_upgrade_stage_t::wait_for_upgrade_handling_result_or_nothing;
const auto handling_result = m_request_handler(
std::make_shared< generic_request_t >(
request_id,
std::move( parser_ctx.m_header ),
std::move( parser_ctx.m_body ),
parser_ctx.make_chunked_input_info_if_necessary(),
shared_from_concrete< connection_base_t >(),
m_remote_endpoint,
m_settings->extra_data_factory() ) );
switch( handling_result )
{
case request_handling_status_t::not_handled:
case request_handling_status_t::rejected:
if( m_socket.is_open() )
{
// Request is rejected, so our socket
// must not be moved out to websocket connection.
// If handler refused request, say not implemented.
write_response_parts_impl(
request_id,
response_output_flags_t{
response_parts_attr_t::final_parts,
response_connection_attr_t::connection_close },
write_group_t{ create_not_implemented_resp() } );
}
else
{
// Request is rejected, but the socket
// was moved out to somewhere else???
m_logger.error( [&]{
return fmt::format(
"[connection:{}] upgrade request handler rejects "
"request, but socket was moved out from connection",
connection_id() );
} );
}
break;
case request_handling_status_t::accepted:
/* nothing to do */
break;
}
// Else 2 cases:
// 1. request is handled asynchronously, so
// what happens next depends on handling.
// 2. handling was immediate, so further destiny
// of a connection was already determined.
//
// In both cases: here do nothing.
// We can't even do read-only access because
// upgrade handling might take place
// in distinct execution context.
// So no even a log messages here.
}
virtual void
write_response_parts(
request_id_t request_id,
response_output_flags_t response_output_flags,
write_group_t wg ) override
{
asio_ns::dispatch(
this->get_executor(),
[ this,
request_id,
response_output_flags,
actual_wg = std::move( wg ),
ctx = shared_from_this() ]
// NOTE that this lambda is noexcept since v.0.6.0.
() mutable noexcept
{
try
{
write_response_parts_impl(
request_id,
response_output_flags,
std::move( actual_wg ) );
}
catch( const std::exception & ex )
{
trigger_error_and_close( [&]{
return fmt::format(
"[connection:{}] unable to handle response: {}",
connection_id(),
ex.what() );
} );
}
} );
}
void
write_response_parts_impl(
request_id_t request_id,
response_output_flags_t response_output_flags,
write_group_t wg )
{
auto invoke_after_write_cb_with_error = [&]{
try
{
wg.invoke_after_write_notificator_if_exists(
make_asio_compaible_error(
asio_convertible_error_t::write_was_not_executed ) );
}
catch( const std::exception & ex )
{
m_logger.error( [&]{
return fmt::format(
"[connection:{}] notificator error: {}",
connection_id(),
ex.what() );
} );
}
};
if( m_socket.is_open() )
{
if( connection_upgrade_stage_t::
wait_for_upgrade_handling_result_or_nothing ==
m_input.m_connection_upgrade_stage )
{
// It is response for a connection-upgrade request.
// If we receive it here then it is constructed via
// message builder and so connection was not transformed
// to websocket connection.
// So it is necessary to resume pipeline logic that was stopped
// for upgrade-request to be handled as the only request
// on the connection for that moment.
if( !m_response_coordinator.is_full() )
{
wait_for_http_message();
}
}
if( !m_response_coordinator.closed() )
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] append response (#{}), "
"flags: {}, write group size: {}",
connection_id(),
request_id,
response_output_flags,
wg.items_count() );
} );
m_response_coordinator.append_response(
request_id,
response_output_flags,
std::move( wg ) );
init_write_if_necessary();
}
else
{
m_logger.warn( [&]{
return fmt::format(
"[connection:{}] receive response parts for "
"request (#{}), but response with connection-close "
"attribute happened before",
connection_id(),
request_id );
} );
invoke_after_write_cb_with_error();
}
}
else
{
m_logger.warn( [&]{
return fmt::format(
"[connection:{}] try to write response, "
"while socket is closed",
connection_id() );
} );
invoke_after_write_cb_with_error();
}
}
// Check if there is something to write,
// and if so starts write operation.
void
init_write_if_necessary()
{
assert( !m_response_coordinator.closed() );
if( !m_write_output_ctx.transmitting() )
{
init_write();
}
}
void
init_write()
{
// Here: not writing anything to socket, so
// write operation can be initiated.
// Remember if all response cells were busy.
const bool response_coordinator_full_before =
m_response_coordinator.is_full();
auto next_write_group = m_response_coordinator.pop_ready_buffers();
if( next_write_group )
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] start next write group for response (#{}), "
"size: {}",
this->connection_id(),
next_write_group->second,
next_write_group->first.items_count() );
} );
// Check if all response cells busy:
const bool response_coordinator_full_after =
m_response_coordinator.is_full();
// Whether we need to resume read after this group is written?
m_init_read_after_this_write =
response_coordinator_full_before &&
!response_coordinator_full_after;
if( 0 < next_write_group->first.status_line_size() )
{
// We need to extract status line out of the first buffer
assert(
writable_item_type_t::trivial_write_operation ==
next_write_group->first.items().front().write_type() );
m_logger.trace( [&]{
// Get status line:
const string_view_t
status_line{
asio_ns::buffer_cast< const char * >(
next_write_group->first.items().front().buf() ),
next_write_group->first.status_line_size() };
return
fmt::format(
"[connection:{}] start response (#{}): {}",
this->connection_id(),
next_write_group->second,
status_line );
} );
}
// Initialize write context with a new write group.
m_write_output_ctx.start_next_write_group(
std::move( next_write_group->first ) );
// Start the loop of sending data from current write group.
handle_current_write_ctx();
}
else
{
handle_nothing_to_write();
}
}
// Use aliases for shorter names.
using none_write_operation_t = write_group_output_ctx_t::none_write_operation_t;
using trivial_write_operation_t = write_group_output_ctx_t::trivial_write_operation_t;
using file_write_operation_t = write_group_output_ctx_t::file_write_operation_t;
void
handle_current_write_ctx() noexcept
{
try
{
auto wo = m_write_output_ctx.extract_next_write_operation();
if( holds_alternative< trivial_write_operation_t >( wo ) )
{
handle_trivial_write_operation( get< trivial_write_operation_t >( wo ) );
}
else if( holds_alternative< file_write_operation_t >( wo ) )
{
handle_file_write_operation( get< file_write_operation_t >( wo ) );
}
else
{
assert( holds_alternative< none_write_operation_t >( wo ) );
finish_handling_current_write_ctx();
}
}
catch( const std::exception & ex )
{
trigger_error_and_close( [&]{
return fmt::format(
"[connection:{}] handle_current_write_ctx failed: {}",
connection_id(),
ex.what() );
} );
}
}
void
handle_trivial_write_operation( const trivial_write_operation_t & op )
{
// Asio buffers (param for async write):
auto & bufs = op.get_trivial_bufs();
if( m_response_coordinator.closed() )
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] sending resp data with "
"connection-close attribute "
"buf count: {}, "
"total size: {}",
connection_id(),
bufs.size(),
op.size() );
} );
// Reading new requests is useless.
asio_ns::error_code ignored_ec;
m_socket.cancel( ignored_ec );
}
else
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] sending resp data, "
"buf count: {}, "
"total size: {}",
connection_id(),
bufs.size(),
op.size() ); } );
}
// There is somethig to write.
asio_ns::async_write(
m_socket,
bufs,
asio_ns::bind_executor(
this->get_executor(),
[this, ctx = shared_from_this()]
// NOTE: since v.0.6.0 this lambda is noexcept.
( const asio_ns::error_code & ec, std::size_t written ) noexcept
{
if( !ec )
{
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] outgoing data was sent: {} bytes",
connection_id(),
written );
} );
}
RESTINIO_ENSURE_NOEXCEPT_CALL( after_write( ec ) );
} ) );
guard_write_operation();
}
void
handle_file_write_operation( file_write_operation_t & op )
{
if( m_response_coordinator.closed() )
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] sending resp file data with "
"connection-close attribute, "
"total size: {}",
connection_id(),
op.size() );
} );
// Reading new requests is useless.
asio_ns::error_code ignored_ec;
m_socket.cancel( ignored_ec );
}
else
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] sending resp file data, total size: {}",
connection_id(),
op.size() );
} );
}
guard_sendfile_operation( op.timelimit() );
auto op_ctx = op;
op_ctx.start_sendfile_operation(
this->get_executor(),
m_socket,
asio_ns::bind_executor(
this->get_executor(),
[this, ctx = shared_from_this(),
// Store operation context till the end
op_ctx ]
// NOTE: since v.0.6.0 this lambda is noexcept
(const asio_ns::error_code & ec, file_size_t written ) mutable noexcept
{
// NOTE: op_ctx should be reset just before return from
// that lambda. We can't call reset() until the end of
// the lambda because lambda object itself will be
// destroyed.
auto op_ctx_reseter = restinio::utils::at_scope_exit(
[&op_ctx] {
// Reset sendfile operation context.
RESTINIO_ENSURE_NOEXCEPT_CALL( op_ctx.reset() );
} );
if( !ec )
{
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] file data was sent: {} bytes",
connection_id(),
written );
} );
}
else
{
restinio::utils::log_error_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] send file data error: {} ({}) bytes",
connection_id(),
ec.value(),
ec.message() );
} );
}
RESTINIO_ENSURE_NOEXCEPT_CALL( after_write( ec ) );
} ) );
}
void
finish_handling_current_write_ctx()
{
// Finishing writing this group.
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] finishing current write group",
this->connection_id() );
} );
// Group notificators are called from here (if exist):
m_write_output_ctx.finish_write_group();
if( !m_response_coordinator.closed() )
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] should keep alive",
this->connection_id() );
} );
if( connection_upgrade_stage_t::none ==
m_input.m_connection_upgrade_stage )
{
// Run ordinary HTTP logic.
if( m_init_read_after_this_write )
{
wait_for_http_message();
}
// Start another write opertion
// if there is something to send.
init_write_if_necessary();
}
else
{
if( m_response_coordinator.empty() )
{
// Here upgrade req is the only request
// to by handled by this connection.
// So it is safe to call a handler for it.
handle_upgrade_request();
}
else
{
// Do not start reading in any case,
// but if there is at least one request preceding
// upgrade-req, logic must continue http interaction.
init_write_if_necessary();
}
}
}
else
{
// No keep-alive, close connection.
close();
}
}
void
handle_nothing_to_write()
{
if( m_response_coordinator.closed() )
{
// Bufs empty but there happened to
// be a response context marked as complete
// (final_parts) and having connection-close attr.
// It is because `init_write_if_necessary()`
// is called only under `!m_response_coordinator.closed()`
// condition, so if no bufs were obtained
// and response coordinator is closed means
// that a first response stored by
// response coordinator was marked as complete
// without data.
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] last sent response was marked "
"as complete",
connection_id() ); } );
close();
}
else
{
// Not writing anything, so need to deal with timouts.
if( m_response_coordinator.empty() )
{
// No requests in processing.
// So set read next request timeout.
guard_read_operation();
}
else
{
// Have requests in process.
// So take control over request handling.
guard_request_handling_operation();
}
}
}
void
after_write( const asio_ns::error_code & ec ) noexcept
{
if( !ec )
{
RESTINIO_ENSURE_NOEXCEPT_CALL( handle_current_write_ctx() );
}
else
{
if( !error_is_operation_aborted( ec ) )
{
trigger_error_and_close( [&]{
return fmt::format(
"[connection:{}] unable to write: {}",
connection_id(),
ec.message() );
} );
}
// else: Operation aborted only in case of close was called.
try
{
m_write_output_ctx.fail_write_group( ec );
}
catch( const std::exception & ex )
{
restinio::utils::log_error_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] notificator error: {}",
connection_id(),
ex.what() );
} );
}
}
}
void
close() noexcept
{
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] close",
connection_id() );
} );
// shutdown() and close() should be called regardless of
// possible exceptions.
restinio::utils::suppress_exceptions(
m_logger,
"connection.socket.shutdown",
[this] {
asio_ns::error_code ignored_ec;
m_socket.shutdown(
asio_ns::ip::tcp::socket::shutdown_both,
ignored_ec );
} );
restinio::utils::suppress_exceptions(
m_logger,
"connection.socket.close",
[this] {
m_socket.close();
} );
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] close: close socket",
connection_id() );
} );
// Clear stuff.
RESTINIO_ENSURE_NOEXCEPT_CALL( cancel_timeout_checking() );
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] close: timer canceled",
connection_id() );
} );
RESTINIO_ENSURE_NOEXCEPT_CALL( m_response_coordinator.reset() );
restinio::utils::log_trace_noexcept( m_logger,
[&]{
return fmt::format(
"[connection:{}] close: reset responses data",
connection_id() );
} );
// Inform state listener if it used.
m_settings->call_state_listener_suppressing_exceptions(
[this]() noexcept {
return connection_state::notice_t{
this->connection_id(),
this->m_remote_endpoint,
connection_state::closed_t{}
};
} );
}
template< typename Message_Builder >
void
trigger_error_and_close( Message_Builder msg_builder ) noexcept
{
// An exception from logger/msg_builder shouldn't prevent
// a call to close().
restinio::utils::log_error_noexcept(
m_logger, std::move(msg_builder) );
RESTINIO_ENSURE_NOEXCEPT_CALL( close() );
}
stream_socket_t m_socket;
connection_settings_handle_t< Traits > m_settings;
const endpoint_t m_remote_endpoint;
connection_input_t m_input;
write_group_output_ctx_t m_write_output_ctx;
// Memo flag: whether we need to resume read after this group is written
bool m_init_read_after_this_write{ false };
response_coordinator_t m_response_coordinator;
static connection_t &
cast_to_self( tcp_connection_ctx_base_t & base )
{
return static_cast< connection_t & >( base );
}
virtual void
check_timeout( tcp_connection_ctx_handle_t & self ) override
{
asio_ns::dispatch(
this->get_executor(),
[ ctx = std::move( self ) ]
// NOTE: this lambda is noexcept since v.0.6.0.
() noexcept {
auto & conn_object = cast_to_self( *ctx );
// If an exception will be thrown we can only
// close the connection.
try
{
conn_object.check_timeout_impl();
}
catch( const std::exception & x )
{
conn_object.trigger_error_and_close( [&] {
return fmt::format( "[connection: {}] unexpected "
"error during timeout handling: {}",
conn_object.connection_id(),
x.what() );
} );
}
} );
}
using timout_cb_t = void (connection_t::* )( void );
timout_cb_t m_current_timeout_cb{ nullptr };
std::chrono::steady_clock::time_point m_current_timeout_after;
timer_guard_t m_timer_guard;
tcp_connection_ctx_weak_handle_t m_prepared_weak_ctx;
void
check_timeout_impl()
{
if( std::chrono::steady_clock::now() > m_current_timeout_after )
{
if( m_current_timeout_cb )
(this->*m_current_timeout_cb)();
}
else
{
init_next_timeout_checking();
}
}
void
init_next_timeout_checking()
{
m_timer_guard.schedule( m_prepared_weak_ctx );
}
void
cancel_timeout_checking() noexcept
{
m_current_timeout_cb = nullptr;
RESTINIO_ENSURE_NOEXCEPT_CALL( m_timer_guard.cancel() );
}
void
schedule_operation_timeout_callback(
std::chrono::steady_clock::time_point timeout_after,
timout_cb_t timout_cb )
{
m_current_timeout_after = timeout_after;
m_current_timeout_cb = timout_cb;
}
void
schedule_operation_timeout_callback(
std::chrono::steady_clock::duration timeout,
timout_cb_t timout_cb )
{
schedule_operation_timeout_callback(
std::chrono::steady_clock::now() + timeout,
timout_cb );
}
void
handle_xxx_timeout( const char * operation_name )
{
m_logger.trace( [&]{
return fmt::format(
"[connection:{}] {} timed out",
connection_id(),
operation_name );
} );
close();
}
void
handle_read_timeout()
{
handle_xxx_timeout( "wait for request" );
}
void
guard_read_operation()
{
if( m_response_coordinator.empty() )
{
schedule_operation_timeout_callback(
m_settings->m_read_next_http_message_timelimit,
&connection_t::handle_read_timeout );
}
}
void
handle_request_handling_timeout()
{
handle_xxx_timeout( "handle request" );
}
void
guard_request_handling_operation()
{
if( !m_write_output_ctx.transmitting() )
{
schedule_operation_timeout_callback(
m_settings->m_handle_request_timeout,
&connection_t::handle_request_handling_timeout );
}
}
void
handle_write_response_timeout()
{
handle_xxx_timeout( "writing response" );
}
void
guard_write_operation()
{
schedule_operation_timeout_callback(
m_settings->m_write_http_response_timelimit,
&connection_t::handle_write_response_timeout );
}
void
handle_sendfile_timeout()
{
handle_xxx_timeout( "writing response (sendfile)" );
}
void
guard_sendfile_operation( std::chrono::steady_clock::duration timelimit )
{
if( std::chrono::steady_clock::duration::zero() == timelimit )
timelimit = m_settings->m_write_http_response_timelimit;
schedule_operation_timeout_callback(
timelimit,
&connection_t::handle_sendfile_timeout );
}
request_handler_t & m_request_handler;
logger_t & m_logger;
lifetime_monitor_t m_lifetime_monitor;
};
//
// connection_factory_t
//
template < typename Traits >
class connection_factory_t
{
public:
using logger_t = typename Traits::logger_t;
using stream_socket_t = typename Traits::stream_socket_t;
using lifetime_monitor_t =
typename connection_count_limit_types<Traits>::lifetime_monitor_t;
connection_factory_t(
connection_settings_handle_t< Traits > connection_settings,
std::unique_ptr< socket_options_setter_t > socket_options_setter )
: m_connection_settings{ std::move( connection_settings ) }
, m_socket_options_setter{ std::move( socket_options_setter ) }
, m_logger{ *(m_connection_settings->m_logger ) }
{}
// NOTE: since v.0.6.3 it returns non-empty
// shared_ptr<connection_t<Traits>> or an exception is thrown in
// the case of an error.
// NOTE: since v.0.6.12 it accepts yet another parameter: lifetime_monitor.
auto
create_new_connection(
stream_socket_t socket,
endpoint_t remote_endpoint,
lifetime_monitor_t lifetime_monitor )
{
using connection_type_t = connection_t< Traits >;
{
socket_options_t options{ socket.lowest_layer() };
(*m_socket_options_setter)( options );
}
return std::make_shared< connection_type_t >(
m_connection_id_counter++,
std::move( socket ),
m_connection_settings,
std::move( remote_endpoint ),
std::move( lifetime_monitor ) );
}
private:
connection_id_t m_connection_id_counter{ 1 };
connection_settings_handle_t< Traits > m_connection_settings;
std::unique_ptr< socket_options_setter_t > m_socket_options_setter;
logger_t & m_logger;
};
} /* namespace impl */
} /* namespace restinio */
asio_include.hpp
at_scope_exit.hpp
A simple implementation of at_scope_exit concept.
restinio::connection_count_limits::connection_lifetime_monitor_t
Helper type for controlling the lifetime of the connection.
Definition: connection_count_limiter.hpp:375
restinio::connection_state::accepted_t
Type of object that tells that new connection has been accepted.
Definition: connection_state_listener.hpp:36
restinio::connection_state::closed_t
Type of object that tells that the connection has been closed.
Definition: connection_state_listener.hpp:183
restinio::connection_state::notice_t
An object with info about connection to be passed to state listener.
Definition: connection_state_listener.hpp:225
restinio::generic_request_t
HTTP Request data.
Definition: request_handler.hpp:201
restinio::http_header_fields_t::fields_count
auto fields_count() const noexcept
Definition: http_headers.hpp:1493
restinio::impl::connection_base_t
HTTP connection base.
Definition: connection_base.hpp:29
restinio::impl::connection_factory_t
Factory for connections.
Definition: connection.hpp:1709
restinio::impl::connection_factory_t::m_socket_options_setter
std::unique_ptr< socket_options_setter_t > m_socket_options_setter
Definition: connection.hpp:1754
restinio::impl::connection_factory_t::connection_factory_t
connection_factory_t(connection_settings_handle_t< Traits > connection_settings, std::unique_ptr< socket_options_setter_t > socket_options_setter)
Definition: connection.hpp:1716
restinio::impl::connection_factory_t::logger_t
typename Traits::logger_t logger_t
Definition: connection.hpp:1711
restinio::impl::connection_factory_t::m_logger
logger_t & m_logger
Definition: connection.hpp:1756
restinio::impl::connection_factory_t::m_connection_settings
connection_settings_handle_t< Traits > m_connection_settings
Definition: connection.hpp:1752
restinio::impl::connection_factory_t::create_new_connection
auto create_new_connection(stream_socket_t socket, endpoint_t remote_endpoint, lifetime_monitor_t lifetime_monitor)
Definition: connection.hpp:1729
restinio::impl::connection_factory_t::stream_socket_t
typename Traits::stream_socket_t stream_socket_t
Definition: connection.hpp:1712
restinio::impl::connection_factory_t::m_connection_id_counter
connection_id_t m_connection_id_counter
Definition: connection.hpp:1750
restinio::impl::connection_factory_t::lifetime_monitor_t
typename connection_count_limit_types< Traits >::lifetime_monitor_t lifetime_monitor_t
Definition: connection.hpp:1714
restinio::impl::connection_t
Context for handling http connections.
Definition: connection.hpp:306
restinio::impl::connection_t::check_timeout
virtual void check_timeout(tcp_connection_ctx_handle_t &self) override
Schedules real timedout operations check on the executer of a connection.
Definition: connection.hpp:1514
restinio::impl::connection_t::operator=
connection_t & operator=(const connection_t &)=delete
restinio::impl::connection_t::strand_t
typename Traits::strand_t strand_t
Definition: connection.hpp:315
restinio::impl::connection_t::handle_upgrade_request
void handle_upgrade_request()
Calls handler for upgrade request.
Definition: connection.hpp:757
restinio::impl::connection_t::init_write_if_necessary
void init_write_if_necessary()
Definition: connection.hpp:978
restinio::impl::connection_t::m_prepared_weak_ctx
tcp_connection_ctx_weak_handle_t m_prepared_weak_ctx
A prepared weak handle for passing it to timer guard.
Definition: connection.hpp:1551
restinio::impl::connection_t::on_request_message_complete
void on_request_message_complete()
Handle a given request message.
Definition: connection.hpp:626
restinio::impl::connection_t::handle_request_handling_timeout
void handle_request_handling_timeout()
Definition: connection.hpp:1635
restinio::impl::connection_t::lifetime_monitor_t
typename connection_count_limit_types< Traits >::lifetime_monitor_t lifetime_monitor_t
Definition: connection.hpp:318
restinio::impl::connection_t::write_response_parts
virtual void write_response_parts(request_id_t request_id, response_output_flags_t response_output_flags, write_group_t wg) override
Write parts for specified request.
Definition: connection.hpp:846
restinio::impl::connection_t::handle_xxx_timeout
void handle_xxx_timeout(const char *operation_name)
Definition: connection.hpp:1604
restinio::impl::connection_t::guard_write_operation
void guard_write_operation()
Start guard write operation if necessary.
Definition: connection.hpp:1660
restinio::impl::connection_t::finish_handling_current_write_ctx
void finish_handling_current_write_ctx()
Do post write actions for current write group.
Definition: connection.hpp:1252
restinio::impl::connection_t::m_remote_endpoint
const endpoint_t m_remote_endpoint
Remote endpoint for this connection.
Definition: connection.hpp:1487
restinio::impl::connection_t::m_lifetime_monitor
lifetime_monitor_t m_lifetime_monitor
Monitor of the connection lifetime.
Definition: connection.hpp:1699
restinio::impl::connection_t::m_socket
stream_socket_t m_socket
Connection.
Definition: connection.hpp:1481
restinio::impl::connection_t::m_input
connection_input_t m_input
Input routine.
Definition: connection.hpp:1490
restinio::impl::connection_t::schedule_operation_timeout_callback
void schedule_operation_timeout_callback(std::chrono::steady_clock::time_point timeout_after, timout_cb_t timout_cb)
Helper function to work with timer guard.
Definition: connection.hpp:1585
restinio::impl::connection_t::guard_sendfile_operation
void guard_sendfile_operation(std::chrono::steady_clock::duration timelimit)
Definition: connection.hpp:1674
restinio::impl::connection_t::m_request_handler
request_handler_t & m_request_handler
Request handler.
Definition: connection.hpp:1686
restinio::impl::connection_t::handle_trivial_write_operation
void handle_trivial_write_operation(const trivial_write_operation_t &op)
Run trivial buffers write operation.
Definition: connection.hpp:1109
restinio::impl::connection_t::handle_nothing_to_write
void handle_nothing_to_write()
Definition: connection.hpp:1311
restinio::impl::connection_t::handle_file_write_operation
void handle_file_write_operation(file_write_operation_t &op)
Run sendfile write operation.
Definition: connection.hpp:1172
restinio::impl::connection_t::m_current_timeout_cb
timout_cb_t m_current_timeout_cb
Callback to all if timeout happened.
Definition: connection.hpp:1544
restinio::impl::connection_t::~connection_t
~connection_t() override
Definition: connection.hpp:361
restinio::impl::connection_t::wait_for_http_message
void wait_for_http_message()
Start reading next htttp-message.
Definition: connection.hpp:409
restinio::impl::connection_t::after_read
void after_read(const asio_ns::error_code &ec, std::size_t length) noexcept
Handle read operation result.
Definition: connection.hpp:510
restinio::impl::connection_t::m_logger
logger_t & m_logger
Logger for operation.
Definition: connection.hpp:1689
restinio::impl::connection_t::m_current_timeout_after
std::chrono::steady_clock::time_point m_current_timeout_after
Timeout point of a current guarded operation.
Definition: connection.hpp:1547
restinio::impl::connection_t::init_write
void init_write()
Initiate write operation.
Definition: connection.hpp:990
restinio::impl::connection_t::timer_manager_t
typename Traits::timer_manager_t timer_manager_t
Definition: connection.hpp:310
restinio::impl::connection_t::move_upgrade_internals
upgrade_internals_t move_upgrade_internals()
Move socket out of connection.
Definition: connection.hpp:462
restinio::impl::connection_t::cancel_timeout_checking
void cancel_timeout_checking() noexcept
Stop timout guarding.
Definition: connection.hpp:1577
restinio::impl::connection_t::cast_to_self
static connection_t & cast_to_self(tcp_connection_ctx_base_t &base)
Timer to controll operations.
Definition: connection.hpp:1506
restinio::impl::connection_t::connection_t
connection_t(const connection_t &)=delete
restinio::impl::connection_t::handle_current_write_ctx
void handle_current_write_ctx() noexcept
Start/continue/continue handling output data of current write group.
Definition: connection.hpp:1076
restinio::impl::connection_t::timout_cb_t
void(connection_t::*)(void) timout_cb_t
Callback type for timedout operations.
Definition: connection.hpp:1541
restinio::impl::connection_t::connection_t
connection_t(connection_id_t conn_id, stream_socket_t &&socket, connection_settings_handle_t< Traits > settings, endpoint_t remote_endpoint, lifetime_monitor_t lifetime_monitor)
Definition: connection.hpp:320
restinio::impl::connection_t::close
void close() noexcept
Close connection functions.
Definition: connection.hpp:1398
restinio::impl::connection_t::handle_write_response_timeout
void handle_write_response_timeout()
Definition: connection.hpp:1653
restinio::impl::connection_t::logger_t
typename Traits::logger_t logger_t
Definition: connection.hpp:314
restinio::impl::connection_t::after_write
void after_write(const asio_ns::error_code &ec) noexcept
Handle write response finished.
Definition: connection.hpp:1357
restinio::impl::connection_t::trigger_error_and_close
void trigger_error_and_close(Message_Builder msg_builder) noexcept
Trigger an error.
Definition: connection.hpp:1469
restinio::impl::connection_t::m_response_coordinator
response_coordinator_t m_response_coordinator
Response coordinator.
Definition: connection.hpp:1499
restinio::impl::connection_t::guard_request_handling_operation
void guard_request_handling_operation()
Start guard request handling operation if necessary.
Definition: connection.hpp:1642
restinio::impl::connection_t::timer_guard_t
typename timer_manager_t::timer_guard_t timer_guard_t
Definition: connection.hpp:311
restinio::impl::connection_t::request_handler_t
request_handler_type_from_traits_t< Traits > request_handler_t
Definition: connection.hpp:312
restinio::impl::connection_t::init_next_timeout_checking
void init_next_timeout_checking()
Schedule next timeout checking.
Definition: connection.hpp:1570
restinio::impl::connection_t::consume_data
void consume_data(const char *data, std::size_t length)
Parse some data.
Definition: connection.hpp:579
restinio::impl::connection_t::consume_message
void consume_message()
Start (continue) a chain of read-parse-read-... operations.
Definition: connection.hpp:474
restinio::impl::connection_t::m_timer_guard
timer_guard_t m_timer_guard
Timer guard.
Definition: connection.hpp:1549
restinio::impl::connection_t::init
void init()
Definition: connection.hpp:372
restinio::impl::connection_t::stream_socket_t
typename Traits::stream_socket_t stream_socket_t
Definition: connection.hpp:316
restinio::impl::connection_t::check_timeout_impl
void check_timeout_impl()
Check timed out operation.
Definition: connection.hpp:1555
restinio::impl::connection_t::m_settings
connection_settings_handle_t< Traits > m_settings
Common paramaters of a connection.
Definition: connection.hpp:1484
restinio::impl::connection_t::handle_sendfile_timeout
void handle_sendfile_timeout()
Definition: connection.hpp:1668
restinio::impl::connection_t::guard_read_operation
void guard_read_operation()
Statr guard read operation if necessary.
Definition: connection.hpp:1624
restinio::impl::connection_t::write_response_parts_impl
void write_response_parts_impl(request_id_t request_id, response_output_flags_t response_output_flags, write_group_t wg)
Write parts for specified request.
Definition: connection.hpp:886
restinio::impl::connection_t::connection_t
connection_t(connection_t &&)=delete
restinio::impl::connection_t::schedule_operation_timeout_callback
void schedule_operation_timeout_callback(std::chrono::steady_clock::duration timeout, timout_cb_t timout_cb)
Definition: connection.hpp:1594
restinio::impl::connection_t::m_init_read_after_this_write
bool m_init_read_after_this_write
Definition: connection.hpp:1496
restinio::impl::connection_t::handle_read_timeout
void handle_read_timeout()
Definition: connection.hpp:1617
restinio::impl::connection_t::m_write_output_ctx
write_group_output_ctx_t m_write_output_ctx
Write to socket operation context.
Definition: connection.hpp:1493
restinio::impl::executor_wrapper_t
Wrapper for an executor (strand) used by connections.
Definition: executor_wrapper.hpp:25
restinio::impl::executor_wrapper_t< Traits::strand_t >::get_executor
Traits::strand_t & get_executor() noexcept
An executor for callbacks on async operations.
Definition: executor_wrapper.hpp:35
restinio::impl::fixed_buffer_t
Helper class for reading bytes and feeding them to parser.
Definition: fixed_buffer.hpp:27
restinio::impl::fixed_buffer_t::length
std::size_t length() const noexcept
How many unconsumed bytes are there in buffer.
Definition: fixed_buffer.hpp:63
restinio::impl::fixed_buffer_t::consumed_bytes
void consumed_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
Definition: fixed_buffer.hpp:56
restinio::impl::fixed_buffer_t::obtained_bytes
void obtained_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
Definition: fixed_buffer.hpp:48
restinio::impl::fixed_buffer_t::make_asio_buffer
auto make_asio_buffer() noexcept
Make asio buffer for reading bytes from socket.
Definition: fixed_buffer.hpp:41
restinio::impl::fixed_buffer_t::bytes
const char * bytes() const noexcept
Get pointer to unconsumed bytes.
Definition: fixed_buffer.hpp:69
restinio::impl::response_coordinator_t
Coordinator for process of sending responses with respect to http pipeline technique and chunk transf...
Definition: response_coordinator.hpp:289
restinio::impl::response_coordinator_t::reset
void reset() noexcept
Remove all contexts.
Definition: response_coordinator.hpp:416
restinio::impl::response_coordinator_t::register_new_request
request_id_t register_new_request()
Create a new request and reserve context for its response.
Definition: response_coordinator.hpp:315
restinio::impl::response_coordinator_t::is_able_to_get_more_messages
bool is_able_to_get_more_messages() const noexcept
Check if it is possible to accept more requests.
Definition: response_coordinator.hpp:308
restinio::impl::response_coordinator_t::is_full
bool is_full() const noexcept
Definition: response_coordinator.hpp:303
restinio::impl::response_coordinator_t::empty
bool empty() const noexcept
Definition: response_coordinator.hpp:302
restinio::impl::response_coordinator_t::pop_ready_buffers
optional_t< std::pair< write_group_t, request_id_t > > pop_ready_buffers()
Extract a portion of data available for write.
Definition: response_coordinator.hpp:371
restinio::impl::response_coordinator_t::closed
bool closed() const noexcept
Definition: response_coordinator.hpp:301
restinio::impl::response_coordinator_t::append_response
void append_response(request_id_t req_id, response_output_flags_t response_output_flags, write_group_t wg)
Add outgoing data for specified request.
Definition: response_coordinator.hpp:324
restinio::impl::tls_socket_t
Socket adapter for asio::ssl::stream< asio::ip::tcp::socket >.
Definition: tls_socket.hpp:37
restinio::impl::write_group_output_ctx_t::file_write_operation_t
Write operaton using sendfile.
Definition: write_group_output_ctx.hpp:142
restinio::impl::write_group_output_ctx_t::file_write_operation_t::timelimit
auto timelimit() const noexcept
Get the timelimit on this sendfile operation.
Definition: write_group_output_ctx.hpp:193
restinio::impl::write_group_output_ctx_t::file_write_operation_t::start_sendfile_operation
void start_sendfile_operation(default_asio_executor executor, Socket &socket, After_Write_CB after_sendfile_cb)
Start a sendfile operation.
Definition: write_group_output_ctx.hpp:167
restinio::impl::write_group_output_ctx_t::file_write_operation_t::size
auto size() const noexcept
Get the size of sendfile operation.
Definition: write_group_output_ctx.hpp:212
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t
Trivial write operaton.
Definition: write_group_output_ctx.hpp:106
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::size
auto size() const noexcept
The size of data within this operation.
Definition: write_group_output_ctx.hpp:133
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::get_trivial_bufs
const std::vector< asio_ns::const_buffer > & get_trivial_bufs() const noexcept
Get buffer "iovec" for performing gather write.
Definition: write_group_output_ctx.hpp:127
restinio::impl::write_group_output_ctx_t
Helper class for writting response data.
Definition: write_group_output_ctx.hpp:80
restinio::impl::write_group_output_ctx_t::fail_write_group
void fail_write_group(const asio_ns::error_code &ec)
Handle current group write process failed.
Definition: write_group_output_ctx.hpp:283
restinio::impl::write_group_output_ctx_t::extract_next_write_operation
solid_write_operation_variant_t extract_next_write_operation()
et an object with next write operation to perform.
Definition: write_group_output_ctx.hpp:253
restinio::impl::write_group_output_ctx_t::finish_write_group
void finish_write_group()
Finish writing group normally.
Definition: write_group_output_ctx.hpp:294
restinio::impl::write_group_output_ctx_t::start_next_write_group
void start_next_write_group(optional_t< write_group_t > next_wg) noexcept
Start handlong next write group.
Definition: write_group_output_ctx.hpp:239
restinio::impl::write_group_output_ctx_t::transmitting
bool transmitting() const noexcept
Check if data is trunsmitting now.
Definition: write_group_output_ctx.hpp:235
restinio::incoming_http_msg_limits_t
A type of holder of limits related to an incoming HTTP message.
Definition: incoming_http_msg_limits.hpp:69
restinio::socket_options_t
An adapter for setting acceptor options before running server.
Definition: settings.hpp:249
restinio::tcp_connection_ctx_base_t
TCP connection base.
Definition: tcp_connection_ctx_base.hpp:29
restinio::tcp_connection_ctx_base_t::connection_id
connection_id_t connection_id() const noexcept
Get connection id.
Definition: tcp_connection_ctx_base.hpp:38
restinio::write_group_t
Group of writable items transported to the context of underlying connection as one solid piece.
Definition: buffers.hpp:692
restinio::write_group_t::invoke_after_write_notificator_if_exists
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
Definition: buffers.hpp:815
restinio::write_group_t::items_count
auto items_count() const noexcept
Get the count of stored items.
Definition: buffers.hpp:832
RESTINIO_ENSURE_NOEXCEPT_CALL
#define RESTINIO_ENSURE_NOEXCEPT_CALL(expr)
A wrapper around static_assert for checking that an expression is noexcept and execution of that expr...
Definition: compiler_features.hpp:60
RESTINIO_NODISCARD
#define RESTINIO_NODISCARD
Definition: compiler_features.hpp:33
connection_base.hpp
connection_count_limiter.hpp
Stuff related to limits of active parallel connections.
connection_settings.hpp
exception.hpp
executor_wrapper.hpp
fixed_buffer.hpp
header_helpers.hpp
http_headers.hpp
include_fmtlib.hpp
A special wrapper around fmtlib include files.
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:465
restinio::http_field_parsers::qvalue_details::zero
constexpr underlying_uint_t zero
The minimal allowed value for a qvalue.
Definition: basics.hpp:41
restinio::impl::make_tls_socket_pointer_for_state_listener
tls_socket_t * make_tls_socket_pointer_for_state_listener(asio_ns::ip::tcp::socket &) noexcept
Definition: connection.hpp:277
restinio::impl::connection_settings_handle_t
std::shared_ptr< connection_settings_t< Traits > > connection_settings_handle_t
Definition: connection_settings.hpp:235
restinio::impl::create_parser_settings
http_parser_settings create_parser_settings() noexcept
Include parser callbacks.
Definition: connection.hpp:152
restinio::impl::create_not_implemented_resp
auto create_not_implemented_resp()
Definition: header_helpers.hpp:156
restinio::impl::prepare_connection_and_start_read
void prepare_connection_and_start_read(asio_ns::ip::tcp::socket &, Connection &, Start_Read_CB start_read_cb, Failed_CB)
Definition: connection.hpp:265
restinio::impl::connection_upgrade_stage_t
connection_upgrade_stage_t
Enum for a flag specifying that connection is going to upgrade or not.
Definition: connection.hpp:206
restinio::impl::connection_upgrade_stage_t::wait_for_upgrade_handling_result_or_nothing
@ wait_for_upgrade_handling_result_or_nothing
Handler for request with connection-upgrade header was called so any response data comming is for tha...
restinio::impl::connection_upgrade_stage_t::none
@ none
No connection request in progress.
restinio::impl::connection_upgrade_stage_t::pending_upgrade_handling
@ pending_upgrade_handling
Request with connection-upgrade header came and waits for request handler to be called in non pipelin...
restinio::utils::suppress_exceptions
void suppress_exceptions(Logger &&logger, const char *block_description, Lambda &&lambda) noexcept
Helper function for execution a block of code with suppression of any exceptions raised inside that b...
Definition: suppress_exceptions.hpp:94
restinio::utils::at_scope_exit
scope_exit_details::at_exit_t< L > at_scope_exit(L &&l)
Helper function for creation action to be performed at scope exit.
Definition: at_scope_exit.hpp:60
restinio::utils::log_error_noexcept
void log_error_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
Definition: suppress_exceptions.hpp:71
restinio::utils::log_trace_noexcept
void log_trace_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
Definition: suppress_exceptions.hpp:32
restinio::websocket::basic::upgrade
ws_handle_t upgrade(generic_request_type_from_traits_t< Traits > &req, activation_t activation_flag, http_header_fields_t upgrade_response_header_fields, WS_Message_Handler ws_message_handler)
Upgrade http-connection of a current request to a websocket connection.
Definition: websocket.hpp:215
restinio
Definition: asio_include.hpp:21
restinio::tcp_connection_ctx_handle_t
std::shared_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_handle_t
Alias for http connection handle.
Definition: tcp_connection_ctx_base.hpp:62
restinio::file_size_t
std::uint64_t file_size_t
Definition: sendfile_defs_default.hpp:23
restinio::chunked_input_info_unique_ptr_t
std::unique_ptr< chunked_input_info_t > chunked_input_info_unique_ptr_t
Alias of unique_ptr for chunked_input_info.
Definition: chunked_input_info.hpp:230
restinio::tcp_connection_ctx_weak_handle_t
std::weak_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_weak_handle_t
Alias for http connection weak handle.
Definition: tcp_connection_ctx_base.hpp:65
restinio::string_view_t
nonstd::string_view string_view_t
Definition: string_view.hpp:19
restinio::request_id_t
unsigned int request_id_t
Request id in scope of single connection.
Definition: common_types.hpp:70
restinio::writable_item_type_t::trivial_write_operation
@ trivial_write_operation
Item is a buffer and must be written trivially.
restinio::error_is_operation_aborted
bool error_is_operation_aborted(const asio_ns::error_code &ec) noexcept
Definition: asio_include.hpp:27
restinio::request_handling_status_t::accepted
@ accepted
Request accepted for handling.
restinio::request_handling_status_t::not_handled
@ not_handled
The request wasn't handled. If there is another handler to be tried it should be tried....
restinio::request_handling_status_t::rejected
@ rejected
Request wasn't accepted for handling.
restinio::request_handler_type_from_traits_t
typename details::actual_request_handler_type_detector< typename Traits::request_handler_t, typename Traits::extra_data_factory_t >::request_handler_t request_handler_type_from_traits_t
A metafunction for extraction a request-handler type from server's traits.
Definition: traits.hpp:379
restinio::asio_convertible_error_t::write_was_not_executed
@ write_was_not_executed
After write notificator error: data was not sent, connection closed (or aborted) before a given piece...
restinio::error_is_eof
bool error_is_eof(const asio_ns::error_code &ec) noexcept
Definition: asio_include.hpp:33
restinio::endpoint_t
asio_ns::ip::tcp::endpoint endpoint_t
An alias for endpoint type from Asio.
Definition: common_types.hpp:177
restinio::response_connection_attr_t::connection_close
@ connection_close
This response says to close connection.
restinio::make_asio_compaible_error
asio_ns::error_code make_asio_compaible_error(asio_convertible_error_t err) noexcept
Make restinio error_code compatible with asio_ns::error_code.
Definition: asio_include.hpp:210
restinio::response_parts_attr_t::final_parts
@ final_parts
Final parts (response ands with these parts).
restinio::connection_id_t
std::uint64_t connection_id_t
Type for ID of connection.
Definition: common_types.hpp:174
std
STL namespace.
parser_callbacks.ipp
restinio_url_cb
int restinio_url_cb(http_parser *parser, const char *at, size_t length)
Definition: parser_callbacks.ipp:10
restinio_header_value_cb
int restinio_header_value_cb(http_parser *parser, const char *at, size_t length)
Definition: parser_callbacks.ipp:80
restinio_body_cb
int restinio_body_cb(http_parser *parser, const char *at, size_t length)
Definition: parser_callbacks.ipp:159
restinio_chunk_complete_cb
int restinio_chunk_complete_cb(http_parser *)
Definition: parser_callbacks.ipp:218
restinio_headers_complete_cb
int restinio_headers_complete_cb(http_parser *parser)
Definition: parser_callbacks.ipp:124
restinio_header_field_cb
int restinio_header_field_cb(http_parser *parser, const char *at, size_t length)
Definition: parser_callbacks.ipp:35
restinio_chunk_header_cb
int restinio_chunk_header_cb(http_parser *parser)
Definition: parser_callbacks.ipp:186
request_handler.hpp
response_coordinator.hpp
safe_uint_truncate.hpp
Helpers for safe truncation of unsigned integers.
sendfile_operation.hpp
restinio::http_request_header_t
Req header.
Definition: http_headers.hpp:1859
restinio::impl::chunked_input_info_block_t
Bunch of data related to chunked input.
Definition: chunked_input_info.hpp:116
restinio::impl::chunked_input_info_block_t::m_chunks
std::vector< chunk_info_t > m_chunks
All non-empty chunks from the input.
Definition: chunked_input_info.hpp:118
restinio::impl::chunked_input_info_block_t::m_trailing_fields
http_header_fields_t m_trailing_fields
Trailing fields found in the input.
Definition: chunked_input_info.hpp:125
restinio::impl::connection_input_t
Data associated with connection read routine.
Definition: connection.hpp:226
restinio::impl::connection_input_t::connection_input_t
connection_input_t(std::size_t buffer_size, incoming_http_msg_limits_t limits)
Definition: connection.hpp:227
restinio::impl::connection_input_t::m_parser_ctx
http_parser_ctx_t m_parser_ctx
Definition: connection.hpp:237
restinio::impl::connection_input_t::m_buf
fixed_buffer_t m_buf
Input buffer.
Definition: connection.hpp:241
restinio::impl::connection_input_t::m_read_operation_is_running
bool m_read_operation_is_running
Flag to track whether read operation is performed now.
Definition: connection.hpp:248
restinio::impl::connection_input_t::reset_parser
void reset_parser()
Prepare parser for reading new http-message.
Definition: connection.hpp:252
restinio::impl::connection_input_t::m_parser
http_parser m_parser
HTTP-parser.
Definition: connection.hpp:236
restinio::impl::connection_input_t::m_connection_upgrade_stage
connection_upgrade_stage_t m_connection_upgrade_stage
Connection upgrade request stage.
Definition: connection.hpp:244
restinio::impl::connection_t::upgrade_internals_t
Internals that are necessary for upgrade.
Definition: connection.hpp:442
restinio::impl::connection_t::upgrade_internals_t::m_socket
stream_socket_t m_socket
Definition: connection.hpp:456
restinio::impl::connection_t::upgrade_internals_t::m_lifetime_monitor
lifetime_monitor_t m_lifetime_monitor
Definition: connection.hpp:457
restinio::impl::connection_t::upgrade_internals_t::m_settings
connection_settings_handle_t< Traits > m_settings
Definition: connection.hpp:455
restinio::impl::connection_t::upgrade_internals_t::upgrade_internals_t
upgrade_internals_t(connection_settings_handle_t< Traits > settings, stream_socket_t socket, lifetime_monitor_t lifetime_monitor)
Definition: connection.hpp:446
restinio::impl::connection_t::upgrade_internals_t::upgrade_internals_t
upgrade_internals_t(upgrade_internals_t &&)=default
restinio::impl::http_parser_ctx_t
Parsing result context for using in parser callbacks.
Definition: connection.hpp:49
restinio::impl::http_parser_ctx_t::reset
void reset()
Prepare context to handle new request.
Definition: connection.hpp:105
restinio::impl::http_parser_ctx_t::make_chunked_input_info_if_necessary
RESTINIO_NODISCARD chunked_input_info_unique_ptr_t make_chunked_input_info_if_necessary()
Creates an instance of chunked_input_info if there is an info about chunks in the body.
Definition: connection.hpp:124
restinio::impl::http_parser_ctx_t::m_leading_headers_completed
bool m_leading_headers_completed
Definition: connection.hpp:65
restinio::impl::http_parser_ctx_t::m_header
http_request_header_t m_header
Request data.
Definition: connection.hpp:52
restinio::impl::http_parser_ctx_t::m_total_field_count
std::size_t m_total_field_count
Total number of parsed HTTP-fields.
Definition: connection.hpp:84
restinio::impl::http_parser_ctx_t::m_body
std::string m_body
Definition: connection.hpp:53
restinio::impl::http_parser_ctx_t::m_last_was_value
bool m_last_was_value
Definition: connection.hpp:60
restinio::impl::http_parser_ctx_t::m_message_complete
bool m_message_complete
Flag: is http message parsed completely.
Definition: connection.hpp:74
restinio::impl::http_parser_ctx_t::m_limits
const incoming_http_msg_limits_t m_limits
Limits for the incoming message.
Definition: connection.hpp:91
restinio::impl::http_parser_ctx_t::m_chunked_info_block
chunked_input_info_block_t m_chunked_info_block
Definition: connection.hpp:70
restinio::impl::http_parser_ctx_t::m_current_field_name
std::string m_current_field_name
Parser context temp values and flags.
Definition: connection.hpp:58
restinio::impl::http_parser_ctx_t::http_parser_ctx_t
http_parser_ctx_t(incoming_http_msg_limits_t limits)
The main constructor.
Definition: connection.hpp:98
restinio::impl::http_parser_ctx_t::m_last_value_total_size
std::size_t m_last_value_total_size
Definition: connection.hpp:59
restinio::impl::write_group_output_ctx_t::none_write_operation_t
None write operation.
Definition: write_group_output_ctx.hpp:232
restinio::response_output_flags_t
Response output flags for buffers commited to response-coordinator.
Definition: common_types.hpp:123
write_group_output_ctx.hpp