Crow  1.1
A C++ microframework for the web
 
Loading...
Searching...
No Matches
websocket.h
1#pragma once
2#include <array>
3#include <memory>
4#include <thread>
5#include "crow/logging.h"
6#include "crow/socket_adaptors.h"
7#include "crow/http_request.h"
8#include "crow/TinySHA1.hpp"
9#include "crow/utility.h"
10
11namespace crow // NOTE: Already documented in "crow/app.h"
12{
13#ifdef CROW_USE_BOOST
14 namespace asio = boost::asio;
15 using error_code = boost::system::error_code;
16#else
17 using error_code = asio::error_code;
18#endif
19
20 /**
21 * \namespace crow::websocket
22 * \brief Namespace that includes the \ref Connection class
23 * and \ref connection struct. Useful for WebSockets connection.
24 *
25 * Used specially in crow/websocket.h, crow/app.h and crow/routing.h
26 */
27 namespace websocket
28 {
29 enum class WebSocketReadState
30 {
31 MiniHeader,
32 Len16,
33 Len64,
34 Mask,
35 Payload,
36 };
37
38 // Codes taken from https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1
39 enum CloseStatusCode : uint16_t {
40 NormalClosure = 1000,
41 EndpointGoingAway = 1001,
42 ProtocolError = 1002,
43 UnacceptableData = 1003,
44 InconsistentData = 1007,
45 PolicyViolated = 1008,
46 MessageTooBig = 1009,
47 ExtensionsNotNegotiated = 1010,
48 UnexpectedCondition = 1011,
49
50 // Reserved for applications only, should not send/receive these to/from clients
51 NoStatusCodePresent = 1005,
52 ClosedAbnormally = 1006,
53 TLSHandshakeFailure = 1015,
54
55 StartStatusCodesForLibraries = 3000,
56 StartStatusCodesForPrivateUse = 4000,
57 // Status code should be between 1000 and 4999 inclusive
58 StartStatusCodes = NormalClosure,
59 EndStatusCodes = 4999,
60 };
61
62 /// A base class for websocket connection.
64 {
65 virtual void send_binary(std::string msg) = 0;
66 virtual void send_text(std::string msg) = 0;
67 virtual void send_ping(std::string msg) = 0;
68 virtual void send_pong(std::string msg) = 0;
69 virtual void close(std::string const& msg = "quit", uint16_t status_code = CloseStatusCode::NormalClosure) = 0;
70 virtual std::string get_remote_ip() = 0;
71 virtual std::string get_subprotocol() const = 0;
72 virtual ~connection() = default;
73
74 void userdata(void* u) { userdata_ = u; }
75 void* userdata() { return userdata_; }
76
77 private:
78 void* userdata_;
79 };
80
81 // Modified version of the illustration in RFC6455 Section-5.2
82 //
83 //
84 // 0 1 2 3 -byte
85 // 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 -bit
86 // +-+-+-+-+-------+-+-------------+-------------------------------+
87 // |F|R|R|R| opcode|M| Payload len | Extended payload length |
88 // |I|S|S|S| (4) |A| (7) | (16/64) |
89 // |N|V|V|V| |S| | (if payload len==126/127) |
90 // | |1|2|3| |K| | |
91 // +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
92 // | Extended payload length continued, if payload len == 127 |
93 // + - - - - - - - - - - - - - - - +-------------------------------+
94 // | |Masking-key, if MASK set to 1 |
95 // +-------------------------------+-------------------------------+
96 // | Masking-key (continued) | Payload Data |
97 // +-------------------------------- - - - - - - - - - - - - - - - +
98 // : Payload Data continued ... :
99 // + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
100 // | Payload Data continued ... |
101 // +---------------------------------------------------------------+
102 //
103
104 /// A websocket connection.
105
106 template<typename Adaptor, typename Handler>
107 class Connection : public connection, public std::enable_shared_from_this<Connection<Adaptor, Handler>>
108 {
109 public:
110 /// Factory for a connection.
111 ///
112 /// Requires a request with an "Upgrade: websocket" header.<br>
113 /// Automatically handles the handshake.
114 static void create(const crow::request& req, Adaptor adaptor, Handler* handler,
115 uint64_t max_payload, const std::vector<std::string>& subprotocols,
116 std::function<void(crow::websocket::connection&)> open_handler,
117 std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler,
118 std::function<void(crow::websocket::connection&, const std::string&, uint16_t)> close_handler,
119 std::function<void(crow::websocket::connection&, const std::string&)> error_handler,
120 std::function<bool(const crow::request&, void**)> accept_handler,
121 bool mirror_protocols)
122 {
123 auto conn = std::shared_ptr<Connection>(new Connection(std::move(adaptor),
124 handler, max_payload,
125 std::move(open_handler),
126 std::move(message_handler),
127 std::move(close_handler),
128 std::move(error_handler),
129 std::move(accept_handler)));
130
131 // Perform handshake validation
132 if (!utility::string_equals(req.get_header_value("upgrade"), "websocket"))
133 {
134 conn->adaptor_.close();
135 return;
136 }
137
138 std::string requested_subprotocols_header = req.get_header_value("Sec-WebSocket-Protocol");
139 if (!subprotocols.empty() || !requested_subprotocols_header.empty())
140 {
141 auto requested_subprotocols = utility::split(requested_subprotocols_header, ", ");
142 auto subprotocol = utility::find_first_of(subprotocols.begin(), subprotocols.end(), requested_subprotocols.begin(), requested_subprotocols.end());
143 if (subprotocol != subprotocols.end())
144 {
145 conn->subprotocol_ = *subprotocol;
146 }
147 }
148
149 if (mirror_protocols & !requested_subprotocols_header.empty())
150 {
151 conn->subprotocol_ = requested_subprotocols_header;
152 }
153
154 if (conn->accept_handler_)
155 {
156 void* ud = nullptr;
157 if (!conn->accept_handler_(req, &ud))
158 {
159 conn->adaptor_.close();
160 return;
161 }
162 conn->userdata(ud);
163 }
164
165 // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
166 // Sec-WebSocket-Version: 13
167 std::string magic = req.get_header_value("Sec-WebSocket-Key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
168 sha1::SHA1 s;
169 s.processBytes(magic.data(), magic.size());
170 uint8_t digest[20];
171 s.getDigestBytes(digest);
172
173 conn->handler_->add_websocket(conn);
174 conn->start(crow::utility::base64encode((unsigned char*)digest, 20));
175 }
176
177 ~Connection() noexcept override = default;
178
179 template<typename Callable>
181 {
182 Callable callable;
183 std::weak_ptr<void> watch;
184
185 void operator()()
186 {
187 if (auto anchor = watch.lock())
188 {
189 std::move(callable)();
190 }
191 }
192 };
193
194 /// Send data through the socket.
195 template<typename CompletionHandler>
196 void dispatch(CompletionHandler&& handler)
197 {
198 asio::dispatch(adaptor_.get_io_context(),
199 WeakWrappedMessage<typename std::decay<CompletionHandler>::type>{
200 std::forward<CompletionHandler>(handler), anchor_});
201 }
202
203 /// Send data through the socket and return immediately.
204 template<typename CompletionHandler>
205 void post(CompletionHandler&& handler)
206 {
207 asio::post(adaptor_.get_io_context(),
208 WeakWrappedMessage<typename std::decay<CompletionHandler>::type>{
209 std::forward<CompletionHandler>(handler), anchor_});
210 }
211
212 /// Send a "Ping" message.
213
214 ///
215 /// Usually invoked to check if the other point is still online.
216 void send_ping(std::string msg) override
217 {
218 send_data(0x9, std::move(msg));
219 }
220
221 /// Send a "Pong" message.
222
223 ///
224 /// Usually automatically invoked as a response to a "Ping" message.
225 void send_pong(std::string msg) override
226 {
227 send_data(0xA, std::move(msg));
228 }
229
230 /// Send a binary encoded message.
231 void send_binary(std::string msg) override
232 {
233 send_data(0x2, std::move(msg));
234 }
235
236 /// Send a plaintext message.
237 void send_text(std::string msg) override
238 {
239 send_data(0x1, std::move(msg));
240 }
241
242 /// Send a close signal.
243
244 ///
245 /// Sets a flag to destroy the object once the message is sent.
246 void close(std::string const& msg, uint16_t status_code) override
247 {
248 dispatch([this, msg, status_code]() mutable {
249 has_sent_close_ = true;
250 if (has_recv_close_ && !is_close_handler_called_)
251 {
252 is_close_handler_called_ = true;
253 if (close_handler_)
254 close_handler_(*this, msg, status_code);
255 }
256 auto header = build_header(0x8, msg.size() + 2);
257 char status_buf[2];
258 *(uint16_t*)(status_buf) = htons(status_code);
259
260 write_buffers_.emplace_back(std::move(header));
261 write_buffers_.emplace_back(std::string(status_buf, 2));
262 write_buffers_.emplace_back(msg);
263 do_write();
264 });
265 }
266
267 std::string get_remote_ip() override
268 {
269 return adaptor_.address();
270 }
271
272 void set_max_payload_size(uint64_t payload)
273 {
274 max_payload_bytes_ = payload;
275 }
276
277 /// Returns the matching client/server subprotocol, empty string if none matched.
278 std::string get_subprotocol() const override
279 {
280 return subprotocol_;
281 }
282
283 protected:
284 /// Generate the websocket headers using an opcode and the message size (in bytes).
285 std::string build_header(int opcode, size_t size)
286 {
287 char buf[2 + 8] = "\x80\x00";
288 buf[0] += opcode;
289 if (size < 126)
290 {
291 buf[1] += static_cast<char>(size);
292 return {buf, buf + 2};
293 }
294 else if (size < 0x10000)
295 {
296 buf[1] += 126;
297 *(uint16_t*)(buf + 2) = htons(static_cast<uint16_t>(size));
298 return {buf, buf + 4};
299 }
300 else
301 {
302 buf[1] += 127;
303 *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));
304 return {buf, buf + 10};
305 }
306 }
307
308 /// Send the HTTP upgrade response.
309
310 ///
311 /// Finishes the handshake process, then starts reading messages from the socket.
312 void start(std::string&& hello)
313 {
314 static const std::string header =
315 "HTTP/1.1 101 Switching Protocols\r\n"
316 "Upgrade: websocket\r\n"
317 "Connection: Upgrade\r\n"
318 "Sec-WebSocket-Accept: ";
319 write_buffers_.emplace_back(header);
320 write_buffers_.emplace_back(std::move(hello));
321 write_buffers_.emplace_back(crlf);
322 if (!subprotocol_.empty())
323 {
324 write_buffers_.emplace_back("Sec-WebSocket-Protocol: ");
325 write_buffers_.emplace_back(subprotocol_);
326 write_buffers_.emplace_back(crlf);
327 }
328 write_buffers_.emplace_back(crlf);
329 do_write();
330 if (open_handler_)
331 open_handler_(*this);
332 do_read();
333 }
334
335 /// Read a websocket message.
336
337 ///
338 /// Involves:<br>
339 /// Handling headers (opcodes, size).<br>
340 /// Unmasking the payload.<br>
341 /// Reading the actual payload.<br>
342 void do_read()
343 {
344 if (has_sent_close_ && has_recv_close_)
345 {
346 close_connection_ = true;
347 adaptor_.shutdown_readwrite();
348 adaptor_.close();
350 return;
351 }
352
353 is_reading = true;
354 switch (state_)
355 {
356 case WebSocketReadState::MiniHeader:
357 {
358 mini_header_ = 0;
359 //asio::async_read(adaptor_.socket(), asio::buffer(&mini_header_, 1),
360 adaptor_.socket().async_read_some(
361 asio::buffer(&mini_header_, 2),
362 [this](const error_code& ec, std::size_t
363#ifdef CROW_ENABLE_DEBUG
364 bytes_transferred
365#endif
366 )
367
368 {
369 is_reading = false;
370 mini_header_ = ntohs(mini_header_);
371#ifdef CROW_ENABLE_DEBUG
372
373 if (!ec && bytes_transferred != 2)
374 {
375 throw std::runtime_error("WebSocket:MiniHeader:async_read fail:asio bug?");
376 }
377#endif
378
379 if (!ec)
380 {
381 if ((mini_header_ & 0x80) == 0x80)
382 has_mask_ = true;
383 else //if the websocket specification is enforced and the message isn't masked, terminate the connection
384 {
385#ifndef CROW_ENFORCE_WS_SPEC
386 has_mask_ = false;
387#else
388 close_connection_ = true;
389 adaptor_.shutdown_readwrite();
390 adaptor_.close();
391 if (error_handler_)
392 error_handler_(*this, "Client connection not masked.");
393 check_destroy(CloseStatusCode::UnacceptableData);
394#endif
395 }
396
397 if ((mini_header_ & 0x7f) == 127)
398 {
399 state_ = WebSocketReadState::Len64;
400 }
401 else if ((mini_header_ & 0x7f) == 126)
402 {
403 state_ = WebSocketReadState::Len16;
404 }
405 else
406 {
407 remaining_length_ = mini_header_ & 0x7f;
408 state_ = WebSocketReadState::Mask;
409 }
410 do_read();
411 }
412 else
413 {
414 close_connection_ = true;
415 adaptor_.shutdown_readwrite();
416 adaptor_.close();
417 if (error_handler_)
418 error_handler_(*this, ec.message());
420 }
421 });
422 }
423 break;
424 case WebSocketReadState::Len16:
425 {
426 remaining_length_ = 0;
427 remaining_length16_ = 0;
428 asio::async_read(
429 adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
430 [this](const error_code& ec, std::size_t
431#ifdef CROW_ENABLE_DEBUG
432 bytes_transferred
433#endif
434 ) {
435 is_reading = false;
436 remaining_length16_ = ntohs(remaining_length16_);
437 remaining_length_ = remaining_length16_;
438#ifdef CROW_ENABLE_DEBUG
439 if (!ec && bytes_transferred != 2)
440 {
441 throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
442 }
443#endif
444
445 if (!ec)
446 {
447 state_ = WebSocketReadState::Mask;
448 do_read();
449 }
450 else
451 {
452 close_connection_ = true;
453 adaptor_.shutdown_readwrite();
454 adaptor_.close();
455 if (error_handler_)
456 error_handler_(*this, ec.message());
458 }
459 });
460 }
461 break;
462 case WebSocketReadState::Len64:
463 {
464 asio::async_read(
465 adaptor_.socket(), asio::buffer(&remaining_length_, 8),
466 [this](const error_code& ec, std::size_t
467#ifdef CROW_ENABLE_DEBUG
468 bytes_transferred
469#endif
470 ) {
471 is_reading = false;
472 remaining_length_ = ((1 == ntohl(1)) ? (remaining_length_) : (static_cast<uint64_t>(ntohl((remaining_length_)&0xFFFFFFFF)) << 32) | ntohl((remaining_length_) >> 32));
473#ifdef CROW_ENABLE_DEBUG
474 if (!ec && bytes_transferred != 8)
475 {
476 throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
477 }
478#endif
479
480 if (!ec)
481 {
482 state_ = WebSocketReadState::Mask;
483 do_read();
484 }
485 else
486 {
487 close_connection_ = true;
488 adaptor_.shutdown_readwrite();
489 adaptor_.close();
490 if (error_handler_)
491 error_handler_(*this, ec.message());
493 }
494 });
495 }
496 break;
497 case WebSocketReadState::Mask:
498 if (remaining_length_ > max_payload_bytes_)
499 {
500 close_connection_ = true;
501 adaptor_.close();
502 if (error_handler_)
503 error_handler_(*this, "Message length exceeds maximum payload.");
504 check_destroy(MessageTooBig);
505 }
506 else if (has_mask_)
507 {
508 asio::async_read(
509 adaptor_.socket(), asio::buffer((char*)&mask_, 4),
510 [this](const error_code& ec, std::size_t
511#ifdef CROW_ENABLE_DEBUG
512 bytes_transferred
513#endif
514 ) {
515 is_reading = false;
516#ifdef CROW_ENABLE_DEBUG
517 if (!ec && bytes_transferred != 4)
518 {
519 throw std::runtime_error("WebSocket:Mask:async_read fail:asio bug?");
520 }
521#endif
522
523 if (!ec)
524 {
525 state_ = WebSocketReadState::Payload;
526 do_read();
527 }
528 else
529 {
530 close_connection_ = true;
531 if (error_handler_)
532 error_handler_(*this, ec.message());
533 adaptor_.shutdown_readwrite();
534 adaptor_.close();
536 }
537 });
538 }
539 else
540 {
541 state_ = WebSocketReadState::Payload;
542 do_read();
543 }
544 break;
545 case WebSocketReadState::Payload:
546 {
547 auto to_read = static_cast<std::uint64_t>(buffer_.size());
548 if (remaining_length_ < to_read)
549 to_read = remaining_length_;
550 adaptor_.socket().async_read_some(
551 asio::buffer(buffer_, static_cast<std::size_t>(to_read)),
552 [this](const error_code& ec, std::size_t bytes_transferred) {
553 is_reading = false;
554
555 if (!ec)
556 {
557 fragment_.insert(fragment_.end(), buffer_.begin(), buffer_.begin() + bytes_transferred);
558 remaining_length_ -= bytes_transferred;
559 if (remaining_length_ == 0)
560 {
561 if (handle_fragment())
562 {
563 state_ = WebSocketReadState::MiniHeader;
564 do_read();
565 }
566 }
567 else
568 do_read();
569 }
570 else
571 {
572 close_connection_ = true;
573 if (error_handler_)
574 error_handler_(*this, ec.message());
575 adaptor_.shutdown_readwrite();
576 adaptor_.close();
577 check_destroy();
578 }
579 });
580 }
581 break;
582 }
583 }
584
585 /// Check if the FIN bit is set.
586 bool is_FIN()
587 {
588 return mini_header_ & 0x8000;
589 }
590
591 /// Extract the opcode from the header.
592 int opcode()
593 {
594 return (mini_header_ & 0x0f00) >> 8;
595 }
596
597 /// Process the payload fragment.
598
599 ///
600 /// Unmasks the fragment, checks the opcode, merges fragments into 1 message body, and calls the appropriate handler.
602 {
603 if (has_mask_)
604 {
605 for (decltype(fragment_.length()) i = 0; i < fragment_.length(); i++)
606 {
607 fragment_[i] ^= ((char*)&mask_)[i % 4];
608 }
609 }
610 switch (opcode())
611 {
612 case 0: // Continuation
613 {
614 message_ += fragment_;
615 if (is_FIN())
616 {
617 if (message_handler_)
618 message_handler_(*this, message_, is_binary_);
619 message_.clear();
620 }
621 }
622 break;
623 case 1: // Text
624 {
625 is_binary_ = false;
626 message_ += fragment_;
627 if (is_FIN())
628 {
629 if (message_handler_)
630 message_handler_(*this, message_, is_binary_);
631 message_.clear();
632 }
633 }
634 break;
635 case 2: // Binary
636 {
637 is_binary_ = true;
638 message_ += fragment_;
639 if (is_FIN())
640 {
641 if (message_handler_)
642 message_handler_(*this, message_, is_binary_);
643 message_.clear();
644 }
645 }
646 break;
647 case 0x8: // Close
648 {
649 has_recv_close_ = true;
650
651
652 uint16_t status_code = NoStatusCodePresent;
653 std::string::size_type message_start = 2;
654 if (fragment_.size() >= 2)
655 {
656 status_code = ntohs(((uint16_t*)fragment_.data())[0]);
657 } else {
658 // no message will crash substr
659 message_start = 0;
660 }
661
662 if (!has_sent_close_)
663 {
664 close(fragment_.substr(message_start), status_code);
665 }
666 else
667 {
668
669 close_connection_ = true;
670 if (!is_close_handler_called_)
671 {
672 if (close_handler_)
673 close_handler_(*this, fragment_.substr(message_start), status_code);
674 is_close_handler_called_ = true;
675 }
676 adaptor_.shutdown_readwrite();
677 adaptor_.close();
678
679 // Close handler must have been called at this point so code does not matter
680 check_destroy();
681 return false;
682 }
683 }
684 break;
685 case 0x9: // Ping
686 {
687 send_pong(fragment_);
688 }
689 break;
690 case 0xA: // Pong
691 {
692 pong_received_ = true;
693 }
694 break;
695 }
696
697 fragment_.clear();
698 return true;
699 }
700
701 /// Send the buffers' data through the socket.
702
703 ///
704 /// Also destroys the object if the Close flag is set.
705 void do_write()
706 {
707 if (write_buffers_.empty()) return;
708
709 sending_buffers_.swap(write_buffers_);
710 std::vector<asio::const_buffer> buffers;
711 buffers.reserve(sending_buffers_.size());
712 for (auto& s : sending_buffers_)
713 {
714 buffers.emplace_back(asio::buffer(s));
715 }
716 auto watch = std::weak_ptr<void>{anchor_};
717 asio::async_write(
718 adaptor_.socket(), buffers,
719 [this, watch](const error_code& ec, std::size_t /*bytes_transferred*/) {
720 auto anchor = watch.lock();
721 if (anchor == nullptr)
722 return;
723
724 if (!ec && !close_connection_)
725 {
726 sending_buffers_.clear();
727 if (!write_buffers_.empty())
728 do_write();
729 if (has_sent_close_)
730 close_connection_ = true;
731 }
732 else
733 {
734 sending_buffers_.clear();
735 close_connection_ = true;
736 check_destroy();
737 }
738 });
739 }
740
741 /// Destroy the Connection.
742 void check_destroy(websocket::CloseStatusCode code = CloseStatusCode::ClosedAbnormally)
743 {
744 // Note that if the close handler was not yet called at this point we did not receive a close packet (or send one)
745 // and thus we use ClosedAbnormally unless instructed otherwise
746 if (!is_close_handler_called_)
747 {
748 if (close_handler_)
749 {
750 close_handler_(*this, "uncleanly", code);
751 }
752 }
753
754 handler_->remove_websocket(this->shared_from_this());
755 }
756
757
759 {
760 std::string payload;
761 Connection* self;
762 int opcode;
763
764 void operator()()
765 {
766 self->send_data_impl(this);
767 }
768 };
769
770 void send_data_impl(SendMessageType* s)
771 {
772 auto header = build_header(s->opcode, s->payload.size());
773 write_buffers_.emplace_back(std::move(header));
774 write_buffers_.emplace_back(std::move(s->payload));
775 do_write();
776 }
777
778 void send_data(int opcode, std::string&& msg)
779 {
780 SendMessageType event_arg{
781 std::move(msg),
782 this,
783 opcode};
784
785 post(std::move(event_arg));
786 }
787
788 private:
789 Connection(Adaptor&& adaptor, Handler* handler, uint64_t max_payload,
790 std::function<void(crow::websocket::connection&)> open_handler,
791 std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler,
792 std::function<void(crow::websocket::connection&, const std::string&, uint16_t)> close_handler,
793 std::function<void(crow::websocket::connection&, const std::string&)> error_handler,
794 std::function<bool(const crow::request&, void**)> accept_handler):
795 adaptor_(std::move(adaptor)),
796 handler_(handler),
797 max_payload_bytes_(max_payload),
798 open_handler_(std::move(open_handler)),
799 message_handler_(std::move(message_handler)),
800 close_handler_(std::move(close_handler)),
801 error_handler_(std::move(error_handler)),
802 accept_handler_(std::move(accept_handler))
803 {}
804
805 Adaptor adaptor_;
806 Handler* handler_;
807
808 std::vector<std::string> sending_buffers_;
809 std::vector<std::string> write_buffers_;
810
811 std::array<char, 4096> buffer_;
812 bool is_binary_;
813 std::string message_;
814 std::string fragment_;
815 WebSocketReadState state_{WebSocketReadState::MiniHeader};
816 uint16_t remaining_length16_{0};
817 uint64_t remaining_length_{0};
818 uint64_t max_payload_bytes_{UINT64_MAX};
819 std::string subprotocol_;
820 bool close_connection_{false};
821 bool is_reading{false};
822 bool has_mask_{false};
823 uint32_t mask_;
824 uint16_t mini_header_;
825 bool has_sent_close_{false};
826 bool has_recv_close_{false};
827 bool error_occurred_{false};
828 bool pong_received_{false};
829 bool is_close_handler_called_{false};
830
831 std::shared_ptr<void> anchor_ = std::make_shared<int>(); // Value is just for placeholding
832
833 std::function<void(crow::websocket::connection&)> open_handler_;
834 std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler_;
835 std::function<void(crow::websocket::connection&, const std::string&, uint16_t status_code)> close_handler_;
836 std::function<void(crow::websocket::connection&, const std::string&)> error_handler_;
837 std::function<bool(const crow::request&, void**)> accept_handler_;
838 };
839 } // namespace websocket
840} // namespace crow
TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based on the implementation in ...
A websocket connection.
Definition websocket.h:108
void dispatch(CompletionHandler &&handler)
Send data through the socket.
Definition websocket.h:196
void do_read()
Read a websocket message.
Definition websocket.h:342
void send_pong(std::string msg) override
Send a "Pong" message.
Definition websocket.h:225
bool handle_fragment()
Process the payload fragment.
Definition websocket.h:601
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:285
void close(std::string const &msg, uint16_t status_code) override
Send a close signal.
Definition websocket.h:246
void send_text(std::string msg) override
Send a plaintext message.
Definition websocket.h:237
std::string get_subprotocol() const override
Returns the matching client/server subprotocol, empty string if none matched.
Definition websocket.h:278
int opcode()
Extract the opcode from the header.
Definition websocket.h:592
void do_write()
Send the buffers' data through the socket.
Definition websocket.h:705
void start(std::string &&hello)
Send the HTTP upgrade response.
Definition websocket.h:312
bool is_FIN()
Check if the FIN bit is set.
Definition websocket.h:586
void send_ping(std::string msg) override
Send a "Ping" message.
Definition websocket.h:216
void send_binary(std::string msg) override
Send a binary encoded message.
Definition websocket.h:231
void check_destroy(websocket::CloseStatusCode code=CloseStatusCode::ClosedAbnormally)
Destroy the Connection.
Definition websocket.h:742
void post(CompletionHandler &&handler)
Send data through the socket and return immediately.
Definition websocket.h:205
static void create(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, bool mirror_protocols)
Definition websocket.h:114
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
A base class for websocket connection.
Definition websocket.h:64