Merge pull request #31 from an-tao/dev

Optimize routing
This commit is contained in:
An Tao 2019-01-19 01:59:49 +08:00 committed by GitHub
commit 5ae35abc5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 311 additions and 229 deletions

View File

@ -10,7 +10,7 @@ class ApiTest : public drogon::HttpController<ApiTest>
public: public:
METHOD_LIST_BEGIN METHOD_LIST_BEGIN
//use METHOD_ADD to add your custom processing function here; //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::rootPost, "", Post);
METHOD_ADD(ApiTest::get, "/get/{2}/{1}", Get); //path will be /api/v1/apitest/get/{arg2}/{arg1} 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 METHOD_ADD(ApiTest::your_method_name, "/{1}/List?P2={2}", Get); //path will be /api/v1/apitest/{arg1}/list

View File

@ -3,7 +3,7 @@
GIT_VER=$(git log|grep ^commit|wc -l|sed -e "s/^ *//") GIT_VER=$(git log|grep ^commit|wc -l|sed -e "s/^ *//")
MD5=$(git log|head -1|awk '{printf $2}') MD5=$(git log|head -1|awk '{printf $2}')
TMP_FILE=/tmp/version 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} echo "#define VERSION_MD5 \"$MD5\"" >> ${TMP_FILE}
if [ ! -f $1 ];then if [ ! -f $1 ];then
mv -f ${TMP_FILE} $1 mv -f ${TMP_FILE} $1

View File

@ -379,19 +379,24 @@ void HttpAppFrameworkImpl::run()
void HttpAppFrameworkImpl::doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> &chain, void HttpAppFrameworkImpl::doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> &chain,
const HttpRequestImplPtr &req, const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id, const std::shared_ptr<std::string> &sessionIdPtr,
const std::function<void()> &missCallback) std::function<void()> &&missCallback)
{ {
if (chain && chain->size() > 0) if (chain && chain->size() > 0)
{ {
auto filter = chain->front(); auto filter = chain->front();
chain->pop(); chain->pop();
filter->doFilter(req, [=](HttpResponsePtr res) { filter->doFilter(req,
[=](HttpResponsePtr res) {
if (needSetJsessionid) if (needSetJsessionid)
res->addCookie("JSESSIONID", session_id); res->addCookie("JSESSIONID", *sessionIdPtr);
callback(res); }, [=]() { doFilterChain(chain, req, callback, needSetJsessionid, session_id, missCallback); }); (*callbackPtr)(res);
},
[=, missCallback = std::move(missCallback)]() mutable {
doFilterChain(chain, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
});
} }
else else
{ {
@ -400,10 +405,10 @@ void HttpAppFrameworkImpl::doFilterChain(const std::shared_ptr<std::queue<std::s
} }
void HttpAppFrameworkImpl::doFilters(const std::vector<std::string> &filters, void HttpAppFrameworkImpl::doFilters(const std::vector<std::string> &filters,
const HttpRequestImplPtr &req, const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id, const std::shared_ptr<std::string> &sessionIdPtr,
const std::function<void()> &missCallback) std::function<void()> &&missCallback)
{ {
std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> filterPtrs; std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> filterPtrs;
if (!filters.empty()) if (!filters.empty())
@ -421,7 +426,7 @@ void HttpAppFrameworkImpl::doFilters(const std::vector<std::string> &filters,
} }
} }
} }
doFilterChain(filterPtrs, req, callback, needSetJsessionid, session_id, missCallback); doFilterChain(filterPtrs, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
} }
void HttpAppFrameworkImpl::onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr) void HttpAppFrameworkImpl::onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr)
{ {
@ -575,12 +580,12 @@ void HttpAppFrameworkImpl::setUploadPath(const std::string &uploadPath)
} }
} }
void HttpAppFrameworkImpl::onNewWebsockRequest(const HttpRequestImplPtr &req, void HttpAppFrameworkImpl::onNewWebsockRequest(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
const WebSocketConnectionPtr &wsConnPtr) const WebSocketConnectionPtr &wsConnPtr)
{ {
_websockCtrlsRouter.route(req, callback, wsConnPtr); _websockCtrlsRouter.route(req, std::move(callback), wsConnPtr);
} }
void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const std::function<void(const HttpResponsePtr &)> &callback) void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
{ {
LOG_TRACE << "new request:" << req->peerAddr().toIpPort() << "->" << req->localAddr().toIpPort(); LOG_TRACE << "new request:" << req->peerAddr().toIpPort() << "->" << req->localAddr().toIpPort();
LOG_TRACE << "Headers " << req->methodString() << " " << req->path(); LOG_TRACE << "Headers " << req->methodString() << " " << req->path();
@ -624,7 +629,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s
(std::dynamic_pointer_cast<HttpRequestImpl>(req))->setSession((*_sessionMapPtr)[session_id]); (std::dynamic_pointer_cast<HttpRequestImpl>(req))->setSession((*_sessionMapPtr)[session_id]);
} }
std::string path = req->path(); const std::string &path = req->path();
auto pos = path.rfind("."); auto pos = path.rfind(".");
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
@ -775,11 +780,8 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s
} }
} }
//find simple controller //Route to controller
if (_httpSimpleCtrlsRouter.route(req, callback, needSetJsessionid, session_id)) _httpSimpleCtrlsRouter.route(req, std::move(callback), needSetJsessionid, std::move(session_id));
return;
//Find http controller
_httpCtrlsRouter.route(req, callback, needSetJsessionid, session_id);
} }
void HttpAppFrameworkImpl::readSendFile(const std::string &filePath, const HttpRequestImplPtr &req, const HttpResponsePtr &resp) void HttpAppFrameworkImpl::readSendFile(const std::string &filePath, const HttpRequestImplPtr &req, const HttpResponsePtr &resp)

