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