118 uint64_t max_payload,
const std::vector<std::string>& subprotocols,
123 std::function<
void(
const crow::request&, std::optional<crow::response>&,
void**)> accept_handler,
124 bool mirror_protocols)
126 auto conn = std::shared_ptr<Connection>(
new Connection(std::move(adaptor),
127 handler, max_payload,
128 std::move(open_handler),
129 std::move(message_handler),
130 std::move(close_handler),
131 std::move(error_handler),
132 std::move(accept_handler)));
135 if (!utility::string_equals(req.get_header_value(
"upgrade"),
"websocket"))
137 conn->adaptor_.close();
141 std::string requested_subprotocols_header = req.get_header_value(
"Sec-WebSocket-Protocol");
142 if (!subprotocols.empty() || !requested_subprotocols_header.empty())
144 auto requested_subprotocols = utility::split(requested_subprotocols_header,
", ");
145 auto subprotocol = utility::find_first_of(subprotocols.begin(), subprotocols.end(), requested_subprotocols.begin(), requested_subprotocols.end());
146 if (subprotocol != subprotocols.end())
148 conn->subprotocol_ = *subprotocol;
152 if (mirror_protocols & !requested_subprotocols_header.empty())
154 conn->subprotocol_ = requested_subprotocols_header;
157 if (conn->accept_handler_)
160 std::optional<crow::response> res;
161 conn->accept_handler_(req, res, &ud);
164 std::vector<asio::const_buffer> buffers;
165 auto server_name =
"";
166 std::string content_length_buffer;
167 res->write_header_into_buffer(buffers, content_length_buffer, req.
keep_alive, server_name);
168 buffers.emplace_back(res->body.data(), res->body.size());
170 asio::write(conn->adaptor_.socket(), buffers, ec);
171 conn->adaptor_.close();
179 std::string magic = req.get_header_value(
"Sec-WebSocket-Key") +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
181 s.processBytes(magic.data(), magic.size());
183 s.getDigestBytes(digest);
185 conn->handler_->add_websocket(conn);
186 conn->start(crow::utility::base64encode((
unsigned char*)digest, 20));
356 if (has_sent_close_ && has_recv_close_)
358 close_connection_ =
true;
359 adaptor_.shutdown_readwrite();
368 case WebSocketReadState::MiniHeader:
372 adaptor_.socket().async_read_some(
373 asio::buffer(&mini_header_, 2),
374 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
375#ifdef CROW_ENABLE_DEBUG
381 shared_this->is_reading =
false;
382 shared_this->mini_header_ = ntohs(shared_this->mini_header_);
383#ifdef CROW_ENABLE_DEBUG
385 if (!ec && bytes_transferred != 2)
387 throw std::runtime_error(
"WebSocket:MiniHeader:async_read fail:asio bug?");
393 if ((shared_this->mini_header_ & 0x80) == 0x80)
394 shared_this->has_mask_ =
true;
397#ifndef CROW_ENFORCE_WS_SPEC
398 shared_this->has_mask_ =
false;
400 shared_this->close_connection_ =
true;
401 shared_this->adaptor_.shutdown_readwrite();
402 shared_this->adaptor_.close();
403 if (shared_this->error_handler_)
404 shared_this->error_handler_(*shared_this,
"Client connection not masked.");
405 shared_this->check_destroy(CloseStatusCode::UnacceptableData);
409 if ((shared_this->mini_header_ & 0x7f) == 127)
411 shared_this->state_ = WebSocketReadState::Len64;
413 else if ((shared_this->mini_header_ & 0x7f) == 126)
415 shared_this->state_ = WebSocketReadState::Len16;
419 shared_this->remaining_length_ = shared_this->mini_header_ & 0x7f;
420 shared_this->state_ = WebSocketReadState::Mask;
422 shared_this->do_read();
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, ec.message());
431 shared_this->check_destroy();
436 case WebSocketReadState::Len16:
438 remaining_length_ = 0;
439 remaining_length16_ = 0;
441 adaptor_.socket(), asio::buffer(&remaining_length16_, 2),
442 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
443#ifdef CROW_ENABLE_DEBUG
447 shared_this->is_reading = false;
448 shared_this->remaining_length16_ = ntohs(shared_this->remaining_length16_);
449 shared_this->remaining_length_ = shared_this->remaining_length16_;
450#ifdef CROW_ENABLE_DEBUG
451 if (!ec && bytes_transferred != 2)
453 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
459 shared_this->state_ = WebSocketReadState::Mask;
460 shared_this->do_read();
464 shared_this->close_connection_ =
true;
465 shared_this->adaptor_.shutdown_readwrite();
466 shared_this->adaptor_.close();
467 if (shared_this->error_handler_)
468 shared_this->error_handler_(*shared_this, ec.message());
469 shared_this->check_destroy();
474 case WebSocketReadState::Len64:
477 adaptor_.socket(), asio::buffer(&remaining_length_, 8),
478 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
479#ifdef CROW_ENABLE_DEBUG
483 shared_this->is_reading = false;
484 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));
485#ifdef CROW_ENABLE_DEBUG
486 if (!ec && bytes_transferred != 8)
488 throw std::runtime_error(
"WebSocket:Len16:async_read fail:asio bug?");
494 shared_this->state_ = WebSocketReadState::Mask;
495 shared_this->do_read();
499 shared_this->close_connection_ =
true;
500 shared_this->adaptor_.shutdown_readwrite();
501 shared_this->adaptor_.close();
502 if (shared_this->error_handler_)
503 shared_this->error_handler_(*shared_this, ec.message());
504 shared_this->check_destroy();
509 case WebSocketReadState::Mask:
510 if (remaining_length_ > max_payload_bytes_)
512 close_connection_ =
true;
515 error_handler_(*
this,
"Message length exceeds maximum payload.");
521 adaptor_.socket(), asio::buffer((
char*)&mask_, 4),
522 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t
523#ifdef CROW_ENABLE_DEBUG
527 shared_this->is_reading = false;
528#ifdef CROW_ENABLE_DEBUG
529 if (!ec && bytes_transferred != 4)
531 throw std::runtime_error(
"WebSocket:Mask:async_read fail:asio bug?");
537 shared_this->state_ = WebSocketReadState::Payload;
538 shared_this->do_read();
542 shared_this->close_connection_ =
true;
543 if (shared_this->error_handler_)
544 shared_this->error_handler_(*shared_this, ec.message());
545 shared_this->adaptor_.shutdown_readwrite();
546 shared_this->adaptor_.close();
547 shared_this->check_destroy();
553 state_ = WebSocketReadState::Payload;
557 case WebSocketReadState::Payload:
559 auto to_read =
static_cast<std::uint64_t
>(buffer_.size());
560 if (remaining_length_ < to_read)
561 to_read = remaining_length_;
562 adaptor_.socket().async_read_some(
563 asio::buffer(buffer_,
static_cast<std::size_t
>(to_read)),
564 [shared_this = this->shared_from_this()](
const error_code& ec, std::size_t bytes_transferred) {
565 shared_this->is_reading =
false;
569 shared_this->fragment_.insert(shared_this->fragment_.end(), shared_this->buffer_.begin(), shared_this->buffer_.begin() + bytes_transferred);
570 shared_this->remaining_length_ -= bytes_transferred;
571 if (shared_this->remaining_length_ == 0)
573 if (shared_this->handle_fragment())
575 shared_this->state_ = WebSocketReadState::MiniHeader;
576 shared_this->do_read();
580 shared_this->do_read();
584 shared_this->close_connection_ =
true;
585 if (shared_this->error_handler_)
586 shared_this->error_handler_(*shared_this, ec.message());
587 shared_this->adaptor_.shutdown_readwrite();
588 shared_this->adaptor_.close();
589 shared_this->check_destroy();
719 if (write_buffers_.empty())
return;
721 sending_buffers_.swap(write_buffers_);
722 std::vector<asio::const_buffer> buffers;
723 buffers.reserve(sending_buffers_.size());
724 for (
auto& s : sending_buffers_)
726 buffers.emplace_back(asio::buffer(s));
728 auto watch = std::weak_ptr<void>{anchor_};
730 adaptor_.socket(), buffers,
731 [shared_this = this->shared_from_this(), watch](
const error_code& ec, std::size_t ) {
732 auto anchor = watch.lock();
733 if (anchor == nullptr)
736 if (!ec && !shared_this->close_connection_)
738 shared_this->sending_buffers_.clear();
739 if (!shared_this->write_buffers_.empty())
740 shared_this->do_write();
741 if (shared_this->has_sent_close_)
742 shared_this->close_connection_ = true;
746 shared_this->sending_buffers_.clear();
747 shared_this->close_connection_ = true;
748 shared_this->check_destroy();