3 #include "crow/logging.h"
4 #include "crow/socket_adaptors.h"
5 #include "crow/http_request.h"
7 #include "crow/utility.h"
12 namespace asio = boost::asio;
13 using error_code = boost::system::error_code;
15 using error_code = asio::error_code;
27 enum class WebSocketReadState
37 enum CloseStatusCode : uint16_t {
39 EndpointGoingAway = 1001,
41 UnacceptableData = 1003,
42 InconsistentData = 1007,
43 PolicyViolated = 1008,
45 ExtensionsNotNegotiated = 1010,
46 UnexpectedCondition = 1011,
49 NoStatusCodePresent = 1005,
50 ClosedAbnormally = 1006,
51 TLSHandshakeFailure = 1015,
53 StartStatusCodesForLibraries = 3000,
54 StartStatusCodesForPrivateUse = 4000,
56 StartStatusCodes = NormalClosure,
57 EndStatusCodes = 4999,
63 virtual void send_binary(std::string msg) = 0;
64 virtual void send_text(std::string msg) = 0;
65 virtual void send_ping(std::string msg) = 0;
66 virtual void send_pong(std::string msg) = 0;
67 virtual void close(std::string
const& msg =
"quit", uint16_t status_code = CloseStatusCode::NormalClosure) = 0;
68 virtual std::string get_remote_ip() = 0;
69 virtual std::string get_subprotocol()
const = 0;
72 void userdata(
void* u) { userdata_ = u; }
73 void* userdata() {
return userdata_; }
104 template<
typename Adaptor,
typename Handler>
114 uint64_t max_payload,
const std::vector<std::string>& subprotocols,
119 std::function<
bool(
const crow::request&,
void**)> accept_handler):
120 adaptor_(std::move(adaptor)),
122 max_payload_bytes_(max_payload),
123 open_handler_(std::move(open_handler)),
124 message_handler_(std::move(message_handler)),
125 close_handler_(std::move(close_handler)),
126 error_handler_(std::move(error_handler)),
127 accept_handler_(std::move(accept_handler))
129 if (!utility::string_equals(req.get_header_value(
"upgrade"),
"websocket"))
132 handler_->remove_websocket(
this);
137 std::string requested_subprotocols_header = req.get_header_value(
"Sec-WebSocket-Protocol");
138 if (!subprotocols.empty() || !requested_subprotocols_header.empty())
140 auto requested_subprotocols = utility::split(requested_subprotocols_header,
", ");
141 auto subprotocol = utility::find_first_of(subprotocols.begin(), subprotocols.end(), requested_subprotocols.begin(), requested_subprotocols.end());
142 if (subprotocol != subprotocols.end())
144 subprotocol_ = *subprotocol;
151 if (!accept_handler_(req, &ud))
154 handler_->remove_websocket(
this);
163 std::string magic = req.get_header_value(
"Sec-WebSocket-Key") +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
165 s.processBytes(magic.data(), magic.size());
167 s.getDigestBytes(digest);
169 start(crow::utility::base64encode((
unsigned char*)digest, 20));
175 auto watch = std::weak_ptr<void>{anchor_};
180 while (watch.use_count() > 2)
182 std::this_thread::yield();
186 template<
typename Callable>
190 std::weak_ptr<void> watch;
194 if (
auto anchor = watch.lock())
196 std::move(callable)();
202 template<
typename CompletionHandler>
205 asio::dispatch(adaptor_.get_io_service(),
207 std::forward<CompletionHandler>(handler), anchor_});
211 template<
typename CompletionHandler>
212 void post(CompletionHandler&& handler)
214 asio::post(adaptor_.get_io_service(),
216 std::forward<CompletionHandler>(handler), anchor_});
225 send_data(0x9, std::move(msg));
234 send_data(0xA, std::move(msg));
240 send_data(0x2, std::move(msg));
246 send_data(0x1, std::move(msg));
253 void close(std::string
const& msg, uint16_t status_code)
override
255 dispatch([
this, msg, status_code]()
mutable {
256 has_sent_close_ =
true;
257 if (has_recv_close_ && !is_close_handler_called_)
259 is_close_handler_called_ =
true;
261 close_handler_(*
this, msg, status_code);
265 *(uint16_t*)(status_buf) = htons(status_code);
267 write_buffers_.emplace_back(std::move(header));
268 write_buffers_.emplace_back(std::string(status_buf, 2));
269 write_buffers_.emplace_back(msg);
274 std::string get_remote_ip()
override
276 return adaptor_.remote_endpoint().address().to_string();
279 void set_max_payload_size(uint64_t payload)
281 max_payload_bytes_ = payload;
294 char buf[2 + 8] =
"\x80\x00";
298 buf[1] +=
static_cast<char>(size);
299 return {buf, buf + 2};
301 else if (size < 0x10000)
304 *(uint16_t*)(buf + 2) = htons(
static_cast<uint16_t
>(size));
305 return {buf, buf + 4};
310 *
reinterpret_cast<uint64_t*
>(buf + 2) = ((1 == htonl(1)) ?
static_cast<uint64_t
>(size) : (
static_cast<uint64_t
>(htonl((size)&0xFFFFFFFF)) << 32) | htonl(
static_cast<uint64_t
>(size) >> 32));
311 return {buf, buf + 10};
321 static const std::string header =
322 "HTTP/1.1 101 Switching Protocols\r\n"
323 "Upgrade: websocket\r\n"
324 "Connection: Upgrade\r\n"
325 "Sec-WebSocket-Accept: ";
326 write_buffers_.emplace_back(header);
327 write_buffers_.emplace_back(std::move(hello));
328 write_buffers_.emplace_back(crlf);
329 if (!subprotocol_.empty())
331 write_buffers_.emplace_back(
"Sec-WebSocket-Protocol: ");
332 write_buffers_.emplace_back(subprotocol_);
333 write_buffers_.emplace_back(crlf);
335 write_buffers_.emplace_back(crlf);
338 open_handler_(*
this);
351 if (has_sent_close_ && has_recv_close_)
353 close_connection_ =
true;
354 adaptor_.shutdown_readwrite();
363 case WebSocketReadState::MiniHeader:
367 adaptor_.socket().async_read_some(
368 asio::buffer(&mini_header_, 2),
369 [
this](
const error_code& ec, std::size_t
370 #ifdef CROW_ENABLE_DEBUG
377 mini_header_ = ntohs(mini_header_);
378 #ifdef CROW_ENABLE_DEBUG
380 if (!ec && bytes_transferred != 2)
382 throw std::runtime_error(
"WebSocket:MiniHeader:async_read fail:asio bug?");
388 if ((mini_header_ & 0x80) == 0x80)
392 #ifndef CROW_ENFORCE_WS_SPEC
395 close_connection_ =
true;
396 adaptor_.shutdown_readwrite();
399 error_handler_(*
this,
"Client connection not masked.");
404 if ((mini_header_ & 0x7f) == 127)
406 state_ = WebSocketReadState::Len64;
408 else if ((mini_header_ & 0x7f) == 126)
410 state_ = WebSocketReadState::Len16;
414 remaining_length_ = mini_header_ & 0x7f;
415 state_ = WebSocketReadState::Mask;
421 close_connection_ =
true;
422 adaptor_.shutdown_readwrite();
425 error_handler_(*
this, ec.message());
431 case WebSocketReadState::Len16:
433 remaining_length_ = 0;
434 remaining_length16_ = 0;
436 adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
437 [
this](
const error_code& ec, std::size_t
438 #ifdef CROW_ENABLE_DEBUG
443 remaining_length16_ = ntohs(remaining_length16_);
444 remaining_length_ = remaining_length16_;
445 #ifdef CROW_ENABLE_DEBUG
446 if (!ec && bytes_transferred != 2)
448 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
454 state_ = WebSocketReadState::Mask;
459 close_connection_ =
true;
460 adaptor_.shutdown_readwrite();
463 error_handler_(*
this, ec.message());
469 case WebSocketReadState::Len64:
472 adaptor_.socket(), asio::buffer(&remaining_length_, 8),
473 [
this](
const error_code& ec, std::size_t
474 #ifdef CROW_ENABLE_DEBUG
479 remaining_length_ = ((1 == ntohl(1)) ? (remaining_length_) : (static_cast<uint64_t>(ntohl((remaining_length_)&0xFFFFFFFF)) << 32) | ntohl((remaining_length_) >> 32));
480 #ifdef CROW_ENABLE_DEBUG
481 if (!ec && bytes_transferred != 8)
483 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
489 state_ = WebSocketReadState::Mask;
494 close_connection_ =
true;
495 adaptor_.shutdown_readwrite();
498 error_handler_(*
this, ec.message());
504 case WebSocketReadState::Mask:
505 if (remaining_length_ > max_payload_bytes_)
507 close_connection_ =
true;
510 error_handler_(*
this,
"Message length exceeds maximum payload.");
516 adaptor_.socket(), asio::buffer((
char*)&mask_, 4),
517 [
this](
const error_code& ec, std::size_t
518 #ifdef CROW_ENABLE_DEBUG
523 #ifdef CROW_ENABLE_DEBUG
524 if (!ec && bytes_transferred != 4)
526 throw std::runtime_error(
"WebSocket:Mask:async_read fail:asio bug?");
532 state_ = WebSocketReadState::Payload;
537 close_connection_ =
true;
539 error_handler_(*
this, ec.message());
540 adaptor_.shutdown_readwrite();
548 state_ = WebSocketReadState::Payload;
552 case WebSocketReadState::Payload:
554 auto to_read =
static_cast<std::uint64_t
>(buffer_.size());
555 if (remaining_length_ < to_read)
556 to_read = remaining_length_;
557 adaptor_.socket().async_read_some(
558 asio::buffer(buffer_,
static_cast<std::size_t
>(to_read)),
559 [
this](
const error_code& ec, std::size_t bytes_transferred) {
564 fragment_.insert(fragment_.end(), buffer_.begin(), buffer_.begin() + bytes_transferred);
565 remaining_length_ -= bytes_transferred;
566 if (remaining_length_ == 0)
568 if (handle_fragment())
570 state_ = WebSocketReadState::MiniHeader;
579 close_connection_ =
true;
581 error_handler_(*
this, ec.message());
582 adaptor_.shutdown_readwrite();
595 return mini_header_ & 0x8000;
601 return (mini_header_ & 0x0f00) >> 8;
612 for (decltype(fragment_.length()) i = 0; i < fragment_.length(); i++)
614 fragment_[i] ^= ((
char*)&mask_)[i % 4];
621 message_ += fragment_;
624 if (message_handler_)
625 message_handler_(*
this, message_, is_binary_);
633 message_ += fragment_;
636 if (message_handler_)
637 message_handler_(*
this, message_, is_binary_);
645 message_ += fragment_;
648 if (message_handler_)
649 message_handler_(*
this, message_, is_binary_);
656 has_recv_close_ =
true;
659 uint16_t status_code = NoStatusCodePresent;
660 std::string::size_type message_start = 2;
661 if (fragment_.size() >= 2)
663 status_code = ntohs(((uint16_t*)fragment_.data())[0]);
669 if (!has_sent_close_)
671 close(fragment_.substr(message_start), status_code);
676 close_connection_ =
true;
677 if (!is_close_handler_called_)
680 close_handler_(*
this, fragment_.substr(message_start), status_code);
681 is_close_handler_called_ =
true;
683 adaptor_.shutdown_readwrite();
694 send_pong(fragment_);
699 pong_received_ =
true;
714 if (sending_buffers_.empty())
716 sending_buffers_.swap(write_buffers_);
717 std::vector<asio::const_buffer> buffers;
718 buffers.reserve(sending_buffers_.size());
719 for (
auto& s : sending_buffers_)
721 buffers.emplace_back(asio::buffer(s));
723 auto watch = std::weak_ptr<void>{anchor_};
725 adaptor_.socket(), buffers,
726 [&, watch](
const error_code& ec, std::size_t ) {
727 if (!ec && !close_connection_)
729 sending_buffers_.clear();
730 if (!write_buffers_.empty())
733 close_connection_ = true;
737 auto anchor = watch.lock();
738 if (anchor == nullptr) { return; }
740 sending_buffers_.clear();
741 close_connection_ =
true;
749 void check_destroy(websocket::CloseStatusCode code = CloseStatusCode::ClosedAbnormally)
753 if (!is_close_handler_called_)
755 close_handler_(*
this,
"uncleanly", code);
756 handler_->remove_websocket(
this);
757 if (sending_buffers_.empty() && !is_reading)
770 self->send_data_impl(
this);
776 auto header = build_header(s->opcode, s->payload.size());
777 write_buffers_.emplace_back(std::move(header));
778 write_buffers_.emplace_back(std::move(s->payload));
782 void send_data(
int opcode, std::string&& msg)
784 SendMessageType event_arg{
789 post(std::move(event_arg));
796 std::vector<std::string> sending_buffers_;
797 std::vector<std::string> write_buffers_;
799 std::array<char, 4096> buffer_;
801 std::string message_;
802 std::string fragment_;
803 WebSocketReadState state_{WebSocketReadState::MiniHeader};
804 uint16_t remaining_length16_{0};
805 uint64_t remaining_length_{0};
806 uint64_t max_payload_bytes_{UINT64_MAX};
807 std::string subprotocol_;
808 bool close_connection_{
false};
809 bool is_reading{
false};
810 bool has_mask_{
false};
812 uint16_t mini_header_;
813 bool has_sent_close_{
false};
814 bool has_recv_close_{
false};
815 bool error_occurred_{
false};
816 bool pong_received_{
false};
817 bool is_close_handler_called_{
false};
819 std::shared_ptr<void> anchor_ = std::make_shared<int>();
825 std::function<bool(
const crow::request&,
void**)> accept_handler_;
TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based on the implementation in ...
A websocket connection.
Definition: websocket.h:106
void dispatch(CompletionHandler &&handler)
Send data through the socket.
Definition: websocket.h:203
void do_read()
Read a websocket message.
Definition: websocket.h:349
Connection(const crow::request &req, Adaptor &&adaptor, Handler *handler, uint64_t max_payload, const std::vector< std::string > &subprotocols, std::function< void(crow::websocket::connection &)> open_handler, std::function< void(crow::websocket::connection &, const std::string &, bool)> message_handler, std::function< void(crow::websocket::connection &, const std::string &, uint16_t)> close_handler, std::function< void(crow::websocket::connection &, const std::string &)> error_handler, std::function< bool(const crow::request &, void **)> accept_handler)
Constructor for a connection.
Definition: websocket.h:113
void send_pong(std::string msg) override
Send a "Pong" message.
Definition: websocket.h:232
bool handle_fragment()
Process the payload fragment.
Definition: websocket.h:608
std::string build_header(int opcode, size_t size)
Generate the websocket headers using an opcode and the message size (in bytes).
Definition: websocket.h:292
void close(std::string const &msg, uint16_t status_code) override
Send a close signal.
Definition: websocket.h:253
void send_text(std::string msg) override
Send a plaintext message.
Definition: websocket.h:244
std::string get_subprotocol() const override
Returns the matching client/server subprotocol, empty string if none matched.
Definition: websocket.h:285
int opcode()
Extract the opcode from the header.
Definition: websocket.h:599
void do_write()
Send the buffers' data through the socket.
Definition: websocket.h:712
void start(std::string &&hello)
Send the HTTP upgrade response.
Definition: websocket.h:319
bool is_FIN()
Check if the FIN bit is set.
Definition: websocket.h:593
void send_ping(std::string msg) override
Send a "Ping" message.
Definition: websocket.h:223
void send_binary(std::string msg) override
Send a binary encoded message.
Definition: websocket.h:238
void check_destroy(websocket::CloseStatusCode code=CloseStatusCode::ClosedAbnormally)
Destroy the Connection.
Definition: websocket.h:749
void post(CompletionHandler &&handler)
Send data through the socket and return immediately.
Definition: websocket.h:212
A tiny SHA1 algorithm implementation used internally in the Crow server (specifically in crow/websock...
Definition: TinySHA1.hpp:48
The main namespace of the library. In this namespace is defined the most important classes and functi...
An HTTP request.
Definition: http_request.h:36
Definition: websocket.h:763
Definition: websocket.h:188
A base class for websocket connection.
Definition: websocket.h:62