1.Add gzip option in config file;

2.rename config example file's name
This commit is contained in:
antao 2018-10-14 11:53:05 +08:00
parent f6c50f2370
commit 93a07ed17a
7 changed files with 357 additions and 326 deletions

View File

@ -2,6 +2,7 @@
*/ */
{ {
//ssl:the global ssl files setting //ssl:the global ssl files setting
/*
"ssl": { "ssl": {
"cert": "../../trantor/trantor/tests/server.pem", "cert": "../../trantor/trantor/tests/server.pem",
"key": "../../trantor/trantor/tests/server.pem" "key": "../../trantor/trantor/tests/server.pem"
@ -24,7 +25,7 @@
"cert": "", "cert": "",
"key": "" "key": ""
} }
], ],*/
"app": { "app": {
//threads_num:num of threads,1 by default //threads_num:num of threads,1 by default
"threads_num": 16, "threads_num": 16,
@ -32,17 +33,30 @@
"enable_session": false, "enable_session": false,
"session_timeout": 0, "session_timeout": 0,
//document_root:Root path of HTTP document,defaut path is ./ //document_root:Root path of HTTP document,defaut path is ./
"document_root":"./", "document_root": "./",
/* file_types: /* file_types:
* HTTP download file types,The file types supported by drogon * HTTP download file types,The file types supported by drogon
* by default are "html", "js", "css", "xml", "xsl", "txt", "svg", * by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
* "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg", * "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
* "gif", "bmp", "ico", "icns", etc. */ * "gif", "bmp", "ico", "icns", etc. */
"file_types":["gif","png","jpg","js","css","html","ico","swf","xap","apk","cur","xml"], "file_types": [
"gif",
"png",
"jpg",
"js",
"css",
"html",
"ico",
"swf",
"xap",
"apk",
"cur",
"xml"
],
//max_connections:max connections number,100000 by default //max_connections:max connections number,100000 by default
"max_connections":100000, "max_connections": 100000,
//max_connections_per_ip:max connections number per clinet,0 by default which means no limit //max_connections_per_ip:max connections number per clinet,0 by default which means no limit
"max_connections_per_ip":0, "max_connections_per_ip": 0,
//Load_dynamic_views: false by default, when set to true, drogon will //Load_dynamic_views: false by default, when set to true, drogon will
//compile and load dynamically "CSP View Files" in directories defined //compile and load dynamically "CSP View Files" in directories defined
//by "dynamic_views_path" //by "dynamic_views_path"
@ -51,25 +65,27 @@
//it will be relative path of document_root path //it will be relative path of document_root path
//"dynamic_views_path":["./views"], //"dynamic_views_path":["./views"],
//log:set log output,drogon output logs to stdout by default //log:set log output,drogon output logs to stdout by default
"log":{ "log": {
//log_path:log file path,empty by default,in which case,log will output to the stdout //log_path:log file path,empty by default,in which case,log will output to the stdout
"log_path":"./", "log_path": "./",
//logfile_base_name:log file base name,empty by default which means drogon will name logfile as //logfile_base_name:log file base name,empty by default which means drogon will name logfile as
//drogon.log ... //drogon.log ...
"logfile_base_name":"", "logfile_base_name": "",
//log_size_limit:100000000 bytes by default, //log_size_limit:100000000 bytes by default,
//When the log file size reaches "log_size_limit", the log file will be switched. //When the log file size reaches "log_size_limit", the log file will be switched.
"log_size_limit":100000000, "log_size_limit": 100000000,
//log_level:"DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN" //log_level:"DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
//The TRACE level is only valid when built in DEBUG mode. //The TRACE level is only valid when built in DEBUG mode.
"log_level":"DEBUG" "log_level": "DEBUG"
}, },
//run_as_daemon:false by default //run_as_daemon:false by default
"run_as_daemon":false, "run_as_daemon": false,
//relaunch_on_error:false by default,if true,the program will be restart by parent after exit; //relaunch_on_error:false by default,if true,the program will be restart by parent after exit;
"relaunch_on_error":false, "relaunch_on_error": false,
//use_sendfile:true by default,if ture,the program will //use_sendfile:true by default,if ture,the program will
//use sendfile() system-call to send static file to client; //use sendfile() system-call to send static file to client;
"use_sendfile":true "use_sendfile": true,
//use_gzip:true by default,use gzip to compress the response body's content;
"use_gzip": true
} }
} }

View File

