Merge branch 'master' of https://github.com/an-tao/drogon
This commit is contained in:
commit
a4b8d1d421
|
@ -7,21 +7,16 @@ IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
|||
if(version LESS 4.9.0)
|
||||
MESSAGE(STATUS "gcc is too old")
|
||||
stop()
|
||||
endif()
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17)
|
||||
if(COMPILER_SUPPORTS_CXX17)
|
||||
message(STATUS "support c++17")
|
||||
elseif (version LESS 6.1.0)
|
||||
MESSAGE(STATUS "c++11")
|
||||
set(CMAKE_CXX_STD_FLAGS c++11)
|
||||
elseif(version LESS 7.1.0)
|
||||
set(CMAKE_CXX_STD_FLAGS c++14)
|
||||
MESSAGE(STATUS "c++14")
|
||||
else()
|
||||
set(CMAKE_CXX_STD_FLAGS c++17)
|
||||
set(DR_DEFS "USE_STD_ANY")
|
||||
elseif(COMPILER_SUPPORTS_CXX14)
|
||||
message(STATUS "support c++14")
|
||||
set(CMAKE_CXX_STD_FLAGS c++14)
|
||||
elseif(COMPILER_SUPPORTS_CXX11)
|
||||
message(STATUS "support c++11")
|
||||
set(CMAKE_CXX_STD_FLAGS c++11)
|
||||
MESSAGE(STATUS "c++17")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_CXX_STD_FLAGS c++11)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
![](https://github.com/an-tao/drogon/wiki/images/drogon-white.jpg)
|
||||
|
||||
**Drogon** is a C++11-based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. Drogon's main application platform is Linux. For debugging purposes, it also supports Mac OS. There is no plan to support Windows. Its main features are as follows:
|
||||
**Drogon** is a C++11-based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon in the American TV series "Game of Thrones" that I really like.
|
||||
|
||||
Drogon's main application platform is Linux. For debugging purposes, it also supports Mac OS. There is no plan to support Windows. Its main features are as follows:
|
||||
|
||||
* The network layer uses a NIO framework based on epoll (poll under MacOS) to provide high-concurrency, high-performance network IO;
|
||||
* Full asynchronous programming mode;
|
||||
|
@ -11,7 +13,7 @@
|
|||
* Support view page dynamic loading (dynamic compilation and loading at runtime);
|
||||
* Very convenient and flexible path to controller handler mapping scheme;
|
||||
* Support filter chain to facilitate the execution of unified logic (such as login verification, Http Method constraint verification, etc.) before the controller;
|
||||
* Support https (based on OpenSSL implementation);
|
||||
* Support https (based on OpenSSL);
|
||||
* Support websocket (server side);
|
||||
* Support Json format request and response;
|
||||
* Support file download and upload;
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
"file_types":["gif","png","jpg","js","css","html","ico","swf","xap","apk","cur","xml"],
|
||||
//max_connections:max connections number,100000 by default
|
||||
"max_connections":100000,
|
||||
//max_connections_per_ip:max connections number per clinet,0 by default which means no limit
|
||||
"max_connections_per_ip":0,
|
||||
//Load_dynamic_views: false by default, when set to true, drogon will
|
||||
//compile and load dynamically "CSP View Files" in directories defined
|
||||
//by "dynamic_views_path"
|
||||
|
@ -56,12 +58,15 @@
|
|||
//drogon.log ...
|
||||
"logfile_base_name":"",
|
||||
//log_size_limit:100000000 bytes by default,
|
||||
//When the log file size reaches "log_size_limit", the log file is switched.
|
||||
//When the log file size reaches "log_size_limit", the log file will be switched.
|
||||
"log_size_limit":100000000
|
||||
},
|
||||
//run_as_daemon:false by default
|
||||
"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
|
||||
"relaunch_on_error":false,
|
||||
//use_sendfile:true by default,if ture,the program will
|
||||
//use sendfile() system-call to send static file to client;
|
||||
"use_sendfile":true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,31 +28,28 @@ static void newCmakeFile(std::ofstream &cmakeFile,const std::string &projectName
|
|||
"if(OpenSSL_FOUND)\n"
|
||||
"link_libraries(ssl crypto)\n"
|
||||
"endif()\n"
|
||||
"\n"
|
||||
"IF (CMAKE_SYSTEM_NAME MATCHES \"Linux\")\n"
|
||||
" EXEC_PROGRAM (gcc ARGS \"--version | grep '^gcc'|awk '{print $3}' | sed s'/)//g' | sed s'/-.*//g'\" OUTPUT_VARIABLE version)\n"
|
||||
" MESSAGE(STATUS \"This is gcc version:: \" ${version})\n"
|
||||
" if(version LESS 4.9.0)\n"
|
||||
" MESSAGE(STATUS \"gcc is too old\")\n"
|
||||
" stop()\n"
|
||||
" endif()\n"
|
||||
" include(CheckCXXCompilerFlag)\n"
|
||||
" CHECK_CXX_COMPILER_FLAG(\"-std=c++11\" COMPILER_SUPPORTS_CXX11)\n"
|
||||
" CHECK_CXX_COMPILER_FLAG(\"-std=c++14\" COMPILER_SUPPORTS_CXX14)\n"
|
||||
" CHECK_CXX_COMPILER_FLAG(\"-std=c++17\" COMPILER_SUPPORTS_CXX17)\n"
|
||||
" if(COMPILER_SUPPORTS_CXX17)\n"
|
||||
" message(STATUS \"support c++17\")\n"
|
||||
" set(CMAKE_CXX_STD_FLAGS c++17)\n"
|
||||
" set(DEFS \"USE_STD_ANY\")\n"
|
||||
" elseif(COMPILER_SUPPORTS_CXX14)\n"
|
||||
" message(STATUS \"support c++14\")\n"
|
||||
" set(CMAKE_CXX_STD_FLAGS c++14)\n"
|
||||
" elseif(COMPILER_SUPPORTS_CXX11)\n"
|
||||
" message(STATUS \"support c++11\")\n"
|
||||
" elseif (version LESS 6.1.0)\n"
|
||||
" MESSAGE(STATUS \"c++11\")\n"
|
||||
" set(CMAKE_CXX_STD_FLAGS c++11)\n"
|
||||
" elseif(version LESS 7.1.0)\n"
|
||||
" set(CMAKE_CXX_STD_FLAGS c++14)\n"
|
||||
" MESSAGE(STATUS \"c++14\")\n"
|
||||
" else()\n"
|
||||
" set(CMAKE_CXX_STD_FLAGS c++17)\n"
|
||||
" set(DR_DEFS \"USE_STD_ANY\")\n"
|
||||
" MESSAGE(STATUS \"c++17\")\n"
|
||||
" endif()\n"
|
||||
"else()\n"
|
||||
" set(CMAKE_CXX_STD_FLAGS c++11)\n"
|
||||
"endif()\n"
|
||||
"\n"
|
||||
"if(CMAKE_BUILD_TYPE STREQUAL \"\")\n"
|
||||
" set(CMAKE_BUILD_TYPE Release)\n"
|
||||
"endif()\n"
|
||||
|
@ -88,9 +85,9 @@ static void newMainFile(std::ofstream &mainFile)
|
|||
{
|
||||
mainFile<<"#include <drogon/HttpAppFramework.h>\n"
|
||||
"int main() {\n"
|
||||
" //设置http监听的地址和端口\n"
|
||||
" //Set HTTP listener address and port\n"
|
||||
" drogon::HttpAppFramework::instance().addListener(\"0.0.0.0\",80);\n"
|
||||
" //运行http框架,程序阻塞在底层的事件循环中\n"
|
||||
" //Run HTTP framework,the method will block in the inner event loop\n"
|
||||
" drogon::HttpAppFramework::instance().run();\n"
|
||||
" return 0;\n"
|
||||
"}";
|
||||
|
@ -200,6 +197,80 @@ static void newJsonFindFile(std::ofstream &jsonFile)
|
|||
"\tJSONCPP_INCLUDE_DIR JSONCPP_LIBRARY)\n"
|
||||
"mark_as_advanced (JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY)\n";
|
||||
}
|
||||
|
||||
static void newConfigFile(std::ofstream &configFile)
|
||||
{
|
||||
configFile<<"/* This is a JSON format configuration file\n"
|
||||
"*/\n"
|
||||
"{\n"
|
||||
" //ssl:the global ssl files setting\n"
|
||||
" \"ssl\": {\n"
|
||||
" \"cert\": \"../../trantor/trantor/tests/server.pem\",\n"
|
||||
" \"key\": \"../../trantor/trantor/tests/server.pem\"\n"
|
||||
" },\n"
|
||||
" \"listeners\": [\n"
|
||||
" {\n"
|
||||
" //address:ip address,0.0.0.0 by default\n"
|
||||
" \"address\": \"0.0.0.0\",\n"
|
||||
" //port:port number\n"
|
||||
" \"port\": 80,\n"
|
||||
" //https:if use https for security,false by default\n"
|
||||
" \"https\": false\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"address\": \"0.0.0.0\",\n"
|
||||
" \"port\": 443,\n"
|
||||
" \"https\": true,\n"
|
||||
" //cert,key:cert file path and key file path,empty by default,\n"
|
||||
" //if empty,use global setting\n"
|
||||
" \"cert\": \"\",\n"
|
||||
" \"key\": \"\"\n"
|
||||
" }\n"
|
||||
" ],\n"
|
||||
" \"app\": {\n"
|
||||
" //threads_num:num of threads,1 by default\n"
|
||||
" \"threads_num\": 16,\n"
|
||||
" //enable_session:false by default\n"
|
||||
" \"enable_session\": false,\n"
|
||||
" \"session_timeout\": 0,\n"
|
||||
" //document_root:Root path of HTTP document,defaut path is ./\n"
|
||||
" \"document_root\":\"./\",\n"
|
||||
" /* file_types:\n"
|
||||
" * HTTP download file types,The file types supported by drogon\n"
|
||||
" * by default are \"html\", \"js\", \"css\", \"xml\", \"xsl\", \"txt\", \"svg\",\n"
|
||||
" * \"ttf\", \"otf\", \"woff2\", \"woff\" , \"eot\", \"png\", \"jpg\", \"jpeg\",\n"
|
||||
" * \"gif\", \"bmp\", \"ico\", \"icns\", etc. */\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\":100000,\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"
|
||||
" //by \"dynamic_views_path\"\n"
|
||||
" \"load_dynamic_views\":true,\n"
|
||||
" //dynamic_views_path: if the path isn't prefixed with / or ./,\n"
|
||||
" //it will be relative path of document_root path\n"
|
||||
" \"dynamic_views_path\":[\"./views\"],\n"
|
||||
" //log:set log output,drogon output logs to stdout by default\n"
|
||||
" \"log\":{\n"
|
||||
" //log_path:log file path,empty by default,in which case,log will output to the stdout\n"
|
||||
" \"log_path\":\"./\",\n"
|
||||
" //logfile_base_name:log file base name,empty by default which means drogon will name logfile as\n"
|
||||
" //drogon.log ...\n"
|
||||
" \"logfile_base_name\":\"\",\n"
|
||||
" //log_size_limit:100000000 bytes by default,\n"
|
||||
" //When the log file size reaches \"log_size_limit\", the log file is switched.\n"
|
||||
" \"log_size_limit\":100000000\n"
|
||||
" },\n"
|
||||
" //run_as_daemon:false by default\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,\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\":true\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
}
|
||||
void create_project::createProject(const std::string &projectName)
|
||||
{
|
||||
|
||||
|
@ -211,7 +282,8 @@ void create_project::createProject(const std::string &projectName)
|
|||
std::cout<<"create a project named "<<projectName<<std::endl;
|
||||
mkdir(projectName.data(),0755);
|
||||
//1.create CMakeLists.txt
|
||||
chdir(projectName.data());
|
||||
auto r=chdir(projectName.data());
|
||||
(void)(r);
|
||||
std::ofstream cmakeFile("CMakeLists.txt",std::ofstream::out);
|
||||
newCmakeFile(cmakeFile,projectName);
|
||||
std::ofstream mainFile("main.cc",std::ofstream::out);
|
||||
|
@ -225,4 +297,6 @@ void create_project::createProject(const std::string &projectName)
|
|||
newJsonFindFile(jsonFile);
|
||||
std::ofstream gitFile(".gitignore",std::ofstream::out);
|
||||
newGitIgFile(gitFile);
|
||||
std::ofstream configFile("config.json",std::ofstream::out);
|
||||
newConfigFile(configFile);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,13 @@ void TimeFilter::doFilter(const HttpRequestPtr& req,
|
|||
const FilterChainCallback &ccb)
|
||||
{
|
||||
trantor::Date now=trantor::Date::date();
|
||||
LOG_TRACE<<"";
|
||||
if(!req->session())
|
||||
{
|
||||
//no session support by framework,pls enable session
|
||||
auto resp=HttpResponse::newNotFoundResponse();
|
||||
cb(resp);
|
||||
return;
|
||||
}
|
||||
if(req->session()->find(VDate))
|
||||
{
|
||||
auto lastDate=req->session()->get<trantor::Date>(VDate);
|
||||
|
|
|
@ -10,8 +10,8 @@ namespace api
|
|||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
//use METHOD_ADD to add your custom processing function here;
|
||||
METHOD_ADD(ApiTest::get,"/get/{2}/{1}","drogon::GetFilter");//path will be /api/v1/ApiTest/get/{arg2}/{arg1}
|
||||
METHOD_ADD(ApiTest::your_method_name,"/{1}/list?p2={2}","drogon::GetFilter");//path will be /api/v1/ApiTest/{arg1}/list
|
||||
METHOD_ADD(ApiTest::get,"/get/{2}/{1}","drogon::GetFilter");//path will be /api/v1/apitest/get/{arg2}/{arg1}
|
||||
METHOD_ADD(ApiTest::your_method_name,"/{1}/list?p2={2}","drogon::GetFilter");//path will be /api/v1/apitest/{arg1}/list
|
||||
|
||||
METHOD_LIST_END
|
||||
//your declaration of processing function maybe like this:
|
||||
|
|
|
@ -21,6 +21,22 @@ public:
|
|||
para["string p3"]=p3;
|
||||
para["int p4"]=std::to_string(p4);
|
||||
|
||||
data.insert("parameters",para);
|
||||
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
|
||||
callback(res);
|
||||
}
|
||||
static void staticHandle(const HttpRequestPtr& req,
|
||||
const std::function<void (const HttpResponsePtr &)>&callback,
|
||||
int p1,const std::string &p2,const std::string &p3,int p4)
|
||||
{
|
||||
HttpViewData data;
|
||||
data.insert("title",std::string("ApiTest::get"));
|
||||
std::map<std::string,std::string> para;
|
||||
para["int p1"]=std::to_string(p1);
|
||||
para["string p2"]=p2;
|
||||
para["string p3"]=p3;
|
||||
para["int p4"]=std::to_string(p4);
|
||||
|
||||
data.insert("parameters",para);
|
||||
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
|
||||
callback(res);
|
||||
|
@ -83,7 +99,7 @@ int main()
|
|||
|
||||
std::cout<<banner<<std::endl;
|
||||
|
||||
drogon::HttpAppFramework::instance().addListener("0.0.0.0",12345);
|
||||
// drogon::HttpAppFramework::instance().addListener("0.0.0.0",12345);
|
||||
drogon::HttpAppFramework::instance().addListener("0.0.0.0",8080);
|
||||
//#ifdef USE_OPENSSL
|
||||
// //https
|
||||
|
@ -95,6 +111,7 @@ int main()
|
|||
trantor::Logger::setLogLevel(trantor::Logger::TRACE);
|
||||
//class function
|
||||
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle1/{1}/{2}/?p3={3}&p4={4}",&A::handle);
|
||||
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle11/{1}/{2}/?p3={3}&p4={4}",&A::staticHandle);
|
||||
//lambda example
|
||||
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle2/{1}/{2}",[](const HttpRequestPtr&req,const std::function<void (const HttpResponsePtr &)>&callback,int a,float b){
|
||||
LOG_DEBUG<<"int a="<<a;
|
||||
|
@ -123,7 +140,7 @@ int main()
|
|||
drogon::HttpAppFramework::instance().enableSession(1200);
|
||||
//start app framework
|
||||
//drogon::HttpAppFramework::instance().enableDynamicViewsLoading({"/tmp/views"});
|
||||
drogon::HttpAppFramework::instance().loadConfigFile("../../drogon.conf.example");
|
||||
drogon::HttpAppFramework::instance().loadConfigFile("../../config.json.example");
|
||||
drogon::HttpAppFramework::instance().run();
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace drogon
|
|||
__cxxabiv1::__cxa_demangle( mangled_name, nullptr, &len, &status ), &std::free ) ;
|
||||
return ptr.get() ;
|
||||
}
|
||||
virtual ~DrObjectBase(){}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -75,9 +75,6 @@ namespace drogon
|
|||
virtual void registerHttpSimpleController(const std::string &pathName,
|
||||
const std::string &crtlName,
|
||||
const std::vector<std::string> &filters=std::vector<std::string>())=0;
|
||||
virtual void registerHttpApiController(const std::string &pathPattern,
|
||||
const HttpApiBinderBasePtr &binder,
|
||||
const std::vector<std::string> &filters=std::vector<std::string>())=0;
|
||||
template <typename FUNCTION>
|
||||
static void registerHttpApiMethod(const std::string &pathPattern,
|
||||
FUNCTION && function,
|
||||
|
@ -100,6 +97,7 @@ namespace drogon
|
|||
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;
|
||||
|
||||
|
@ -109,5 +107,12 @@ namespace drogon
|
|||
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;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -161,6 +161,8 @@ namespace drogon
|
|||
static HttpResponsePtr newHttpJsonResponse(const Json::Value &data);
|
||||
static HttpResponsePtr newHttpViewResponse(const std::string &viewName,const HttpViewData& data);
|
||||
static HttpResponsePtr newLocationRedirectResponse(const std::string &path);
|
||||
|
||||
virtual ~HttpResponse(){}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace drogon{
|
|||
|
||||
template<typename> struct FunctionTraits;
|
||||
|
||||
//functor,lambda,std::function...
|
||||
template <typename Function>
|
||||
struct FunctionTraits : public FunctionTraits<
|
||||
decltype(&std::remove_reference<Function>::type::operator())
|
||||
|
@ -33,7 +34,7 @@ namespace drogon{
|
|||
{return std::string("Functor");}
|
||||
};
|
||||
|
||||
|
||||
//class instance method of const object
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
|
@ -47,8 +48,7 @@ namespace drogon{
|
|||
static const std::string name(){return std::string("Class Function");}
|
||||
};
|
||||
|
||||
/* support the non-const operator ()
|
||||
* this will work with user defined functors */
|
||||
//class instance method of non-const object
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
|
@ -62,31 +62,7 @@ namespace drogon{
|
|||
static const std::string name(){return std::string("Class Function");}
|
||||
};
|
||||
|
||||
//class function
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct FunctionTraits<
|
||||
ReturnType(ClassType::*)(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)>&callback,Arguments...) const
|
||||
> : FunctionTraits<ReturnType(ClassType::*)(Arguments...)> {
|
||||
static const bool isHTTPApiFunction=true;
|
||||
static const std::string name(){return std::string("Class Const Api Function");}
|
||||
};
|
||||
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct FunctionTraits<
|
||||
ReturnType(ClassType::*)(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)>&callback,Arguments...)
|
||||
> : FunctionTraits<ReturnType(ClassType::*)(Arguments...)> {
|
||||
static const bool isHTTPApiFunction=true;
|
||||
static const std::string name(){return std::string("Class Api Function");}
|
||||
};
|
||||
//normal function
|
||||
//normal function for HTTP handling
|
||||
template <
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
|
@ -97,18 +73,8 @@ namespace drogon{
|
|||
static const bool isHTTPApiFunction=true;
|
||||
|
||||
};
|
||||
//std::function
|
||||
// template <
|
||||
// typename ReturnType,
|
||||
// typename... Arguments
|
||||
// >
|
||||
// struct FunctionTraits<std::function<
|
||||
// ReturnType(const HttpRequest& req,const std::function<void (const HttpResponsePtr &)>& callback,Arguments...)>>
|
||||
// :FunctionTraits<ReturnType(*)(Arguments...)> {
|
||||
// static const bool isHTTPApiFunction=true;
|
||||
// static const std::string name(){return std::string("std::function");}
|
||||
// };
|
||||
|
||||
//normal function
|
||||
template <
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
|
|
|
@ -77,6 +77,8 @@ static void loadApp(const Json::Value &app)
|
|||
auto timeout=app.get("session_timeout",0).asUInt64();
|
||||
if(enableSession)
|
||||
HttpAppFramework::instance().enableSession(timeout);
|
||||
else
|
||||
HttpAppFramework::instance().disableSession();
|
||||
//document root
|
||||
auto documentRoot=app.get("document_root","").asString();
|
||||
if(documentRoot!="")
|
||||
|
@ -101,6 +103,13 @@ static void loadApp(const Json::Value &app)
|
|||
{
|
||||
HttpAppFramework::instance().setMaxConnectionNum(maxConns);
|
||||
}
|
||||
//max connections per IP
|
||||
auto maxConnsPerIP=app.get("max_connections_per_ip",0).asUInt64();
|
||||
if(maxConnsPerIP>0)
|
||||
{
|
||||
HttpAppFramework::instance().setMaxConnectionNumPerIP(maxConnsPerIP);
|
||||
}
|
||||
|
||||
//dynamic views
|
||||
auto enableDynamicViews=app.get("load_dynamic_views",false).asBool();
|
||||
if(enableDynamicViews)
|
||||
|
@ -131,6 +140,8 @@ static void loadApp(const Json::Value &app)
|
|||
{
|
||||
HttpAppFramework::instance().enableRelaunchOnError();
|
||||
}
|
||||
auto useSendfile=app.get("use_sendfile",true).asBool();
|
||||
HttpAppFramework::instance().enableSendfile(useSendfile);
|
||||
}
|
||||
static void loadListeners(const Json::Value &listeners)
|
||||
{
|
||||
|
@ -157,7 +168,7 @@ static void loadSSL(const Json::Value &sslFiles)
|
|||
HttpAppFramework::instance().setSSLFiles(cert,key);
|
||||
}
|
||||
void ConfigLoader::load() {
|
||||
std::cout<<_configJsonRoot<<std::endl;
|
||||
//std::cout<<_configJsonRoot<<std::endl;
|
||||
loadApp(_configJsonRoot["app"]);
|
||||
loadSSL(_configJsonRoot["ssl"]);
|
||||
loadListeners(_configJsonRoot["listeners"]);
|
||||
|
|
|
@ -229,6 +229,10 @@ void HttpAppFrameworkImpl::setMaxConnectionNum(size_t maxConnections)
|
|||
{
|
||||
_maxConnectionNum=maxConnections;
|
||||
}
|
||||
void HttpAppFrameworkImpl::setMaxConnectionNumPerIP(size_t maxConnectionsPerIP)
|
||||
{
|
||||
_maxConnectionNumPerIP=maxConnectionsPerIP;
|
||||
}
|
||||
void HttpAppFrameworkImpl::loadConfigFile(const std::string &fileName)
|
||||
{
|
||||
ConfigLoader loader(fileName);
|
||||
|
@ -506,10 +510,30 @@ void HttpAppFrameworkImpl::onConnection(const TcpConnectionPtr &conn)
|
|||
LOG_ERROR<<"too much connections!force close!";
|
||||
conn->forceClose();
|
||||
}
|
||||
else if(_maxConnectionNumPerIP>0)
|
||||
{
|
||||
{
|
||||
auto iter=_connectionsNumMap.find(conn->peerAddr().toIp());
|
||||
if(iter==_connectionsNumMap.end())
|
||||
{
|
||||
_connectionsNumMap[conn->peerAddr().toIp()]=0;
|
||||
}
|
||||
if(_connectionsNumMap[conn->peerAddr().toIp()]++>=_maxConnectionNumPerIP)
|
||||
{
|
||||
conn->forceClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_connectionNum--;
|
||||
|
||||
if(_maxConnectionNumPerIP>0&&_connectionsNumMap.find(conn->peerAddr().toIp())!=_connectionsNumMap.end())
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_connectionsNumMapMutex);
|
||||
_connectionsNumMap[conn->peerAddr().toIp()]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string parseWebsockFrame(trantor::MsgBuffer *buffer)
|
||||
|
@ -892,18 +916,26 @@ void HttpAppFrameworkImpl::readSendFile(const std::string& filePath,const HttpRe
|
|||
}
|
||||
}
|
||||
|
||||
std::streambuf * pbuf = infile.rdbuf();
|
||||
std::streamsize size = pbuf->pubseekoff(0,infile.end);
|
||||
pbuf->pubseekoff(0,infile.beg); // rewind
|
||||
std::string str;
|
||||
str.resize(size);
|
||||
pbuf->sgetn (&str[0],size);
|
||||
infile.close();
|
||||
if(_useSendfile&&
|
||||
(req->getHeader("Accept-Encoding").find("gzip")==std::string::npos||
|
||||
resp->getContentTypeCode()>=CT_APPLICATION_OCTET_STREAM))
|
||||
{
|
||||
//binary file or no gzip supported by client
|
||||
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->setSendfile(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::streambuf * pbuf = infile.rdbuf();
|
||||
std::streamsize size = pbuf->pubseekoff(0,infile.end);
|
||||
pbuf->pubseekoff(0,infile.beg); // rewind
|
||||
std::string str;
|
||||
str.resize(size);
|
||||
pbuf->sgetn (&str[0],size);
|
||||
LOG_INFO << "file len:" << str.length();
|
||||
resp->setBody(std::move(str));
|
||||
}
|
||||
|
||||
resp->setStatusCode(HttpResponse::k200OK);
|
||||
LOG_INFO << "file len:" << str.length();
|
||||
resp->setBody(std::move(str));
|
||||
|
||||
}
|
||||
|
||||
trantor::EventLoop *HttpAppFrameworkImpl::loop()
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace drogon
|
|||
{
|
||||
public:
|
||||
HttpAppFrameworkImpl():
|
||||
_connectionNum(0)
|
||||
_connectionNum(0)
|
||||
{
|
||||
}
|
||||
virtual void addListener(const std::string &ip,
|
||||
|
@ -53,9 +53,6 @@ namespace drogon
|
|||
const std::string &crtlName,
|
||||
const std::vector<std::string> &filters=
|
||||
std::vector<std::string>())override ;
|
||||
virtual void registerHttpApiController(const std::string &pathPattern,
|
||||
const HttpApiBinderBasePtr &binder,
|
||||
const std::vector<std::string> &filters=std::vector<std::string>()) override ;
|
||||
virtual void enableSession(const size_t timeout=0) override { _useSession=true;_sessionTimeout=timeout;}
|
||||
virtual void disableSession() override { _useSession=false;}
|
||||
virtual const std::string & getDocumentRoot() const override {return _rootPath;}
|
||||
|
@ -63,20 +60,26 @@ namespace drogon
|
|||
virtual void setFileTypes(const std::vector<std::string> &types) override;
|
||||
virtual void enableDynamicViewsLoading(const std::vector<std::string> &libPaths) override;
|
||||
virtual void setMaxConnectionNum(size_t maxConnections) override;
|
||||
virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP) override;
|
||||
virtual void loadConfigFile(const std::string &fileName) override;
|
||||
virtual void enableRunAsDaemon() override {_runAsDaemon=true;}
|
||||
virtual void enableRelaunchOnError() override {_relaunchOnError=true;}
|
||||
virtual void setLogPath(const std::string &logPath,
|
||||
const std::string &logfileBaseName="",
|
||||
size_t logfileSize=100000000) override;
|
||||
virtual void enableSendfile(bool sendFile) override {_useSendfile=sendFile;}
|
||||
~HttpAppFrameworkImpl(){
|
||||
//Destroy the following objects before _loop destruction
|
||||
_sharedLibManagerPtr.reset();
|
||||
_sessionMapPtr.reset();
|
||||
}
|
||||
//Destroy the following objects before _loop destruction
|
||||
_sharedLibManagerPtr.reset();
|
||||
_sessionMapPtr.reset();
|
||||
}
|
||||
|
||||
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;
|
||||
void onAsyncRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback);
|
||||
void onNewWebsockRequest(const HttpRequestPtr& req,
|
||||
|
@ -104,11 +107,11 @@ namespace drogon
|
|||
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,
|
||||
const std::string &session_id,
|
||||
const std::function<void ()> &missCallback);
|
||||
const HttpRequestPtr& req,
|
||||
const std::function<void (const HttpResponsePtr &)> & callback,
|
||||
bool needSetJsessionid,
|
||||
const std::string &session_id,
|
||||
const std::function<void ()> &missCallback);
|
||||
//
|
||||
struct ControllerAndFiltersName
|
||||
{
|
||||
|
@ -162,12 +165,19 @@ namespace drogon
|
|||
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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <drogon/HttpAppFramework.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
using namespace trantor;
|
||||
using namespace drogon;
|
||||
|
@ -313,12 +314,30 @@ std::string HttpResponseImpl::web_response_code_to_string(int code)
|
|||
}
|
||||
void HttpResponseImpl::appendToBuffer(MsgBuffer* output) const
|
||||
{
|
||||
char buf[32];
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof buf, "HTTP/1.1 %d ", _statusCode);
|
||||
output->append(buf);
|
||||
output->append(_statusMessage);
|
||||
output->append("\r\n");
|
||||
snprintf(buf, sizeof buf, "Content-Length: %lu\r\n", _body.size());
|
||||
if(_sendfileName.empty())
|
||||
{
|
||||
snprintf(buf, sizeof buf, "Content-Length: %lu\r\n", _body.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat filestat;
|
||||
if(stat(_sendfileName.c_str(), &filestat)<0)
|
||||
{
|
||||
LOG_SYSERR<<_sendfileName<<" stat error";
|
||||
return;
|
||||
}
|
||||
#ifdef __linux__
|
||||
snprintf(buf, sizeof buf, "Content-Length: %ld\r\n",filestat.st_size);
|
||||
#else
|
||||
snprintf(buf, sizeof buf, "Content-Length: %lld\r\n",filestat.st_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
output->append(buf);
|
||||
if(_headers.find("Connection")==_headers.end())
|
||||
{
|
||||
|
|
|
@ -268,6 +268,12 @@ namespace drogon
|
|||
}
|
||||
return _jsonPtr;
|
||||
}
|
||||
const std::string &sendfileName() const {
|
||||
return _sendfileName;
|
||||
}
|
||||
void setSendfile(const std::string &filename){
|
||||
_sendfileName=filename;
|
||||
}
|
||||
protected:
|
||||
static std::string web_content_type_to_string(uint8_t contenttype);
|
||||
static const std::string web_content_type_and_charset_to_string(uint8_t contenttype,
|
||||
|
@ -288,6 +294,7 @@ namespace drogon
|
|||
size_t _current_chunk_length;
|
||||
uint8_t _contentType=CT_TEXT_HTML;
|
||||
|
||||
std::string _sendfileName;
|
||||
mutable std::shared_ptr<Json::Value> _jsonPtr;
|
||||
//trantor::Date receiveTime_;
|
||||
|
||||
|
|
|
@ -177,7 +177,10 @@ void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequestPtr& r
|
|||
//if the request method is HEAD,remove the body of response(rfc2616-9.4)
|
||||
if(_isHeadMethod)
|
||||
response->setBody(std::string());
|
||||
if(response->getContentTypeCode()<CT_APPLICATION_OCTET_STREAM&&
|
||||
auto & sendfileName=std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName();
|
||||
|
||||
if(sendfileName.empty()&&
|
||||
response->getContentTypeCode()<CT_APPLICATION_OCTET_STREAM&&
|
||||
response->getBody().length()>1024&&
|
||||
req->getHeader("Accept-Encoding").find("gzip")!=std::string::npos)
|
||||
{
|
||||
|
@ -240,6 +243,11 @@ void HttpServer::sendResponse(const TcpConnectionPtr& conn,
|
|||
MsgBuffer buf;
|
||||
std::dynamic_pointer_cast<HttpResponseImpl>(response)->appendToBuffer(&buf);
|
||||
conn->send(std::move(buf));
|
||||
auto & sendfileName=std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName();
|
||||
if(!sendfileName.empty())
|
||||
{
|
||||
conn->sendFile(sendfileName.c_str());
|
||||
}
|
||||
if (response->closeConnection()) {
|
||||
conn->shutdown();
|
||||
}
|
||||
|
|
|
@ -115,7 +115,9 @@ void SharedLibManager::managerLibs()
|
|||
std::string cmd="drogon_ctl create view ";
|
||||
cmd.append(filename).append(" -o ").append(libPath);
|
||||
LOG_TRACE<<cmd;
|
||||
system(cmd.c_str());
|
||||
auto r=system(cmd.c_str());
|
||||
//FIXME:handle r
|
||||
(void)(r);
|
||||
auto srcFile=filename.substr(0,pos);
|
||||
srcFile.append(".cc");
|
||||
DLStat dlStat;
|
||||
|
|
2
trantor
2
trantor
|
@ -1 +1 @@
|
|||
Subproject commit 4c0a8bb59b4c77622fb004df932401422a966492
|
||||
Subproject commit 5555d02c1a33b8597d35ca56a614d9ecafdc41ca
|
Loading…
Reference in New Issue