120 uint64_t max_payload,
const std::vector<std::string>& subprotocols,
125 std::function<
void(
const crow::request&, std::optional<crow::response>&,
void**)> accept_handler,
126 bool mirror_protocols,
129 auto conn = std::shared_ptr<Connection>(
new Connection(std::move(adaptor),
130 handler, max_payload,
131 std::move(open_handler),
132 std::move(message_handler),
133 std::move(close_handler),
134 std::move(error_handler),
135 std::move(accept_handler)));
138 detail::socket::apply_tcp_socket_options(conn->adaptor_.socket(), tcp_options);
141 if (!utility::string_equals(req.get_header_value(
"upgrade"),
"websocket"))
143 conn->adaptor_.close();
147 std::string requested_subprotocols_header = req.get_header_value(
"Sec-WebSocket-Protocol");
148 if (!subprotocols.empty() || !requested_subprotocols_header.empty())
150 auto requested_subprotocols = utility::split(requested_subprotocols_header,
", ");
151 auto subprotocol = utility::find_first_of(subprotocols.begin(), subprotocols.end(), requested_subprotocols.begin(), requested_subprotocols.end());
152 if (subprotocol != subprotocols.end())
154 conn->subprotocol_ = *subprotocol;
158 if (mirror_protocols & !requested_subprotocols_header.empty())
160 conn->subprotocol_ = requested_subprotocols_header;
163 if (conn->accept_handler_)
166 std::optional<crow::response> res;
167 conn->accept_handler_(req, res, &ud);
170 std::vector<asio::const_buffer> buffers;
171 auto server_name =
"";
172 std::string content_length_buffer;
173 res->write_header_into_buffer(buffers, content_length_buffer, req.
keep_alive, server_name);
174 buffers.emplace_back(res->body.data(), res->body.size());
176 asio::write(conn->adaptor_.socket(), buffers, ec);
177 conn->adaptor_.close();
185 std::string magic = req.get_header_value(
"Sec-WebSocket-Key") +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
187 s.processBytes(magic.data(), magic.size());
189 s.getDigestBytes(digest);
191 conn->handler_->add_websocket(conn);
192 conn->start(crow::utility::base64encode((
unsigned char*)digest, 20));
264 void close(std::string
const& msg, uint16_t status_code)
override
266 dispatch([shared_this = this->shared_from_this(), msg, status_code]()
mutable {
267 shared_this->has_sent_close_ =
true;
268 if (shared_this->has_recv_close_ && !shared_this->is_close_handler_called_)
270 shared_this->is_close_handler_called_ = true;
271 if (shared_this->close_handler_)
272 shared_this->close_handler_(*shared_this, msg, status_code);
275 switch(status_code) {
277 case NoStatusCodePresent:
278 case ClosedAbnormally:
279 case TLSHandshakeFailure:
283 shared_this->write_buffers_.emplace_back(shared_this->build_header(0x8, 0));
287 auto header = shared_this->build_header(0x8, msg.size() + 2);
289 *(uint16_t*)(status_buf) = htons(status_code);
291 shared_this->write_buffers_.emplace_back(std::move(header));
292 shared_this->write_buffers_.emplace_back(std::string(status_buf, 2));
293 shared_this->write_buffers_.emplace_back(msg);
296 shared_this->do_write();
383 if (has_sent_close_ && has_recv_close_)
385 close_connection_ =
true;
386 adaptor_.shutdown_readwrite();
395 case WebSocketReadState::MiniHeader:
399 adaptor_.socket(), asio::buffer(&mini_header_, 2),
400 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
401#ifdef CROW_ENABLE_DEBUG
407 shared_this->is_reading = false;
408 shared_this->mini_header_ = ntohs(shared_this->mini_header_);
409#ifdef CROW_ENABLE_DEBUG
411 if (!ec && bytes_transferred != 2)
413 throw std::runtime_error(
"WebSocket:MiniHeader:async_read fail:asio bug?");
419 if ((shared_this->mini_header_ & 0x80) == 0x80)
420 shared_this->has_mask_ =
true;
423#ifndef CROW_ENFORCE_WS_SPEC
424 shared_this->has_mask_ =
false;
426 shared_this->close_connection_ =
true;
427 shared_this->adaptor_.shutdown_readwrite();
428 shared_this->adaptor_.close();
429 if (shared_this->error_handler_)
430 shared_this->error_handler_(*shared_this,
"Client connection not masked.");
431 shared_this->check_destroy(CloseStatusCode::UnacceptableData);
435 if ((shared_this->mini_header_ & 0x7f) == 127)
437 shared_this->state_ = WebSocketReadState::Len64;
439 else if ((shared_this->mini_header_ & 0x7f) == 126)
441 shared_this->state_ = WebSocketReadState::Len16;
445 shared_this->remaining_length_ = shared_this->mini_header_ & 0x7f;
446 shared_this->state_ = WebSocketReadState::Mask;
448 shared_this->do_read();
452 shared_this->close_connection_ =
true;
453 shared_this->adaptor_.shutdown_readwrite();
454 shared_this->adaptor_.close();
455 if (shared_this->error_handler_)
456 shared_this->error_handler_(*shared_this, ec.message());
457 shared_this->check_destroy();
462 case WebSocketReadState::Len16:
464 remaining_length_ = 0;
465 remaining_length16_ = 0;
467 adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
468 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
469#ifdef CROW_ENABLE_DEBUG
473 shared_this->is_reading = false;
474 shared_this->remaining_length16_ = ntohs(shared_this->remaining_length16_);
475 shared_this->remaining_length_ = shared_this->remaining_length16_;
476#ifdef CROW_ENABLE_DEBUG
477 if (!ec && bytes_transferred != 2)
479 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
485 shared_this->state_ = WebSocketReadState::Mask;
486 shared_this->do_read();
490 shared_this->close_connection_ =
true;
491 shared_this->adaptor_.shutdown_readwrite();
492 shared_this->adaptor_.close();
493 if (shared_this->error_handler_)
494 shared_this->error_handler_(*shared_this, ec.message());
495 shared_this->check_destroy();
500 case WebSocketReadState::Len64:
503 adaptor_.socket(), asio::buffer(&remaining_length_, 8),
504 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
505#ifdef CROW_ENABLE_DEBUG
509 shared_this->is_reading = false;
510 shared_this->remaining_length_ = ((1 == ntohl(1)) ? (shared_this->remaining_length_) : (static_cast<uint64_t>(ntohl((shared_this->remaining_length_)&0xFFFFFFFF)) << 32) | ntohl((shared_this->remaining_length_) >> 32));
511#ifdef CROW_ENABLE_DEBUG
512 if (!ec && bytes_transferred != 8)
514 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
520 shared_this->state_ = WebSocketReadState::Mask;
521 shared_this->do_read();
525 shared_this->close_connection_ =
true;
526 shared_this->adaptor_.shutdown_readwrite();
527 shared_this->adaptor_.close();
528 if (shared_this->error_handler_)
529 shared_this->error_handler_(*shared_this, ec.message());
530 shared_this->check_destroy();
535 case WebSocketReadState::Mask:
536 if (message_.size() > max_payload_bytes_ ||
537 remaining_length_ > max_payload_bytes_ - message_.size())
539 close_connection_ =
true;
542 error_handler_(*
this,
"Message length exceeds maximum payload.");
543 check_destroy(MessageTooBig);
548 adaptor_.socket(), asio::buffer((
char*)&mask_, 4),
549 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
550#ifdef CROW_ENABLE_DEBUG
554 shared_this->is_reading = false;
555#ifdef CROW_ENABLE_DEBUG
556 if (!ec && bytes_transferred != 4)
558 throw std::runtime_error(
"WebSocket:Mask:async_read fail:asio bug?");
564 shared_this->state_ = WebSocketReadState::Payload;
565 shared_this->do_read();
569 shared_this->close_connection_ =
true;
570 if (shared_this->error_handler_)
571 shared_this->error_handler_(*shared_this, ec.message());
572 shared_this->adaptor_.shutdown_readwrite();
573 shared_this->adaptor_.close();
574 shared_this->check_destroy();
580 state_ = WebSocketReadState::Payload;
584 case WebSocketReadState::Payload:
586 auto to_read =
static_cast<std::uint64_t
>(buffer_.size());
587 if (remaining_length_ < to_read)
588 to_read = remaining_length_;
589 adaptor_.socket().async_read_some(
590 asio::buffer(buffer_,
static_cast<std::size_t
>(to_read)),
591 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t bytes_transferred) {
592 shared_this->is_reading =
false;
596 shared_this->fragment_.insert(shared_this->fragment_.end(), shared_this->buffer_.begin(), shared_this->buffer_.begin() + bytes_transferred);
597 shared_this->remaining_length_ -= bytes_transferred;
598 if (shared_this->remaining_length_ == 0)
600 if (shared_this->handle_fragment())
602 shared_this->state_ = WebSocketReadState::MiniHeader;
603 shared_this->do_read();
607 shared_this->do_read();
611 shared_this->close_connection_ =
true;
612 if (shared_this->error_handler_)
613 shared_this->error_handler_(*shared_this, ec.message());
614 shared_this->adaptor_.shutdown_readwrite();
615 shared_this->adaptor_.close();
616 shared_this->check_destroy();
644 for (
decltype(fragment_.length()) i = 0; i < fragment_.length(); i++)
646 fragment_[i] ^= ((
char*)&mask_)[i % 4];
649 if ((mini_header_ & 0x7000) != 0)
652 error_handler_(*
this,
"RSV bits set without a negotiated extension.");
653 close(
"", CloseStatusCode::ProtocolError);
654 check_destroy(CloseStatusCode::ProtocolError);
657 if ((opcode() & 0x8) != 0 && (!is_FIN() || fragment_.size() > 125))
660 error_handler_(*
this,
"Fragmented or oversized control frame.");
661 close(
"", CloseStatusCode::ProtocolError);
662 check_destroy(CloseStatusCode::ProtocolError);
669 if (!has_unfinished_message_)
672 error_handler_(*
this,
"Continuation frame without a message to continue.");
673 close(
"", CloseStatusCode::ProtocolError);
674 check_destroy(CloseStatusCode::ProtocolError);
677 message_ += fragment_;
680 has_unfinished_message_ =
false;
681 if (message_handler_)
682 message_handler_(*
this, message_, is_binary_);
690 if (has_unfinished_message_)
693 error_handler_(*
this,
"New message before the fragmented message was finished.");
694 close(
"", CloseStatusCode::ProtocolError);
695 check_destroy(CloseStatusCode::ProtocolError);
698 is_binary_ = opcode() == 2;
699 message_ += fragment_;
702 if (message_handler_)
703 message_handler_(*
this, message_, is_binary_);
708 has_unfinished_message_ =
true;
714 has_recv_close_ =
true;
715 uint16_t status_code = NoStatusCodePresent;
716 std::string::size_type message_start = 2;
717 if (fragment_.size() >= 2)
719 status_code = ntohs(((uint16_t*)fragment_.data())[0]);
725 if (!has_sent_close_)
727 if (fragment_.size() == 1 || (fragment_.size() >= 2 && !is_valid_close_code(status_code)))
730 error_handler_(*
this,
"Invalid close frame.");
731 close(
"", CloseStatusCode::ProtocolError);
735 close(fragment_.substr(message_start), status_code);
741 close_connection_ =
true;
742 if (!is_close_handler_called_)
745 close_handler_(*
this, fragment_.substr(message_start), status_code);
746 is_close_handler_called_ =
true;
748 adaptor_.shutdown_readwrite();
759 send_pong(fragment_);
764 pong_received_ =
true;
770 error_handler_(*
this,
"Reserved opcode.");
771 close(
"", CloseStatusCode::ProtocolError);
772 check_destroy(CloseStatusCode::ProtocolError);
787 if (sending_buffers_.empty()) {
788 if (write_buffers_.empty())
return;
790 sending_buffers_.swap(write_buffers_);
791 std::vector<asio::const_buffer> buffers;
792 buffers.reserve(sending_buffers_.size());
793 for (
auto &s: sending_buffers_)
795 buffers.emplace_back(asio::buffer(s));
797 auto watch = std::weak_ptr<void>{anchor_};
799 adaptor_.socket(), buffers,
800 [shared_this = this->shared_from_this(), watch](
const error_code &ec, std::size_t ) {
801 auto anchor = watch.lock();
802 if (anchor == nullptr)
805 if (!ec && !shared_this->close_connection_)
807 shared_this->sending_buffers_.clear();
808 if (!shared_this->write_buffers_.empty())
809 shared_this->do_write();
810 if (shared_this->has_sent_close_)
811 shared_this->close_connection_ = true;
815 shared_this->sending_buffers_.clear();
816 shared_this->close_connection_ = true;
817 shared_this->check_destroy();