修复HTTP请求体缓冲区限制问题 - 支持大规模批量删除操作
根本问题: - HTTP服务器固定4KB缓冲区导致大JSON请求被截断 - 批量删除多个组件时请求体超过缓冲区限制 核心修复: - HttpServer: 实现ReadCompleteRequest方法支持动态缓冲区 - 基于Content-Length头完整读取HTTP请求体 - Config: 添加MAX_REQUEST_SIZE=1MB上限保护机制 - 支持任意数量组件路径的批量删除操作 修复效果: - 解决11个、25个路径批量删除失败问题 - 修复薄壳化分析等大JSON请求处理 - 保持所有现有功能正常运行 - 向后兼容,不影响现有API调用 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7471895fa3
commit
45f455e0c2
3
Config.h
3
Config.h
@ -19,6 +19,9 @@ public:
|
||||
// 缓冲区大小
|
||||
static const int BUFFER_SIZE = 4096;
|
||||
|
||||
// HTTP请求限制
|
||||
static const int MAX_REQUEST_SIZE = 1048576; // 1MB maximum request size
|
||||
|
||||
// Creo配置
|
||||
static const int CREO_CHECK_INTERVAL_MS = 100; // 检查间隔
|
||||
|
||||
|
||||
127
HttpServer.cpp
127
HttpServer.cpp
@ -108,28 +108,13 @@ DWORD WINAPI HttpServer::ServerThread(LPVOID lpParam) {
|
||||
}
|
||||
|
||||
void HttpServer::HandleClient(SOCKET client_socket) {
|
||||
char buffer[Config::BUFFER_SIZE];
|
||||
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
|
||||
|
||||
// 检查recv错误和超时情况
|
||||
if (bytes_received == SOCKET_ERROR) {
|
||||
int error = WSAGetLastError();
|
||||
if (error == WSAETIMEDOUT) {
|
||||
// 接收超时,直接返回避免阻塞
|
||||
return;
|
||||
}
|
||||
// 其他网络错误,直接返回
|
||||
// 读取完整的HTTP请求
|
||||
std::string raw_request = ReadCompleteRequest(client_socket);
|
||||
if (raw_request.empty()) {
|
||||
// 读取失败或超时,直接返回
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_received <= 0) {
|
||||
// 连接关闭或无数据,直接返回
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[bytes_received] = '\0';
|
||||
std::string raw_request(buffer);
|
||||
|
||||
HttpRequest request = ParseRequest(raw_request);
|
||||
HttpResponse response;
|
||||
|
||||
@ -199,6 +184,110 @@ HttpRequest HttpServer::ParseRequest(const std::string& raw_request) {
|
||||
return request;
|
||||
}
|
||||
|
||||
std::string HttpServer::ReadCompleteRequest(SOCKET client_socket) {
|
||||
std::string complete_request;
|
||||
char buffer[Config::BUFFER_SIZE];
|
||||
int total_received = 0;
|
||||
int content_length = -1;
|
||||
bool headers_complete = false;
|
||||
size_t header_end_pos = 0;
|
||||
|
||||
try {
|
||||
// First, read headers to determine Content-Length
|
||||
while (!headers_complete && total_received < Config::MAX_REQUEST_SIZE) {
|
||||
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
|
||||
|
||||
// Check for recv errors and timeout
|
||||
if (bytes_received == SOCKET_ERROR) {
|
||||
int error = WSAGetLastError();
|
||||
if (error == WSAETIMEDOUT) {
|
||||
return ""; // Timeout, return empty
|
||||
}
|
||||
return ""; // Other network error, return empty
|
||||
}
|
||||
|
||||
if (bytes_received <= 0) {
|
||||
return ""; // Connection closed or no data
|
||||
}
|
||||
|
||||
buffer[bytes_received] = '\0';
|
||||
complete_request.append(buffer, bytes_received);
|
||||
total_received += bytes_received;
|
||||
|
||||
// Check if headers are complete (look for \r\n\r\n)
|
||||
size_t header_separator = complete_request.find("\r\n\r\n");
|
||||
if (header_separator != std::string::npos) {
|
||||
headers_complete = true;
|
||||
header_end_pos = header_separator + 4;
|
||||
|
||||
// Parse Content-Length from headers
|
||||
std::string headers_part = complete_request.substr(0, header_end_pos);
|
||||
size_t cl_pos = headers_part.find("Content-Length:");
|
||||
if (cl_pos != std::string::npos) {
|
||||
size_t cl_start = cl_pos + 15; // Length of "Content-Length:"
|
||||
size_t cl_end = headers_part.find("\r\n", cl_start);
|
||||
if (cl_end != std::string::npos) {
|
||||
std::string cl_str = headers_part.substr(cl_start, cl_end - cl_start);
|
||||
// Remove leading/trailing whitespace
|
||||
cl_str.erase(0, cl_str.find_first_not_of(" \t"));
|
||||
cl_str.erase(cl_str.find_last_not_of(" \t") + 1);
|
||||
try {
|
||||
content_length = std::stoi(cl_str);
|
||||
} catch (...) {
|
||||
content_length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no Content-Length header found, assume no body or return what we have
|
||||
if (content_length < 0) {
|
||||
return complete_request;
|
||||
}
|
||||
|
||||
// Check if request size exceeds limit
|
||||
if (content_length > Config::MAX_REQUEST_SIZE) {
|
||||
return ""; // Request too large
|
||||
}
|
||||
|
||||
// Calculate how much body data we already have
|
||||
int current_body_length = complete_request.length() - header_end_pos;
|
||||
|
||||
// Read remaining body data if needed
|
||||
while (current_body_length < content_length && total_received < Config::MAX_REQUEST_SIZE) {
|
||||
int bytes_needed = content_length - current_body_length;
|
||||
int bytes_to_read = min(bytes_needed, sizeof(buffer) - 1);
|
||||
|
||||
int bytes_received = recv(client_socket, buffer, bytes_to_read, 0);
|
||||
|
||||
if (bytes_received == SOCKET_ERROR) {
|
||||
int error = WSAGetLastError();
|
||||
if (error == WSAETIMEDOUT) {
|
||||
break; // Timeout, return what we have
|
||||
}
|
||||
break; // Other error, return what we have
|
||||
}
|
||||
|
||||
if (bytes_received <= 0) {
|
||||
break; // Connection closed
|
||||
}
|
||||
|
||||
buffer[bytes_received] = '\0';
|
||||
complete_request.append(buffer, bytes_received);
|
||||
current_body_length += bytes_received;
|
||||
total_received += bytes_received;
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
// Any exception during reading, return empty
|
||||
return "";
|
||||
}
|
||||
|
||||
return complete_request;
|
||||
}
|
||||
|
||||
void HttpServer::SendResponse(SOCKET client_socket, const HttpResponse& response) {
|
||||
std::ostringstream response_stream;
|
||||
|
||||
|
||||
@ -47,6 +47,7 @@ public:
|
||||
private:
|
||||
static DWORD WINAPI ServerThread(LPVOID lpParam);
|
||||
void HandleClient(SOCKET client_socket);
|
||||
std::string ReadCompleteRequest(SOCKET client_socket);
|
||||
HttpRequest ParseRequest(const std::string& raw_request);
|
||||
void SendResponse(SOCKET client_socket, const HttpResponse& response);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user