156 lines
4.9 KiB
C++
156 lines
4.9 KiB
C++
#ifndef HTTP_CLIENT_H
|
||
#define HTTP_CLIENT_H
|
||
|
||
#include "http.h"
|
||
#include "tcp.h"
|
||
#include <freertos/FreeRTOS.h>
|
||
#include <freertos/event_groups.h>
|
||
|
||
#include <map>
|
||
#include <string>
|
||
#include <functional>
|
||
#include <mutex>
|
||
#include <condition_variable>
|
||
#include <optional>
|
||
#include <memory>
|
||
#include <deque>
|
||
#include <cstring>
|
||
|
||
#define EC801E_HTTP_EVENT_HEADERS_RECEIVED (1 << 0)
|
||
#define EC801E_HTTP_EVENT_BODY_RECEIVED (1 << 1)
|
||
#define EC801E_HTTP_EVENT_ERROR (1 << 2)
|
||
#define EC801E_HTTP_EVENT_COMPLETE (1 << 3)
|
||
|
||
class NetworkInterface;
|
||
|
||
class HttpClient : public Http {
|
||
public:
|
||
HttpClient(NetworkInterface* network, int connect_id = 0);
|
||
~HttpClient();
|
||
|
||
void SetTimeout(int timeout_ms) override;
|
||
void SetHeader(const std::string& key, const std::string& value) override;
|
||
void SetContent(std::string&& content) override;
|
||
bool Open(const std::string& method, const std::string& url) override;
|
||
void Close() override;
|
||
int Read(char* buffer, size_t buffer_size) override;
|
||
int Write(const char* buffer, size_t buffer_size) override;
|
||
|
||
int GetStatusCode() override;
|
||
std::string GetResponseHeader(const std::string& key) const override;
|
||
size_t GetBodyLength() override;
|
||
std::string ReadAll() override;
|
||
|
||
private:
|
||
// 数据块结构,用于队列缓冲
|
||
struct DataChunk {
|
||
std::string data;
|
||
size_t offset = 0; // 当前读取偏移
|
||
|
||
// 使用移动构造函数避免拷贝
|
||
DataChunk(std::string&& d) : data(std::move(d)), offset(0) {}
|
||
DataChunk(const std::string& d) : data(d), offset(0) {}
|
||
|
||
size_t available() const {
|
||
return data.size() - offset;
|
||
}
|
||
|
||
size_t read(char* buffer, size_t size) {
|
||
size_t bytes_to_read = std::min(size, available());
|
||
if (bytes_to_read > 0) {
|
||
memcpy(buffer, data.data() + offset, bytes_to_read);
|
||
offset += bytes_to_read;
|
||
}
|
||
return bytes_to_read;
|
||
}
|
||
|
||
bool empty() const {
|
||
return offset >= data.size();
|
||
}
|
||
};
|
||
|
||
// 头部条目结构体,用于高效存储和查找
|
||
struct HeaderEntry {
|
||
std::string original_key; // 保留原始大小写的key(用于输出HTTP头部)
|
||
std::string value; // 头部值
|
||
|
||
HeaderEntry() = default;
|
||
HeaderEntry(const std::string& key, const std::string& val)
|
||
: original_key(key), value(val) {}
|
||
};
|
||
|
||
NetworkInterface* network_;
|
||
int connect_id_;
|
||
std::unique_ptr<Tcp> tcp_;
|
||
EventGroupHandle_t event_group_handle_;
|
||
std::mutex mutex_;
|
||
std::condition_variable cv_;
|
||
|
||
// 用于读取操作的专门锁和缓冲区队列
|
||
std::mutex read_mutex_;
|
||
std::deque<DataChunk> body_chunks_;
|
||
std::condition_variable write_cv_;
|
||
const size_t MAX_BODY_CHUNKS_SIZE = 8192;
|
||
|
||
int status_code_ = -1;
|
||
int timeout_ms_ = 30000;
|
||
std::string rx_buffer_;
|
||
std::map<std::string, HeaderEntry> headers_; // key为小写,用于快速查找
|
||
std::string url_;
|
||
std::string method_;
|
||
std::string protocol_;
|
||
std::string host_;
|
||
std::string path_;
|
||
int port_ = 80;
|
||
std::optional<std::string> content_ = std::nullopt;
|
||
std::map<std::string, HeaderEntry> response_headers_; // key为小写,用于快速查找
|
||
|
||
// 移除原来的 body_ 变量,现在使用 body_chunks_ 队列
|
||
size_t body_offset_ = 0;
|
||
size_t content_length_ = 0;
|
||
size_t total_body_received_ = 0; // 总共接收的响应体字节数
|
||
bool eof_ = false;
|
||
bool connected_ = false;
|
||
bool headers_received_ = false;
|
||
bool request_chunked_ = false;
|
||
bool response_chunked_ = false;
|
||
bool connection_error_ = false; // 新增:标记连接是否异常断开
|
||
|
||
// HTTP 协议解析状态
|
||
enum class ParseState {
|
||
STATUS_LINE,
|
||
HEADERS,
|
||
BODY,
|
||
CHUNK_SIZE,
|
||
CHUNK_DATA,
|
||
CHUNK_TRAILER,
|
||
COMPLETE
|
||
};
|
||
ParseState parse_state_ = ParseState::STATUS_LINE;
|
||
size_t chunk_size_ = 0;
|
||
size_t chunk_received_ = 0;
|
||
|
||
// 私有方法
|
||
bool ParseUrl(const std::string& url);
|
||
std::string BuildHttpRequest();
|
||
void OnTcpData(const std::string& data);
|
||
void OnTcpDisconnected();
|
||
void ProcessReceivedData();
|
||
bool ParseStatusLine(const std::string& line);
|
||
bool ParseHeaderLine(const std::string& line);
|
||
void ParseChunkedBody(const std::string& data);
|
||
void ParseRegularBody(const std::string& data);
|
||
size_t ParseChunkSize(const std::string& chunk_size_line);
|
||
std::string GetNextLine(std::string& buffer);
|
||
bool HasCompleteLine(const std::string& buffer);
|
||
void SetError();
|
||
|
||
// 新增:向读取队列添加数据的方法
|
||
void AddBodyData(const std::string& data);
|
||
void AddBodyData(std::string&& data); // 移动版本
|
||
|
||
// 新增:检查数据是否完整接收
|
||
bool IsDataComplete() const;
|
||
};
|
||
|
||
#endif |