Go to the documentation of this file.
15 #include <http_parser.h>
93 :
m_buf{ buffer_size }
121 typename WS_Message_Handler >
165 "[connection:{}] move socket to [ws_connection:{}]",
172 "[ws_connection:{}] start connection with {}",
178 m_settings->call_state_listener( [
this]() noexcept {
179 return connection_state::notice_t {
182 connection_state::upgraded_to_websocket_t{}
199 "[ws_connection:{}] destructor called",
213 [
this, ctx = shared_from_this() ]
223 "[ws_connection:{}] shutdown",
230 catch(
const std::exception & ex )
235 "[ws_connection:{}] shutdown operation error: {}",
249 [
this, ctx = shared_from_this() ]
260 "[ws_connection:{}] kill",
269 catch(
const std::exception & ex )
274 "[ws_connection:{}] kill operation error: {}",
291 [
this, ctx = shared_from_this(), wswh =
std::move( wswh ) ]
305 catch(
const std::exception & ex )
311 "[ws_connection:{}] unable to init read: {}",
323 bool is_close_frame )
override
330 ctx = shared_from_this(),
345 "[ws_connection:{}] cannot write to websocket: "
346 "write operations disabled",
351 catch(
const std::exception & ex )
357 "[ws_connection:{}] unable to write data: {}",
378 "[ws_connection:{}] close socket",
386 "ws_connection.close_impl.socket.shutdown",
388 asio_ns::error_code ignored_ec;
390 asio_ns::ip::tcp::socket::shutdown_both,
396 "ws_connection.close_impl.socket.close",
432 opcode_t::connection_close_frame,
435 bufs.emplace_back(
std::move( payload ) );
448 std::string desc = std::string{} )
462 template<
typename MSG_BUILDER >
466 MSG_BUILDER msg_builder ) noexcept
474 m_logger,
"ws_connection.call_close_handler_if_necessary",
489 "[ws_connection:{}] start reading header",
514 "[ws_connection:{}] continue reading message",
520 asio_ns::bind_executor(
522 [
this, ctx = shared_from_this() ]
524 (
const asio_ns::error_code & ec, std::size_t length ) noexcept
530 catch(
const std::exception & ex )
536 "[ws_connection:{}] after read header callback error: {}",
550 status_code_t::connection_lost,
553 "[ws_connection:{}] {}: {}",
563 const asio_ns::error_code & ec,
570 "[ws_connection:{}] received {} bytes",
598 assert( nparsed == length );
609 "[ws_connection:{}] start handling {} ({:#x})",
612 static_cast<std::uint16_t
>(md.
m_opcode) );
615 const auto validation_result =
618 if( validation_state_t::frame_header_is_valid != validation_result )
622 "[ws_connection:{}] invalid header",
653 const auto payload_length =
658 if( payload_length == 0 )
665 const auto payload_part_size =
675 const std::size_t length_remaining =
676 payload_length - payload_part_size;
683 if( 0 == length_remaining )
707 std::size_t length_remaining,
709 bool do_validate_payload_and_call_msg_handler =
true )
712 asio_ns::buffer( payload_data, length_remaining ),
713 asio_ns::bind_executor(
716 ctx = shared_from_this(),
719 do_validate_payload_and_call_msg_handler ]
721 (
const asio_ns::error_code & ec, std::size_t length ) noexcept
730 do_validate_payload_and_call_msg_handler );
732 catch(
const std::exception & ex )
738 "[ws_connection:{}] after read payload callback error: {}",
750 std::size_t length_remaining,
751 const asio_ns::error_code & ec,
753 bool do_validate_payload_and_call_msg_handler =
true )
759 "[ws_connection:{}] received {} bytes",
764 assert( length <= length_remaining );
766 const std::size_t next_length_remaining =
767 length_remaining - length;
769 if( do_validate_payload_and_call_msg_handler )
773 if( 0 == next_length_remaining )
785 payload_data + length,
786 next_length_remaining,
787 do_validate_payload_and_call_msg_handler );
795 if( 0 == next_length_remaining )
802 payload_data + length,
803 length_remaining - length,
804 do_validate_payload_and_call_msg_handler );
826 catch(
const std::exception & ex )
830 "[ws_connection:{}] execute handler error: {}",
843 std::size_t next_length_remaining )
845 const auto validation_result =
848 if( validation_state_t::payload_part_is_valid != validation_result )
861 if( 0 == next_length_remaining )
868 const bool do_validate_payload_and_call_msg_handler =
false;
870 payload_data + length,
871 next_length_remaining,
872 do_validate_payload_and_call_msg_handler );
887 "[ws_connection:{}] invalid paload",
891 if( validation_state_t::invalid_close_code == validation_result )
940 if( validation_state_t::frame_is_valid == validation_result )
944 if( opcode_t::connection_close_frame == md.m_opcode )
948 "[ws_connection:{}] got close frame from peer, status: {}",
950 static_cast<std::uint16_t
>(
964 std::make_shared< message_t >(
976 if( opcode_t::connection_close_frame == md.m_opcode )
985 "[ws_connection:{}] expected close frame came",
1008 std::make_shared< message_t >(
1010 opcode_t::connection_close_frame,
1021 if( is_close_frame )
1025 "[ws_connection:{}] user sends close frame",
1047 "[ws_connection:{}] try to write while socket is closed",
1055 asio_convertible_error_t::write_was_not_executed ) );
1081 if( next_write_group )
1085 "[ws_connection:{}] start next write group, "
1088 next_write_group->items_count() );
1112 if( holds_alternative< trivial_write_operation_t >( wo ) )
1116 else if( holds_alternative< none_write_operation_t >( wo ) )
1122 assert( holds_alternative< file_write_operation_t >( wo ) );
1123 throw exception_t{
"sendfile write operation not implemented" };
1126 catch(
const std::exception & ex )
1132 "[ws_connection:{}] handle_current_write_ctx failed: {}",
1147 "[ws_connection:{}] sending data with "
1157 asio_ns::async_write(
1160 asio_ns::bind_executor(
1163 ctx = shared_from_this() ]
1165 (
const asio_ns::error_code & ec, std::size_t written ) noexcept
1173 "[ws_connection:{}] outgoing data was sent: {} bytes",
1181 catch(
const std::exception & ex )
1187 "[ws_connection:{}] after write callback error: {}",
1202 "[ws_connection:{}] finishing current write group",
1225 status_code_t::connection_lost,
1228 "[ws_connection:{}] unable to write: {}",
1237 catch(
const std::exception & ex )
1241 "[ws_connection:{}] notificator error: {}",
1284 conn_object.check_timeout_impl();
1286 catch(
const std::exception & x )
1288 conn_object.trigger_error_and_close(
1291 return fmt::format(
"[connection: {}] unexpected "
1292 "error during timeout handling: {}",
1293 conn_object.connection_id(),
1302 std::chrono::steady_clock::time_point::max();
1309 const auto now = std::chrono::steady_clock::now();
1314 "[wd_connection:{}] write operation timed out",
1325 "[wd_connection:{}] waiting for close-frame from peer timed out",
1348 std::chrono::steady_clock::now() +
m_settings->m_write_http_response_timelimit;
1355 std::chrono::steady_clock::now() +
m_settings->m_read_next_http_message_timelimit;
1411 template <
typename Action >
void handle_trivial_write_operation(const trivial_write_operation_t &op)
connection_id_t connection_id() const noexcept
Get connection id.
asio_ns::error_code make_asio_compaible_error(asio_convertible_error_t err) noexcept
Make restinio error_code compatible with asio_ns::error_code.
Exception class for all exceptions thrown by RESTinio.
void send_close_frame_to_peer(std::string payload)
Send close frame to peer.
std::size_t length() const noexcept
How many unconsumed bytes are there in buffer.
void write_data_impl(write_group_t wg, bool is_close_frame)
Implementation of writing data performed on the asio_ns::io_context.
Helper class for reading bytes and feeding them to parser.
std::shared_ptr< message_t > message_handle_t
Request handler, that is the type for calling request handlers.
void start_read_header()
Start the process of reading ws messages from socket.
Traits::strand_t & get_executor() noexcept
An executor for callbacks on async operations.
restinio::impl::connection_settings_handle_t< Traits > m_settings
Common paramaters of a connection.
WS_Message_Handler message_handler_t
void init_next_timeout_checking()
schedule next timeout checking.
static ws_connection_t & cast_to_self(tcp_connection_ctx_base_t &base)
Timers.
void disable()
Disable ation: action will not be executed even on a first shot.
timer_guard_t m_timer_guard
bool transmitting() const noexcept
Check if data is trunsmitting now.
const char * opcode_to_string(opcode_t opcode)
Helper sunction to get method string name.
Helper class for writting response data.
solid_write_operation_variant_t extract_next_write_operation()
et an object with next write operation to perform.
write_state_t m_write_state
A state of a websocket output.
Helper type for controlling the lifetime of the connection.
void fail_write_group(const asio_ns::error_code &ec)
Handle current group write process failed.
ws_outgoing_data_t m_outgoing_data
Output buffers queue.
const message_details_t & current_message() const
Get current mesasge details.
void after_read_payload(char *payload_data, std::size_t length_remaining, const asio_ns::error_code &ec, std::size_t length, bool do_validate_payload_and_call_msg_handler=true)
Handle read operation result, when reading payload.
constexpr final_frame_flag_t not_final_frame
ws_protocol_validator_t m_protocol_validator
Helper for validating protocol.
Wrapper for an executor (strand) used by connections.
@ write_enabled
Able to append outgoing data.
connection_input_t m_input
Input routine.
void call_handler_on_current_message()
void start_next_write_group(optional_t< write_group_t > next_wg) noexcept
Start handlong next write group.
void consume_header_from_buffer(const char *data, std::size_t length)
Parse header from internal buffer.
void init_read(ws_handle_t wsh) override
Start reading ws-messages.
void handle_parsed_and_valid_header(const message_details_t &md)
Handle parsed and valid header.
void consumed_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
std::uint64_t connection_id_t
Type for ID of connection.
void init_write_if_necessary()
Checks if there is something to write, and if so starts write operation.
void handle_invalid_payload(validation_state_t validation_result)
Handle payload errors.
virtual void write_data(write_group_t wg, bool is_close_frame) override
Write pieces of outgoing data.
restinio::impl::write_group_output_ctx_t m_write_output_ctx
Write to socket operation context.
void guard_write_operation()
Start guard write operation if necessary.
optional_t< write_group_t > pop_ready_buffers()
#define RESTINIO_ENSURE_NOEXCEPT_CALL(expr)
A wrapper around static_assert for checking that an expression is noexcept and execution of that expr...
Websocket message class with more detailed protocol information.
virtual void check_timeout(tcp_connection_ctx_handle_t &self) override
void start_read_payload(char *payload_data, std::size_t length_remaining, bool do_validate_payload_and_call_msg_handler=true)
Start reading message payload.
std::weak_ptr< ws_t > ws_weak_handle_t
void obtained_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
void handle_current_write_ctx()
validation_state_t process_and_unmask_next_payload_part(char *data, size_t size)
Validate next part of current frame and reset source part to unmasked data.
A helper class for running exclusive action. Only a first action will run.
virtual void shutdown() override
Shutdown websocket.
Context for handling websocket connections.
void log_error_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
@ read_nothing
Do not read anything (before activation).
typename Traits::timer_manager_t timer_manager_t
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
size_t parser_execute(const char *data, size_t size)
Parse piece of data from buffer.
void append(write_group_t wg)
Add buffers to queue.
void graceful_close()
Close WebSocket connection in a graceful manner.
std::shared_ptr< connection_settings_t< Traits > > connection_settings_handle_t
tcp_connection_ctx_weak_handle_t m_prepared_weak_ctx
void handle_parsed_header(const message_details_t &md)
Handle parsed header.
std::size_t uint64_to_size_t(std::uint64_t v)
Helper function for truncating uint64 to std::size_t with exception if that truncation will lead to d...
std::queue< write_group_t > write_groups_queue_t
auto make_asio_buffer() noexcept
Make asio buffer for reading bytes from socket.
typename timer_manager_t::timer_guard_t timer_guard_t
std::shared_ptr< ws_t > ws_handle_t
Alias for ws_t handle.
void log_trace_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
ws_connection_t(const ws_connection_t &)=delete
logger_t & m_logger
Logger for operation.
std::shared_ptr< timer_manager_t > timer_manager_handle_t
typename Traits::logger_t logger_t
raw_data_t write_message_details(const message_details_t &message)
Serialize websocket message details into bytes buffer.
void run_if_first(Action &&action) noexcept(noexcept(action()))
write_state_t
Websocket output states.
ws_weak_handle_t m_websocket_weak_handle
A waek handler for owning ws_t to use it when call message handler.
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...
void reset()
Reset to initial state.
A special wrapper around fmtlib include files.
constexpr final_frame_flag_t final_frame
typename Traits::stream_socket_t stream_socket_t
~ws_connection_t() override
one_shot_action_t m_close_impl
typename Traits::strand_t strand_t
Class for websocket protocol validations.
ws_connection_t & operator=(const ws_connection_t &)=delete
lifetime_monitor_t m_lifetime_monitor
Monitor of the connection lifetime.
validation_state_t finish_frame()
Make final checks of payload if it is necessary and reset state.
void init_write()
Initiate write operation.
@ read_any_frame
Reads any type of frame and serve it to user.
void after_read_header(const asio_ns::error_code &ec, std::size_t length)
Handle read operation result, when reading header.
one_shot_action_t m_close_frame_to_peer
validation_state_t process_new_frame(const message_details_t &frame)
Start work with new frame.
void call_message_handler(message_handle_t close_frame)
Call user message handler with current message.
Group of writable items transported to the context of underlying connection as one solid piece.
void start_waiting_close_frame_only()
Start waiting for close-frame.
bool validate_payload_part(char *payload_data, std::size_t length, std::size_t next_length_remaining)
Validates a part of received payload.
message_handler_t m_msg_handler
Websocket message handler provided by user.
ws_connection_t(ws_connection_t &&)=delete
constexpr size_t websocket_header_max_size()
Max possible size of websocket frame header (a part before payload).
void reset()
Reset internal state.
@ read_only_close_frame
Reads only close frame: skip all frames until close-frame.
one_shot_action_t m_close_frame_to_user
void finish_write_group()
Finish writing group normally.
const std::vector< asio_ns::const_buffer > & get_trivial_bufs() const noexcept
Get buffer "iovec" for performing gather write.
read_state_t m_read_state
A state of a websocket input.
WebSocket connection base.
auto size() const noexcept
The size of data within this operation.
restinio::impl::executor_wrapper_t< typename Traits::strand_t > executor_wrapper_base_t
virtual void kill() override
Kill websocket.
void send_close_frame_to_peer(status_code_t code, std::string desc=std::string{})
Send close frame to peer.
status_code_t status_code_from_bin(string_view_t data)
validation_state_t
States of validated frame.
std::shared_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_handle_t
Alias for http connection handle.
read_state_t
Websocket input states.
void finish_handling_current_write_ctx()
Do post write actions for current write group.
std::uint64_t payload_len() const
Get payload len.
Detection of compiler version and absence of various features.
@ write_disabled
No more outgoing data can be added (e.g. close-frame was sent).
std::weak_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_weak_handle_t
Alias for http connection weak handle.
std::chrono::steady_clock::time_point m_write_operation_timeout_after
void handle_read_error(const char *desc, const asio_ns::error_code &ec)
Handle read error (reading header or payload)
void after_write(const asio_ns::error_code &ec)
Handle write response finished.
const char * bytes() const noexcept
Get pointer to unconsumed bytes.
void guard_close_frame_from_peer_operation()
void check_timeout_impl()
Helpers for safe truncation of unsigned integers.
void trigger_error_and_close(status_code_t status, MSG_BUILDER msg_builder) noexcept
Trigger an error.
A queue for outgoing buffers.
std::chrono::steady_clock::time_point m_close_frame_from_peer_timeout_after
std::string status_code_to_bin(status_code_t code)
void call_close_handler_if_necessary(status_code_t status)
void consume_header_from_socket()
Initiate read operation on socket to receive bytes for header.
std::vector< writable_item_t > writable_items_container_t
bool header_parsed() const
Check header of current websocket message is parsed.
void close_impl() noexcept
Standard close routine.
stream_socket_t m_socket
Connection.
typename connection_count_limit_types< Traits >::lifetime_monitor_t lifetime_monitor_t
write_groups_queue_t m_awaiting_write_groups
A queue of buffers.
Write operaton using sendfile.