View File

@ -39,8 +39,8 @@ class HttpAppFrameworkImpl : public HttpAppFramework
{ {
public: public:
HttpAppFrameworkImpl() HttpAppFrameworkImpl()
: _httpSimpleCtrlsRouter(*this), : _httpCtrlsRouter(*this),
_httpCtrlsRouter(*this), _httpSimpleCtrlsRouter(*this, _httpCtrlsRouter),
_websockCtrlsRouter(*this), _websockCtrlsRouter(*this),
_uploadPath(_rootPath + "uploads"), _uploadPath(_rootPath + "uploads"),
_connectionNum(0) _connectionNum(0)
@ -118,19 +118,19 @@ class HttpAppFrameworkImpl : public HttpAppFramework
#endif #endif
void doFilters(const std::vector<std::string> &filters, void doFilters(const std::vector<std::string> &filters,
const HttpRequestImplPtr &req, const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id, const std::shared_ptr<std::string> &sessionIdPtr,
const std::function<void()> &missCallback); std::function<void()> &&missCallback);
private: private:
virtual void registerHttpController(const std::string &pathPattern, virtual void registerHttpController(const std::string &pathPattern,
const internal::HttpBinderBasePtr &binder, const internal::HttpBinderBasePtr &binder,
const std::vector<HttpMethod> &validMethods = std::vector<HttpMethod>(), const std::vector<HttpMethod> &validMethods = std::vector<HttpMethod>(),
const std::vector<std::string> &filters = std::vector<std::string>()) override; const std::vector<std::string> &filters = std::vector<std::string>()) override;
void onAsyncRequest(const HttpRequestImplPtr &req, const std::function<void(const HttpResponsePtr &)> &callback); void onAsyncRequest(const HttpRequestImplPtr &req, std::function<void(const HttpResponsePtr &)> &&callback);
void onNewWebsockRequest(const HttpRequestImplPtr &req, void onNewWebsockRequest(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
const WebSocketConnectionPtr &wsConnPtr); const WebSocketConnectionPtr &wsConnPtr);
void onWebsockMessage(const WebSocketConnectionPtr &wsConnPtr, trantor::MsgBuffer *buffer); void onWebsockMessage(const WebSocketConnectionPtr &wsConnPtr, trantor::MsgBuffer *buffer);
void onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr); void onWebsockDisconnect(const WebSocketConnectionPtr &wsConnPtr);
@ -142,10 +142,10 @@ class HttpAppFrameworkImpl : public HttpAppFramework
const std::vector<std::string> &filters); const std::vector<std::string> &filters);
void doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> &chain, void doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> &chain,
const HttpRequestImplPtr &req, const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id, const std::shared_ptr<std::string> &sessionIdPtr,
const std::function<void()> &missCallback); std::function<void()> &&missCallback);
//We use a uuid string as session id; //We use a uuid string as session id;
//set _sessionTimeout=0 to make location session valid forever based on cookies; //set _sessionTimeout=0 to make location session valid forever based on cookies;
@ -157,8 +157,9 @@ class HttpAppFrameworkImpl : public HttpAppFramework
std::unique_ptr<CacheMap<std::string, SessionPtr>> _sessionMapPtr; std::unique_ptr<CacheMap<std::string, SessionPtr>> _sessionMapPtr;
std::unique_ptr<CacheMap<std::string, HttpResponsePtr>> _responseCachingMap; std::unique_ptr<CacheMap<std::string, HttpResponsePtr>> _responseCachingMap;
HttpSimpleControllersRouter _httpSimpleCtrlsRouter;
HttpControllersRouter _httpCtrlsRouter; HttpControllersRouter _httpCtrlsRouter;
HttpSimpleControllersRouter _httpSimpleCtrlsRouter;
WebsocketControllersRouter _websockCtrlsRouter; WebsocketControllersRouter _websockCtrlsRouter;
bool _enableLastModify = true; bool _enableLastModify = true;

