Files
blackbird/libhttp/inc/us/detail/HttpServerImpl.hpp
T
qing e815f0ec40 fix(gateway,libhttp): 修复进程无法退出bug,完成P0安全问题修复
安全修复(P0):
- 修复4处错误消息泄露内部步骤问题,替换为用户友好文案
- 修正拼写错误 "Registe" -> "Registration"
- 修正注册失败HTTP状态码 400 -> 500
- 所有P0严重问题100%修复,安全评级提升至A-

稳定性修复(关键):
- 修复信号处理非async-signal-safe问题:仅设置原子标志,杜绝死锁
- 新增SIGPIPE忽略处理,防止写关闭socket时进程意外终止
- 修复Listener::doAccept()关闭后无限递归导致CPU 100%空转bug
- 新增Listener::close()方法,stop()先关闭acceptor再停止ioc
- 改进stop()流程:acceptor->WS客户端->ioc->worker线程 有序关闭
- 新增双重超时保护:stop() 8秒、日志flush 3秒,超时强制exit保证进程绝不挂死
- 服务器事件循环改为独立线程运行,主线程负责信号检测和关闭协调

文档:
- 新增CHANGELOG.md更新日志
- 更新gateway安全审计文档,添加稳定性修复记录
- 更新docs/INDEX.md文档索引
2026-08-07 23:07:35 +08:00

185 lines
6.3 KiB
C++

