Files
micro_servers/libhttp/inc/us/HttpClient.hpp
T
qing 85e0d0740b fix(libhttp): HttpClient 响应大小限制防 OOM
- request_stream_sync 改为真流式,按块回调不二次缓冲
- 新增 set_max_response_size/get_max_response_size(默认 10MB,对齐 WAF)
- write_callback 超限返回 0 中止传输并抛异常
- 更新审计文档 P1-2 状态、README v3.4.0、INDEX 移除不存在的文档
2026-08-04 15:12:06 +08:00

115 lines
4.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <string>
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <curl/curl.h>
#include <openssl/ssl.h>
// Boost.Beast for WebSocket client
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/ssl/stream.hpp>
namespace pmc::net {
namespace beast = boost::beast;
namespace asio = boost::asio;
namespace websocket = beast::websocket;
using tcp = asio::ip::tcp;
enum class HttpMethod {
GET,
POST,
PUT,
DELETE,
PATCH,
HEAD,
OPTIONS
};
class HttpClient {
public:
HttpClient();
~HttpClient();
HttpClient(const HttpClient&) = delete;
HttpClient& operator=(const HttpClient&) = delete;
void set_header(const std::string& header);
void clear_headers();
const std::map<std::string, std::string>& get_response_headers() const;
long get_response_code() const;
// ===== HTTP Methods (Synchronous, libcurl-based) =====
void request_stream_sync(
HttpMethod method,
const std::string& url,
const std::string& data,
std::function<void(const std::string&)> callback);
void get_stream_sync(const std::string& url, std::function<void(const std::string&)> callback);
void post_stream_sync(const std::string& url, const std::string& data, std::function<void(const std::string&)> callback);
void put_stream_sync(const std::string& url, const std::string& data, std::function<void(const std::string&)> callback);
void delete_stream_sync(const std::string& url, std::function<void(const std::string&)> callback);
// ===== 响应体大小限制(防 OOM)=====
// 设置下游响应体大小上限(字节)。0 表示不限制(默认 10MB,与 WAF 对齐)。
// 超限时 write_callback 返回 0 中止传输,request_stream_sync 抛异常。
void set_max_response_size(size_t bytes);
size_t get_max_response_size() const;
// ===== WebSocket Methods (Synchronous, Boost.Beast-based) =====
bool ws_connect(const std::string& url, int timeout_ms = 5000);
bool ws_connect(const std::string& host, const std::string& port,
const std::string& path = "/", bool ssl = false, int timeout_ms = 5000);
bool ws_send(const std::string& message);
bool ws_send_binary(const void* data, size_t size);
std::string ws_recv(int timeout_ms = 0);
bool ws_is_connected() const;
void ws_close();
std::string ws_get_host() const;
std::string ws_get_port() const;
std::string ws_get_path() const;
private:
CURL* curl_ = nullptr;
struct curl_slist* headers_ = nullptr;
std::map<std::string, std::string> response_headers_;
long response_code_ = 0;
size_t max_response_size_ = 10 * 1024 * 1024; // 默认 10MB,对齐 WAF;0 表示不限制
struct WsState {
asio::io_context ioc;
std::unique_ptr<beast::tcp_stream> tcp_stream;
std::unique_ptr<asio::ssl::context> ssl_ctx;
std::unique_ptr<asio::ssl::stream<tcp::socket&>> ssl_stream;
std::unique_ptr<websocket::stream<tcp::socket&>> ws_stream;
std::unique_ptr<websocket::stream<asio::ssl::stream<tcp::socket&>&>> wss_stream;
bool ssl_enabled = false;
bool connected = false;
std::string host;
std::string port;
std::string path;
};
std::unique_ptr<WsState> ws_state_;
void set_http_method(HttpMethod method, const std::string& data);
static size_t header_callback(char* buffer, size_t size, size_t nitems, void* userdata);
static size_t write_callback(char* ptr, size_t size, size_t nmemb, void* userdata);
static void parse_ws_url(const std::string& url_part, std::string& host, std::string& port,
std::string& path, const char* default_port);
};
// Backward compatibility aliases
using WebSocketClientBase = HttpClient;
using WebSocketClient = HttpClient;
} // namespace pmc::net