View File

@ -138,9 +138,9 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
} }
void HttpControllersRouter::route(const HttpRequestImplPtr &req, void HttpControllersRouter::route(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id) std::string &&session_id)
{ {
//find http controller //find http controller
if (_ctrlRegex.mark_count() > 0) if (_ctrlRegex.mark_count() > 0)
@ -156,10 +156,10 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
if (result[i].str() == req->path() && i <= _ctrlVector.size()) if (result[i].str() == req->path() && i <= _ctrlVector.size())
{ {
size_t ctlIndex = i - 1; size_t ctlIndex = i - 1;
auto &router = _ctrlVector[ctlIndex]; auto &routerItem = _ctrlVector[ctlIndex];
//LOG_TRACE << "got http access,regex=" << binder.pathParameterPattern; //LOG_TRACE << "got http access,regex=" << binder.pathParameterPattern;
assert(Invalid > req->method()); assert(Invalid > req->method());
auto &binder = router._binders[req->method()]; auto &binder = routerItem._binders[req->method()];
if (!binder) if (!binder)
{ {
//Invalid Http Method //Invalid Http Method
@ -170,11 +170,51 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
} }
auto &filters = binder->filtersName; auto &filters = binder->filtersName;
_appImpl.doFilters(filters, req, callback, needSetJsessionid, session_id, [=]() { if (!filters.empty())
{
auto sessionIdPtr = std::make_shared<std::string>(std::move(session_id));
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
_appImpl.doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=]() {
doControllerHandler(binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
else
{
doControllerHandler(binder, routerItem, req, std::move(callback), needSetJsessionid, std::move(session_id));
}
}
}
}
else
{
//No controller found
auto res = drogon::HttpResponse::newNotFoundResponse();
if (needSetJsessionid)
res->addCookie("JSESSIONID", session_id);
callback(res);
}
}
else
{
//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<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid,
std::string &&session_id)
{
HttpResponsePtr responsePtr; HttpResponsePtr responsePtr;
{ {
std::lock_guard<std::mutex> guard(*(binder->binderMtx)); std::lock_guard<std::mutex> guard(*(ctrlBinderPtr->binderMtx));
responsePtr = binder->responsePtr; responsePtr = ctrlBinderPtr->responsePtr;
} }
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->createDate().after(responsePtr->expiredTime())))) if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->createDate().after(responsePtr->expiredTime()))))
@ -195,28 +235,28 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
return; return;
} }
std::vector<std::string> params(binder->parameterPlaces.size()); std::vector<std::string> params(ctrlBinderPtr->parameterPlaces.size());
std::smatch r; std::smatch r;
if (std::regex_match(req->path(), r, router._regex)) if (std::regex_match(req->path(), r, routerItem._regex))
{ {
for (size_t j = 1; j < r.size(); j++) for (size_t j = 1; j < r.size(); j++)
{ {
size_t place = binder->parameterPlaces[j - 1]; size_t place = ctrlBinderPtr->parameterPlaces[j - 1];
if (place > params.size()) if (place > params.size())
params.resize(place); params.resize(place);
params[place - 1] = r[j].str(); params[place - 1] = r[j].str();
LOG_TRACE << "place=" << place << " para:" << params[place - 1]; LOG_TRACE << "place=" << place << " para:" << params[place - 1];
} }
} }
if (binder->queryParametersPlaces.size() > 0) if (ctrlBinderPtr->queryParametersPlaces.size() > 0)
{ {
auto qureyPara = req->getParameters(); auto qureyPara = req->getParameters();
for (auto parameter : qureyPara) for (auto parameter : qureyPara)
{ {
if (binder->queryParametersPlaces.find(parameter.first) != if (ctrlBinderPtr->queryParametersPlaces.find(parameter.first) !=
binder->queryParametersPlaces.end()) ctrlBinderPtr->queryParametersPlaces.end())
{ {
auto place = binder->queryParametersPlaces.find(parameter.first)->second; auto place = ctrlBinderPtr->queryParametersPlaces.find(parameter.first)->second;
if (place > params.size()) if (place > params.size())
params.resize(place); params.resize(place);
params[place - 1] = parameter.second; params[place - 1] = parameter.second;
@ -230,7 +270,7 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
paraList.push_back(std::move(p)); paraList.push_back(std::move(p));
} }
binder->binderPtr->handleHttpRequest(paraList, req, [=](const HttpResponsePtr &resp) { 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; LOG_TRACE << "http resp:needSetJsessionid=" << needSetJsessionid << ";JSESSIONID=" << session_id;
auto newResp = resp; auto newResp = resp;
if (resp->expiredTime() >= 0) if (resp->expiredTime() >= 0)
@ -238,42 +278,21 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
//cache the response; //cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString(); std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
{ {
std::lock_guard<std::mutex> guard(*(binder->binderMtx)); std::lock_guard<std::mutex> guard(*(ctrlBinderPtr->binderMtx));
binder->responsePtr = resp; ctrlBinderPtr->responsePtr = resp;
} }
} }
if (needSetJsessionid) if (needSetJsessionid)
{
if (resp->expiredTime() >= 0)
{ {
//make a copy //make a copy
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp)); newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp));
newResp->setExpiredTime(-1); //make it temporary newResp->setExpiredTime(-1); //make it temporary
}
newResp->addCookie("JSESSIONID", session_id); newResp->addCookie("JSESSIONID", session_id);
} }
callback(newResp); callback(newResp);
}); });
return; return;
});
}
}
}
else
{
//No controller found
auto res = drogon::HttpResponse::newNotFoundResponse();
if (needSetJsessionid)
res->addCookie("JSESSIONID", session_id);
callback(res);
}
}
else
{
//No controller found
auto res = drogon::HttpResponse::newNotFoundResponse();
if (needSetJsessionid)
res->addCookie("JSESSIONID", session_id);
callback(res);
}
} }

