Peek asio https ssl流,而不从输入流中删除



我使用asio单机版和来自Eidheim的HTTPS包装器(EidheimsSimpleHttpsServer(在Windows上设置一个具有异步重请求处理和线程池的HTTPS服务器。HTTPS服务器偶尔会收到原始套接字查询,因为我想替换旧的套接字服务器,如果客户端应用程序不是最新的,他们不会发送HTTP格式的查询。对于HTTP,这没有问题,因为如果传入查询没有HTTP格式,我可以更改Read(from socket(方法,改为使用遗留代码进行请求处理。

现在,在HTTPS ssl套接字流上尝试同样的操作,服务器首先需要在进行任何读取之前执行ssl握手,因此我需要在握手之前读取(peek(套接字,以验证它是否需要纯套接字回退方法或标准HTTPS方法。

但是,每当我在握手之前手动读取套接字时,输入流中的字节都会丢失,并且还无法将这些丢失的字节提供给握手/读取过程。

因此,我认为将字节留在输入流上并进行窥探会更容易,但我还没有找到窥探asio::ssl::stream的方法。(async_receive和标志message_peek应该可以工作,但我找不到。我找到的唯一文档是boost::beast(

我唯一的角度是重写接受函数,如果握手成功,就会调用读取:

(来自https://gitlab.com/eidheim/Simple-Web-Server/-/blob/master/server_https.hpp)

void accept() override {
auto connection = create_connection(*io_service, context);
acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const error_code& ec) {
auto lock = connection->handler_runner->continue_lock();
if (!lock)
return;
if (ec != error::operation_aborted)
this->accept();
auto session = std::make_shared<Session>(config.max_request_streambuf_size, connection);
if (!ec) {
asio::ip::tcp::no_delay option(true);
error_code ec;
session->connection->socket->lowest_layer().set_option(option, ec);
session->connection->set_timeout(config.timeout_request);
// ***** I need to read (peek) before this to decide if a handshake is needed *****
session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code& ec) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if (!lock)
return;
if (!ec)
this->read(session);
else if (this->on_error)
this->on_error(session->request, ec);
});
}
else if (this->on_error)
this->on_error(session->request, ec);
});
}

有人知道如何窥探asio-ssl流吗(实际上我只需要第一个字节(?或者有人了解这个图书馆,并对如何解决这个问题有另一个想法吗?还有其他我可以研究的混合(asio(服务器(https和原始套接字(的例子吗?

谢谢Naturlux

事实证明,窥探套接字是不鼓励的,而且也很难实现,使用asio单机版更是如此。我发现的解决方法是这样的:

  • 从Asio Standalone库切换到boost::Asio,因为boost::Asio对Asio命名空间有额外的过载(至少在比较atm最新版本boost1.72.0和asio1.13.0时(
  • 如本文所述(在使用Boost::asio之前,是否可以在从套接字读取之后进行async_handshake?(如果之前需要从ssl流中进行任何读取,则读取整个握手,并将读取缓冲区作为第二个参数传递给async_hand shake重载(请参阅第一点(

对我来说,它看起来像这样:

void accept() override {
auto connection = create_connection(*io_service, context);
acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const error_code &ec) {
auto lock = connection->handler_runner->continue_lock();
if(!lock)
return;
if(ec != error::operation_aborted)
this->accept();
auto session = std::make_shared<Session>(config.max_request_streambuf_size, connection);
if(!ec) {
asio::ip::tcp::no_delay option(true);
error_code ec;
session->connection->socket->lowest_layer().set_option(option, ec);
//read some bytes, needed before the handshake
const unsigned int bytesToRead = 1;
int size_of_the_data = 100;
std::vector<unsigned char> _raw_buffer(size_of_the_data);
asio::mutable_buffers_1 sslBuffer(asio::buffer(_raw_buffer, size_of_the_data));
//You should make this async!
asio::read(session->connection->socket->next_layer(), boost::asio::buffer(sslBuffer, bytesToRead), asio::transfer_exactly(bytesToRead));
//Get the read data from the buffer in a readable form
unsigned char * firstByte = asio::buffer_cast<unsigned char*>(sslBuffer);
//Use the data somehow (in my case, use the first Byte to see if I need raw socket handling or ssl handshake + https handling)
if (SocketQuery::CheckForSocketQuery(firstByte[0])) {
this->read_socket(session, firstByte[0]);
}
else
{
//read handshake, 4000 Bytes should be way more than any handshake needs (which is something between 200 and 400 bytes usually)
//You should make this async!
std::size_t bytesOfHandshake = session->connection->socket->next_layer().read_some(boost::asio::buffer(sslBuffer + bytesToRead, 4000));
bytesOfHandshake += bytesToRead;
session->connection->set_timeout(config.timeout_request);
//Use overload of async_handshake with buffer as second parameter
//Note that the async callback lambda is expected to take the buffer and buffer size as you see below
session->connection->socket->async_handshake(asio::ssl::stream_base::server, asio::buffer(sslBuffer, bytesOfHandshake), [this, sslBuffer, session](const error_code& ecHttps, std::size_t bufferSize) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if (!lock)
return;
if (!ecHttps)
{
this->read(session);
}
else if (this->on_error)
{
this->on_error(session->request, ecHttps);
wxLogMessage("server error: " + wxString(ecHttps.message()));
}
else
{
wxLogMessage("server error: " + wxString(ecHttps.message()));
}
});
}
}
else if(this->on_error)
this->on_error(session->request, ec);
});
}

最新更新