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