24 #ifndef STATICLIB_PION_WEBSOCKET_HPP
25 #define STATICLIB_PION_WEBSOCKET_HPP
30 #include <unordered_map>
35 #include "staticlib/support.hpp"
36 #include "staticlib/utils.hpp"
37 #include "staticlib/websocket.hpp"
46 namespace websocket_detail {
56 std::vector<sl::websocket::frame>& frames_ref;
60 sl::websocket::masked_payload_source src_single;
64 sl::io::multi_source<std::vector<sl::websocket::masked_payload_source>>
src_multi;
76 if (1 == frames.size()) {
77 return frames[0].payload_unmasked();
79 return sl::websocket::masked_payload_source({
nullptr, 0}, 0);
84 auto vec = std::vector<sl::websocket::masked_payload_source>();
85 if (frames.size() > 1) {
86 for (
auto& fr : frames) {
87 vec.emplace_back(fr.payload_unmasked());
90 return sl::io::make_multi_source(std::move(vec));
109 frames_ref(other.frames_ref),
110 src_single(std::move(other.src_single)),
125 std::streamsize
read(sl::io::span<char> span) {
126 if (1 == frames_ref.size()) {
127 return src_single.read(span);
128 }
else if (frames_ref.size() > 1) {
131 return std::char_traits<char>::eof();
146 enum class close_status : uint32_t {
148 going_away = 0xe9030288,
149 protocol_error = 0xea030288,
150 overflow = 0xf1030288,
155 std::unique_ptr<http_request> request;
156 std::shared_ptr<tcp_connection> connection;
159 std::function<void(std::unique_ptr<websocket>)> on_open_fun;
160 std::function<void(std::unique_ptr<websocket>)> on_message_fun;
161 std::function<void(std::unique_ptr<websocket>)> on_close_fun;
164 const size_t receive_buffer_max_size;
165 const size_t frames_max_count;
168 std::vector<asio::const_buffer> payload_buffers;
169 std::vector<std::unique_ptr<char[]>> payload_cache;
170 size_t payload_length = 0;
173 std::vector<char> receive_buffer;
174 std::vector<std::unique_ptr<char[]>> frames_cache;
175 std::vector<sl::websocket::frame> frames;
189 websocket(std::unique_ptr<http_request> req, std::shared_ptr<tcp_connection> conn,
190 std::function<
void(std::unique_ptr<websocket>)> open_handler,
191 std::function<
void(std::unique_ptr<websocket>)> message_handler,
192 std::function<
void(std::unique_ptr<websocket>)> close_handler,
193 size_t max_receive_cache_size_bytes = (1024*1024),
194 size_t max_cached_frames_count = 1024) :
195 request(std::move(req)),
196 connection(std::move(conn)),
197 on_open_fun(std::move(open_handler)),
198 on_message_fun(std::move(message_handler)),
199 on_close_fun(std::move(close_handler)),
200 receive_buffer_max_size(max_receive_cache_size_bytes),
201 frames_max_count(max_cached_frames_count) {
202 connection->set_lifecycle(tcp_connection::lifecycle::close);
210 connection->finish();
232 return request->get_header(
"Sec-WebSocket-Key");
260 if(frames.size() > 0) {
261 return frames[0].type();
263 return sl::websocket::frame_type::invalid;
283 void write(sl::io::span<const char> data) {
284 if (data.size() > 0) {
285 payload_buffers.push_back(add_to_payload_cache(data));
286 payload_length += data.size();
298 if (data.size() > 0) {
299 payload_buffers.push_back(asio::buffer(data.data(), data.size()));
300 payload_length += data.size();
312 24 == req.
get_header(
"Sec-WebSocket-Key").length();
321 static void start(std::unique_ptr<websocket>
self) {
322 self->prepare_handshake();
323 send_internal(std::move(
self),
324 [](std::unique_ptr<websocket>
self) {
325 on_open(std::move(
self));
334 static void receive(std::unique_ptr<websocket>
self) {
335 self->clear_frames_cache();
336 process_receive_buffer(std::move(
self));
346 static void send(std::unique_ptr<websocket>
self,
347 sl::websocket::frame_type msg_type = sl::websocket::frame_type::text) {
359 template<
typename Handler>
360 static void send_message(std::unique_ptr<websocket>
self, sl::websocket::frame_type msg_type,
362 self->prepare_header(msg_type);
364 post_with_strand(std::move(
self),
365 [handler](std::unique_ptr<websocket>
self) {
366 send_internal(std::move(
self), std::move(handler));
384 static void broadcast(std::vector<std::shared_ptr<tcp_connection>>& connections,
385 sl::io::span<const char> msg,
386 sl::websocket::frame_type msg_type = sl::websocket::frame_type::text) {
388 auto holder = std::make_shared<std::vector<char>>();
389 auto hbuf = std::array<char, 10>();
390 auto header = sl::websocket::frame::make_header(hbuf, msg_type, msg.size());
391 holder->resize(header.size() + msg.size());
392 std::memcpy(holder->data(), header.data(), header.size());
393 std::memcpy(holder->data() + header.size(), msg.data(), msg.size());
396 for (
auto& el : connections) {
397 send_broadcast(std::move(el), holder);
407 static void close(std::unique_ptr<websocket>
self,
const close_status& status = close_status::normal) {
408 on_close(std::move(
self), status);
419 asio::const_buffer add_to_payload_cache(sl::io::span<const char> buf) {
420 payload_cache.emplace_back(
new char[buf.size()]);
421 char* dest = payload_cache.back().get();
422 std::memcpy(dest, buf.data(), buf.size());
423 return asio::buffer(dest, buf.size());
426 void add_to_receive_buffer(sl::io::span<const char> buf) {
427 auto size = receive_buffer.size();
428 receive_buffer.resize(size + buf.size());
429 std::memcpy(receive_buffer.data() + size, buf.data(), buf.size());
432 void remove_frame_from_receive_buffer(sl::websocket::frame& frame) {
433 auto receive_tail = receive_buffer.size() - frame.size();
434 if (0 == receive_tail) {
435 receive_buffer.clear();
437 std::memmove(receive_buffer.data(), receive_buffer.data() + frame.size(), receive_tail);
438 receive_buffer.resize(receive_tail);
442 void add_to_frames_cache(sl::websocket::frame& frame) {
443 frames_cache.emplace_back(
new char[frame.size()]);
444 char* dest = frames_cache.back().get();
445 std::memcpy(dest, frame.data(), frame.size());
446 frames.emplace_back(sl::websocket::frame({dest, frame.size()}));
447 remove_frame_from_receive_buffer(frame);
450 void clear_payload() {
451 payload_buffers.clear();
452 payload_buffers.push_back(asio::buffer(sl::utils::empty_string().data(), 0));
453 payload_cache.clear();
457 void clear_frames_cache() {
459 if (frames.size() > 0) {
460 remove_frame_from_receive_buffer(frames.back());
462 frames_cache.clear();
466 void prepare_header(sl::websocket::frame_type msg_type) {
467 auto buf = std::array<char, 10>();
468 auto header = sl::websocket::frame::make_header(buf, msg_type, payload_length);
469 payload_cache.emplace_back(
new char[header.size()]);
470 char* dest = payload_cache.back().get();
471 std::memcpy(dest, header.data(), header.size());
472 payload_buffers[0] = asio::buffer(dest, header.size());
475 void prepare_handshake() {
476 write(sl::websocket::handshake::make_response_line());
477 auto& key = request->get_header(
"Sec-WebSocket-Key");
478 auto headers = sl::websocket::handshake::make_response_headers(key);
479 for (
auto& ha : headers) {
488 bool receive_buffer_overflow(
size_t addition) {
489 return receive_buffer.size() + addition > receive_buffer_max_size;
492 bool frames_cache_overflow() {
493 return frames.size() >= frames_max_count;
496 template<
typename Handler>
497 static void post_with_strand(std::unique_ptr<websocket>
self, Handler handler) {
498 auto self_ptr =
self.get();
499 auto self_shared = sl::support::make_shared_with_release_deleter(
self.release());
501 [self_shared, handler]() {
502 auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared);
503 if (
nullptr !=
self.
get()) {
504 handler(std::move(
self));
509 self_ptr->connection->get_strand().post(std::move(post_handler));
512 template<
typename Handler>
513 static void send_internal(std::unique_ptr<websocket>
self, Handler handler) {
514 auto self_ptr =
self.get();
515 auto self_shared = sl::support::make_shared_with_release_deleter(
self.release());
517 [self_shared, handler](
const asio::error_code& ec, size_t) {
518 auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared);
519 if (
nullptr !=
self.
get()) {
520 self->clear_payload();
522 handler(std::move(
self));
525 " code: [" << ec <<
"]" <<
526 " message: [" << ec.message() <<
"]" <<
527 " id: [" <<
self->get_id() <<
"]" <<
528 " path: [" <<
self->request->get_resource() <<
"]");
529 on_close(std::move(
self), close_status::error);
535 auto send_handler_stranded = self_ptr->connection->get_strand().wrap(send_handler);
536 self_ptr->connection->async_write(self_ptr->payload_buffers, std::move(send_handler_stranded));
539 static void send_close(std::unique_ptr<websocket>
self,
const close_status& status) {
540 auto self_ptr =
self.get();
541 auto self_shared = sl::support::make_shared_with_release_deleter(
self.release());
543 [self_shared](
const asio::error_code&, size_t) {
544 auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared);
545 if (
nullptr !=
self.
get()) {
546 auto self_ptr =
self.get();
547 self_ptr->on_close_fun(std::move(
self));
553 auto send_handler_stranded = self_ptr->connection->get_strand().wrap(send_handler);
554 auto msg = asio::buffer(std::addressof(status),
sizeof(status));
555 self_ptr->connection->async_write(std::move(msg), std::move(send_handler_stranded));
558 static void receive_internal(std::unique_ptr<websocket>
self) {
559 auto self_ptr =
self.get();
560 auto self_shared = sl::support::make_shared_with_release_deleter(
self.release());
562 [self_shared](
const std::error_code& ec,
size_t bytes_read) {
563 auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared);
564 if (
nullptr !=
self.
get()) {
566 const char* dptr =
self->connection->get_read_buffer().data();
567 auto buf = sl::io::make_span(dptr, bytes_read);
568 consume(std::move(
self), buf);
571 " code: [" << ec <<
"]" <<
572 " message: [" << ec.message() <<
"]" <<
573 " id: [" <<
self->get_id() <<
"]" <<
574 " path: [" <<
self->request->get_resource() <<
"]");
575 on_close(std::move(
self), close_status::error);
581 auto read_handler_stranded = self_ptr->connection->get_strand().wrap(std::move(read_handler));
582 self_ptr->connection->async_read_some(std::move(read_handler_stranded));
585 static void send_broadcast(std::shared_ptr<tcp_connection> conn,
586 std::shared_ptr<std::vector<char>> data) {
589 conn->async_write(asio::buffer(data->data(), data->size()),
590 [data](
const std::error_code&,
size_t){ });
592 conn->get_strand().post(std::move(handler));
595 static void consume(std::unique_ptr<websocket>
self, sl::io::span<const char> buf) {
597 if (self->receive_buffer_overflow(buf.size())) {
599 " id: [" << self->get_id() <<
"]" <<
600 " path: [" <<
self->request->get_resource() <<
"]");
601 on_close(std::move(
self), close_status::overflow);
604 self->add_to_receive_buffer(buf);
605 process_receive_buffer(std::move(
self));
608 static void process_receive_buffer(std::unique_ptr<websocket>
self) {
609 auto frame = sl::websocket::frame(self->receive_buffer_span());
611 if (!frame.is_well_formed()) {
613 "Invalid frame received, header: [" << frame.header_hex() <<
"]" <<
614 " id: [" <<
self->get_id() <<
"]" <<
615 " path: [" <<
self->request->get_resource() <<
"]");
616 on_close(std::move(
self), close_status::protocol_error);
620 if (!frame.is_complete()) {
621 receive_internal(std::move(
self));
625 if (!frame.is_final()) {
626 on_continuation(std::move(
self), frame);
630 process_final_frame(std::move(
self), frame);
633 static void process_final_frame(std::unique_ptr<websocket>
self, sl::websocket::frame frame) {
634 self->frames.push_back(frame);
636 switch (frame.type()) {
637 case sl::websocket::frame_type::text:
638 case sl::websocket::frame_type::binary:
639 case sl::websocket::frame_type::continuation:
640 on_message(std::move(
self));
642 case sl::websocket::frame_type::ping:
643 on_ping(std::move(
self), frame);
645 case sl::websocket::frame_type::close:
646 on_close(std::move(
self), close_status::normal);
649 on_close(std::move(
self), close_status::protocol_error);
654 static void on_open(std::unique_ptr<websocket>
self) {
656 " id: [" << self->get_id() <<
"]" <<
657 " path: [" <<
self->request->get_resource() <<
"]");
658 auto self_ptr =
self.get();
659 self_ptr->on_open_fun(std::move(
self));
662 static void on_message(std::unique_ptr<websocket>
self) {
663 auto self_ptr =
self.get();
664 self_ptr->on_message_fun(std::move(
self));
667 static void on_close(std::unique_ptr<websocket>
self,
const close_status& status) {
669 " id: [" << self->get_id() <<
"]" <<
670 " path: [" <<
self->request->get_resource() <<
"]");
671 send_close(std::move(
self), status);
674 static void on_ping(std::unique_ptr<websocket>
self, sl::websocket::frame frame) {
675 if (frame.payload_length() > 0) {
676 auto src = frame.payload_unmasked();
677 auto buf = std::array<char, (1<<7)>();
678 auto len = src.read({buf.data(), buf.size()});
679 self->write({buf.data(), len});
681 send_internal(std::move(
self),
682 [](std::unique_ptr<websocket>
self) {
687 static void on_continuation(std::unique_ptr<websocket>
self, sl::websocket::frame frame) {
688 if (self->frames_cache_overflow()) {
690 " id: [" << self->get_id() <<
"]" <<
691 " path: [" <<
self->request->get_resource() <<
"]");
692 on_close(std::move(
self), close_status::overflow);
695 self->add_to_frames_cache(frame);
697 post_with_strand(std::move(
self), websocket::process_receive_buffer);
700 sl::io::span<const char> receive_buffer_span() {
701 return sl::io::make_span(
702 const_cast<const char*>(receive_buffer.data()),
703 receive_buffer.size());
710 using websocket_ptr = std::unique_ptr<websocket>;
714 using websocket_handler_type = std::function<void(std::unique_ptr<websocket>)>;