为什么这个 C++ ASIO,BEAST 服务器在执行 HTTPS/SSL 请求时进入错误状态

Why does this C++ ASIO, BEAST server go into a bad state when a HTTPS/SSL request is performed

我想编写一个响应 HTTP 请求的服务器。我不关心 HTTPS。如果有人执行 HTTPS 请求,我想拒绝该请求并继续其他 HTTP 请求。我的代码如下所示:

#include <boost/asio.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <thread>
#include <iostream>
using namespace std;

int main(){
    boost::asio::io_context ioc;
    boost::asio::ip::tcp::acceptor acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), 8000));
    boost::beast::flat_buffer request_buffer;
    for(;;){
        boost::asio::ip::tcp::socket socket(ioc);
        acceptor.accept(socket);

        boost::beast::http::request<boost::beast::http::string_body> request;
        try{
            boost::beast::http::read(socket, request_buffer, request);
            cout << "OK" << endl;

            boost::beast::http::response<boost::beast::http::string_body> response(boost::beast::http::status::ok, request.version());
            std::string body = "hello";
            response.content_length(body.size());
            response.body() = std::move(body);
            boost::beast::http::write(socket, response);

        }catch(...){
            cout << "BAD" << endl;
        }
        socket.close();
    }
}

我运行代码并使用 Firefox 按以下顺序执行请求:

  1. 一个 http 请求
  2. 一个 https 请求
  3. 一个 http 请求

我希望得到以下服务器输出:

OK
BAD
OK

然而,我得到的是:

OK
BAD
BAD
BAD
BAD
BAD
BAD
BAD
BAD
BAD
BAD
BAD
BAD

抛出的函数是boost::beast::http::read。但是,我不明白为什么。在调用之间我创建了一个新的套接字对象,因此我的理解是第二个请求的结果不应该影响第三个。但是,显然我的理解是不正确的。有人能解释一下我对 ASIO and/or BEAST 工作原理的理解哪里错了吗?谢谢:)

HTTPS 是基于 SSL 流的 HTTP。 SSL 流是通过普通的 TCP 套接字实现的。 Beast 抛出 "Read" 因为它没有看到 HTTP 请求,它只是看到了看起来像随机二进制数据的东西。它不知道(也没有检测到它是 SSL 流)。

您看到如此多 "BAD" 行的原因是 Firefox 看到 TLS 流尝试连接然后失败。它只是重试 SSL 流连接。所以你最终得到了多条 BAD 连接线。

这就是默认 HTTP 端口为 80 而默认 HTTPS 端口为 443 的原因。与 HTTP 服务器的 HTTPS 客户端连接永远不会工作,并且会产生您所看到的结果类型。

更新: 您进入 BAD 循环的原因是 request_buffer 没有在错误时被清除,因此它包含第一个 SSL 数据连接,每次从新套接字读取数据时都会附加到该数据。

最简单的修复方法是将 request_buffer 的定义移动到与请求对象相同的位置。或者您可以 consume 在循环之前未处理的数据。