@ -204,7 +204,7 @@ static void newConfigFile(std::ofstream &configFile)
"*/\n" "*/\n"
"{\n" "{\n"
" //ssl:the global ssl files setting\n" " //ssl:the global ssl files setting\n"
" \"ssl\": {\n" " /*\"ssl\": {\n"
" \"cert\": \"../../trantor/trantor/tests/server.pem\",\n" " \"cert\": \"../../trantor/trantor/tests/server.pem\",\n"
" \"key\": \"../../trantor/trantor/tests/server.pem\"\n" " \"key\": \"../../trantor/trantor/tests/server.pem\"\n"
" },\n" " },\n"
@ -226,7 +226,7 @@ static void newConfigFile(std::ofstream &configFile)
" \"cert\": \"\",\n" " \"cert\": \"\",\n"
" \"key\": \"\"\n" " \"key\": \"\"\n"
" }\n" " }\n"
" ],\n" " ],*/\n"
" \"app\": {\n" " \"app\": {\n"
" //threads_num:num of threads,1 by default\n" " //threads_num:num of threads,1 by default\n"
" \"threads_num\": 16,\n" " \"threads_num\": 16,\n"
@ -234,40 +234,45 @@ static void newConfigFile(std::ofstream &configFile)
" \"enable_session\": false,\n" " \"enable_session\": false,\n"
" \"session_timeout\": 0,\n" " \"session_timeout\": 0,\n"
" //document_root:Root path of HTTP document,defaut path is ./\n" " //document_root:Root path of HTTP document,defaut path is ./\n"
" \"document_root\":\"./\",\n" " \"document_root\": \"./\",\n"
" /* file_types:\n" " /* file_types:\n"
" * HTTP download file types,The file types supported by drogon\n" " * HTTP download file types,The file types supported by drogon\n"
" * by default are \"html\", \"js\", \"css\", \"xml\", \"xsl\", \"txt\", \"svg\",\n" " * by default are \"html\", \"js\", \"css\", \"xml\", \"xsl\", \"txt\", \"svg\",\n"
" * \"ttf\", \"otf\", \"woff2\", \"woff\" , \"eot\", \"png\", \"jpg\", \"jpeg\",\n" " * \"ttf\", \"otf\", \"woff2\", \"woff\" , \"eot\", \"png\", \"jpg\", \"jpeg\",\n"
" * \"gif\", \"bmp\", \"ico\", \"icns\", etc. */\n" " * \"gif\", \"bmp\", \"ico\", \"icns\", etc. */\n"
" \"file_types\":[\"gif\",\"png\",\"jpg\",\"js\",\"css\",\"html\",\"ico\",\"swf\",\"xap\",\"apk\",\"cur\",\"xml\"],\n" " \"file_types\": [\"gif\",\"png\",\"jpg\",\"js\",\"css\",\"html\",\"ico\",\"swf\",\"xap\",\"apk\",\"cur\",\"xml\"],\n"
" //max_connections:max connections number,100000 by default\n" " //max_connections:max connections number,100000 by default\n"
" \"max_connections\":100000,\n" " \"max_connections\": 100000,\n"
" //Load_dynamic_views: false by default, when set to true, drogon will\n" " //Load_dynamic_views: false by default, when set to true, drogon will\n"
" //compile and load dynamically \"CSP View Files\" in directories defined\n" " //compile and load dynamically \"CSP View Files\" in directories defined\n"
" //by \"dynamic_views_path\"\n" " //by \"dynamic_views_path\"\n"
" \"load_dynamic_views\":true,\n" " \"load_dynamic_views\": true,\n"
" //dynamic_views_path: if the path isn't prefixed with / or ./,\n" " //dynamic_views_path: if the path isn't prefixed with / or ./,\n"
" //it will be relative path of document_root path\n" " //it will be relative path of document_root path\n"
" \"dynamic_views_path\":[\"./views\"],\n" " \"dynamic_views_path\": [\"./views\"],\n"
" //log:set log output,drogon output logs to stdout by default\n" " //log:set log output,drogon output logs to stdout by default\n"
" \"log\":{\n" " \"log\": {\n"
" //log_path:log file path,empty by default,in which case,log will output to the stdout\n" " //log_path:log file path,empty by default,in which case,log will output to the stdout\n"
" \"log_path\":\"./\",\n" " \"log_path\": \"./\",\n"
" //logfile_base_name:log file base name,empty by default which means drogon will name logfile as\n" " //logfile_base_name:log file base name,empty by default which means 'drogon' will name logfile as\n"
" //drogon.log ...\n" " //drogon.log ...\n"
" \"logfile_base_name\":\"\",\n" " \"logfile_base_name\": \"\",\n"
" //log_size_limit:100000000 bytes by default,\n" " //log_size_limit:100000000 bytes by default,\n"
" //When the log file size reaches \"log_size_limit\", the log file is switched.\n" " //When the log file size reaches \"log_size_limit\", the log file is switched.\n"
" \"log_size_limit\":100000000\n" " \"log_size_limit\": 100000000,\n"
" //log_level:\"DEBUG\" by default,options:\"TRACE\",\"DEBUG\",\"INFO\",\"WARN\"\n"
" //The TRACE level is only valid when built in DEBUG mode.\n"
" \"log_level\": \"DEBUG\"\n"
" },\n" " },\n"
" //run_as_daemon:false by default\n" " //run_as_daemon:false by default\n"
" \"run_as_daemon\":false,\n" " \"run_as_daemon\": false,\n"
" //relaunch_on_error:false by default,if true,the program will be restart by parent after exit;\n" " //relaunch_on_error:false by default,if true,the program will be restart by parent after exit;\n"
" \"relaunch_on_error\":false,\n" " \"relaunch_on_error\": false,\n"
" //use_sendfile:true by default,if ture,the program will\n" " //use_sendfile:true by default,if ture,the program will\n"
" //use sendfile() system-call to send static file to client;\n" " //use sendfile() system-call to send static file to client;\n"
" \"use_sendfile\":true\n" " \"use_sendfile\": true,\n"
" //use_gzip:true by default,use gzip to compress the response body's content;\n"
" \"use_gzip\": true\n"
" }\n" " }\n"
"}\n"; "}\n";
} }

