From 868ac73345019c398e6f12249dc4050efdd336a8 Mon Sep 17 00:00:00 2001 From: antao Date: Sun, 16 Sep 2018 15:31:25 +0800 Subject: [PATCH 01/13] Update CMakeLists.txt --- CMakeLists.txt | 21 ++++++++------------- drogon_ctl/create_project.cc | 25 +++++++++++-------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e2e67f0..dfea0a1c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/drogon_ctl/create_project.cc b/drogon_ctl/create_project.cc index 75502199..7585d8c1 100644 --- a/drogon_ctl/create_project.cc +++ b/drogon_ctl/create_project.cc @@ -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" From 1d90dfe20472b68ff7cd8feb4333d027b38299ff Mon Sep 17 00:00:00 2001 From: antao Date: Sun, 16 Sep 2018 15:34:11 +0800 Subject: [PATCH 02/13] Update trantor --- trantor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trantor b/trantor index 4c0a8bb5..87aa3947 160000 --- a/trantor +++ b/trantor @@ -1 +1 @@ -Subproject commit 4c0a8bb59b4c77622fb004df932401422a966492 +Subproject commit 87aa3947909b8b8eeb67066eb1491d7a26f83a9e From 01ea43a5a79014b9002e1dc00fe3f39da3247a07 Mon Sep 17 00:00:00 2001 From: an-tao Date: Mon, 17 Sep 2018 10:31:28 +0800 Subject: [PATCH 03/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb04e35a..14471f14 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,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; From 735d423fa55b65ab1fd5b7bc3004b87ec7dc1510 Mon Sep 17 00:00:00 2001 From: antao Date: Tue, 18 Sep 2018 16:46:02 +0800 Subject: [PATCH 04/13] Fix bugs of non-virtual destructor --- examples/simple_example/main.cc | 2 +- lib/inc/drogon/DrObject.h | 1 + lib/inc/drogon/HttpResponse.h | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/simple_example/main.cc b/examples/simple_example/main.cc index e64c404a..3267b27d 100755 --- a/examples/simple_example/main.cc +++ b/examples/simple_example/main.cc @@ -123,7 +123,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(); } diff --git a/lib/inc/drogon/DrObject.h b/lib/inc/drogon/DrObject.h index c72b3a0c..9ce78d5a 100755 --- a/lib/inc/drogon/DrObject.h +++ b/lib/inc/drogon/DrObject.h @@ -40,6 +40,7 @@ namespace drogon __cxxabiv1::__cxa_demangle( mangled_name, nullptr, &len, &status ), &std::free ) ; return ptr.get() ; } + virtual ~DrObjectBase(){} }; diff --git a/lib/inc/drogon/HttpResponse.h b/lib/inc/drogon/HttpResponse.h index c8f724fb..e4a8355d 100755 --- a/lib/inc/drogon/HttpResponse.h +++ b/lib/inc/drogon/HttpResponse.h @@ -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(){} }; } From 575d28e77d62e07eeadda0dae497fd05acacb4f1 Mon Sep 17 00:00:00 2001 From: an-tao Date: Tue, 18 Sep 2018 23:22:18 +0800 Subject: [PATCH 05/13] Update trantor --- trantor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trantor b/trantor index 87aa3947..f6bd78b2 160000 --- a/trantor +++ b/trantor @@ -1 +1 @@ -Subproject commit 87aa3947909b8b8eeb67066eb1491d7a26f83a9e +Subproject commit f6bd78b27a04a92af4aa76648276812a24515534 From 5238da4df75f7c29522cfd1abdd2197e892e901f Mon Sep 17 00:00:00 2001 From: antao Date: Tue, 25 Sep 2018 18:07:29 +0800 Subject: [PATCH 06/13] Use sendfile() system-call --- config.json.example | 5 ++++- examples/simple_example/main.cc | 2 +- lib/inc/drogon/HttpAppFramework.h | 10 +++++++--- lib/src/ConfigLoader.cc | 4 +++- lib/src/HttpAppFrameworkImpl.cc | 28 ++++++++++++++++++---------- lib/src/HttpAppFrameworkImpl.h | 29 ++++++++++++++++------------- lib/src/HttpResponseImpl.cc | 19 +++++++++++++++++-- lib/src/HttpResponseImpl.h | 7 +++++++ lib/src/HttpServer.cc | 10 +++++++++- trantor | 2 +- 10 files changed, 83 insertions(+), 33 deletions(-) diff --git a/config.json.example b/config.json.example index 3c47d23d..12e39dde 100644 --- a/config.json.example +++ b/config.json.example @@ -62,6 +62,9 @@ //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 } } \ No newline at end of file diff --git a/examples/simple_example/main.cc b/examples/simple_example/main.cc index 3267b27d..b83c2182 100755 --- a/examples/simple_example/main.cc +++ b/examples/simple_example/main.cc @@ -83,7 +83,7 @@ int main() std::cout< &filters=std::vector())=0; - virtual void registerHttpApiController(const std::string &pathPattern, - const HttpApiBinderBasePtr &binder, - const std::vector &filters=std::vector())=0; template static void registerHttpApiMethod(const std::string &pathPattern, FUNCTION && function, @@ -109,5 +106,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 &filters=std::vector())=0; + }; } diff --git a/lib/src/ConfigLoader.cc b/lib/src/ConfigLoader.cc index 94e6c749..e34b918b 100644 --- a/lib/src/ConfigLoader.cc +++ b/lib/src/ConfigLoader.cc @@ -131,6 +131,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 +159,7 @@ static void loadSSL(const Json::Value &sslFiles) HttpAppFramework::instance().setSSLFiles(cert,key); } void ConfigLoader::load() { - std::cout<<_configJsonRoot<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(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() diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index 50fe778e..eb7f66f1 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -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 &filters= std::vector())override ; - virtual void registerHttpApiController(const std::string &pathPattern, - const HttpApiBinderBasePtr &binder, - const std::vector &filters=std::vector()) 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;} @@ -69,14 +66,19 @@ namespace drogon 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 &filters=std::vector()) override ; + std::vector> _listeners; void onAsyncRequest(const HttpRequestPtr& req,const std::function & callback); void onNewWebsockRequest(const HttpRequestPtr& req, @@ -104,11 +106,11 @@ namespace drogon const std::string &session_id, const std::function &missCallback); void doFilterChain(const std::shared_ptr>> &chain, - const HttpRequestPtr& req, - const std::function & callback, - bool needSetJsessionid, - const std::string &session_id, - const std::function &missCallback); + const HttpRequestPtr& req, + const std::function & callback, + bool needSetJsessionid, + const std::string &session_id, + const std::function &missCallback); // struct ControllerAndFiltersName { @@ -169,5 +171,6 @@ namespace drogon std::string _logPath=""; std::string _logfileBaseName=""; size_t _logfileSize=100000000; + bool _useSendfile=true; }; } diff --git a/lib/src/HttpResponseImpl.cc b/lib/src/HttpResponseImpl.cc index f3354f3c..eed9fb30 100755 --- a/lib/src/HttpResponseImpl.cc +++ b/lib/src/HttpResponseImpl.cc @@ -27,6 +27,7 @@ #include #include #include +#include using namespace trantor; using namespace drogon; @@ -313,12 +314,26 @@ 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; + } + snprintf(buf, sizeof buf, "Content-Length: %lld\r\n",filestat.st_size); + } + output->append(buf); if(_headers.find("Connection")==_headers.end()) { diff --git a/lib/src/HttpResponseImpl.h b/lib/src/HttpResponseImpl.h index 5787d2cd..01179962 100755 --- a/lib/src/HttpResponseImpl.h +++ b/lib/src/HttpResponseImpl.h @@ -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 _jsonPtr; //trantor::Date receiveTime_; diff --git a/lib/src/HttpServer.cc b/lib/src/HttpServer.cc index cc7970b5..5da3407e 100755 --- a/lib/src/HttpServer.cc +++ b/lib/src/HttpServer.cc @@ -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()(response)->sendfileName(); + + if(sendfileName.empty()&& + response->getContentTypeCode()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(response)->appendToBuffer(&buf); conn->send(std::move(buf)); + auto & sendfileName=std::dynamic_pointer_cast(response)->sendfileName(); + if(!sendfileName.empty()) + { + conn->sendFile(sendfileName.c_str()); + } if (response->closeConnection()) { conn->shutdown(); } diff --git a/trantor b/trantor index 87aa3947..19693734 160000 --- a/trantor +++ b/trantor @@ -1 +1 @@ -Subproject commit 87aa3947909b8b8eeb67066eb1491d7a26f83a9e +Subproject commit 19693734fa9b8e48887a255368b289542adb43f7 From 0d3e9e6e74e1ea7ef408bfab1134702078b9b227 Mon Sep 17 00:00:00 2001 From: an-tao <20741618@qq.com> Date: Tue, 25 Sep 2018 21:46:26 +0800 Subject: [PATCH 07/13] Fix some compilation warnings --- drogon_ctl/create_project.cc | 3 ++- lib/src/ConfigLoader.cc | 2 ++ lib/src/HttpResponseImpl.cc | 4 ++++ lib/src/SharedLibManager.cc | 4 +++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drogon_ctl/create_project.cc b/drogon_ctl/create_project.cc index 7585d8c1..5d20ab9d 100644 --- a/drogon_ctl/create_project.cc +++ b/drogon_ctl/create_project.cc @@ -208,7 +208,8 @@ void create_project::createProject(const std::string &projectName) std::cout<<"create a project named "<append(buf); diff --git a/lib/src/SharedLibManager.cc b/lib/src/SharedLibManager.cc index deb5ad22..9d5026e9 100755 --- a/lib/src/SharedLibManager.cc +++ b/lib/src/SharedLibManager.cc @@ -115,7 +115,9 @@ void SharedLibManager::managerLibs() std::string cmd="drogon_ctl create view "; cmd.append(filename).append(" -o ").append(libPath); LOG_TRACE< Date: Tue, 25 Sep 2018 22:45:47 +0800 Subject: [PATCH 08/13] Modify drogon_ctl --- drogon_ctl/create_project.cc | 80 +++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/drogon_ctl/create_project.cc b/drogon_ctl/create_project.cc index 5d20ab9d..c57dbe51 100644 --- a/drogon_ctl/create_project.cc +++ b/drogon_ctl/create_project.cc @@ -85,9 +85,9 @@ static void newMainFile(std::ofstream &mainFile) { mainFile<<"#include \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" "}"; @@ -197,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) { @@ -223,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); } From c4a6793ca693e620ff478c89232519c591218ed7 Mon Sep 17 00:00:00 2001 From: antao Date: Thu, 27 Sep 2018 18:26:45 +0800 Subject: [PATCH 09/13] Update trantor --- trantor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trantor b/trantor index 19693734..5555d02c 160000 --- a/trantor +++ b/trantor @@ -1 +1 @@ -Subproject commit 19693734fa9b8e48887a255368b289542adb43f7 +Subproject commit 5555d02c1a33b8597d35ca56a614d9ecafdc41ca From 0cd9a2cee3757e97be55f1e716627fe9ce96902f Mon Sep 17 00:00:00 2001 From: antao Date: Sat, 29 Sep 2018 15:30:27 +0800 Subject: [PATCH 10/13] Add config option max_connections_per_ip --- config.json.example | 2 ++ lib/inc/drogon/HttpAppFramework.h | 1 + lib/src/ConfigLoader.cc | 7 +++++++ lib/src/HttpAppFrameworkImpl.cc | 24 ++++++++++++++++++++++++ lib/src/HttpAppFrameworkImpl.h | 7 +++++++ 5 files changed, 41 insertions(+) diff --git a/config.json.example b/config.json.example index 12e39dde..a3174729 100644 --- a/config.json.example +++ b/config.json.example @@ -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" diff --git a/lib/inc/drogon/HttpAppFramework.h b/lib/inc/drogon/HttpAppFramework.h index d9c794c6..5fdf7b44 100755 --- a/lib/inc/drogon/HttpAppFramework.h +++ b/lib/inc/drogon/HttpAppFramework.h @@ -97,6 +97,7 @@ namespace drogon virtual void enableDynamicViewsLoading(const std::vector &libPaths)=0; virtual void setMaxConnectionNum(size_t maxConnections)=0; + virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP)=0; virtual void loadConfigFile(const std::string &fileName)=0; diff --git a/lib/src/ConfigLoader.cc b/lib/src/ConfigLoader.cc index 651e1590..7f7106f2 100644 --- a/lib/src/ConfigLoader.cc +++ b/lib/src/ConfigLoader.cc @@ -103,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) diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index daa49075..55445e28 100755 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -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 guard(_connectionsNumMapMutex); + _connectionsNumMap[conn->peerAddr().toIp()]--; + } } } std::string parseWebsockFrame(trantor::MsgBuffer *buffer) diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index eb7f66f1..c3850d70 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -60,6 +60,7 @@ namespace drogon virtual void setFileTypes(const std::vector &types) override; virtual void enableDynamicViewsLoading(const std::vector &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;} @@ -164,7 +165,13 @@ namespace drogon std::string _sslKeyPath; size_t _maxConnectionNum=100000; + size_t _maxConnectionNumPerIP=0; + std::atomic _connectionNum; + std::unordered_map _connectionsNumMap; + + std::mutex _connectionsNumMapMutex; + bool _runAsDaemon=false; bool _relaunchOnError=false; From d04efa98b21cca1db2082e8790c0e239e040064b Mon Sep 17 00:00:00 2001 From: antao Date: Sat, 29 Sep 2018 17:33:19 +0800 Subject: [PATCH 11/13] 1.Simplify the FunctionTraits; 2.Fix simple_example's bugs --- examples/simple_example/TimeFilter.cpp | 8 ++++- examples/simple_example/api_v1_ApiTest.h | 4 +-- examples/simple_example/main.cc | 17 +++++++++ lib/inc/drogon/utils/FunctionTraits.h | 44 +++--------------------- 4 files changed, 31 insertions(+), 42 deletions(-) diff --git a/examples/simple_example/TimeFilter.cpp b/examples/simple_example/TimeFilter.cpp index 7e964ef7..95daf0ce 100755 --- a/examples/simple_example/TimeFilter.cpp +++ b/examples/simple_example/TimeFilter.cpp @@ -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(VDate); diff --git a/examples/simple_example/api_v1_ApiTest.h b/examples/simple_example/api_v1_ApiTest.h index 3e4c188d..46c2a21c 100755 --- a/examples/simple_example/api_v1_ApiTest.h +++ b/examples/simple_example/api_v1_ApiTest.h @@ -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: diff --git a/examples/simple_example/main.cc b/examples/simple_example/main.cc index b83c2182..a4719a70 100755 --- a/examples/simple_example/main.cc +++ b/examples/simple_example/main.cc @@ -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&callback, + int p1,const std::string &p2,const std::string &p3,int p4) + { + HttpViewData data; + data.insert("title",std::string("ApiTest::get")); + std::map 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); @@ -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&callback,int a,float b){ LOG_DEBUG<<"int a="< struct FunctionTraits; + //functor,lambda,std::function... template struct FunctionTraits : public FunctionTraits< decltype(&std::remove_reference::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&callback,Arguments...) const - > : FunctionTraits { - 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&callback,Arguments...) - > : FunctionTraits { - 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& callback,Arguments...)>> -// :FunctionTraits { -// static const bool isHTTPApiFunction=true; -// static const std::string name(){return std::string("std::function");} -// }; + //normal function template < typename ReturnType, typename... Arguments From d008bda302bff7a1faaa6f601c4ce4bf17734086 Mon Sep 17 00:00:00 2001 From: an-tao Date: Tue, 2 Oct 2018 16:49:59 +0800 Subject: [PATCH 12/13] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 14471f14..1758c028 100755 --- a/README.md +++ b/README.md @@ -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; From d129e43cccb2fdc8f2d6c5fe3eb22ccf7ae40ba4 Mon Sep 17 00:00:00 2001 From: antao Date: Tue, 2 Oct 2018 17:20:32 +0800 Subject: [PATCH 13/13] Update config.json.example --- config.json.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json.example b/config.json.example index a3174729..b6bc1d0e 100644 --- a/config.json.example +++ b/config.json.example @@ -58,7 +58,7 @@ //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 @@ -69,4 +69,4 @@ //use sendfile() system-call to send static file to client; "use_sendfile":true } -} \ No newline at end of file +}