View File

@ -36,9 +36,9 @@ class HttpControllersRouter : public trantor::NonCopyable
const std::vector<HttpMethod> &validMethods, const std::vector<HttpMethod> &validMethods,
const std::vector<std::string> &filters); const std::vector<std::string> &filters);
void route(const HttpRequestImplPtr &req, void route(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id); std::string &&session_id);
private: private:
struct CtrlBinder struct CtrlBinder
@ -61,5 +61,12 @@ class HttpControllersRouter : public trantor::NonCopyable
std::mutex _ctrlMutex; std::mutex _ctrlMutex;
std::regex _ctrlRegex; std::regex _ctrlRegex;
HttpAppFrameworkImpl &_appImpl; HttpAppFrameworkImpl &_appImpl;
void doControllerHandler(const CtrlBinderPtr &ctrlBinderPtr,
const HttpControllerRouterItem &routerItem,
const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid,
std::string &&session_id);
}; };
} // namespace drogon } // namespace drogon

View File

@ -26,7 +26,7 @@ using namespace std::placeholders;
using namespace drogon; using namespace drogon;
using namespace trantor; using namespace trantor;
static void defaultHttpAsyncCallback(const HttpRequestPtr &, const std::function<void(const HttpResponsePtr &resp)> &callback) static void defaultHttpAsyncCallback(const HttpRequestPtr &, std::function<void(const HttpResponsePtr &resp)> &&callback)
{ {
auto resp = HttpResponse::newNotFoundResponse(); auto resp = HttpResponse::newNotFoundResponse();
resp->setCloseConnection(true); resp->setCloseConnection(true);
@ -34,7 +34,7 @@ static void defaultHttpAsyncCallback(const HttpRequestPtr &, const std::function
} }
static void defaultWebSockAsyncCallback(const HttpRequestPtr &, static void defaultWebSockAsyncCallback(const HttpRequestPtr &,
const std::function<void(const HttpResponsePtr &resp)> &callback, std::function<void(const HttpResponsePtr &resp)> &&callback,
const WebSocketConnectionPtr &wsConnPtr) const WebSocketConnectionPtr &wsConnPtr)
{ {
auto resp = HttpResponse::newNotFoundResponse(); auto resp = HttpResponse::newNotFoundResponse();

View File

@ -32,9 +32,9 @@ typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
class HttpServer : trantor::NonCopyable class HttpServer : trantor::NonCopyable
{ {
public: public:
typedef std::function<void(const HttpRequestImplPtr &, const std::function<void(const HttpResponsePtr &)> &)> HttpAsyncCallback; typedef std::function<void(const HttpRequestImplPtr &, std::function<void(const HttpResponsePtr &)> &&)> HttpAsyncCallback;
typedef std::function<void(const HttpRequestImplPtr &, typedef std::function<void(const HttpRequestImplPtr &,
const std::function<void(const HttpResponsePtr &)> &, std::function<void(const HttpResponsePtr &)> &&,
const WebSocketConnectionPtr &)> const WebSocketConnectionPtr &)>
WebSocketNewAsyncCallback; WebSocketNewAsyncCallback;
typedef std::function<void(const WebSocketConnectionPtr &)> typedef std::function<void(const WebSocketConnectionPtr &)>

View File

@ -64,18 +64,18 @@ void HttpSimpleControllersRouter::registerHttpSimpleController(const std::string
} }
} }
bool HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req, void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id) std::string &&session_id)
{ {
std::string pathLower(req->path()); std::string pathLower(req->path().length(), 0);
std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), tolower); std::transform(req->path().begin(), req->path().end(), pathLower.begin(), tolower);
if (_simpCtrlMap.find(pathLower) != _simpCtrlMap.end()) if (_simpCtrlMap.find(pathLower) != _simpCtrlMap.end())
{ {
auto &ctrlInfo = _simpCtrlMap[pathLower]; auto &ctrlInfo = _simpCtrlMap[pathLower];
if (ctrlInfo._validMethodsFlags.size() > 0) if (!ctrlInfo._validMethodsFlags.empty())
{ {
assert(ctrlInfo._validMethodsFlags.size() > req->method()); assert(ctrlInfo._validMethodsFlags.size() > req->method());
if (ctrlInfo._validMethodsFlags[req->method()] == 0) if (ctrlInfo._validMethodsFlags[req->method()] == 0)
@ -84,11 +84,33 @@ bool HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
auto res = drogon::HttpResponse::newHttpResponse(); auto res = drogon::HttpResponse::newHttpResponse();
res->setStatusCode(HttpResponse::k405MethodNotAllowed); res->setStatusCode(HttpResponse::k405MethodNotAllowed);
callback(res); callback(res);
return true; return;
} }
} }
auto &filters = ctrlInfo.filtersName; auto &filters = ctrlInfo.filtersName;
_appImpl.doFilters(filters, req, callback, needSetJsessionid, session_id, [=]() { if (!filters.empty())
{
auto sessionIdPtr = std::make_shared<std::string>(std::move(session_id));
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(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));
}
void HttpSimpleControllersRouter::doControllerHandler(std::string &&pathLower,
const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid,
std::string &&session_id)
{
auto &ctrlItem = _simpCtrlMap[pathLower]; auto &ctrlItem = _simpCtrlMap[pathLower];
const std::string &ctrlName = ctrlItem.controllerName; const std::string &ctrlName = ctrlItem.controllerName;
std::shared_ptr<HttpSimpleControllerBase> controller; std::shared_ptr<HttpSimpleControllerBase> controller;
@ -126,7 +148,7 @@ bool HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
} }
else else
{ {
controller->asyncHandleHttpRequest(req, [=](const HttpResponsePtr &resp) { controller->asyncHandleHttpRequest(req, [=, callback = std::move(callback), pathLower = std::move(pathLower), session_id = std::move(session_id)](const HttpResponsePtr &resp) {
auto newResp = resp; auto newResp = resp;
if (resp->expiredTime() >= 0) if (resp->expiredTime() >= 0)
{ {
@ -139,13 +161,15 @@ bool HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
} }
} }
if (needSetJsessionid) if (needSetJsessionid)
{
if (resp->expiredTime() >= 0)
{ {
//make a copy //make a copy
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp)); newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp));
newResp->setExpiredTime(-1); //make it temporary newResp->setExpiredTime(-1); //make it temporary
}
newResp->addCookie("JSESSIONID", session_id); newResp->addCookie("JSESSIONID", session_id);
} }
callback(newResp); callback(newResp);
}); });
} }
@ -161,8 +185,4 @@ bool HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
callback(res); callback(res);
} }
});
return true;
}
return false;
} }

