From 1c2fc1d968ce3e0c8531afad2e4cb26eed607ae1 Mon Sep 17 00:00:00 2001 From: ithewei Date: Thu, 6 Aug 2026 12:21:00 +0800 Subject: [PATCH] fix(http): handle oversized response header in FileCache send path FileCache reserves a fixed block before the file content so header+body can be sent as one buffer. prepend_header() previously returned void and silently did nothing when the header exceeded the reserve (1K): the file was then served with a missing/garbage header and the caller had no way to know. - Bump the reserve from 1K to 4K (covers normal responses incl. long cookies / CORS / CSP headers), so the fast single-buffer path is taken in practice. - prepend_header() now returns bool. When the header still doesn't fit, HttpHandler falls back to sending the header first, then the file content (pResp->content already points at fc->filebuf) via the existing SEND_BODY state -- correct instead of silently broken. Verified: normal static file serve unchanged; a response with a >4K header still delivers both the full header and the intact file body. Minimal alternative to #823 (avoids its LRU/concurrency/config rework). --- http/server/FileCache.h | 11 ++++++++--- http/server/HttpHandler.cpp | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/http/server/FileCache.h b/http/server/FileCache.h index 363c41d88..2e0d51aff 100644 --- a/http/server/FileCache.h +++ b/http/server/FileCache.h @@ -10,7 +10,7 @@ #include "hstring.h" #include "LRUCache.h" -#define HTTP_HEADER_MAX_LENGTH 1024 // 1K +#define HTTP_HEADER_MAX_LENGTH 4096 // 4K #define FILE_CACHE_MAX_NUM 100 #define FILE_CACHE_MAX_SIZE (1 << 22) // 4M @@ -48,11 +48,16 @@ typedef struct file_cache_s { filebuf.len = filesize; } - void prepend_header(const char* header, int len) { - if (len > HTTP_HEADER_MAX_LENGTH) return; + // Prepend the response header into the space reserved before filebuf so the + // header + file content can be sent as one buffer (httpbuf). Returns false + // if the header does not fit the reserved space; the caller must then send + // the header and filebuf separately (filebuf stays intact either way). + bool prepend_header(const char* header, int len) { + if (len > HTTP_HEADER_MAX_LENGTH) return false; httpbuf.base = filebuf.base - len; httpbuf.len = len + filebuf.len; memcpy(httpbuf.base, header, len); + return true; } } file_cache_t; diff --git a/http/server/HttpHandler.cpp b/http/server/HttpHandler.cpp index 4345a05bc..fa2013b32 100644 --- a/http/server/HttpHandler.cpp +++ b/http/server/HttpHandler.cpp @@ -856,11 +856,18 @@ int HttpHandler::GetSendData(char** data, size_t* len) { // FileCache // NOTE: no copy filebuf, more efficient header = pResp->Dump(true, false); - fc->prepend_header(header.c_str(), header.size()); - *data = fc->httpbuf.base; - *len = fc->httpbuf.len; - state = SEND_DONE; - return *len; + if (fc->prepend_header(header.c_str(), header.size())) { + // header fit the reserved space: send header + file content + // as one buffer. + *data = fc->httpbuf.base; + *len = fc->httpbuf.len; + state = SEND_DONE; + return *len; + } + // header too large for the reserved space: send the header now, + // then the file content (pResp->content points at fc->filebuf). + state = SEND_BODY; + goto return_header; } // API service content_length = pResp->ContentLength();