Modifying the routing algorithm of HTTP controllers
This commit is contained in:
parent
b05e56ff6b
commit
5c96c4e6a2
|
@ -1,6 +1,18 @@
|
||||||
#include "api_v1_ApiTest.h"
|
#include "api_v1_ApiTest.h"
|
||||||
using namespace api::v1;
|
using namespace api::v1;
|
||||||
//add definition of your processing function here
|
//add definition of your processing function here
|
||||||
|
void ApiTest::rootGet(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
|
||||||
|
{
|
||||||
|
auto res = HttpResponse::newHttpResponse();
|
||||||
|
res->setBody("ROOT Get!!!");
|
||||||
|
callback(res);
|
||||||
|
}
|
||||||
|
void ApiTest::rootPost(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
|
||||||
|
{
|
||||||
|
auto res = HttpResponse::newHttpResponse();
|
||||||
|
res->setBody("ROOT Post!!!");
|
||||||
|
callback(res);
|
||||||
|
}
|
||||||
void ApiTest::get(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, int p1, std::string &&p2)
|
void ApiTest::get(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, int p1, std::string &&p2)
|
||||||
{
|
{
|
||||||
HttpViewData data;
|
HttpViewData data;
|
||||||
|
|
|
@ -10,7 +10,9 @@ 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::get, "/get/{2}/{1}", Get); //path will be /api/v1/apitest/get/{arg2}/{arg1}
|
METHOD_ADD(ApiTest::rootGet, "", Get);
|
||||||
|
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
|
METHOD_ADD(ApiTest::your_method_name, "/{1}/List?P2={2}", Get); //path will be /api/v1/apitest/{arg1}/list
|
||||||
METHOD_ADD(ApiTest::staticApi, "/static", Get, Post);
|
METHOD_ADD(ApiTest::staticApi, "/static", Get, Post);
|
||||||
METHOD_ADD(ApiTest::get2, "/get/{1}", Get);
|
METHOD_ADD(ApiTest::get2, "/get/{1}", Get);
|
||||||
|
@ -20,6 +22,8 @@ class ApiTest : public drogon::HttpController<ApiTest>
|
||||||
void your_method_name(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, double p1, int p2) const;
|
void your_method_name(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, double p1, int p2) const;
|
||||||
void staticApi(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
void staticApi(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||||
void get2(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, std::string &&p1);
|
void get2(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, std::string &&p1);
|
||||||
|
void rootGet(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||||
|
void rootPost(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||||
};
|
};
|
||||||
} // namespace v1
|
} // namespace v1
|
||||||
} // namespace api
|
} // namespace api
|
||||||
|
|
|
@ -112,11 +112,11 @@ void HttpAppFrameworkImpl::setFileTypes(const std::vector<std::string> &types)
|
||||||
void HttpAppFrameworkImpl::initRegex()
|
void HttpAppFrameworkImpl::initRegex()
|
||||||
{
|
{
|
||||||
std::string regString;
|
std::string regString;
|
||||||
for (auto &binder : _ctrlVector)
|
for (auto &router : _ctrlVector)
|
||||||
{
|
{
|
||||||
std::regex reg("\\(\\[\\^/\\]\\*\\)");
|
std::regex reg("\\(\\[\\^/\\]\\*\\)");
|
||||||
std::string tmp = std::regex_replace(binder.pathParameterPattern, reg, "[^/]*");
|
std::string tmp = std::regex_replace(router.pathParameterPattern, reg, "[^/]*");
|
||||||
binder._regex = std::regex(binder.pathParameterPattern, std::regex_constants::icase);
|
router._regex = std::regex(router.pathParameterPattern, std::regex_constants::icase);
|
||||||
regString.append("(").append(tmp).append(")|");
|
regString.append("(").append(tmp).append(")|");
|
||||||
}
|
}
|
||||||
if (regString.length() > 0)
|
if (regString.length() > 0)
|
||||||
|
@ -239,23 +239,52 @@ void HttpAppFrameworkImpl::addHttpPath(const std::string &path,
|
||||||
paras = results.suffix();
|
paras = results.suffix();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct CtrlBinder _binder;
|
auto pathParameterPattern = std::regex_replace(originPath, regex, "([^/]*)");
|
||||||
_binder.parameterPlaces = std::move(places);
|
auto binderInfo = CtrlBinderPtr(new CtrlBinder);
|
||||||
_binder.queryParametersPlaces = std::move(parametersPlaces);
|
binderInfo->filtersName = filters;
|
||||||
_binder.binderPtr = binder;
|
binderInfo->binderPtr = binder;
|
||||||
_binder.filtersName = filters;
|
binderInfo->parameterPlaces = std::move(places);
|
||||||
_binder.pathParameterPattern = std::regex_replace(originPath, regex, "([^/]*)");
|
binderInfo->queryParametersPlaces = std::move(parametersPlaces);
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(_ctrlMutex);
|
||||||
|
for (auto &router : _ctrlVector)
|
||||||
|
{
|
||||||
|
if (router.pathParameterPattern == pathParameterPattern)
|
||||||
|
{
|
||||||
|
if (validMethods.size() > 0)
|
||||||
|
{
|
||||||
|
for (auto method : validMethods)
|
||||||
|
{
|
||||||
|
router._binders[method] = binderInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Invalid; i++)
|
||||||
|
router._binders[i] = binderInfo;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HttpControllerRouterItem router;
|
||||||
|
router.pathParameterPattern = pathParameterPattern;
|
||||||
if (validMethods.size() > 0)
|
if (validMethods.size() > 0)
|
||||||
{
|
{
|
||||||
_binder._validMethodsFlags.resize(Invalid, 0);
|
|
||||||
for (auto method : validMethods)
|
for (auto method : validMethods)
|
||||||
{
|
{
|
||||||
_binder._validMethodsFlags[method] = 1;
|
router._binders[method] = binderInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Invalid; i++)
|
||||||
|
router._binders[i] = binderInfo;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(_ctrlMutex);
|
std::lock_guard<std::mutex> guard(_ctrlMutex);
|
||||||
_ctrlVector.push_back(std::move(_binder));
|
_ctrlVector.push_back(std::move(router));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void HttpAppFrameworkImpl::registerHttpController(const std::string &pathPattern,
|
void HttpAppFrameworkImpl::registerHttpController(const std::string &pathPattern,
|
||||||
|
@ -1062,28 +1091,25 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s
|
||||||
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 &binder = _ctrlVector[ctlIndex];
|
auto &router = _ctrlVector[ctlIndex];
|
||||||
//LOG_TRACE << "got http access,regex=" << binder.pathParameterPattern;
|
//LOG_TRACE << "got http access,regex=" << binder.pathParameterPattern;
|
||||||
if (binder._validMethodsFlags.size() > 0)
|
assert(Invalid > req->method());
|
||||||
|
auto &binder = router._binders[req->method()];
|
||||||
|
if (!binder)
|
||||||
{
|
{
|
||||||
assert(binder._validMethodsFlags.size() > req->method());
|
//Invalid Http Method
|
||||||
if (binder._validMethodsFlags[req->method()] == 0)
|
auto res = drogon::HttpResponse::newHttpResponse();
|
||||||
{
|
res->setStatusCode(HttpResponse::k405MethodNotAllowed);
|
||||||
//Invalid Http Method
|
callback(res);
|
||||||
auto res = drogon::HttpResponse::newHttpResponse();
|
return;
|
||||||
res->setStatusCode(HttpResponse::k405MethodNotAllowed);
|
|
||||||
callback(res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
auto &filters = binder.filtersName;
|
|
||||||
doFilters(filters, req, callback, needSetJsessionid, session_id, [=]() {
|
|
||||||
auto &binder = _ctrlVector[ctlIndex];
|
|
||||||
|
|
||||||
|
auto &filters = binder->filtersName;
|
||||||
|
doFilters(filters, req, callback, needSetJsessionid, session_id, [=]() {
|
||||||
HttpResponsePtr responsePtr;
|
HttpResponsePtr responsePtr;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(*(binder.binderMtx));
|
std::lock_guard<std::mutex> guard(*(binder->binderMtx));
|
||||||
responsePtr = binder.responsePtr.lock();
|
responsePtr = binder->responsePtr.lock();
|
||||||
}
|
}
|
||||||
if (responsePtr)
|
if (responsePtr)
|
||||||
{
|
{
|
||||||
|
@ -1103,28 +1129,28 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> params(binder.parameterPlaces.size());
|
std::vector<std::string> params(binder->parameterPlaces.size());
|
||||||
std::smatch r;
|
std::smatch r;
|
||||||
if (std::regex_match(req->path(), r, binder._regex))
|
if (std::regex_match(req->path(), r, router._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 = binder->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 (binder->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 (binder->queryParametersPlaces.find(parameter.first) !=
|
||||||
binder.queryParametersPlaces.end())
|
binder->queryParametersPlaces.end())
|
||||||
{
|
{
|
||||||
auto place = binder.queryParametersPlaces.find(parameter.first)->second;
|
auto place = binder->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;
|
||||||
|
@ -1138,7 +1164,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s
|
||||||
paraList.push_back(std::move(p));
|
paraList.push_back(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
binder.binderPtr->handleHttpRequest(paraList, req, [=](const HttpResponsePtr &resp) {
|
binder->binderPtr->handleHttpRequest(paraList, req, [=](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)
|
||||||
|
@ -1147,9 +1173,9 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s
|
||||||
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
|
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
|
||||||
{
|
{
|
||||||
auto &binderIterm = _ctrlVector[ctlIndex];
|
auto &binderIterm = _ctrlVector[ctlIndex];
|
||||||
std::lock_guard<std::mutex> guard(*(binderIterm.binderMtx));
|
std::lock_guard<std::mutex> guard(*(binder->binderMtx));
|
||||||
_responseCacheMap->insert(binderIterm.pathParameterPattern, resp, resp->expiredTime());
|
_responseCacheMap->insert(binderIterm.pathParameterPattern, resp, resp->expiredTime());
|
||||||
binderIterm.responsePtr = resp;
|
binder->responsePtr = resp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needSetJsessionid)
|
if (needSetJsessionid)
|
||||||
|
|
|
@ -152,7 +152,7 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||||
const std::string &session_id,
|
const std::string &session_id,
|
||||||
const std::function<void()> &missCallback);
|
const std::function<void()> &missCallback);
|
||||||
//
|
//
|
||||||
struct ControllerAndFiltersName
|
struct SimpleControllerRouterItem
|
||||||
{
|
{
|
||||||
std::string controllerName;
|
std::string controllerName;
|
||||||
std::vector<std::string> filtersName;
|
std::vector<std::string> filtersName;
|
||||||
|
@ -161,29 +161,33 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||||
std::weak_ptr<HttpResponse> responsePtr;
|
std::weak_ptr<HttpResponse> responsePtr;
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
};
|
};
|
||||||
std::unordered_map<std::string, ControllerAndFiltersName> _simpCtrlMap;
|
std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap;
|
||||||
std::mutex _simpCtrlMutex;
|
std::mutex _simpCtrlMutex;
|
||||||
struct WSCtrlAndFiltersName
|
struct WebSocketControllerRouterItem
|
||||||
{
|
{
|
||||||
WebSocketControllerBasePtr controller;
|
WebSocketControllerBasePtr controller;
|
||||||
std::vector<std::string> filtersName;
|
std::vector<std::string> filtersName;
|
||||||
};
|
};
|
||||||
std::unordered_map<std::string, WSCtrlAndFiltersName> _websockCtrlMap;
|
std::unordered_map<std::string, WebSocketControllerRouterItem> _websockCtrlMap;
|
||||||
std::mutex _websockCtrlMutex;
|
std::mutex _websockCtrlMutex;
|
||||||
|
|
||||||
struct CtrlBinder
|
struct CtrlBinder
|
||||||
{
|
{
|
||||||
std::string pathParameterPattern;
|
|
||||||
std::vector<size_t> parameterPlaces;
|
|
||||||
std::map<std::string, size_t> queryParametersPlaces;
|
|
||||||
internal::HttpBinderBasePtr binderPtr;
|
internal::HttpBinderBasePtr binderPtr;
|
||||||
std::vector<std::string> filtersName;
|
std::vector<std::string> filtersName;
|
||||||
|
std::vector<size_t> parameterPlaces;
|
||||||
|
std::map<std::string, size_t> queryParametersPlaces;
|
||||||
std::unique_ptr<std::mutex> binderMtx = std::unique_ptr<std::mutex>(new std::mutex);
|
std::unique_ptr<std::mutex> binderMtx = std::unique_ptr<std::mutex>(new std::mutex);
|
||||||
std::weak_ptr<HttpResponse> responsePtr;
|
std::weak_ptr<HttpResponse> responsePtr;
|
||||||
std::vector<int> _validMethodsFlags;
|
|
||||||
std::regex _regex;
|
|
||||||
};
|
};
|
||||||
std::vector<CtrlBinder> _ctrlVector;
|
typedef std::shared_ptr<CtrlBinder> CtrlBinderPtr;
|
||||||
|
struct HttpControllerRouterItem
|
||||||
|
{
|
||||||
|
std::string pathParameterPattern;
|
||||||
|
std::regex _regex;
|
||||||
|
CtrlBinderPtr _binders[Invalid]; //The enum value Invalid is the http methods number
|
||||||
|
};
|
||||||
|
std::vector<HttpControllerRouterItem> _ctrlVector;
|
||||||
std::mutex _ctrlMutex;
|
std::mutex _ctrlMutex;
|
||||||
|
|
||||||
std::regex _ctrlRegex;
|
std::regex _ctrlRegex;
|
||||||
|
|
Loading…
Reference in New Issue