119 uint64_t max_payload,
const std::vector<std::string>& subprotocols,
124 std::function<
void(
const crow::request&, std::optional<crow::response>&,
void**)> accept_handler,
125 bool mirror_protocols,
128 auto conn = std::shared_ptr<Connection>(
new Connection(std::move(adaptor),
129 handler, max_payload,
130 std::move(open_handler),
131 std::move(message_handler),
132 std::move(close_handler),
133 std::move(error_handler),
134 std::move(accept_handler)));
137 detail::socket::apply_tcp_socket_options(conn->adaptor_.socket(), tcp_options);
140 if (!utility::string_equals(req.get_header_value(
"upgrade"),
"websocket"))
142 conn->adaptor_.close();
146 std::string requested_subprotocols_header = req.get_header_value(
"Sec-WebSocket-Protocol");
147 if (!subprotocols.empty() || !requested_subprotocols_header.empty())
149 auto requested_subprotocols = utility::split(requested_subprotocols_header,
", ");
150 auto subprotocol = utility::find_first_of(subprotocols.begin(), subprotocols.end(), requested_subprotocols.begin(), requested_subprotocols.end());
151 if (subprotocol != subprotocols.end())
153 conn->subprotocol_ = *subprotocol;
157 if (mirror_protocols & !requested_subprotocols_header.empty())
159 conn->subprotocol_ = requested_subprotocols_header;
162 if (conn->accept_handler_)
165 std::optional<crow::response> res;
166 conn->accept_handler_(req, res, &ud);
169 std::vector<asio::const_buffer> buffers;
170 auto server_name =
"";
171 std::string content_length_buffer;
172 res->write_header_into_buffer(buffers, content_length_buffer, req.
keep_alive, server_name);
173 buffers.emplace_back(res->body.data(), res->body.size());
175 asio::write(conn->adaptor_.socket(), buffers, ec);
176 conn->adaptor_.close();
184 std::string magic = req.get_header_value(
"Sec-WebSocket-Key") +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
186 s.processBytes(magic.data(), magic.size());
188 s.getDigestBytes(digest);
190 conn->handler_->add_websocket(conn);
191 conn->start(crow::utility::base64encode((
unsigned char*)digest, 20));
361 if (has_sent_close_ && has_recv_close_)
363 close_connection_ =
true;
364 adaptor_.shutdown_readwrite();
373 case WebSocketReadState::MiniHeader:
377 adaptor_.socket().async_read_some(
378 asio::buffer(&mini_header_, 2),
379 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
380#ifdef CROW_ENABLE_DEBUG
386 shared_this->is_reading =
false;
387 shared_this->mini_header_ = ntohs(shared_this->mini_header_);
388#ifdef CROW_ENABLE_DEBUG
390 if (!ec && bytes_transferred != 2)
392 throw std::runtime_error(
"WebSocket:MiniHeader:async_read fail:asio bug?");
398 if ((shared_this->mini_header_ & 0x80) == 0x80)
399 shared_this->has_mask_ =
true;
402#ifndef CROW_ENFORCE_WS_SPEC
403 shared_this->has_mask_ =
false;
405 shared_this->close_connection_ =
true;
406 shared_this->adaptor_.shutdown_readwrite();
407 shared_this->adaptor_.close();
408 if (shared_this->error_handler_)
409 shared_this->error_handler_(*shared_this,
"Client connection not masked.");
410 shared_this->check_destroy(CloseStatusCode::UnacceptableData);
414 if ((shared_this->mini_header_ & 0x7f) == 127)
416 shared_this->state_ = WebSocketReadState::Len64;
418 else if ((shared_this->mini_header_ & 0x7f) == 126)
420 shared_this->state_ = WebSocketReadState::Len16;
424 shared_this->remaining_length_ = shared_this->mini_header_ & 0x7f;
425 shared_this->state_ = WebSocketReadState::Mask;
427 shared_this->do_read();
431 shared_this->close_connection_ =
true;
432 shared_this->adaptor_.shutdown_readwrite();
433 shared_this->adaptor_.close();
434 if (shared_this->error_handler_)
435 shared_this->error_handler_(*shared_this, ec.message());
436 shared_this->check_destroy();
441 case WebSocketReadState::Len16:
443 remaining_length_ = 0;
444 remaining_length16_ = 0;
446 adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
447 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
448#ifdef CROW_ENABLE_DEBUG
452 shared_this->is_reading = false;
453 shared_this->remaining_length16_ = ntohs(shared_this->remaining_length16_);
454 shared_this->remaining_length_ = shared_this->remaining_length16_;
455#ifdef CROW_ENABLE_DEBUG
456 if (!ec && bytes_transferred != 2)
458 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
464 shared_this->state_ = WebSocketReadState::Mask;
465 shared_this->do_read();
469 shared_this->close_connection_ =
true;
470 shared_this->adaptor_.shutdown_readwrite();
471 shared_this->adaptor_.close();
472 if (shared_this->error_handler_)
473 shared_this->error_handler_(*shared_this, ec.message());
474 shared_this->check_destroy();
479 case WebSocketReadState::Len64:
482 adaptor_.socket(), asio::buffer(&remaining_length_, 8),
483 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
484#ifdef CROW_ENABLE_DEBUG
488 shared_this->is_reading = false;
489 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));
490#ifdef CROW_ENABLE_DEBUG
491 if (!ec && bytes_transferred != 8)
493 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
499 shared_this->state_ = WebSocketReadState::Mask;
500 shared_this->do_read();
504 shared_this->close_connection_ =
true;
505 shared_this->adaptor_.shutdown_readwrite();
506 shared_this->adaptor_.close();
507 if (shared_this->error_handler_)
508 shared_this->error_handler_(*shared_this, ec.message());
509 shared_this->check_destroy();
514 case WebSocketReadState::Mask:
515 if (remaining_length_ > max_payload_bytes_)
517 close_connection_ =
true;
520 error_handler_(*
this,
"Message length exceeds maximum payload.");
526 adaptor_.socket(), asio::buffer((
char*)&mask_, 4),
527 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
528#ifdef CROW_ENABLE_DEBUG
532 shared_this->is_reading = false;
533#ifdef CROW_ENABLE_DEBUG
534 if (!ec && bytes_transferred != 4)
536 throw std::runtime_error(
"WebSocket:Mask:async_read fail:asio bug?");
542 shared_this->state_ = WebSocketReadState::Payload;
543 shared_this->do_read();
547 shared_this->close_connection_ =
true;
548 if (shared_this->error_handler_)
549 shared_this->error_handler_(*shared_this, ec.message());
550 shared_this->adaptor_.shutdown_readwrite();
551 shared_this->adaptor_.close();
552 shared_this->check_destroy();
558 state_ = WebSocketReadState::Payload;
562 case WebSocketReadState::Payload:
564 auto to_read =
static_cast<std::uint64_t
>(buffer_.size());
565 if (remaining_length_ < to_read)
566 to_read = remaining_length_;
567 adaptor_.socket().async_read_some(
568 asio::buffer(buffer_,
static_cast<std::size_t
>(to_read)),
569 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t bytes_transferred) {
570 shared_this->is_reading =
false;
574 shared_this->fragment_.insert(shared_this->fragment_.end(), shared_this->buffer_.begin(), shared_this->buffer_.begin() + bytes_transferred);
575 shared_this->remaining_length_ -= bytes_transferred;
576 if (shared_this->remaining_length_ == 0)
578 if (shared_this->handle_fragment())
580 shared_this->state_ = WebSocketReadState::MiniHeader;
581 shared_this->do_read();
585 shared_this->do_read();
589 shared_this->close_connection_ =
true;
590 if (shared_this->error_handler_)
591 shared_this->error_handler_(*shared_this, ec.message());
592 shared_this->adaptor_.shutdown_readwrite();
593 shared_this->adaptor_.close();
594 shared_this->check_destroy();
724 if (sending_buffers_.empty()) {
725 if (write_buffers_.empty())
return;
727 sending_buffers_.swap(write_buffers_);
728 std::vector<asio::const_buffer> buffers;
729 buffers.reserve(sending_buffers_.size());
730 for (
auto &s: sending_buffers_)
732 buffers.emplace_back(asio::buffer(s));
734 auto watch = std::weak_ptr<void>{anchor_};
736 adaptor_.socket(), buffers,
737 [shared_this = this->shared_from_this(), watch](
const error_code &ec, std::size_t ) {
738 auto anchor = watch.lock();
739 if (anchor == nullptr)
742 if (!ec && !shared_this->close_connection_)
744 shared_this->sending_buffers_.clear();
745 if (!shared_this->write_buffers_.empty())
746 shared_this->do_write();
747 if (shared_this->has_sent_close_)
748 shared_this->close_connection_ = true;
752 shared_this->sending_buffers_.clear();
753 shared_this->close_connection_ = true;
754 shared_this->check_destroy();