View File

@ -140,6 +140,6 @@ int main()
drogon::HttpAppFramework::instance().enableSession(60); drogon::HttpAppFramework::instance().enableSession(60);
//start app framework //start app framework
//drogon::HttpAppFramework::instance().enableDynamicViewsLoading({"/tmp/views"}); //drogon::HttpAppFramework::instance().enableDynamicViewsLoading({"/tmp/views"});
// drogon::HttpAppFramework::instance().loadConfigFile("../../config.json.example"); drogon::HttpAppFramework::instance().loadConfigFile("../../config.json.example");
drogon::HttpAppFramework::instance().run(); drogon::HttpAppFramework::instance().run();
} }

View File

@ -39,80 +39,80 @@
#include <vector> #include <vector>
namespace drogon namespace drogon
{ {
//the drogon banner //the drogon banner
const char banner[]= " _ \n" const char banner[] = " _ \n"
" __| |_ __ ___ __ _ ___ _ __ \n" " __| |_ __ ___ __ _ ___ _ __ \n"
" / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n" " / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n"
"| (_| | | | (_) | (_| | (_) | | | |\n" "| (_| | | | (_) | (_| | (_) | | | |\n"
" \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n" " \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n"
" |___/ \n"; " |___/ \n";
inline std::string getVersion() inline std::string getVersion()
{ {
return VERSION; return VERSION;
}
inline std::string getGitCommit()
{
return VERSION_MD5;
}
class HttpAppFramework:public trantor::NonCopyable
{
public:
static HttpAppFramework &instance();
virtual void setThreadNum(size_t threadNum)=0;
virtual void setSSLFiles(const std::string &certPath,
const std::string &keyPath)=0;
virtual void addListener(const std::string &ip,
uint16_t port,
bool useSSL=false,
const std::string & certFile="",
const std::string & keyFile="")=0;
virtual void run()=0;
virtual ~HttpAppFramework();
virtual void registerWebSocketController(const std::string &pathName,
const std::string &crtlName,
const std::vector<std::string> &filters=
std::vector<std::string>())=0;
virtual void registerHttpSimpleController(const std::string &pathName,
const std::string &crtlName,
const std::vector<std::string> &filters=std::vector<std::string>())=0;
template <typename FUNCTION>
static void registerHttpApiMethod(const std::string &pathPattern,
FUNCTION && function,
const std::vector<std::string> &filters=std::vector<std::string>())
{
LOG_TRACE<<"pathPattern:"<<pathPattern;
HttpApiBinderBasePtr binder;
binder=std::make_shared<
HttpApiBinder<FUNCTION>
>(std::forward<FUNCTION>(function));
instance().registerHttpApiController(pathPattern,binder,filters);
}
virtual void enableSession(const size_t timeout=0)=0;
virtual void disableSession()=0;
virtual const std::string & getDocumentRoot() const =0;
virtual void setDocumentRoot(const std::string &rootPath)=0;
virtual void setFileTypes(const std::vector<std::string> &types)=0;
virtual void enableDynamicViewsLoading(const std::vector<std::string> &libPaths)=0;
virtual void setMaxConnectionNum(size_t maxConnections)=0;
virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP)=0;
virtual void loadConfigFile(const std::string &fileName)=0;
virtual void enableRunAsDaemon()=0;
virtual void enableRelaunchOnError()=0;
virtual void setLogPath(const std::string &logPath,
const std::string &logfileBaseName="",
size_t logSize=100000000)=0;
virtual void enableSendfile(bool sendFile)=0;
private:
virtual void registerHttpApiController(const std::string &pathPattern,
const HttpApiBinderBasePtr &binder,
const std::vector<std::string> &filters=std::vector<std::string>())=0;
};
} }
inline std::string getGitCommit()
{
return VERSION_MD5;
}
class HttpAppFramework : public trantor::NonCopyable
{
public:
static HttpAppFramework &instance();
virtual void setThreadNum(size_t threadNum) = 0;
virtual void setSSLFiles(const std::string &certPath,
const std::string &keyPath) = 0;
virtual void addListener(const std::string &ip,
uint16_t port,
bool useSSL = false,
const std::string &certFile = "",
const std::string &keyFile = "") = 0;
virtual void run() = 0;
virtual ~HttpAppFramework();
virtual void registerWebSocketController(const std::string &pathName,
const std::string &crtlName,
const std::vector<std::string> &filters =
std::vector<std::string>()) = 0;
virtual void registerHttpSimpleController(const std::string &pathName,
const std::string &crtlName,
const std::vector<std::string> &filters = std::vector<std::string>()) = 0;
template <typename FUNCTION>
static void registerHttpApiMethod(const std::string &pathPattern,
FUNCTION &&function,
const std::vector<std::string> &filters = std::vector<std::string>())
{
LOG_TRACE << "pathPattern:" << pathPattern;
HttpApiBinderBasePtr binder;
binder = std::make_shared<
HttpApiBinder<FUNCTION>>(std::forward<FUNCTION>(function));
instance().registerHttpApiController(pathPattern, binder, filters);
}
virtual void enableSession(const size_t timeout = 0) = 0;
virtual void disableSession() = 0;
virtual const std::string &getDocumentRoot() const = 0;
virtual void setDocumentRoot(const std::string &rootPath) = 0;
virtual void setFileTypes(const std::vector<std::string> &types) = 0;
virtual void enableDynamicViewsLoading(const std::vector<std::string> &libPaths) = 0;
virtual void setMaxConnectionNum(size_t maxConnections) = 0;
virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP) = 0;
virtual void loadConfigFile(const std::string &fileName) = 0;
virtual void enableRunAsDaemon() = 0;
virtual void enableRelaunchOnError() = 0;
virtual void setLogPath(const std::string &logPath,
const std::string &logfileBaseName = "",
size_t logSize = 100000000) = 0;
virtual void enableSendfile(bool sendFile) = 0;
virtual void enableGzip(bool useGzip) = 0;
virtual bool useGzip() const = 0;
private:
virtual void registerHttpApiController(const std::string &pathPattern,
const HttpApiBinderBasePtr &binder,
const std::vector<std::string> &filters = std::vector<std::string>()) = 0;
};
} // namespace drogon