View File

@ -27,20 +27,24 @@
namespace drogon namespace drogon
{ {
class HttpAppFrameworkImpl; class HttpAppFrameworkImpl;
class HttpControllersRouter;
class HttpSimpleControllersRouter : public trantor::NonCopyable class HttpSimpleControllersRouter : public trantor::NonCopyable
{ {
public: public:
HttpSimpleControllersRouter(HttpAppFrameworkImpl &app) : _appImpl(app) {} HttpSimpleControllersRouter(HttpAppFrameworkImpl &app, HttpControllersRouter &httpCtrlRouter)
: _appImpl(app),
_httpCtrlsRouter(httpCtrlRouter) {}
void registerHttpSimpleController(const std::string &pathName, void registerHttpSimpleController(const std::string &pathName,
const std::string &ctrlName, const std::string &ctrlName,
const std::vector<any> &filtersAndMethods); const std::vector<any> &filtersAndMethods);
bool route(const HttpRequestImplPtr &req, void route(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid, bool needSetJsessionid,
const std::string &session_id); std::string &&session_id);
private: private:
HttpAppFrameworkImpl &_appImpl; HttpAppFrameworkImpl &_appImpl;
HttpControllersRouter &_httpCtrlsRouter;
struct SimpleControllerRouterItem struct SimpleControllerRouterItem
{ {
std::string controllerName; std::string controllerName;
@ -52,5 +56,11 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
}; };
std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap; std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap;
std::mutex _simpCtrlMutex; std::mutex _simpCtrlMutex;
void doControllerHandler(std::string &&pathLower,
const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
bool needSetJsessionid,
std::string &&session_id);
}; };
} // namespace drogon } // namespace drogon

View File

@ -39,7 +39,7 @@ void WebsocketControllersRouter::registerWebSocketController(const std::string &
} }
void WebsocketControllersRouter::route(const HttpRequestImplPtr &req, void WebsocketControllersRouter::route(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
const WebSocketConnectionPtr &wsConnPtr) const WebSocketConnectionPtr &wsConnPtr)
{ {
std::string wsKey = req->getHeaderBy("sec-websocket-key"); std::string wsKey = req->getHeaderBy("sec-websocket-key");
@ -60,7 +60,31 @@ void WebsocketControllersRouter::route(const HttpRequestImplPtr &req,
} }
if (ctrlPtr) if (ctrlPtr)
{ {
_appImpl.doFilters(filtersName, req, callback, false, "", [=]() mutable { if (!filtersName.empty())
{
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(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<void(const HttpResponsePtr &)> &callback,
const WebSocketConnectionPtr &wsConnPtr)
{
wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
unsigned char accKey[SHA_DIGEST_LENGTH]; unsigned char accKey[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const unsigned char *>(wsKey.c_str()), wsKey.length(), accKey); SHA1(reinterpret_cast<const unsigned char *>(wsKey.c_str()), wsKey.length(), accKey);
@ -76,11 +100,4 @@ void WebsocketControllersRouter::route(const HttpRequestImplPtr &req,
wsConnImplPtr->setController(ctrlPtr); wsConnImplPtr->setController(ctrlPtr);
ctrlPtr->handleNewConnection(req, wsConnPtr); ctrlPtr->handleNewConnection(req, wsConnPtr);
return; return;
});
return;
}
}
auto resp = drogon::HttpResponse::newNotFoundResponse();
resp->setCloseConnection(true);
callback(resp);
} }

View File

@ -34,7 +34,7 @@ class WebsocketControllersRouter : public trantor::NonCopyable
const std::string &ctrlName, const std::string &ctrlName,
const std::vector<std::string> &filters); const std::vector<std::string> &filters);
void route(const HttpRequestImplPtr &req, void route(const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback, std::function<void(const HttpResponsePtr &)> &&callback,
const WebSocketConnectionPtr &wsConnPtr); const WebSocketConnectionPtr &wsConnPtr);
private: private:
@ -46,5 +46,11 @@ class WebsocketControllersRouter : public trantor::NonCopyable
}; };
std::unordered_map<std::string, WebSocketControllerRouterItem> _websockCtrlMap; std::unordered_map<std::string, WebSocketControllerRouterItem> _websockCtrlMap;
std::mutex _websockCtrlMutex; std::mutex _websockCtrlMutex;
void doControllerHandler(const WebSocketControllerBasePtr &ctrlPtr,
std::string &wsKey,
const HttpRequestImplPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback,
const WebSocketConnectionPtr &wsConnPtr);
}; };
} // namespace drogon } // namespace drogon