Implement size limits on HTTP header number, header size and body size

This commit is contained in:
dennis 2024-03-20 11:02:49 +08:00
parent 5a137f8b8e
commit 1e0bbe803a
7 changed files with 111 additions and 3 deletions

View File

@ -225,6 +225,12 @@ charSet=utf-8
keepAliveSecond=30 keepAliveSecond=30
#http请求体最大字节数如果post的body太大则不适合缓存body在内存 #http请求体最大字节数如果post的body太大则不适合缓存body在内存
maxReqSize=40960 maxReqSize=40960
#http header请求最大个数大于0才校验
maxReqHeaderNumber=0
#http header请求最大字节数大于0才校验
maxReqHeaderSize=0
#http body请求最大字节数大于0才校验
maxReqBodySize=0
#404网页内容用户可以自定义404网页 #404网页内容用户可以自定义404网页
#notFound=<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>您访问的资源不存在!</h1></center><hr><center>ZLMediaKit-4.0</center></body></html> #notFound=<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>您访问的资源不存在!</h1></center><hr><center>ZLMediaKit-4.0</center></body></html>
#http服务器监听端口 #http服务器监听端口

View File

@ -164,6 +164,9 @@ namespace Http {
#define HTTP_FIELD "http." #define HTTP_FIELD "http."
const string kSendBufSize = HTTP_FIELD "sendBufSize"; const string kSendBufSize = HTTP_FIELD "sendBufSize";
const string kMaxReqSize = HTTP_FIELD "maxReqSize"; const string kMaxReqSize = HTTP_FIELD "maxReqSize";
const string kMaxReqHeaderNumber = HTTP_FIELD "maxReqHeaderNumber";
const string kMaxReqHeaderSize = HTTP_FIELD "maxReqHeaderSize";
const string kMaxReqBodySize = HTTP_FIELD "maxReqBodySize";
const string kKeepAliveSecond = HTTP_FIELD "keepAliveSecond"; const string kKeepAliveSecond = HTTP_FIELD "keepAliveSecond";
const string kCharSet = HTTP_FIELD "charSet"; const string kCharSet = HTTP_FIELD "charSet";
const string kRootPath = HTTP_FIELD "rootPath"; const string kRootPath = HTTP_FIELD "rootPath";

View File

@ -254,6 +254,12 @@ namespace Http {
extern const std::string kSendBufSize; extern const std::string kSendBufSize;
// http 最大请求字节数 // http 最大请求字节数
extern const std::string kMaxReqSize; extern const std::string kMaxReqSize;
// header最大请求个数
extern const std::string kMaxReqHeaderNumber;
// header最大请求字节数
extern const std::string kMaxReqHeaderSize;
// body最大请求字节数
extern const std::string kMaxReqBodySize;
// http keep-alive秒数 // http keep-alive秒数
extern const std::string kKeepAliveSecond; extern const std::string kKeepAliveSecond;
// http 字符编码 // http 字符编码

View File

@ -65,6 +65,10 @@ void HttpRequestSplitter::input(const char *data,size_t len) {
_content_len = onRecvHeader(header_ptr, header_size); _content_len = onRecvHeader(header_ptr, header_size);
} }
if (_content_len == 0 && _remain_data_size > 0) {
onCheckHeader(ptr,_remain_data_size);
}
if(_remain_data_size <= 0){ if(_remain_data_size <= 0){
//没有剩余数据,清空缓存 //没有剩余数据,清空缓存
_remain_data.clear(); _remain_data.clear();

View File

@ -68,7 +68,7 @@ protected:
* @param data content分片或全部数据 * @param data content分片或全部数据
* @param len * @param len
*/ */
virtual void onRecvContent(const char *data,size_t len) {}; virtual void onRecvContent(const char *data, size_t len) {};
/** /**
* *
@ -78,6 +78,13 @@ protected:
*/ */
virtual const char *onSearchPacketTail(const char *data, size_t len); virtual const char *onSearchPacketTail(const char *data, size_t len);
/**
*
* @param data
* @param len
*/
virtual void onCheckHeader(const char *data, size_t len) {};
/** /**
* content len * content len
*/ */

View File

@ -26,6 +26,9 @@ namespace mediakit {
HttpSession::HttpSession(const Socket::Ptr &pSock) : Session(pSock) { HttpSession::HttpSession(const Socket::Ptr &pSock) : Session(pSock) {
//设置默认参数 //设置默认参数
setMaxReqSize(0); setMaxReqSize(0);
setMaxReqHeaderNumber(0);
setMaxReqHeaderSize(0);
setMaxReqBodySize(0);
setTimeoutSec(0); setTimeoutSec(0);
} }
@ -67,6 +70,8 @@ ssize_t HttpSession::onRecvHeader(const char *header, size_t len) {
CHECK(_parser.url()[0] == '/'); CHECK(_parser.url()[0] == '/');
_origin = _parser["Origin"]; _origin = _parser["Origin"];
onCheckHeader(len, _parser.getHeader().size());
urlDecode(_parser); urlDecode(_parser);
auto &cmd = _parser.method(); auto &cmd = _parser.method();
auto it = s_func_map.find(cmd); auto it = s_func_map.find(cmd);
@ -140,11 +145,26 @@ ssize_t HttpSession::onRecvHeader(const char *header, size_t len) {
} }
void HttpSession::onRecvContent(const char *data, size_t len) { void HttpSession::onRecvContent(const char *data, size_t len) {
if (_max_req_body_size > 0 && len > _max_req_body_size) {
WarnL << "Http body size is too huge: " << len << " > " << _max_req_body_size
<< ", please set " << Http::kMaxReqBodySize << " in config.ini file.";
reset();
throw std::out_of_range("Http body size is too huge: " + to_string(len));
}
if (_on_recv_body && !_on_recv_body(data, len)) { if (_on_recv_body && !_on_recv_body(data, len)) {
_on_recv_body = nullptr; _on_recv_body = nullptr;
} }
} }
void HttpSession::onCheckHeader(const char *header, size_t len) {
size_t number = 0;
if (_max_req_header_number > 0) {
number = onSearchHeaderNumber(header, len);
}
onCheckHeader(len, number);
}
void HttpSession::onRecv(const Buffer::Ptr &pBuf) { void HttpSession::onRecv(const Buffer::Ptr &pBuf) {
_ticker.resetTime(); _ticker.resetTime();
input(pBuf->data(), pBuf->size()); input(pBuf->data(), pBuf->size());
@ -182,6 +202,30 @@ void HttpSession::setMaxReqSize(size_t max_req_size) {
setMaxCacheSize(max_req_size); setMaxCacheSize(max_req_size);
} }
void HttpSession::setMaxReqHeaderNumber(size_t max_req_header_number) {
if (!max_req_header_number) {
GET_CONFIG(size_t, s_max_req_header_number, Http::kMaxReqHeaderNumber);
max_req_header_number = s_max_req_header_number;
}
_max_req_header_number = max_req_header_number;
}
void HttpSession::setMaxReqHeaderSize(size_t max_req_header_size) {
if (!max_req_header_size) {
GET_CONFIG(size_t, s_max_req_header_size, Http::kMaxReqHeaderSize);
max_req_header_size = s_max_req_header_size;
}
_max_req_header_size = max_req_header_size;
}
void HttpSession::setMaxReqBodySize(size_t max_req_body_size) {
if (!max_req_body_size) {
GET_CONFIG(size_t, s_max_req_body_size, Http::kMaxReqBodySize);
max_req_body_size = s_max_req_body_size;
}
_max_req_body_size = max_req_body_size;
}
void HttpSession::onManager() { void HttpSession::onManager() {
if (_ticker.elapsedTime() > _keep_alive_sec * 1000) { if (_ticker.elapsedTime() > _keep_alive_sec * 1000) {
//http超时 //http超时
@ -834,4 +878,32 @@ std::shared_ptr<FlvMuxer> HttpSession::getSharedPtr() {
return dynamic_pointer_cast<FlvMuxer>(shared_from_this()); return dynamic_pointer_cast<FlvMuxer>(shared_from_this());
} }
ssize_t HttpSession::onSearchHeaderNumber(const char *data, size_t len) {
ssize_t number = 0;
const char *ptr = data;
const char *pos = nullptr;
while (pos = strstr(ptr, "\r\n")) {
number++;
ptr = pos + 2;
}
return number;
}
void HttpSession::onCheckHeader(size_t len, size_t number)
{
if (_max_req_header_size > 0 && len > _max_req_header_size) {
WarnL << "Http header size is too huge: " << len << " > " << _max_req_header_size
<< ", please set " << Http::kMaxReqHeaderSize << " in config.ini file.";
reset();
throw std::out_of_range("http header size is invalid: " + to_string(len));
}
if (_max_req_header_number > 0 && number > _max_req_header_number) {
WarnL << "Http header number is too huge: " << len << " > " << _max_req_header_number
<< ", please set " << Http::kMaxReqHeaderNumber << " in config.ini file.";
reset();
throw std::out_of_range("http header size is invalid: " + to_string(len));
}
}
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -49,6 +49,9 @@ public:
static std::string urlDecodeComponent(const std::string &str); static std::string urlDecodeComponent(const std::string &str);
void setTimeoutSec(size_t second); void setTimeoutSec(size_t second);
void setMaxReqSize(size_t max_req_size); void setMaxReqSize(size_t max_req_size);
void setMaxReqHeaderNumber(size_t max_req_header_number);
void setMaxReqHeaderSize(size_t max_req_header_size);
void setMaxReqBodySize(size_t max_req_body_size);
protected: protected:
//FlvMuxer override //FlvMuxer override
@ -57,8 +60,9 @@ protected:
std::shared_ptr<FlvMuxer> getSharedPtr() override; std::shared_ptr<FlvMuxer> getSharedPtr() override;
//HttpRequestSplitter override //HttpRequestSplitter override
ssize_t onRecvHeader(const char *data,size_t len) override; ssize_t onRecvHeader(const char *data, size_t len) override;
void onRecvContent(const char *data,size_t len) override; void onRecvContent(const char *data, size_t len) override;
void onCheckHeader(const char *data, size_t len) override;
/** /**
* content * content
@ -126,6 +130,9 @@ private:
//设置socket标志 //设置socket标志
void setSocketFlags(); void setSocketFlags();
ssize_t onSearchHeaderNumber(const char *data, size_t len);
void onCheckHeader(size_t len, size_t number);
protected: protected:
MediaInfo _media_info; MediaInfo _media_info;
@ -136,6 +143,9 @@ private:
size_t _keep_alive_sec = 0; size_t _keep_alive_sec = 0;
//最大http请求字节大小 //最大http请求字节大小
size_t _max_req_size = 0; size_t _max_req_size = 0;
size_t _max_req_header_number = 0;
size_t _max_req_header_size = 0;
size_t _max_req_body_size = 0;
//消耗的总流量 //消耗的总流量
uint64_t _total_bytes_usage = 0; uint64_t _total_bytes_usage = 0;
// http请求中的 Origin字段 // http请求中的 Origin字段