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 {
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: {}",
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 =
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 =
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",
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",
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",
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;
1398 read_only_close_frame,
1411 template <
typename Action >
Helper type for controlling the lifetime of the connection.
An object with info about connection to be passed to state listener.
Type of object that tells that the connection has been upgraded to WebSocket.
Exception class for all exceptions thrown by RESTinio.
Wrapper for an executor (strand) used by connections.
Traits::strand_t & get_executor() noexcept
An executor for callbacks on async operations.
Helper class for reading bytes and feeding them to parser.
std::size_t length() const noexcept
How many unconsumed bytes are there in buffer.
void consumed_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
void obtained_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
auto make_asio_buffer() noexcept
Make asio buffer for reading bytes from socket.
const char * bytes() const noexcept
Get pointer to unconsumed bytes.
Write operaton using sendfile.
auto size() const noexcept
The size of data within this operation.
const std::vector< asio_ns::const_buffer > & get_trivial_bufs() const noexcept
Get buffer "iovec" for performing gather write.
Helper class for writting response data.
void fail_write_group(const asio_ns::error_code &ec)
Handle current group write process failed.
solid_write_operation_variant_t extract_next_write_operation()
et an object with next write operation to perform.
void finish_write_group()
Finish writing group normally.
void start_next_write_group(optional_t< write_group_t > next_wg) noexcept
Start handlong next write group.
bool transmitting() const noexcept
Check if data is trunsmitting now.
connection_id_t connection_id() const noexcept
Get connection id.
Websocket message class with more detailed protocol information.
std::uint64_t payload_len() const
Get payload len.
WebSocket connection base.
A helper class for running exclusive action. Only a first action will run.
void run_if_first(Action &&action) noexcept(noexcept(action()))
void disable()
Disable ation: action will not be executed even on a first shot.
Context for handling websocket connections.
timer_guard_t m_timer_guard
void finish_handling_current_write_ctx()
Do post write actions for current write group.
void after_read_header(const asio_ns::error_code &ec, std::size_t length)
Handle read operation result, when reading header.
restinio::impl::connection_settings_handle_t< Traits > m_settings
Common paramaters of a connection.
void consume_header_from_socket()
Initiate read operation on socket to receive bytes for header.
message_handler_t m_msg_handler
Websocket message handler provided by user.
void handle_parsed_header(const message_details_t &md)
Handle parsed header.
WS_Message_Handler message_handler_t
bool validate_payload_part(char *payload_data, std::size_t length, std::size_t next_length_remaining)
Validates a part of received payload.
ws_weak_handle_t m_websocket_weak_handle
A waek handler for owning ws_t to use it when call message handler.
virtual void shutdown() override
Shutdown websocket.
typename connection_count_limit_types< Traits >::lifetime_monitor_t lifetime_monitor_t
void send_close_frame_to_peer(std::string payload)
Send close frame to peer.
void write_data_impl(write_group_t wg, bool is_close_frame)
Implementation of writing data performed on the asio_ns::io_context.
read_state_t
Websocket input states.
@ read_only_close_frame
Reads only close frame: skip all frames until close-frame.
@ read_nothing
Do not read anything (before activation).
@ read_any_frame
Reads any type of frame and serve it to user.
std::weak_ptr< ws_t > ws_weak_handle_t
void check_timeout_impl()
typename Traits::logger_t logger_t
write_state_t
Websocket output states.
@ write_enabled
Able to append outgoing data.
@ write_disabled
No more outgoing data can be added (e.g. close-frame was sent).
void guard_close_frame_from_peer_operation()
std::chrono::steady_clock::time_point m_close_frame_from_peer_timeout_after
typename timer_manager_t::timer_guard_t timer_guard_t
one_shot_action_t m_close_impl
void init_write_if_necessary()
Checks if there is something to write, and if so starts write operation.
void trigger_error_and_close(status_code_t status, MSG_BUILDER msg_builder) noexcept
Trigger an error.
void start_read_header()
Start the process of reading ws messages from socket.
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.
logger_t & m_logger
Logger for operation.
one_shot_action_t m_close_frame_to_peer
one_shot_action_t m_close_frame_to_user
tcp_connection_ctx_weak_handle_t m_prepared_weak_ctx
void handle_trivial_write_operation(const trivial_write_operation_t &op)
void init_next_timeout_checking()
schedule next timeout checking.
void handle_invalid_payload(validation_state_t validation_result)
Handle payload errors.
void handle_current_write_ctx()
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.
void call_close_handler_if_necessary(status_code_t status)
void consume_header_from_buffer(const char *data, std::size_t length)
Parse header from internal buffer.
void send_close_frame_to_peer(status_code_t code, std::string desc=std::string{})
Send close frame to peer.
ws_connection_t(const ws_connection_t &)=delete
virtual void check_timeout(tcp_connection_ctx_handle_t &self) override
connection_input_t m_input
Input routine.
void handle_read_error(const char *desc, const asio_ns::error_code &ec)
Handle read error (reading header or payload)
void call_handler_on_current_message()
write_state_t m_write_state
A state of a websocket output.
ws_protocol_validator_t m_protocol_validator
Helper for validating protocol.
void handle_parsed_and_valid_header(const message_details_t &md)
Handle parsed and valid header.
ws_connection_t & operator=(const ws_connection_t &)=delete
ws_connection_t(ws_connection_t &&)=delete
void start_waiting_close_frame_only()
Start waiting for close-frame.
std::chrono::steady_clock::time_point m_write_operation_timeout_after
typename Traits::strand_t strand_t
virtual void kill() override
Kill websocket.
void guard_write_operation()
Start guard write operation if necessary.
~ws_connection_t() override
ws_outgoing_data_t m_outgoing_data
Output buffers queue.
void init_read(ws_handle_t wsh) override
Start reading ws-messages.
std::shared_ptr< timer_manager_t > timer_manager_handle_t
void call_message_handler(message_handle_t close_frame)
Call user message handler with current message.
static ws_connection_t & cast_to_self(tcp_connection_ctx_base_t &base)
Timers.
void init_write()
Initiate write operation.
lifetime_monitor_t m_lifetime_monitor
Monitor of the connection lifetime.
void after_write(const asio_ns::error_code &ec)
Handle write response finished.
restinio::impl::write_group_output_ctx_t m_write_output_ctx
Write to socket operation context.
void close_impl() noexcept
Standard close routine.
typename Traits::stream_socket_t stream_socket_t
virtual void write_data(write_group_t wg, bool is_close_frame) override
Write pieces of outgoing data.
stream_socket_t m_socket
Connection.
void graceful_close()
Close WebSocket connection in a graceful manner.
read_state_t m_read_state
A state of a websocket input.
typename Traits::timer_manager_t timer_manager_t
A queue for outgoing buffers.
optional_t< write_group_t > pop_ready_buffers()
write_groups_queue_t m_awaiting_write_groups
A queue of buffers.
void append(write_group_t wg)
Add buffers to queue.
void reset()
Reset internal state.
const message_details_t & current_message() const
Get current mesasge details.
size_t parser_execute(const char *data, size_t size)
Parse piece of data from buffer.
bool header_parsed() const
Check header of current websocket message is parsed.
Class for websocket protocol validations.
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.
validation_state_t process_new_frame(const message_details_t &frame)
Start work with new frame.
validation_state_t finish_frame()
Make final checks of payload if it is necessary and reset state.
void reset()
Reset to initial state.
Group of writable items transported to the context of underlying connection as one solid piece.
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
Detection of compiler version and absence of various features.
#define RESTINIO_ENSURE_NOEXCEPT_CALL(expr)
A wrapper around static_assert for checking that an expression is noexcept and execution of that expr...
A special wrapper around fmtlib include files.
std::shared_ptr< connection_settings_t< Traits > > connection_settings_handle_t
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...
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 log_error_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
void log_trace_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
raw_data_t write_message_details(const message_details_t &message)
Serialize websocket message details into bytes buffer.
constexpr size_t websocket_header_max_size()
Max possible size of websocket frame header (a part before payload).
std::queue< write_group_t > write_groups_queue_t
validation_state_t
States of validated frame.
std::shared_ptr< message_t > message_handle_t
Request handler, that is the type for calling request handlers.
constexpr final_frame_flag_t final_frame
constexpr final_frame_flag_t not_final_frame
const char * opcode_to_string(opcode_t opcode)
Helper sunction to get method string name.
status_code_t status_code_from_bin(string_view_t data)
std::string status_code_to_bin(status_code_t code)
std::shared_ptr< ws_t > ws_handle_t
Alias for ws_t handle.
std::shared_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_handle_t
Alias for http connection handle.
std::vector< writable_item_t > writable_items_container_t
std::weak_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_weak_handle_t
Alias for http connection weak handle.
@ write_was_not_executed
After write notificator error: data was not sent, connection closed (or aborted) before a given piece...
asio_ns::error_code make_asio_compaible_error(asio_convertible_error_t err) noexcept
Make restinio error_code compatible with asio_ns::error_code.
std::uint64_t connection_id_t
Type for ID of connection.
Helpers for safe truncation of unsigned integers.