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));
368 if (has_sent_close_ && has_recv_close_)
370 close_connection_ =
true;
371 adaptor_.shutdown_readwrite();
380 case WebSocketReadState::MiniHeader:
384 adaptor_.socket().async_read_some(
385 asio::buffer(&mini_header_, 2),
386 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
387#ifdef CROW_ENABLE_DEBUG
393 shared_this->is_reading =
false;
394 shared_this->mini_header_ = ntohs(shared_this->mini_header_);
395#ifdef CROW_ENABLE_DEBUG
397 if (!ec && bytes_transferred != 2)
399 throw std::runtime_error(
"WebSocket:MiniHeader:async_read fail:asio bug?");
405 if ((shared_this->mini_header_ & 0x80) == 0x80)
406 shared_this->has_mask_ =
true;
409#ifndef CROW_ENFORCE_WS_SPEC
410 shared_this->has_mask_ =
false;
412 shared_this->close_connection_ =
true;
413 shared_this->adaptor_.shutdown_readwrite();
414 shared_this->adaptor_.close();
415 if (shared_this->error_handler_)
416 shared_this->error_handler_(*shared_this,
"Client connection not masked.");
417 shared_this->check_destroy(CloseStatusCode::UnacceptableData);
421 if ((shared_this->mini_header_ & 0x7f) == 127)
423 shared_this->state_ = WebSocketReadState::Len64;
425 else if ((shared_this->mini_header_ & 0x7f) == 126)
427 shared_this->state_ = WebSocketReadState::Len16;
431 shared_this->remaining_length_ = shared_this->mini_header_ & 0x7f;
432 shared_this->state_ = WebSocketReadState::Mask;
434 shared_this->do_read();
438 shared_this->close_connection_ =
true;
439 shared_this->adaptor_.shutdown_readwrite();
440 shared_this->adaptor_.close();
441 if (shared_this->error_handler_)
442 shared_this->error_handler_(*shared_this, ec.message());
443 shared_this->check_destroy();
448 case WebSocketReadState::Len16:
450 remaining_length_ = 0;
451 remaining_length16_ = 0;
453 adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
454 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
455#ifdef CROW_ENABLE_DEBUG
459 shared_this->is_reading = false;
460 shared_this->remaining_length16_ = ntohs(shared_this->remaining_length16_);
461 shared_this->remaining_length_ = shared_this->remaining_length16_;
462#ifdef CROW_ENABLE_DEBUG
463 if (!ec && bytes_transferred != 2)
465 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
471 shared_this->state_ = WebSocketReadState::Mask;
472 shared_this->do_read();
476 shared_this->close_connection_ =
true;
477 shared_this->adaptor_.shutdown_readwrite();
478 shared_this->adaptor_.close();
479 if (shared_this->error_handler_)
480 shared_this->error_handler_(*shared_this, ec.message());
481 shared_this->check_destroy();
486 case WebSocketReadState::Len64:
489 adaptor_.socket(), asio::buffer(&remaining_length_, 8),
490 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
491#ifdef CROW_ENABLE_DEBUG
495 shared_this->is_reading = false;
496 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));
497#ifdef CROW_ENABLE_DEBUG
498 if (!ec && bytes_transferred != 8)
500 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
506 shared_this->state_ = WebSocketReadState::Mask;
507 shared_this->do_read();
511 shared_this->close_connection_ =
true;
512 shared_this->adaptor_.shutdown_readwrite();
513 shared_this->adaptor_.close();
514 if (shared_this->error_handler_)
515 shared_this->error_handler_(*shared_this, ec.message());
516 shared_this->check_destroy();
521 case WebSocketReadState::Mask:
522 if (message_.size() > max_payload_bytes_ ||
523 remaining_length_ > max_payload_bytes_ - message_.size())
525 close_connection_ =
true;
528 error_handler_(*
this,
"Message length exceeds maximum payload.");
534 adaptor_.socket(), asio::buffer((
char*)&mask_, 4),
535 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
536#ifdef CROW_ENABLE_DEBUG
540 shared_this->is_reading = false;
541#ifdef CROW_ENABLE_DEBUG
542 if (!ec && bytes_transferred != 4)
544 throw std::runtime_error(
"WebSocket:Mask:async_read fail:asio bug?");
550 shared_this->state_ = WebSocketReadState::Payload;
551 shared_this->do_read();
555 shared_this->close_connection_ =
true;
556 if (shared_this->error_handler_)
557 shared_this->error_handler_(*shared_this, ec.message());
558 shared_this->adaptor_.shutdown_readwrite();
559 shared_this->adaptor_.close();
560 shared_this->check_destroy();
566 state_ = WebSocketReadState::Payload;
570 case WebSocketReadState::Payload:
572 auto to_read =
static_cast<std::uint64_t
>(buffer_.size());
573 if (remaining_length_ < to_read)
574 to_read = remaining_length_;
575 adaptor_.socket().async_read_some(
576 asio::buffer(buffer_,
static_cast<std::size_t
>(to_read)),
577 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t bytes_transferred) {
578 shared_this->is_reading =
false;
582 shared_this->fragment_.insert(shared_this->fragment_.end(), shared_this->buffer_.begin(), shared_this->buffer_.begin() + bytes_transferred);
583 shared_this->remaining_length_ -= bytes_transferred;
584 if (shared_this->remaining_length_ == 0)
586 if (shared_this->handle_fragment())
588 shared_this->state_ = WebSocketReadState::MiniHeader;
589 shared_this->do_read();
593 shared_this->do_read();
597 shared_this->close_connection_ =
true;
598 if (shared_this->error_handler_)
599 shared_this->error_handler_(*shared_this, ec.message());
600 shared_this->adaptor_.shutdown_readwrite();
601 shared_this->adaptor_.close();
602 shared_this->check_destroy();
732 if (sending_buffers_.empty()) {
733 if (write_buffers_.empty())
return;
735 sending_buffers_.swap(write_buffers_);
736 std::vector<asio::const_buffer> buffers;
737 buffers.reserve(sending_buffers_.size());
738 for (
auto &s: sending_buffers_)
740 buffers.emplace_back(asio::buffer(s));
742 auto watch = std::weak_ptr<void>{anchor_};
744 adaptor_.socket(), buffers,
745 [shared_this = this->shared_from_this(), watch](
const error_code &ec, std::size_t ) {
746 auto anchor = watch.lock();
747 if (anchor == nullptr)
750 if (!ec && !shared_this->close_connection_)
752 shared_this->sending_buffers_.clear();
753 if (!shared_this->write_buffers_.empty())
754 shared_this->do_write();
755 if (shared_this->has_sent_close_)
756 shared_this->close_connection_ = true;
760 shared_this->sending_buffers_.clear();
761 shared_this->close_connection_ = true;
762 shared_this->check_destroy();