2

我想编写一个响应 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 和/或 BEAST 如何工作的理解是错误的。谢谢 :)

4

1 回答 1

1

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

您看到这么多“坏”行的原因是 Firefox 看到 TLS 流尝试连接然后失败。它只是重试 SSL 流连接。因此,您最终会得到多条 BAD 连接线。

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

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

最简单的解决方法是将 request_buffer 的定义移动到与请求对象相同的位置。或者,您可以在循环返回之前使用未处理的数据。

于 2019-04-03T20:09:36.843 回答