Add two configuration options: the client_max_body_size and the client_max_websocket_message_size
This commit is contained in:
parent
0f6d2e31ac
commit
a85c64ac69
|
@ -21,7 +21,7 @@
|
|||
"port": 443,
|
||||
"https": true,
|
||||
//cert,key: Cert file path and key file path, empty by default,
|
||||
//if empty, use global setting
|
||||
//if empty, use the global setting
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
|
@ -151,7 +151,13 @@
|
|||
//gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
//file with the extension ".gz" in the same path and send the compressed file to the client.
|
||||
//The default value of gzip_static is true.
|
||||
"gzip_static": true
|
||||
"gzip_static": true,
|
||||
//client_max_body_size: Set the max body size of HTTP requests received by drogon. The default value is "1M".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_body_size": "1M",
|
||||
//client_max_websocket_message_size: Set the max size of messages sent by WebSocket client. The default value is "128K".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_websocket_message_size": "128K"
|
||||
},
|
||||
//plugins: Define all plugins running in the application
|
||||
"plugins": [{
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"port": 443,
|
||||
"https": true,
|
||||
//cert,key: Cert file path and key file path, empty by default,
|
||||
//if empty, use global setting
|
||||
//if empty, use the global setting
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
|
@ -151,7 +151,13 @@
|
|||
//gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
//file with the extension ".gz" in the same path and send the compressed file to the client.
|
||||
//The default value of gzip_static is true.
|
||||
"gzip_static": true
|
||||
"gzip_static": true,
|
||||
//client_max_body_size: Set the max body size of HTTP requests received by drogon. The default value is "1M".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_body_size": "1M",
|
||||
//client_max_websocket_message_size: Set the max size of messages sent by WebSocket client. The default value is "128K".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_websocket_message_size": "128K"
|
||||
},
|
||||
//plugins: Define all plugins running in the application
|
||||
"plugins": [{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
GIT_VER=$(git log|grep ^commit|wc -l|sed -e "s/^ *//")
|
||||
MD5=$(git log|head -1|awk '{printf $2}')
|
||||
TMP_FILE=/tmp/version
|
||||
echo "#define VERSION \"0.9.33.$GIT_VER\"" > ${TMP_FILE}
|
||||
echo "#define VERSION \"0.9.34.$GIT_VER\"" > ${TMP_FILE}
|
||||
echo "#define VERSION_MD5 \"$MD5\"" >> ${TMP_FILE}
|
||||
if [ ! -f $1 ];then
|
||||
mv -f ${TMP_FILE} $1
|
||||
|
|
|
@ -652,6 +652,20 @@ public:
|
|||
*/
|
||||
virtual void setGzipStatic(bool useGzipStatic) = 0;
|
||||
|
||||
///Set the max body size of the requests received by drogon. The default value is 1M.
|
||||
/**
|
||||
* NOTE:
|
||||
* This operation can be performed by an option in the configuration file.
|
||||
*/
|
||||
virtual void setClientMaxBodySize(size_t maxSize) = 0;
|
||||
|
||||
///Set the max size of messages sent by WebSocket client. The default value is 128K.
|
||||
/**
|
||||
* NOTE:
|
||||
* This operation can be performed by an option in the configuration file.
|
||||
*/
|
||||
virtual void setClientMaxWebSocketMessageSize(size_t maxSize) = 0;
|
||||
|
||||
#if USE_ORM
|
||||
///Get a database client by @param name
|
||||
/**
|
||||
|
|
|
@ -20,9 +20,76 @@
|
|||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
static bool bytesSize(std::string &sizeStr, size_t &size)
|
||||
{
|
||||
if (sizeStr.empty())
|
||||
{
|
||||
size = -1;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = 1;
|
||||
switch (sizeStr[sizeStr.length() - 1])
|
||||
{
|
||||
case 'k':
|
||||
case 'K':
|
||||
size = 1024;
|
||||
sizeStr.resize(sizeStr.length() - 1);
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
size = (1024 * 1024);
|
||||
sizeStr.resize(sizeStr.length() - 1);
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
size = (1024 * 1024 * 1024);
|
||||
sizeStr.resize(sizeStr.length() - 1);
|
||||
break;
|
||||
#if ((ULONG_MAX) != (UINT_MAX))
|
||||
//64bit system
|
||||
case 't':
|
||||
case 'T':
|
||||
size = (1024 * 1024 * 1024 * 1024);
|
||||
sizeStr.resize(sizeStr.length() - 1);
|
||||
break;
|
||||
#endif
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Invalid value of client_max_body_size: " << sizeStr << std::endl;
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
std::istringstream iss(sizeStr);
|
||||
size_t tmpSize;
|
||||
iss >> tmpSize;
|
||||
if (iss.fail())
|
||||
{
|
||||
std::cerr << "Invalid value of client_max_body_size: " << sizeStr << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
if ((size_t(-1) / tmpSize) >= size)
|
||||
size *= tmpSize;
|
||||
else
|
||||
{
|
||||
size = -1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ConfigLoader::ConfigLoader(const std::string &configFile)
|
||||
{
|
||||
if (access(configFile.c_str(), 0) != 0)
|
||||
|
@ -237,6 +304,25 @@ static void loadApp(const Json::Value &app)
|
|||
drogon::app().setPipeliningRequestsNumber(pipeliningReqs);
|
||||
auto useGzipStatic = app.get("gzip_static", true).asBool();
|
||||
drogon::app().setGzipStatic(useGzipStatic);
|
||||
auto maxBodySize = app.get("client_max_body_size", "1M").asString();
|
||||
size_t size;
|
||||
if (bytesSize(maxBodySize, size))
|
||||
{
|
||||
drogon::app().setClientMaxBodySize(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
exit(-1);
|
||||
}
|
||||
auto maxWsMsgSize = app.get("client_max_websocket_message_size", "128K").asString();
|
||||
if (bytesSize(maxWsMsgSize, size))
|
||||
{
|
||||
drogon::app().setClientMaxWebSocketMessageSize(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
static void loadDbClients(const Json::Value &dbClients)
|
||||
{
|
||||
|
|
|
@ -171,6 +171,10 @@ public:
|
|||
virtual void setKeepaliveRequestsNumber(const size_t number) override { _keepaliveRequestsNumber = number; }
|
||||
virtual void setPipeliningRequestsNumber(const size_t number) override { _pipeliningRequestsNumber = number; }
|
||||
virtual void setGzipStatic(bool useGzipStatic) override { _gzipStaticFlag = useGzipStatic; }
|
||||
virtual void setClientMaxBodySize(size_t maxSize) override { _clientMaxBodySize = maxSize; }
|
||||
virtual void setClientMaxWebSocketMessageSize(size_t maxSize) override { _clientMaxWebSocketMessageSize = maxSize; }
|
||||
size_t getClientMaxBodySize() { return _clientMaxBodySize; }
|
||||
size_t getClientMaxWebSocketMessageSize() { return _clientMaxWebSocketMessageSize; }
|
||||
virtual std::vector<std::tuple<std::string, HttpMethod, std::string>> getHandlersInfo() const override;
|
||||
|
||||
size_t keepaliveRequestsNumber() const { return _keepaliveRequestsNumber; }
|
||||
|
@ -295,6 +299,8 @@ private:
|
|||
bool _useSendfile = true;
|
||||
bool _useGzip = true;
|
||||
bool _gzipStaticFlag = true;
|
||||
size_t _clientMaxBodySize = 1024 * 1024;
|
||||
size_t _clientMaxWebSocketMessageSize = 128 * 1024;
|
||||
int _staticFilesCacheTime = 5;
|
||||
std::unordered_map<std::string, std::weak_ptr<HttpResponse>> _staticFilesCache;
|
||||
std::mutex _staticFilesCacheMutex;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <drogon/HttpTypes.h>
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include "HttpAppFrameworkImpl.h"
|
||||
#include "HttpRequestParser.h"
|
||||
#include "HttpResponseImpl.h"
|
||||
#include "HttpUtils.h"
|
||||
|
@ -177,14 +178,23 @@ bool HttpRequestParser::parseRequest(MsgBuffer *buf)
|
|||
return false;
|
||||
}
|
||||
//rfc2616-8.2.3
|
||||
//TODO: here we can add content-length limitation
|
||||
auto connPtr = _conn.lock();
|
||||
if (connPtr)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k100Continue);
|
||||
auto httpString = std::dynamic_pointer_cast<HttpResponseImpl>(resp)->renderToString();
|
||||
connPtr->send(httpString);
|
||||
if (_request->_contentLen > HttpAppFrameworkImpl::instance().getClientMaxBodySize())
|
||||
{
|
||||
resp->setStatusCode(k413RequestEntityTooLarge);
|
||||
auto httpString = std::dynamic_pointer_cast<HttpResponseImpl>(resp)->renderToString();
|
||||
reset();
|
||||
connPtr->send(httpString);
|
||||
}
|
||||
else
|
||||
{
|
||||
resp->setStatusCode(k100Continue);
|
||||
auto httpString = std::dynamic_pointer_cast<HttpResponseImpl>(resp)->renderToString();
|
||||
connPtr->send(httpString);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!expect.empty())
|
||||
|
@ -198,6 +208,12 @@ bool HttpRequestParser::parseRequest(MsgBuffer *buf)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if (_request->_contentLen > HttpAppFrameworkImpl::instance().getClientMaxBodySize())
|
||||
{
|
||||
buf->retrieveAll();
|
||||
shutdownConnection(k413RequestEntityTooLarge);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -314,7 +330,7 @@ void HttpRequestParser::popFirstRequest()
|
|||
}
|
||||
|
||||
void HttpRequestParser::pushResponseToPipelining(const HttpRequestPtr &req,
|
||||
const HttpResponsePtr &resp)
|
||||
const HttpResponsePtr &resp)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
auto conn = _conn.lock();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "HttpAppFrameworkImpl.h"
|
||||
#include "WebSocketConnectionImpl.h"
|
||||
#include <trantor/net/TcpConnection.h>
|
||||
#include <trantor/net/inner/TcpConnectionImpl.h>
|
||||
|
@ -175,7 +176,6 @@ void WebSocketConnectionImpl::setPingMessage(const std::string &message, const s
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
bool WebSocketMessageParser::parse(trantor::MsgBuffer *buffer)
|
||||
{
|
||||
//According to the rfc6455
|
||||
|
@ -271,6 +271,13 @@ bool WebSocketMessageParser::parse(trantor::MsgBuffer *buffer)
|
|||
}
|
||||
if (isMasked != 0)
|
||||
{
|
||||
//The message is sent by the client, check the length
|
||||
if (length > HttpAppFrameworkImpl::instance().getClientMaxWebSocketMessageSize())
|
||||
{
|
||||
LOG_ERROR << "The size of the WebSocket message is too large!";
|
||||
buffer->retrieveAll();
|
||||
return false;
|
||||
}
|
||||
if (buffer->readableBytes() >= (indexFirstMask + 4 + length))
|
||||
{
|
||||
auto masks = buffer->peek() + indexFirstMask;
|
||||
|
|
Loading…
Reference in New Issue