View File

@ -21,123 +21,123 @@
#include <unistd.h> #include <unistd.h>
using namespace drogon; using namespace drogon;
ConfigLoader::ConfigLoader(const std::string &configFile) { ConfigLoader::ConfigLoader(const std::string &configFile)
if(access(configFile.c_str(),0)!=0) {
if (access(configFile.c_str(), 0) != 0)
{ {
std::cerr<<"Config file "<<configFile<<" not found!"<<std::endl; std::cerr << "Config file " << configFile << " not found!" << std::endl;
exit(1); exit(1);
} }
if(access(configFile.c_str(),R_OK)!=0) if (access(configFile.c_str(), R_OK) != 0)
{ {
std::cerr<<"No permission to read config file "<<configFile<<std::endl; std::cerr << "No permission to read config file " << configFile << std::endl;
exit(1); exit(1);
} }
_configFile=configFile; _configFile = configFile;
std::ifstream infile(configFile.c_str(),std::ifstream::in); std::ifstream infile(configFile.c_str(), std::ifstream::in);
if(infile) if (infile)
{ {
try { try
infile>>_configJsonRoot; {
infile >> _configJsonRoot;
} }
catch (const std::exception &exception) catch (const std::exception &exception)
{ {
std::cerr<<"Configuration file format error! in "<<configFile<<":"<<std::endl; std::cerr << "Configuration file format error! in " << configFile << ":" << std::endl;
std::cerr<<exception.what()<<std::endl; std::cerr << exception.what() << std::endl;
exit(1); exit(1);
} }
} }
} }
ConfigLoader::~ConfigLoader() { ConfigLoader::~ConfigLoader()
{
} }
static void loadLogSetting(const Json::Value &log) static void loadLogSetting(const Json::Value &log)
{ {
if(!log) if (!log)
return; return;
auto logPath=log.get("log_path","").asString(); auto logPath = log.get("log_path", "").asString();
if(logPath!="") if (logPath != "")
{ {
auto baseName=log.get("logfile_base_name","").asString(); auto baseName = log.get("logfile_base_name", "").asString();
auto logSize=log.get("log_size_limit",100000000).asUInt64(); auto logSize = log.get("log_size_limit", 100000000).asUInt64();
HttpAppFramework::instance().setLogPath(logPath,baseName,logSize); HttpAppFramework::instance().setLogPath(logPath, baseName, logSize);
} }
auto logLevel=log.get("log_level","DEBUG").asString(); auto logLevel = log.get("log_level", "DEBUG").asString();
if(logLevel=="TRACE") if (logLevel == "TRACE")
{ {
trantor::Logger::setLogLevel(trantor::Logger::TRACE); trantor::Logger::setLogLevel(trantor::Logger::TRACE);
} }
else if(logLevel=="DEBUG") else if (logLevel == "DEBUG")
{ {
trantor::Logger::setLogLevel(trantor::Logger::DEBUG); trantor::Logger::setLogLevel(trantor::Logger::DEBUG);
} }
else if(logLevel=="INFO") else if (logLevel == "INFO")
{ {
trantor::Logger::setLogLevel(trantor::Logger::INFO); trantor::Logger::setLogLevel(trantor::Logger::INFO);
} }
else if(logLevel=="WARN") else if (logLevel == "WARN")
{ {
trantor::Logger::setLogLevel(trantor::Logger::WARN); trantor::Logger::setLogLevel(trantor::Logger::WARN);
} }
} }
static void loadApp(const Json::Value &app) static void loadApp(const Json::Value &app)
{ {
if(!app) if (!app)
return; return;
//threads number //threads number
auto threadsNum=app.get("threads_num",1).asUInt64(); auto threadsNum = app.get("threads_num", 1).asUInt64();
HttpAppFramework::instance().setThreadNum(threadsNum); HttpAppFramework::instance().setThreadNum(threadsNum);
//session //session
auto enableSession=app.get("enable_session",false).asBool(); auto enableSession = app.get("enable_session", false).asBool();
auto timeout=app.get("session_timeout",0).asUInt64(); auto timeout = app.get("session_timeout", 0).asUInt64();
if(enableSession) if (enableSession)
HttpAppFramework::instance().enableSession(timeout); HttpAppFramework::instance().enableSession(timeout);
else else
HttpAppFramework::instance().disableSession(); HttpAppFramework::instance().disableSession();
//document root //document root
auto documentRoot=app.get("document_root","").asString(); auto documentRoot = app.get("document_root", "").asString();
if(documentRoot!="") if (documentRoot != "")
{ {
HttpAppFramework::instance().setDocumentRoot(documentRoot); HttpAppFramework::instance().setDocumentRoot(documentRoot);
} }
//file types //file types
auto fileTypes=app["file_types"]; auto fileTypes = app["file_types"];
if(fileTypes.isArray()&&!fileTypes.empty()) if (fileTypes.isArray() && !fileTypes.empty())
{ {
std::vector<std::string> types; std::vector<std::string> types;
for(auto fileType:fileTypes) for (auto fileType : fileTypes)
{ {
types.push_back(fileType.asString()); types.push_back(fileType.asString());
LOG_TRACE<<"file type:"<<types.back(); LOG_TRACE << "file type:" << types.back();
} }
HttpAppFramework::instance().setFileTypes(types); HttpAppFramework::instance().setFileTypes(types);
} }
//max connections //max connections
auto maxConns=app.get("max_connections",0).asUInt64(); auto maxConns = app.get("max_connections", 0).asUInt64();
if(maxConns>0) if (maxConns > 0)
{ {
HttpAppFramework::instance().setMaxConnectionNum(maxConns); HttpAppFramework::instance().setMaxConnectionNum(maxConns);
} }
//max connections per IP //max connections per IP
auto maxConnsPerIP=app.get("max_connections_per_ip",0).asUInt64(); auto maxConnsPerIP = app.get("max_connections_per_ip", 0).asUInt64();
if(maxConnsPerIP>0) if (maxConnsPerIP > 0)
{ {
HttpAppFramework::instance().setMaxConnectionNumPerIP(maxConnsPerIP); HttpAppFramework::instance().setMaxConnectionNumPerIP(maxConnsPerIP);
} }
//dynamic views //dynamic views
auto enableDynamicViews=app.get("load_dynamic_views",false).asBool(); auto enableDynamicViews = app.get("load_dynamic_views", false).asBool();
if(enableDynamicViews) if (enableDynamicViews)
{ {
auto viewsPaths=app["dynamic_views_path"]; auto viewsPaths = app["dynamic_views_path"];
if(viewsPaths.isArray()&&viewsPaths.size()>0) if (viewsPaths.isArray() && viewsPaths.size() > 0)
{ {
std::vector<std::string> paths; std::vector<std::string> paths;
for(auto viewsPath:viewsPaths) for (auto viewsPath : viewsPaths)
{ {
paths.push_back(viewsPath.asString()); paths.push_back(viewsPath.asString());
LOG_TRACE<<"views path:"<<paths.back(); LOG_TRACE << "views path:" << paths.back();
} }
HttpAppFramework::instance().enableDynamicViewsLoading(paths); HttpAppFramework::instance().enableDynamicViewsLoading(paths);
} }
@ -145,45 +145,48 @@ static void loadApp(const Json::Value &app)
//log //log
loadLogSetting(app["log"]); loadLogSetting(app["log"]);
//run as daemon //run as daemon
auto runAsDaemon=app.get("run_as_daemon",false).asBool(); auto runAsDaemon = app.get("run_as_daemon", false).asBool();
if(runAsDaemon) if (runAsDaemon)
{ {
HttpAppFramework::instance().enableRunAsDaemon(); HttpAppFramework::instance().enableRunAsDaemon();
} }
//relaunch //relaunch
auto relaunch=app.get("relaunch_on_error",false).asBool(); auto relaunch = app.get("relaunch_on_error", false).asBool();
if(relaunch) if (relaunch)
{ {
HttpAppFramework::instance().enableRelaunchOnError(); HttpAppFramework::instance().enableRelaunchOnError();
} }
auto useSendfile=app.get("use_sendfile",true).asBool(); auto useSendfile = app.get("use_sendfile", true).asBool();
HttpAppFramework::instance().enableSendfile(useSendfile); HttpAppFramework::instance().enableSendfile(useSendfile);
auto useGzip = app.get("use_gzip", true).asBool();
HttpAppFramework::instance().enableGzip(useGzip);
} }
static void loadListeners(const Json::Value &listeners) static void loadListeners(const Json::Value &listeners)
{ {
if(!listeners) if (!listeners)
return; return;
LOG_TRACE<<"Has "<<listeners.size()<<" listeners"; LOG_TRACE << "Has " << listeners.size() << " listeners";
for(auto listener:listeners) for (auto listener : listeners)
{ {
auto addr=listener.get("address","0.0.0.0").asString(); auto addr = listener.get("address", "0.0.0.0").asString();
auto port=(uint16_t)listener.get("port",0).asUInt(); auto port = (uint16_t)listener.get("port", 0).asUInt();
auto useSSL=listener.get("https",false).asBool(); auto useSSL = listener.get("https", false).asBool();
auto cert=listener.get("cert","").asString(); auto cert = listener.get("cert", "").asString();
auto key=listener.get("key","").asString(); auto key = listener.get("key", "").asString();
LOG_TRACE<<"Add listener:"<<addr<<":"<<port; LOG_TRACE << "Add listener:" << addr << ":" << port;
HttpAppFramework::instance().addListener(addr,port,useSSL,cert,key); HttpAppFramework::instance().addListener(addr, port, useSSL, cert, key);
} }
} }
static void loadSSL(const Json::Value &sslFiles) static void loadSSL(const Json::Value &sslFiles)
{ {
if(!sslFiles) if (!sslFiles)
return; return;
auto key=sslFiles.get("key","").asString(); auto key = sslFiles.get("key", "").asString();
auto cert=sslFiles.get("cert","").asString(); auto cert = sslFiles.get("cert", "").asString();
HttpAppFramework::instance().setSSLFiles(cert,key); HttpAppFramework::instance().setSSLFiles(cert, key);
} }
void ConfigLoader::load() { void ConfigLoader::load()
{
//std::cout<<_configJsonRoot<<std::endl; //std::cout<<_configJsonRoot<<std::endl;
loadApp(_configJsonRoot["app"]); loadApp(_configJsonRoot["app"]);
loadSSL(_configJsonRoot["ssl"]); loadSSL(_configJsonRoot["ssl"]);

View File

@ -29,160 +29,166 @@
namespace drogon namespace drogon
{ {
class HttpAppFrameworkImpl:public HttpAppFramework class HttpAppFrameworkImpl : public HttpAppFramework
{
public:
HttpAppFrameworkImpl() : _connectionNum(0)
{ {
public: }
HttpAppFrameworkImpl(): virtual void addListener(const std::string &ip,
_connectionNum(0) uint16_t port,
{ bool useSSL = false,
} const std::string &certFile = "",
virtual void addListener(const std::string &ip, const std::string &keyFile = "") override;
uint16_t port, virtual void setThreadNum(size_t threadNum) override;
bool useSSL=false, virtual void setSSLFiles(const std::string &certPath,
const std::string & certFile="", const std::string &keyPath) override;
const std::string & keyFile="") override; virtual void run() override;
virtual void setThreadNum(size_t threadNum) override; virtual void registerWebSocketController(const std::string &pathName,
virtual void setSSLFiles(const std::string &certPath, const std::string &crtlName,
const std::string &keyPath) override; const std::vector<std::string> &filters =
virtual void run() override ; std::vector<std::string>()) override;
virtual void registerWebSocketController(const std::string &pathName, virtual void registerHttpSimpleController(const std::string &pathName,
const std::string &crtlName, const std::string &crtlName,
const std::vector<std::string> &filters= const std::vector<std::string> &filters =
std::vector<std::string>())override ; std::vector<std::string>()) override;
virtual void registerHttpSimpleController(const std::string &pathName, virtual void enableSession(const size_t timeout = 0) override
const std::string &crtlName, {
const std::vector<std::string> &filters= _useSession = true;
std::vector<std::string>())override ; _sessionTimeout = timeout;
virtual void enableSession(const size_t timeout=0) override { _useSession=true;_sessionTimeout=timeout;} }
virtual void disableSession() override { _useSession=false;} virtual void disableSession() override { _useSession = false; }
virtual const std::string & getDocumentRoot() const override {return _rootPath;} virtual const std::string &getDocumentRoot() const override { return _rootPath; }
virtual void setDocumentRoot(const std::string &rootPath) override {_rootPath=rootPath;} virtual void setDocumentRoot(const std::string &rootPath) override { _rootPath = rootPath; }
virtual void setFileTypes(const std::vector<std::string> &types) override; virtual void setFileTypes(const std::vector<std::string> &types) override;
virtual void enableDynamicViewsLoading(const std::vector<std::string> &libPaths) override; virtual void enableDynamicViewsLoading(const std::vector<std::string> &libPaths) override;
virtual void setMaxConnectionNum(size_t maxConnections) override; virtual void setMaxConnectionNum(size_t maxConnections) override;
virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP) override; virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP) override;
virtual void loadConfigFile(const std::string &fileName) override; virtual void loadConfigFile(const std::string &fileName) override;
virtual void enableRunAsDaemon() override {_runAsDaemon=true;} virtual void enableRunAsDaemon() override { _runAsDaemon = true; }
virtual void enableRelaunchOnError() override {_relaunchOnError=true;} virtual void enableRelaunchOnError() override { _relaunchOnError = true; }
virtual void setLogPath(const std::string &logPath, virtual void setLogPath(const std::string &logPath,
const std::string &logfileBaseName="", const std::string &logfileBaseName = "",
size_t logfileSize=100000000) override; size_t logfileSize = 100000000) override;
virtual void enableSendfile(bool sendFile) override {_useSendfile=sendFile;} virtual void enableSendfile(bool sendFile) override { _useSendfile = sendFile; }
~HttpAppFrameworkImpl(){ virtual void enableGzip(bool useGzip) override { _useGzip = useGzip; }
//Destroy the following objects before _loop destruction virtual bool useGzip() const override { return _useGzip; }
_sharedLibManagerPtr.reset(); ~HttpAppFrameworkImpl()
_sessionMapPtr.reset(); {
} //Destroy the following objects before _loop destruction
_sharedLibManagerPtr.reset();
_sessionMapPtr.reset();
}
trantor::EventLoop *loop(); trantor::EventLoop *loop();
private:
virtual void registerHttpApiController(const std::string &pathPattern,
const HttpApiBinderBasePtr &binder,
const std::vector<std::string> &filters=std::vector<std::string>()) override ;
std::vector<std::tuple<std::string,uint16_t,bool,std::string,std::string>> _listeners; private:
void onAsyncRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback); virtual void registerHttpApiController(const std::string &pathPattern,
void onNewWebsockRequest(const HttpRequestPtr& req, const HttpApiBinderBasePtr &binder,
const std::function<void (const HttpResponsePtr &)> & callback, const std::vector<std::string> &filters = std::vector<std::string>()) override;
const WebSocketConnectionPtr &wsConnPtr);
void onWebsockMessage(const WebSocketConnectionPtr &wsConnPtr,trantor::MsgBuffer *buffer);
void onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr);
void onConnection(const TcpConnectionPtr &conn);
void readSendFile(const std::string& filePath,const HttpRequestPtr& req,const HttpResponsePtr resp);
void addApiPath(const std::string &path,
const HttpApiBinderBasePtr &binder,
const std::vector<std::string> &filters);
void initRegex();
//if uuid package found,we can use a uuid string as session id;
//set _sessionTimeout=0 to make location session valid forever based on cookies;
size_t _sessionTimeout= 0;
bool _useSession= false;
typedef std::shared_ptr<Session> SessionPtr;
std::unique_ptr<CacheMap<std::string,SessionPtr>> _sessionMapPtr;
std::unique_ptr<CacheMap<std::string,HttpResponsePtr>> _responseCacheMap; std::vector<std::tuple<std::string, uint16_t, bool, std::string, std::string>> _listeners;
void onAsyncRequest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
void onNewWebsockRequest(const HttpRequestPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback,
const WebSocketConnectionPtr &wsConnPtr);
void onWebsockMessage(const WebSocketConnectionPtr &wsConnPtr, trantor::MsgBuffer *buffer);
void onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr);
void onConnection(const TcpConnectionPtr &conn);
void readSendFile(const std::string &filePath, const HttpRequestPtr &req, const HttpResponsePtr resp);
void addApiPath(const std::string &path,
const HttpApiBinderBasePtr &binder,
const std::vector<std::string> &filters);
void initRegex();
//if uuid package found,we can use a uuid string as session id;
//set _sessionTimeout=0 to make location session valid forever based on cookies;
size_t _sessionTimeout = 0;
bool _useSession = false;
typedef std::shared_ptr<Session> SessionPtr;
std::unique_ptr<CacheMap<std::string, SessionPtr>> _sessionMapPtr;
void doFilters(const std::vector<std::string> &filters, std::unique_ptr<CacheMap<std::string, HttpResponsePtr>> _responseCacheMap;
const HttpRequestPtr& req,
const std::function<void (const HttpResponsePtr &)> & callback, void doFilters(const std::vector<std::string> &filters,
const HttpRequestPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback,
bool needSetJsessionid,
const std::string &session_id,
const std::function<void()> &missCallback);
void doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> &chain,
const HttpRequestPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id, const std::string &session_id,
const std::function<void ()> &missCallback); const std::function<void()> &missCallback);
void doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> &chain, //
const HttpRequestPtr& req, struct ControllerAndFiltersName
const std::function<void (const HttpResponsePtr &)> & callback, {
bool needSetJsessionid, std::string controllerName;
const std::string &session_id, std::vector<std::string> filtersName;
const std::function<void ()> &missCallback); std::shared_ptr<HttpSimpleControllerBase> controller;
// std::weak_ptr<HttpResponse> responsePtr;
struct ControllerAndFiltersName std::mutex _mutex;
{
std::string controllerName;
std::vector<std::string> filtersName;
std::shared_ptr<HttpSimpleControllerBase> controller;
std::weak_ptr<HttpResponse> responsePtr;
std::mutex _mutex;
};
std::unordered_map<std::string,ControllerAndFiltersName>_simpCtrlMap;
std::mutex _simpCtrlMutex;
struct WSCtrlAndFiltersName
{
WebSocketControllerBasePtr controller;
std::vector<std::string> filtersName;
};
std::unordered_map<std::string,WSCtrlAndFiltersName> _websockCtrlMap;
std::mutex _websockCtrlMutex;
struct ApiBinder
{
std::string pathParameterPattern;
std::vector<size_t> parameterPlaces;
std::map<std::string,size_t> queryParametersPlaces;
HttpApiBinderBasePtr binderPtr;
std::vector<std::string> filtersName;
std::unique_ptr <std::mutex> binderMtx=std::unique_ptr<std::mutex>(new std::mutex);
std::weak_ptr<HttpResponse> responsePtr;
};
//std::unordered_map<std::string,ApiBinder>_apiCtrlMap;
std::vector<ApiBinder>_apiCtrlVector;
std::mutex _apiCtrlMutex;
std::regex _apiRegex;
bool _enableLastModify=true;
std::set<std::string> _fileTypeSet={"html","js","css","xml","xsl","txt","svg","ttf",
"otf","woff2","woff","eot","png","jpg","jpeg",
"gif","bmp","ico","icns"};
std::string _rootPath="./";
std::atomic_bool _running;
//tool funcs
size_t _threadNum=1;
std::vector<std::string> _libFilePaths;
std::unique_ptr<SharedLibManager>_sharedLibManagerPtr;
trantor::EventLoop _loop;
std::string _sslCertPath;
std::string _sslKeyPath;
size_t _maxConnectionNum=100000;
size_t _maxConnectionNumPerIP=0;
std::atomic<uint64_t> _connectionNum;
std::unordered_map<std::string,size_t> _connectionsNumMap;
std::mutex _connectionsNumMapMutex;
bool _runAsDaemon=false;
bool _relaunchOnError=false;
std::string _logPath="";
std::string _logfileBaseName="";
size_t _logfileSize=100000000;
bool _useSendfile=true;
}; };
} std::unordered_map<std::string, ControllerAndFiltersName> _simpCtrlMap;
std::mutex _simpCtrlMutex;
struct WSCtrlAndFiltersName
{
WebSocketControllerBasePtr controller;
std::vector<std::string> filtersName;
};
std::unordered_map<std::string, WSCtrlAndFiltersName> _websockCtrlMap;
std::mutex _websockCtrlMutex;
struct ApiBinder
{
std::string pathParameterPattern;
std::vector<size_t> parameterPlaces;
std::map<std::string, size_t> queryParametersPlaces;
HttpApiBinderBasePtr binderPtr;
std::vector<std::string> filtersName;
std::unique_ptr<std::mutex> binderMtx = std::unique_ptr<std::mutex>(new std::mutex);
std::weak_ptr<HttpResponse> responsePtr;
};
//std::unordered_map<std::string,ApiBinder>_apiCtrlMap;
std::vector<ApiBinder> _apiCtrlVector;
std::mutex _apiCtrlMutex;
std::regex _apiRegex;
bool _enableLastModify = true;
std::set<std::string> _fileTypeSet = {"html", "js", "css", "xml", "xsl", "txt", "svg", "ttf",
"otf", "woff2", "woff", "eot", "png", "jpg", "jpeg",
"gif", "bmp", "ico", "icns"};
std::string _rootPath = "./";
std::atomic_bool _running;
//tool funcs
size_t _threadNum = 1;
std::vector<std::string> _libFilePaths;
std::unique_ptr<SharedLibManager> _sharedLibManagerPtr;
trantor::EventLoop _loop;
std::string _sslCertPath;
std::string _sslKeyPath;
size_t _maxConnectionNum = 100000;
size_t _maxConnectionNumPerIP = 0;
std::atomic<uint64_t> _connectionNum;
std::unordered_map<std::string, size_t> _connectionsNumMap;
std::mutex _connectionsNumMapMutex;
bool _runAsDaemon = false;
bool _relaunchOnError = false;
std::string _logPath = "";
std::string _logfileBaseName = "";
size_t _logfileSize = 100000000;
bool _useSendfile = true;
bool _useGzip = true;
};
} // namespace drogon

View File

@ -179,11 +179,12 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestPtr &r
response->setBody(std::string()); response->setBody(std::string());
auto &sendfileName = std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName(); auto &sendfileName = std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName();
auto newResp = response; auto newResp = response;
if (sendfileName.empty() && if (HttpAppFramework::instance().useGzip() &&
response->getContentTypeCode() < CT_APPLICATION_OCTET_STREAM && sendfileName.empty() &&
response->getBody().length() > 1024 &&
req->getHeader("Accept-Encoding").find("gzip") != std::string::npos && req->getHeader("Accept-Encoding").find("gzip") != std::string::npos &&
response->getHeader("Content-Encoding") == "") response->getHeader("Content-Encoding") == "" &&
response->getContentTypeCode() < CT_APPLICATION_OCTET_STREAM &&
response->getBody().length() > 1024)
{ {
//use gzip //use gzip
LOG_TRACE << "Use gzip to compress the body"; LOG_TRACE << "Use gzip to compress the body";