diff --git a/examples/simple_example/api_v1_ApiTest.h b/examples/simple_example/api_v1_ApiTest.h index 6e53f16c..3f5ed7c4 100755 --- a/examples/simple_example/api_v1_ApiTest.h +++ b/examples/simple_example/api_v1_ApiTest.h @@ -10,7 +10,7 @@ class ApiTest : public drogon::HttpController public: METHOD_LIST_BEGIN //use METHOD_ADD to add your custom processing function here; - METHOD_ADD(ApiTest::rootGet, "", Get); + METHOD_ADD(ApiTest::rootGet, "", "TimeFilter", Get, "drogon::LocalHostFilter"); METHOD_ADD(ApiTest::rootPost, "", Post); METHOD_ADD(ApiTest::get, "/get/{2}/{1}", Get); //path will be /api/v1/apitest/get/{arg2}/{arg1} METHOD_ADD(ApiTest::your_method_name, "/{1}/List?P2={2}", Get); //path will be /api/v1/apitest/{arg1}/list diff --git a/get_version.sh b/get_version.sh index 918ca54b..15c1d2af 100755 --- a/get_version.sh +++ b/get_version.sh @@ -3,7 +3,7 @@ GIT_VER=$(git log|grep ^commit|wc -l|sed -e "s/^ *//") MD5=$(git log|head -1|awk '{printf $2}') TMP_FILE=/tmp/version -echo "#define VERSION \"0.9.15.$GIT_VER\"" > ${TMP_FILE} +echo "#define VERSION \"0.9.16.$GIT_VER\"" > ${TMP_FILE} echo "#define VERSION_MD5 \"$MD5\"" >> ${TMP_FILE} if [ ! -f $1 ];then mv -f ${TMP_FILE} $1 diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index d49ef074..5af9ed32 100755 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -379,19 +379,24 @@ void HttpAppFrameworkImpl::run() void HttpAppFrameworkImpl::doFilterChain(const std::shared_ptr>> &chain, const HttpRequestImplPtr &req, - const std::function &callback, + const std::shared_ptr> &callbackPtr, bool needSetJsessionid, - const std::string &session_id, - const std::function &missCallback) + const std::shared_ptr &sessionIdPtr, + std::function &&missCallback) { if (chain && chain->size() > 0) { auto filter = chain->front(); chain->pop(); - filter->doFilter(req, [=](HttpResponsePtr res) { - if (needSetJsessionid) - res->addCookie("JSESSIONID", session_id); - callback(res); }, [=]() { doFilterChain(chain, req, callback, needSetJsessionid, session_id, missCallback); }); + filter->doFilter(req, + [=](HttpResponsePtr res) { + if (needSetJsessionid) + res->addCookie("JSESSIONID", *sessionIdPtr); + (*callbackPtr)(res); + }, + [=, missCallback = std::move(missCallback)]() mutable { + doFilterChain(chain, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback)); + }); } else { @@ -400,10 +405,10 @@ void HttpAppFrameworkImpl::doFilterChain(const std::shared_ptr &filters, const HttpRequestImplPtr &req, - const std::function &callback, + const std::shared_ptr> &callbackPtr, bool needSetJsessionid, - const std::string &session_id, - const std::function &missCallback) + const std::shared_ptr &sessionIdPtr, + std::function &&missCallback) { std::shared_ptr>> filterPtrs; if (!filters.empty()) @@ -421,7 +426,7 @@ void HttpAppFrameworkImpl::doFilters(const std::vector &filters, } } } - doFilterChain(filterPtrs, req, callback, needSetJsessionid, session_id, missCallback); + doFilterChain(filterPtrs, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback)); } void HttpAppFrameworkImpl::onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr) { @@ -575,12 +580,12 @@ void HttpAppFrameworkImpl::setUploadPath(const std::string &uploadPath) } } void HttpAppFrameworkImpl::onNewWebsockRequest(const HttpRequestImplPtr &req, - const std::function &callback, + std::function &&callback, const WebSocketConnectionPtr &wsConnPtr) { - _websockCtrlsRouter.route(req, callback, wsConnPtr); + _websockCtrlsRouter.route(req, std::move(callback), wsConnPtr); } -void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const std::function &callback) +void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::function &&callback) { LOG_TRACE << "new request:" << req->peerAddr().toIpPort() << "->" << req->localAddr().toIpPort(); LOG_TRACE << "Headers " << req->methodString() << " " << req->path(); @@ -624,7 +629,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s (std::dynamic_pointer_cast(req))->setSession((*_sessionMapPtr)[session_id]); } - std::string path = req->path(); + const std::string &path = req->path(); auto pos = path.rfind("."); if (pos != std::string::npos) { @@ -775,11 +780,8 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s } } - //find simple controller - if (_httpSimpleCtrlsRouter.route(req, callback, needSetJsessionid, session_id)) - return; - //Find http controller - _httpCtrlsRouter.route(req, callback, needSetJsessionid, session_id); + //Route to controller + _httpSimpleCtrlsRouter.route(req, std::move(callback), needSetJsessionid, std::move(session_id)); } void HttpAppFrameworkImpl::readSendFile(const std::string &filePath, const HttpRequestImplPtr &req, const HttpResponsePtr &resp) diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index 53b56d66..3d7ab7a1 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -39,8 +39,8 @@ class HttpAppFrameworkImpl : public HttpAppFramework { public: HttpAppFrameworkImpl() - : _httpSimpleCtrlsRouter(*this), - _httpCtrlsRouter(*this), + : _httpCtrlsRouter(*this), + _httpSimpleCtrlsRouter(*this, _httpCtrlsRouter), _websockCtrlsRouter(*this), _uploadPath(_rootPath + "uploads"), _connectionNum(0) @@ -118,19 +118,19 @@ class HttpAppFrameworkImpl : public HttpAppFramework #endif void doFilters(const std::vector &filters, const HttpRequestImplPtr &req, - const std::function &callback, + const std::shared_ptr> &callbackPtr, bool needSetJsessionid, - const std::string &session_id, - const std::function &missCallback); + const std::shared_ptr &sessionIdPtr, + std::function &&missCallback); private: virtual void registerHttpController(const std::string &pathPattern, const internal::HttpBinderBasePtr &binder, const std::vector &validMethods = std::vector(), const std::vector &filters = std::vector()) override; - void onAsyncRequest(const HttpRequestImplPtr &req, const std::function &callback); + void onAsyncRequest(const HttpRequestImplPtr &req, std::function &&callback); void onNewWebsockRequest(const HttpRequestImplPtr &req, - const std::function &callback, + std::function &&callback, const WebSocketConnectionPtr &wsConnPtr); void onWebsockMessage(const WebSocketConnectionPtr &wsConnPtr, trantor::MsgBuffer *buffer); void onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr); @@ -142,10 +142,10 @@ class HttpAppFrameworkImpl : public HttpAppFramework const std::vector &filters); void doFilterChain(const std::shared_ptr>> &chain, const HttpRequestImplPtr &req, - const std::function &callback, + const std::shared_ptr> &callbackPtr, bool needSetJsessionid, - const std::string &session_id, - const std::function &missCallback); + const std::shared_ptr &sessionIdPtr, + std::function &&missCallback); //We use a uuid string as session id; //set _sessionTimeout=0 to make location session valid forever based on cookies; @@ -157,8 +157,9 @@ class HttpAppFrameworkImpl : public HttpAppFramework std::unique_ptr> _sessionMapPtr; std::unique_ptr> _responseCachingMap; - HttpSimpleControllersRouter _httpSimpleCtrlsRouter; HttpControllersRouter _httpCtrlsRouter; + HttpSimpleControllersRouter _httpSimpleCtrlsRouter; + WebsocketControllersRouter _websockCtrlsRouter; bool _enableLastModify = true; diff --git a/lib/src/HttpControllersRouter.cc b/lib/src/HttpControllersRouter.cc index 53128ec3..ef6c7fec 100644 --- a/lib/src/HttpControllersRouter.cc +++ b/lib/src/HttpControllersRouter.cc @@ -138,9 +138,9 @@ void HttpControllersRouter::addHttpPath(const std::string &path, } void HttpControllersRouter::route(const HttpRequestImplPtr &req, - const std::function &callback, + std::function &&callback, bool needSetJsessionid, - const std::string &session_id) + std::string &&session_id) { //find http controller if (_ctrlRegex.mark_count() > 0) @@ -156,10 +156,10 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req, if (result[i].str() == req->path() && i <= _ctrlVector.size()) { size_t ctlIndex = i - 1; - auto &router = _ctrlVector[ctlIndex]; + auto &routerItem = _ctrlVector[ctlIndex]; //LOG_TRACE << "got http access,regex=" << binder.pathParameterPattern; assert(Invalid > req->method()); - auto &binder = router._binders[req->method()]; + auto &binder = routerItem._binders[req->method()]; if (!binder) { //Invalid Http Method @@ -170,89 +170,18 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req, } auto &filters = binder->filtersName; - _appImpl.doFilters(filters, req, callback, needSetJsessionid, session_id, [=]() { - HttpResponsePtr responsePtr; - { - std::lock_guard guard(*(binder->binderMtx)); - responsePtr = binder->responsePtr; - } - - if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->createDate().after(responsePtr->expiredTime())))) - { - //use cached response! - LOG_TRACE << "Use cached response"; - - if (!needSetJsessionid) - callback(responsePtr); - else - { - //make a copy response; - auto newResp = std::make_shared(*std::dynamic_pointer_cast(responsePtr)); - newResp->setExpiredTime(-1); //make it temporary - newResp->addCookie("JSESSIONID", session_id); - callback(newResp); - } - return; - } - - std::vector params(binder->parameterPlaces.size()); - std::smatch r; - if (std::regex_match(req->path(), r, router._regex)) - { - for (size_t j = 1; j < r.size(); j++) - { - size_t place = binder->parameterPlaces[j - 1]; - if (place > params.size()) - params.resize(place); - params[place - 1] = r[j].str(); - LOG_TRACE << "place=" << place << " para:" << params[place - 1]; - } - } - if (binder->queryParametersPlaces.size() > 0) - { - auto qureyPara = req->getParameters(); - for (auto parameter : qureyPara) - { - if (binder->queryParametersPlaces.find(parameter.first) != - binder->queryParametersPlaces.end()) - { - auto place = binder->queryParametersPlaces.find(parameter.first)->second; - if (place > params.size()) - params.resize(place); - params[place - 1] = parameter.second; - } - } - } - std::list paraList; - for (auto p : params) - { - LOG_TRACE << p; - paraList.push_back(std::move(p)); - } - - binder->binderPtr->handleHttpRequest(paraList, req, [=](const HttpResponsePtr &resp) { - LOG_TRACE << "http resp:needSetJsessionid=" << needSetJsessionid << ";JSESSIONID=" << session_id; - auto newResp = resp; - if (resp->expiredTime() >= 0) - { - //cache the response; - std::dynamic_pointer_cast(resp)->makeHeaderString(); - { - std::lock_guard guard(*(binder->binderMtx)); - binder->responsePtr = resp; - } - } - if (needSetJsessionid) - { - //make a copy - newResp = std::make_shared(*std::dynamic_pointer_cast(resp)); - newResp->setExpiredTime(-1); //make it temporary - newResp->addCookie("JSESSIONID", session_id); - } - callback(newResp); + if (!filters.empty()) + { + auto sessionIdPtr = std::make_shared(std::move(session_id)); + auto callbackPtr = std::make_shared>(std::move(callback)); + _appImpl.doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=]() { + doControllerHandler(binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr)); }); - return; - }); + } + else + { + doControllerHandler(binder, routerItem, req, std::move(callback), needSetJsessionid, std::move(session_id)); + } } } } @@ -262,7 +191,6 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req, auto res = drogon::HttpResponse::newNotFoundResponse(); if (needSetJsessionid) res->addCookie("JSESSIONID", session_id); - callback(res); } } @@ -270,10 +198,101 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req, { //No controller found auto res = drogon::HttpResponse::newNotFoundResponse(); - if (needSetJsessionid) res->addCookie("JSESSIONID", session_id); - callback(res); } +} + +void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderPtr, + const HttpControllerRouterItem &routerItem, + const HttpRequestImplPtr &req, + std::function &&callback, + bool needSetJsessionid, + std::string &&session_id) +{ + HttpResponsePtr responsePtr; + { + std::lock_guard guard(*(ctrlBinderPtr->binderMtx)); + responsePtr = ctrlBinderPtr->responsePtr; + } + + if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->createDate().after(responsePtr->expiredTime())))) + { + //use cached response! + LOG_TRACE << "Use cached response"; + + if (!needSetJsessionid) + callback(responsePtr); + else + { + //make a copy response; + auto newResp = std::make_shared(*std::dynamic_pointer_cast(responsePtr)); + newResp->setExpiredTime(-1); //make it temporary + newResp->addCookie("JSESSIONID", session_id); + callback(newResp); + } + return; + } + + std::vector params(ctrlBinderPtr->parameterPlaces.size()); + std::smatch r; + if (std::regex_match(req->path(), r, routerItem._regex)) + { + for (size_t j = 1; j < r.size(); j++) + { + size_t place = ctrlBinderPtr->parameterPlaces[j - 1]; + if (place > params.size()) + params.resize(place); + params[place - 1] = r[j].str(); + LOG_TRACE << "place=" << place << " para:" << params[place - 1]; + } + } + if (ctrlBinderPtr->queryParametersPlaces.size() > 0) + { + auto qureyPara = req->getParameters(); + for (auto parameter : qureyPara) + { + if (ctrlBinderPtr->queryParametersPlaces.find(parameter.first) != + ctrlBinderPtr->queryParametersPlaces.end()) + { + auto place = ctrlBinderPtr->queryParametersPlaces.find(parameter.first)->second; + if (place > params.size()) + params.resize(place); + params[place - 1] = parameter.second; + } + } + } + std::list paraList; + for (auto p : params) + { + LOG_TRACE << p; + paraList.push_back(std::move(p)); + } + + ctrlBinderPtr->binderPtr->handleHttpRequest(paraList, req, [=, callback = std::move(callback), session_id = std::move(session_id)](const HttpResponsePtr &resp) { + LOG_TRACE << "http resp:needSetJsessionid=" << needSetJsessionid << ";JSESSIONID=" << session_id; + auto newResp = resp; + if (resp->expiredTime() >= 0) + { + //cache the response; + std::dynamic_pointer_cast(resp)->makeHeaderString(); + { + std::lock_guard guard(*(ctrlBinderPtr->binderMtx)); + ctrlBinderPtr->responsePtr = resp; + } + } + if (needSetJsessionid) + { + if (resp->expiredTime() >= 0) + { + //make a copy + newResp = std::make_shared(*std::dynamic_pointer_cast(resp)); + newResp->setExpiredTime(-1); //make it temporary + } + newResp->addCookie("JSESSIONID", session_id); + } + callback(newResp); + }); + return; } \ No newline at end of file diff --git a/lib/src/HttpControllersRouter.h b/lib/src/HttpControllersRouter.h index 92353109..7af3a1e4 100644 --- a/lib/src/HttpControllersRouter.h +++ b/lib/src/HttpControllersRouter.h @@ -36,9 +36,9 @@ class HttpControllersRouter : public trantor::NonCopyable const std::vector &validMethods, const std::vector &filters); void route(const HttpRequestImplPtr &req, - const std::function &callback, + std::function &&callback, bool needSetJsessionid, - const std::string &session_id); + std::string &&session_id); private: struct CtrlBinder @@ -61,5 +61,12 @@ class HttpControllersRouter : public trantor::NonCopyable std::mutex _ctrlMutex; std::regex _ctrlRegex; HttpAppFrameworkImpl &_appImpl; + + void doControllerHandler(const CtrlBinderPtr &ctrlBinderPtr, + const HttpControllerRouterItem &routerItem, + const HttpRequestImplPtr &req, + std::function &&callback, + bool needSetJsessionid, + std::string &&session_id); }; } // namespace drogon \ No newline at end of file diff --git a/lib/src/HttpServer.cc b/lib/src/HttpServer.cc index 9c9cd7fc..b18d615c 100755 --- a/lib/src/HttpServer.cc +++ b/lib/src/HttpServer.cc @@ -26,7 +26,7 @@ using namespace std::placeholders; using namespace drogon; using namespace trantor; -static void defaultHttpAsyncCallback(const HttpRequestPtr &, const std::function &callback) +static void defaultHttpAsyncCallback(const HttpRequestPtr &, std::function &&callback) { auto resp = HttpResponse::newNotFoundResponse(); resp->setCloseConnection(true); @@ -34,7 +34,7 @@ static void defaultHttpAsyncCallback(const HttpRequestPtr &, const std::function } static void defaultWebSockAsyncCallback(const HttpRequestPtr &, - const std::function &callback, + std::function &&callback, const WebSocketConnectionPtr &wsConnPtr) { auto resp = HttpResponse::newNotFoundResponse(); diff --git a/lib/src/HttpServer.h b/lib/src/HttpServer.h index f0688e71..89d6dc71 100755 --- a/lib/src/HttpServer.h +++ b/lib/src/HttpServer.h @@ -32,9 +32,9 @@ typedef std::shared_ptr HttpRequestPtr; class HttpServer : trantor::NonCopyable { public: - typedef std::function &)> HttpAsyncCallback; + typedef std::function &&)> HttpAsyncCallback; typedef std::function &, + std::function &&, const WebSocketConnectionPtr &)> WebSocketNewAsyncCallback; typedef std::function diff --git a/lib/src/HttpSimpleControllersRouter.cc b/lib/src/HttpSimpleControllersRouter.cc index 8e541f5a..8370983b 100644 --- a/lib/src/HttpSimpleControllersRouter.cc +++ b/lib/src/HttpSimpleControllersRouter.cc @@ -64,18 +64,18 @@ void HttpSimpleControllersRouter::registerHttpSimpleController(const std::string } } -bool HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req, - const std::function &callback, +void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req, + std::function &&callback, bool needSetJsessionid, - const std::string &session_id) + std::string &&session_id) { - std::string pathLower(req->path()); - std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), tolower); + std::string pathLower(req->path().length(), 0); + std::transform(req->path().begin(), req->path().end(), pathLower.begin(), tolower); if (_simpCtrlMap.find(pathLower) != _simpCtrlMap.end()) { auto &ctrlInfo = _simpCtrlMap[pathLower]; - if (ctrlInfo._validMethodsFlags.size() > 0) + if (!ctrlInfo._validMethodsFlags.empty()) { assert(ctrlInfo._validMethodsFlags.size() > req->method()); if (ctrlInfo._validMethodsFlags[req->method()] == 0) @@ -84,85 +84,105 @@ bool HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req, auto res = drogon::HttpResponse::newHttpResponse(); res->setStatusCode(HttpResponse::k405MethodNotAllowed); callback(res); - return true; + return; } } auto &filters = ctrlInfo.filtersName; - _appImpl.doFilters(filters, req, callback, needSetJsessionid, session_id, [=]() { - auto &ctrlItem = _simpCtrlMap[pathLower]; - const std::string &ctrlName = ctrlItem.controllerName; - std::shared_ptr controller; - HttpResponsePtr responsePtr; - { - //maybe update controller,so we use lock_guard to protect; - std::lock_guard guard(ctrlItem._mutex); - controller = ctrlItem.controller; - responsePtr = ctrlItem.responsePtr; - if (!controller) - { - auto _object = std::shared_ptr(DrClassMap::newObject(ctrlName)); - controller = std::dynamic_pointer_cast(_object); - ctrlItem.controller = controller; - } - } + if (!filters.empty()) + { + auto sessionIdPtr = std::make_shared(std::move(session_id)); + auto callbackPtr = std::make_shared>(std::move(callback)); + _appImpl.doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, pathLower = std::move(pathLower)]() mutable { + doControllerHandler(std::move(pathLower), req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr)); + }); + } + else + { + doControllerHandler(std::move(pathLower), req, std::move(callback), needSetJsessionid, std::move(session_id)); + } + return; + } + _httpCtrlsRouter.route(req, std::move(callback), needSetJsessionid, std::move(session_id)); +} - if (controller) - { - if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->createDate().after(responsePtr->expiredTime())))) - { - //use cached response! - LOG_TRACE << "Use cached response"; - if (!needSetJsessionid) - callback(responsePtr); - else - { - //make a copy response; - auto newResp = std::make_shared(*std::dynamic_pointer_cast(responsePtr)); - newResp->setExpiredTime(-1); //make it temporary - newResp->addCookie("JSESSIONID", session_id); - callback(newResp); - } - return; - } - else - { - controller->asyncHandleHttpRequest(req, [=](const HttpResponsePtr &resp) { - auto newResp = resp; - if (resp->expiredTime() >= 0) - { - //cache the response; - std::dynamic_pointer_cast(resp)->makeHeaderString(); - { - auto &item = _simpCtrlMap[pathLower]; - std::lock_guard guard(item._mutex); - item.responsePtr = resp; - } - } - if (needSetJsessionid) - { - //make a copy - newResp = std::make_shared(*std::dynamic_pointer_cast(resp)); - newResp->setExpiredTime(-1); //make it temporary - newResp->addCookie("JSESSIONID", session_id); - } +void HttpSimpleControllersRouter::doControllerHandler(std::string &&pathLower, + const HttpRequestImplPtr &req, + std::function &&callback, + bool needSetJsessionid, + std::string &&session_id) +{ + auto &ctrlItem = _simpCtrlMap[pathLower]; + const std::string &ctrlName = ctrlItem.controllerName; + std::shared_ptr controller; + HttpResponsePtr responsePtr; + { + //maybe update controller,so we use lock_guard to protect; + std::lock_guard guard(ctrlItem._mutex); + controller = ctrlItem.controller; + responsePtr = ctrlItem.responsePtr; + if (!controller) + { + auto _object = std::shared_ptr(DrClassMap::newObject(ctrlName)); + controller = std::dynamic_pointer_cast(_object); + ctrlItem.controller = controller; + } + } - callback(newResp); - }); - } - - return; - } + if (controller) + { + if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->createDate().after(responsePtr->expiredTime())))) + { + //use cached response! + LOG_TRACE << "Use cached response"; + if (!needSetJsessionid) + callback(responsePtr); else { - LOG_ERROR << "can't find controller " << ctrlName; - auto res = drogon::HttpResponse::newNotFoundResponse(); - if (needSetJsessionid) - res->addCookie("JSESSIONID", session_id); - - callback(res); + //make a copy response; + auto newResp = std::make_shared(*std::dynamic_pointer_cast(responsePtr)); + newResp->setExpiredTime(-1); //make it temporary + newResp->addCookie("JSESSIONID", session_id); + callback(newResp); } - }); - return true; + return; + } + else + { + controller->asyncHandleHttpRequest(req, [=, callback = std::move(callback), pathLower = std::move(pathLower), session_id = std::move(session_id)](const HttpResponsePtr &resp) { + auto newResp = resp; + if (resp->expiredTime() >= 0) + { + //cache the response; + std::dynamic_pointer_cast(resp)->makeHeaderString(); + { + auto &item = _simpCtrlMap[pathLower]; + std::lock_guard guard(item._mutex); + item.responsePtr = resp; + } + } + if (needSetJsessionid) + { + if (resp->expiredTime() >= 0) + { + //make a copy + newResp = std::make_shared(*std::dynamic_pointer_cast(resp)); + newResp->setExpiredTime(-1); //make it temporary + } + newResp->addCookie("JSESSIONID", session_id); + } + callback(newResp); + }); + } + + return; + } + else + { + LOG_ERROR << "can't find controller " << ctrlName; + auto res = drogon::HttpResponse::newNotFoundResponse(); + if (needSetJsessionid) + res->addCookie("JSESSIONID", session_id); + + callback(res); } - return false; } \ No newline at end of file diff --git a/lib/src/HttpSimpleControllersRouter.h b/lib/src/HttpSimpleControllersRouter.h index 347b4412..65ab8c60 100644 --- a/lib/src/HttpSimpleControllersRouter.h +++ b/lib/src/HttpSimpleControllersRouter.h @@ -27,20 +27,24 @@ namespace drogon { class HttpAppFrameworkImpl; +class HttpControllersRouter; class HttpSimpleControllersRouter : public trantor::NonCopyable { public: - HttpSimpleControllersRouter(HttpAppFrameworkImpl &app) : _appImpl(app) {} + HttpSimpleControllersRouter(HttpAppFrameworkImpl &app, HttpControllersRouter &httpCtrlRouter) + : _appImpl(app), + _httpCtrlsRouter(httpCtrlRouter) {} void registerHttpSimpleController(const std::string &pathName, const std::string &ctrlName, const std::vector &filtersAndMethods); - bool route(const HttpRequestImplPtr &req, - const std::function &callback, + void route(const HttpRequestImplPtr &req, + std::function &&callback, bool needSetJsessionid, - const std::string &session_id); + std::string &&session_id); private: HttpAppFrameworkImpl &_appImpl; + HttpControllersRouter &_httpCtrlsRouter; struct SimpleControllerRouterItem { std::string controllerName; @@ -52,5 +56,11 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable }; std::unordered_map _simpCtrlMap; std::mutex _simpCtrlMutex; + + void doControllerHandler(std::string &&pathLower, + const HttpRequestImplPtr &req, + std::function &&callback, + bool needSetJsessionid, + std::string &&session_id); }; } // namespace drogon diff --git a/lib/src/WebsocketControllersRouter.cc b/lib/src/WebsocketControllersRouter.cc index af847274..abbfa862 100644 --- a/lib/src/WebsocketControllersRouter.cc +++ b/lib/src/WebsocketControllersRouter.cc @@ -39,7 +39,7 @@ void WebsocketControllersRouter::registerWebSocketController(const std::string & } void WebsocketControllersRouter::route(const HttpRequestImplPtr &req, - const std::function &callback, + std::function &&callback, const WebSocketConnectionPtr &wsConnPtr) { std::string wsKey = req->getHeaderBy("sec-websocket-key"); @@ -60,27 +60,44 @@ void WebsocketControllersRouter::route(const HttpRequestImplPtr &req, } if (ctrlPtr) { - _appImpl.doFilters(filtersName, req, callback, false, "", [=]() mutable { - wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); - unsigned char accKey[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast(wsKey.c_str()), wsKey.length(), accKey); - auto base64Key = base64Encode(accKey, SHA_DIGEST_LENGTH); - auto resp = HttpResponse::newHttpResponse(); - resp->setStatusCode(HttpResponse::k101SwitchingProtocols); - resp->addHeader("Upgrade", "websocket"); - resp->addHeader("Connection", "Upgrade"); - resp->addHeader("Sec-WebSocket-Accept", base64Key); - callback(resp); - auto wsConnImplPtr = std::dynamic_pointer_cast(wsConnPtr); - assert(wsConnImplPtr); - wsConnImplPtr->setController(ctrlPtr); - ctrlPtr->handleNewConnection(req, wsConnPtr); - return; - }); + if (!filtersName.empty()) + { + auto callbackPtr = std::make_shared>(std::move(callback)); + _appImpl.doFilters(filtersName, req, callbackPtr, false, nullptr, [=]() mutable { + doControllerHandler(ctrlPtr, wsKey, req, *callbackPtr, wsConnPtr); + }); + } + else + { + doControllerHandler(ctrlPtr, wsKey, req, callback, wsConnPtr); + } return; } } auto resp = drogon::HttpResponse::newNotFoundResponse(); resp->setCloseConnection(true); callback(resp); +} + +void WebsocketControllersRouter::doControllerHandler(const WebSocketControllerBasePtr &ctrlPtr, + std::string &wsKey, + const HttpRequestImplPtr &req, + const std::function &callback, + const WebSocketConnectionPtr &wsConnPtr) +{ + wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + unsigned char accKey[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(wsKey.c_str()), wsKey.length(), accKey); + auto base64Key = base64Encode(accKey, SHA_DIGEST_LENGTH); + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(HttpResponse::k101SwitchingProtocols); + resp->addHeader("Upgrade", "websocket"); + resp->addHeader("Connection", "Upgrade"); + resp->addHeader("Sec-WebSocket-Accept", base64Key); + callback(resp); + auto wsConnImplPtr = std::dynamic_pointer_cast(wsConnPtr); + assert(wsConnImplPtr); + wsConnImplPtr->setController(ctrlPtr); + ctrlPtr->handleNewConnection(req, wsConnPtr); + return; } \ No newline at end of file diff --git a/lib/src/WebsocketControllersRouter.h b/lib/src/WebsocketControllersRouter.h index 7dc21694..1d955aaa 100644 --- a/lib/src/WebsocketControllersRouter.h +++ b/lib/src/WebsocketControllersRouter.h @@ -34,7 +34,7 @@ class WebsocketControllersRouter : public trantor::NonCopyable const std::string &ctrlName, const std::vector &filters); void route(const HttpRequestImplPtr &req, - const std::function &callback, + std::function &&callback, const WebSocketConnectionPtr &wsConnPtr); private: @@ -46,5 +46,11 @@ class WebsocketControllersRouter : public trantor::NonCopyable }; std::unordered_map _websockCtrlMap; std::mutex _websockCtrlMutex; + + void doControllerHandler(const WebSocketControllerBasePtr &ctrlPtr, + std::string &wsKey, + const HttpRequestImplPtr &req, + const std::function &callback, + const WebSocketConnectionPtr &wsConnPtr); }; } // namespace drogon \ No newline at end of file