#ifndef HTTPSERVER_IMPL_HPP
#define HTTPSERVER_IMPL_HPP
#include "us/HttpServer.hpp"
#include <boost/algorithm/string.hpp>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <optional>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <boost/beast/websocket/ssl.hpp>
namespace pmc {
namespace net {
// ===================== 自定义异常 =====================
class HttpServerException : public std::runtime_error {
public:
explicit HttpServerException(const std::string& msg) : runtime_error(msg) {}
};
class HttpListenerException : public HttpServerException {
public:
explicit HttpListenerException(const std::string& msg) : HttpServerException(msg) {}
};
class SSLInitException : public HttpServerException {
public:
explicit SSLInitException(const std::string& msg) : HttpServerException(msg) {}
};
class CreateObjectFailed : public HttpServerException {
public:
explicit CreateObjectFailed(const std::string& msg) : HttpServerException(msg) {}
};
// ===================== Session (完整定义) =====================
class HttpServer::Session : public std::enable_shared_from_this<Session> {
using tcp_stream = beast::tcp_stream;
using ssl_stream = asio::ssl::stream<tcp_stream&>;
using ws_stream = websocket::stream<tcp_stream&>;
using wss_stream = websocket::stream<ssl_stream&>;
// Proxy outbound types
using proxy_ws_stream = websocket::stream<tcp::socket&>;
using proxy_wss_stream = websocket::stream<asio::ssl::stream<tcp::socket&>&>;
public:
Session(tcp::socket&& socket, HttpServer* server)
: stream_(std::move(socket)), server_(server), ssl_enabled_(false),
is_websocket_(false), is_ws_proxy_(false), client_id_("") {}
Session(tcp::socket&& socket, asio::ssl::context& ssl_ctx, HttpServer* server)
: stream_(std::move(socket)), server_(server), ssl_enabled_(true),
is_websocket_(false), is_ws_proxy_(false), client_id_("") {
ssl_stream_ = std::make_unique<ssl_stream>(stream_, ssl_ctx);
}
~Session() { close(); }
void run();
void setRemoteInfo(const std::string& ip, unsigned short port);
void wsSend(const std::string& message);
std::string getClientId() const { return client_id_; }
std::string getRemoteAddress() const { return remote_ip_ + ":" + std::to_string(remote_port_); }
bool isWebSocket() const { return is_websocket_; }
private:
void close();
void doSSLHandshake();
void doRead();
void doReadBody();
void handleRead(beast::error_code ec);
bool isWebSocketUpgrade(const http::request<http::string_body>& req);
void doWsUpgrade();
void doWssUpgrade();
void onWsAccept(beast::error_code ec);
// Regular WebSocket
void doWsRead();
void onWsRead(beast::error_code ec, std::size_t bytes_transferred);
void doWsWrite();
void onWsClose();
// WebSocket Proxy
static void parseProxyUrl(const std::string& url, bool& ssl, std::string& host,
std::string& port, std::string& path);
void doProxyConnect(const std::string& target_url);
void onProxyResolve(beast::error_code ec, tcp::resolver::results_type results);
void onProxyConnect(beast::error_code ec, tcp::endpoint ep);
void onProxySslHandshake(beast::error_code ec);
void onProxyHandshake(beast::error_code ec);
// Client → Backend
void doProxyReadClient();
void onProxyReadClient(beast::error_code ec, std::size_t bytes_transferred);
void doProxyWriteBackend();
// Backend → Client
void doProxyReadBackend();
void onProxyReadBackend(beast::error_code ec, std::size_t bytes_transferred);
void doProxyWriteClient();
void closeProxy(websocket::close_code code);
// Regular HTTP
void processRequest(http::request<http::string_body> req);
void doWrite(std::shared_ptr<http::response<http::string_body>> response);
// Client stream (inbound)
tcp_stream stream_;
std::unique_ptr<ssl_stream> ssl_stream_;
std::unique_ptr<ws_stream> ws_stream_;
std::unique_ptr<wss_stream> wss_stream_;
beast::flat_buffer buffer_;
beast::flat_buffer ws_buffer_;
http::request<http::string_body> request_;
std::optional<http::request_parser<http::string_body>> parser_;
HttpServer* server_;
bool ssl_enabled_;
std::string remote_ip_ = "unknown";
unsigned short remote_port_ = 0;
bool is_websocket_;
bool is_ws_proxy_;
std::string client_id_;
std::string ws_path_;
WebSocketMessageHandler ws_handler_;
std::deque<std::string> ws_send_queue_;
// Proxy state (outbound to backend)
std::string ws_proxy_target_;
bool proxy_ssl_ = false;
bool proxy_connected_ = false;
bool proxy_closed_ = false;
std::string proxy_host_, proxy_port_, proxy_path_;
std::unique_ptr<tcp::resolver> proxy_resolver_;
std::unique_ptr<tcp::socket> proxy_socket_;
std::unique_ptr<beast::tcp_stream> proxy_tcp_stream_;
std::unique_ptr<asio::ssl::context> proxy_ssl_ctx_;
std::unique_ptr<asio::ssl::stream<tcp::socket&>> proxy_ssl_stream_;
std::unique_ptr<proxy_ws_stream> proxy_ws_stream_;
std::unique_ptr<proxy_wss_stream> proxy_wss_stream_;
beast::flat_buffer proxy_client_buffer_;
beast::flat_buffer proxy_backend_buffer_;
std::deque<std::pair<std::string, bool>> proxy_to_backend_queue_;
std::deque<std::pair<std::string, bool>> proxy_to_client_queue_;
};
// ===================== Listener (完整定义) =====================
class HttpServer::Listener : public std::enable_shared_from_this<Listener> {
public:
Listener(asio::io_context& ioc, tcp::endpoint endpoint, HttpServer* server)
: ioc_(ioc), acceptor_(ioc), server_(server), ssl_enabled_(false) {
initAcceptor(endpoint);
}
Listener(asio::io_context& ioc, tcp::endpoint endpoint,
asio::ssl::context& ssl_ctx, HttpServer* server)
: ioc_(ioc), acceptor_(ioc), ssl_ctx_(&ssl_ctx), server_(server), ssl_enabled_(true) {
initAcceptor(endpoint);
}
void run();
void close(); // 关闭 acceptor,停止接受新连接
private:
void initAcceptor(tcp::endpoint ep);
void doAccept();
asio::io_context& ioc_;
tcp::acceptor acceptor_;
asio::ssl::context* ssl_ctx_ = nullptr;
HttpServer* server_;
bool ssl_enabled_;
};
} // namespace net
} // namespace pmc
#endif // HTTPSERVER_IMPL_HPP