Crow  1.1
A C++ microframework for the web
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 
9 namespace 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.
61  struct 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  adaptor_(std::move(adaptor)),
121  handler_(handler),
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))
128  {
129  if (!utility::string_equals(req.get_header_value("upgrade"), "websocket"))
130  {
131  adaptor_.close();
132  handler_->remove_websocket(this);
133  delete this;
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  subprotocol_ = *subprotocol;
145  }
146  }
147 
148  if (accept_handler_)
149  {
150  void* ud = nullptr;
151  if (!accept_handler_(req, &ud))
152  {
153  adaptor_.close();
154  handler_->remove_websocket(this);
155  delete this;
156  return;
157  }
158  userdata(ud);
159  }
160 
161  // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
162  // Sec-WebSocket-Version: 13
163  std::string magic = req.get_header_value("Sec-WebSocket-Key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
164  sha1::SHA1 s;
165  s.processBytes(magic.data(), magic.size());
166  uint8_t digest[20];
167  s.getDigestBytes(digest);
168 
169  start(crow::utility::base64encode((unsigned char*)digest, 20));
170  }
171 
172  ~Connection() noexcept override
173  {
174  // Do not modify anchor_ here since writing shared_ptr is not atomic.
175  auto watch = std::weak_ptr<void>{anchor_};
176 
177  // Wait until all unhandled asynchronous operations to join.
178  // As the deletion occurs inside 'check_destroy()', which already locks
179  // anchor, use count can be 1 on valid deletion context.
180  while (watch.use_count() > 2) // 1 for 'check_destroy() routine', 1 for 'this->anchor_'
181  {
182  std::this_thread::yield();
183  }
184  }
185 
186  template<typename Callable>
188  {
189  Callable callable;
190  std::weak_ptr<void> watch;
191 
192  void operator()()
193  {
194  if (auto anchor = watch.lock())
195  {
196  std::move(callable)();
197  }
198  }
199  };
200 
201  /// Send data through the socket.
202  template<typename CompletionHandler>
203  void dispatch(CompletionHandler&& handler)
204  {
205  asio::dispatch(adaptor_.get_io_service(),
206  WeakWrappedMessage<typename std::decay<CompletionHandler>::type>{
207  std::forward<CompletionHandler>(handler), anchor_});
208  }
209 
210  /// Send data through the socket and return immediately.
211  template<typename CompletionHandler>
212  void post(CompletionHandler&& handler)
213  {
214  asio::post(adaptor_.get_io_service(),
215  WeakWrappedMessage<typename std::decay<CompletionHandler>::type>{
216  std::forward<CompletionHandler>(handler), anchor_});
217  }
218 
219  /// Send a "Ping" message.
220 
221  ///
222  /// Usually invoked to check if the other point is still online.
223  void send_ping(std::string msg) override
224  {
225  send_data(0x9, std::move(msg));
226  }
227 
228  /// Send a "Pong" message.
229 
230  ///
231  /// Usually automatically invoked as a response to a "Ping" message.
232  void send_pong(std::string msg) override
233  {
234  send_data(0xA, std::move(msg));
235  }
236 
237  /// Send a binary encoded message.
238  void send_binary(std::string msg) override
239  {
240  send_data(0x2, std::move(msg));
241  }
242 
243  /// Send a plaintext message.
244  void send_text(std::string msg) override
245  {
246  send_data(0x1, std::move(msg));
247  }
248 
249  /// Send a close signal.
250 
251  ///
252  /// Sets a flag to destroy the object once the message is sent.
253  void close(std::string const& msg, uint16_t status_code) override
254  {
255  dispatch([this, msg, status_code]() mutable {
256  has_sent_close_ = true;
257  if (has_recv_close_ && !is_close_handler_called_)
258  {
259  is_close_handler_called_ = true;
260  if (close_handler_)
261  close_handler_(*this, msg, status_code);
262  }
263  auto header = build_header(0x8, msg.size() + 2);
264  char status_buf[2];
265  *(uint16_t*)(status_buf) = htons(status_code);
266 
267  write_buffers_.emplace_back(std::move(header));
268  write_buffers_.emplace_back(std::string(status_buf, 2));
269  write_buffers_.emplace_back(msg);
270  do_write();
271  });
272  }
273 
274  std::string get_remote_ip() override
275  {
276  return adaptor_.remote_endpoint().address().to_string();
277  }
278 
279  void set_max_payload_size(uint64_t payload)
280  {
281  max_payload_bytes_ = payload;
282  }
283 
284  /// Returns the matching client/server subprotocol, empty string if none matched.
285  std::string get_subprotocol() const override
286  {
287  return subprotocol_;
288  }
289 
290  protected:
291  /// Generate the websocket headers using an opcode and the message size (in bytes).
292  std::string build_header(int opcode, size_t size)
293  {
294  char buf[2 + 8] = "\x80\x00";
295  buf[0] += opcode;
296  if (size < 126)
297  {
298  buf[1] += static_cast<char>(size);
299  return {buf, buf + 2};
300  }
301  else if (size < 0x10000)
302  {
303  buf[1] += 126;
304  *(uint16_t*)(buf + 2) = htons(static_cast<uint16_t>(size));
305  return {buf, buf + 4};
306  }
307  else
308  {
309  buf[1] += 127;
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};
312  }
313  }
314 
315  /// Send the HTTP upgrade response.
316 
317  ///
318  /// Finishes the handshake process, then starts reading messages from the socket.
319  void start(std::string&& hello)
320  {
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())
330  {
331  write_buffers_.emplace_back("Sec-WebSocket-Protocol: ");
332  write_buffers_.emplace_back(subprotocol_);
333  write_buffers_.emplace_back(crlf);
334  }
335  write_buffers_.emplace_back(crlf);
336  do_write();
337  if (open_handler_)
338  open_handler_(*this);
339  do_read();
340  }
341 
342  /// Read a websocket message.
343 
344  ///
345  /// Involves:<br>
346  /// Handling headers (opcodes, size).<br>
347  /// Unmasking the payload.<br>
348  /// Reading the actual payload.<br>
349  void do_read()
350  {
351  if (has_sent_close_ && has_recv_close_)
352  {
353  close_connection_ = true;
354  adaptor_.shutdown_readwrite();
355  adaptor_.close();
356  check_destroy();
357  return;
358  }
359 
360  is_reading = true;
361  switch (state_)
362  {
363  case WebSocketReadState::MiniHeader:
364  {
365  mini_header_ = 0;
366  //asio::async_read(adaptor_.socket(), asio::buffer(&mini_header_, 1),
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
371  bytes_transferred
372 #endif
373  )
374 
375  {
376  is_reading = false;
377  mini_header_ = ntohs(mini_header_);
378 #ifdef CROW_ENABLE_DEBUG
379 
380  if (!ec && bytes_transferred != 2)
381  {
382  throw std::runtime_error("WebSocket:MiniHeader:async_read fail:asio bug?");
383  }
384 #endif
385 
386  if (!ec)
387  {
388  if ((mini_header_ & 0x80) == 0x80)
389  has_mask_ = true;
390  else //if the websocket specification is enforced and the message isn't masked, terminate the connection
391  {
392 #ifndef CROW_ENFORCE_WS_SPEC
393  has_mask_ = false;
394 #else
395  close_connection_ = true;
396  adaptor_.shutdown_readwrite();
397  adaptor_.close();
398  if (error_handler_)
399  error_handler_(*this, "Client connection not masked.");
400  check_destroy(CloseStatusCode::UnacceptableData);
401 #endif
402  }
403 
404  if ((mini_header_ & 0x7f) == 127)
405  {
406  state_ = WebSocketReadState::Len64;
407  }
408  else if ((mini_header_ & 0x7f) == 126)
409  {
410  state_ = WebSocketReadState::Len16;
411  }
412  else
413  {
414  remaining_length_ = mini_header_ & 0x7f;
415  state_ = WebSocketReadState::Mask;
416  }
417  do_read();
418  }
419  else
420  {
421  close_connection_ = true;
422  adaptor_.shutdown_readwrite();
423  adaptor_.close();
424  if (error_handler_)
425  error_handler_(*this, ec.message());
426  check_destroy();
427  }
428  });
429  }
430  break;
431  case WebSocketReadState::Len16:
432  {
433  remaining_length_ = 0;
434  remaining_length16_ = 0;
435  asio::async_read(
436  adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
437  [this](const error_code& ec, std::size_t
438 #ifdef CROW_ENABLE_DEBUG
439  bytes_transferred
440 #endif
441  ) {
442  is_reading = false;
443  remaining_length16_ = ntohs(remaining_length16_);
444  remaining_length_ = remaining_length16_;
445 #ifdef CROW_ENABLE_DEBUG
446  if (!ec && bytes_transferred != 2)
447  {
448  throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
449  }
450 #endif
451 
452  if (!ec)
453  {
454  state_ = WebSocketReadState::Mask;
455  do_read();
456  }
457  else
458  {
459  close_connection_ = true;
460  adaptor_.shutdown_readwrite();
461  adaptor_.close();
462  if (error_handler_)
463  error_handler_(*this, ec.message());
464  check_destroy();
465  }
466  });
467  }
468  break;
469  case WebSocketReadState::Len64:
470  {
471  asio::async_read(
472  adaptor_.socket(), asio::buffer(&remaining_length_, 8),
473  [this](const error_code& ec, std::size_t
474 #ifdef CROW_ENABLE_DEBUG
475  bytes_transferred
476 #endif
477  ) {
478  is_reading = false;
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)
482  {
483  throw std::runtime_error("WebSocket:Len16:async_read fail:asio bug?");
484  }
485 #endif
486 
487  if (!ec)
488  {
489  state_ = WebSocketReadState::Mask;
490  do_read();
491  }
492  else
493  {
494  close_connection_ = true;
495  adaptor_.shutdown_readwrite();
496  adaptor_.close();
497  if (error_handler_)
498  error_handler_(*this, ec.message());
499  check_destroy();
500  }
501  });
502  }
503  break;
504  case WebSocketReadState::Mask:
505  if (remaining_length_ > max_payload_bytes_)
506  {
507  close_connection_ = true;
508  adaptor_.close();
509  if (error_handler_)
510  error_handler_(*this, "Message length exceeds maximum payload.");
511  check_destroy(MessageTooBig);
512  }
513  else if (has_mask_)
514  {
515  asio::async_read(
516  adaptor_.socket(), asio::buffer((char*)&mask_, 4),
517  [this](const error_code& ec, std::size_t
518 #ifdef CROW_ENABLE_DEBUG
519  bytes_transferred
520 #endif
521  ) {
522  is_reading = false;
523 #ifdef CROW_ENABLE_DEBUG
524  if (!ec && bytes_transferred != 4)
525  {
526  throw std::runtime_error("WebSocket:Mask:async_read fail:asio bug?");
527  }
528 #endif
529 
530  if (!ec)
531  {
532  state_ = WebSocketReadState::Payload;
533  do_read();
534  }
535  else
536  {
537  close_connection_ = true;
538  if (error_handler_)
539  error_handler_(*this, ec.message());
540  adaptor_.shutdown_readwrite();
541  adaptor_.close();
542  check_destroy();
543  }
544  });
545  }
546  else
547  {
548  state_ = WebSocketReadState::Payload;
549  do_read();
550  }
551  break;
552  case WebSocketReadState::Payload:
553  {
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) {
560  is_reading = false;
561 
562  if (!ec)
563  {
564  fragment_.insert(fragment_.end(), buffer_.begin(), buffer_.begin() + bytes_transferred);
565  remaining_length_ -= bytes_transferred;
566  if (remaining_length_ == 0)
567  {
568  if (handle_fragment())
569  {
570  state_ = WebSocketReadState::MiniHeader;
571  do_read();
572  }
573  }
574  else
575  do_read();
576  }
577  else
578  {
579  close_connection_ = true;
580  if (error_handler_)
581  error_handler_(*this, ec.message());
582  adaptor_.shutdown_readwrite();
583  adaptor_.close();
584  check_destroy();
585  }
586  });
587  }
588  break;
589  }
590  }
591 
592  /// Check if the FIN bit is set.
593  bool is_FIN()
594  {
595  return mini_header_ & 0x8000;
596  }
597 
598  /// Extract the opcode from the header.
599  int opcode()
600  {
601  return (mini_header_ & 0x0f00) >> 8;
602  }
603 
604  /// Process the payload fragment.
605 
606  ///
607  /// Unmasks the fragment, checks the opcode, merges fragments into 1 message body, and calls the appropriate handler.
609  {
610  if (has_mask_)
611  {
612  for (decltype(fragment_.length()) i = 0; i < fragment_.length(); i++)
613  {
614  fragment_[i] ^= ((char*)&mask_)[i % 4];
615  }
616  }
617  switch (opcode())
618  {
619  case 0: // Continuation
620  {
621  message_ += fragment_;
622  if (is_FIN())
623  {
624  if (message_handler_)
625  message_handler_(*this, message_, is_binary_);
626  message_.clear();
627  }
628  }
629  break;
630  case 1: // Text
631  {
632  is_binary_ = false;
633  message_ += fragment_;
634  if (is_FIN())
635  {
636  if (message_handler_)
637  message_handler_(*this, message_, is_binary_);
638  message_.clear();
639  }
640  }
641  break;
642  case 2: // Binary
643  {
644  is_binary_ = true;
645  message_ += fragment_;
646  if (is_FIN())
647  {
648  if (message_handler_)
649  message_handler_(*this, message_, is_binary_);
650  message_.clear();
651  }
652  }
653  break;
654  case 0x8: // Close
655  {
656  has_recv_close_ = true;
657 
658 
659  uint16_t status_code = NoStatusCodePresent;
660  std::string::size_type message_start = 2;
661  if (fragment_.size() >= 2)
662  {
663  status_code = ntohs(((uint16_t*)fragment_.data())[0]);
664  } else {
665  // no message will crash substr
666  message_start = 0;
667  }
668 
669  if (!has_sent_close_)
670  {
671  close(fragment_.substr(message_start), status_code);
672  }
673  else
674  {
675 
676  close_connection_ = true;
677  if (!is_close_handler_called_)
678  {
679  if (close_handler_)
680  close_handler_(*this, fragment_.substr(message_start), status_code);
681  is_close_handler_called_ = true;
682  }
683  adaptor_.shutdown_readwrite();
684  adaptor_.close();
685 
686  // Close handler must have been called at this point so code does not matter
687  check_destroy();
688  return false;
689  }
690  }
691  break;
692  case 0x9: // Ping
693  {
694  send_pong(fragment_);
695  }
696  break;
697  case 0xA: // Pong
698  {
699  pong_received_ = true;
700  }
701  break;
702  }
703 
704  fragment_.clear();
705  return true;
706  }
707 
708  /// Send the buffers' data through the socket.
709 
710  ///
711  /// Also destroys the object if the Close flag is set.
712  void do_write()
713  {
714  if (sending_buffers_.empty())
715  {
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_)
720  {
721  buffers.emplace_back(asio::buffer(s));
722  }
723  auto watch = std::weak_ptr<void>{anchor_};
724  asio::async_write(
725  adaptor_.socket(), buffers,
726  [&, watch](const error_code& ec, std::size_t /*bytes_transferred*/) {
727  if (!ec && !close_connection_)
728  {
729  sending_buffers_.clear();
730  if (!write_buffers_.empty())
731  do_write();
732  if (has_sent_close_)
733  close_connection_ = true;
734  }
735  else
736  {
737  auto anchor = watch.lock();
738  if (anchor == nullptr) { return; }
739 
740  sending_buffers_.clear();
741  close_connection_ = true;
742  check_destroy();
743  }
744  });
745  }
746  }
747 
748  /// Destroy the Connection.
749  void check_destroy(websocket::CloseStatusCode code = CloseStatusCode::ClosedAbnormally)
750  {
751  // Note that if the close handler was not yet called at this point we did not receive a close packet (or send one)
752  // and thus we use ClosedAbnormally unless instructed otherwise
753  if (!is_close_handler_called_)
754  if (close_handler_)
755  close_handler_(*this, "uncleanly", code);
756  handler_->remove_websocket(this);
757  if (sending_buffers_.empty() && !is_reading)
758  delete this;
759  }
760 
761 
763  {
764  std::string payload;
765  Connection* self;
766  int opcode;
767 
768  void operator()()
769  {
770  self->send_data_impl(this);
771  }
772  };
773 
774  void send_data_impl(SendMessageType* s)
775  {
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));
779  do_write();
780  }
781 
782  void send_data(int opcode, std::string&& msg)
783  {
784  SendMessageType event_arg{
785  std::move(msg),
786  this,
787  opcode};
788 
789  post(std::move(event_arg));
790  }
791 
792  private:
793  Adaptor adaptor_;
794  Handler* handler_;
795 
796  std::vector<std::string> sending_buffers_;
797  std::vector<std::string> write_buffers_;
798 
799  std::array<char, 4096> buffer_;
800  bool is_binary_;
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};
811  uint32_t mask_;
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};
818 
819  std::shared_ptr<void> anchor_ = std::make_shared<int>(); // Value is just for placeholding
820 
821  std::function<void(crow::websocket::connection&)> open_handler_;
822  std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler_;
823  std::function<void(crow::websocket::connection&, const std::string&, uint16_t status_code)> close_handler_;
824  std::function<void(crow::websocket::connection&, const std::string&)> error_handler_;
825  std::function<bool(const crow::request&, void**)> accept_handler_;
826  };
827  } // namespace websocket
828 } // 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: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
A base class for websocket connection.
Definition: websocket.h:62