安全修复(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文档索引
185 lines
6.3 KiB
C++
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
|