diff --git a/examples/simple_example/api_v1_ApiTest.cc b/examples/simple_example/api_v1_ApiTest.cc index 41f1ab7b..8c204da6 100755 --- a/examples/simple_example/api_v1_ApiTest.cc +++ b/examples/simple_example/api_v1_ApiTest.cc @@ -1,6 +1,18 @@ #include "api_v1_ApiTest.h" using namespace api::v1; //add definition of your processing function here +void ApiTest::rootGet(const HttpRequestPtr &req, const std::function &callback) +{ + auto res = HttpResponse::newHttpResponse(); + res->setBody("ROOT Get!!!"); + callback(res); +} +void ApiTest::rootPost(const HttpRequestPtr &req, const std::function &callback) +{ + auto res = HttpResponse::newHttpResponse(); + res->setBody("ROOT Post!!!"); + callback(res); +} void ApiTest::get(const HttpRequestPtr &req, const std::function &callback, int p1, std::string &&p2) { HttpViewData data; diff --git a/examples/simple_example/api_v1_ApiTest.h b/examples/simple_example/api_v1_ApiTest.h index 6807ca8f..f0d5def0 100755 --- a/examples/simple_example/api_v1_ApiTest.h +++ b/examples/simple_example/api_v1_ApiTest.h @@ -10,7 +10,9 @@ class ApiTest : public drogon::HttpController public: METHOD_LIST_BEGIN //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::staticApi, "/static", Get, Post); METHOD_ADD(ApiTest::get2, "/get/{1}", Get); @@ -20,6 +22,8 @@ class ApiTest : public drogon::HttpController void your_method_name(const HttpRequestPtr &req, const std::function &callback, double p1, int p2) const; void staticApi(const HttpRequestPtr &req, const std::function &callback); void get2(const HttpRequestPtr &req, const std::function &callback, std::string &&p1); + void rootGet(const HttpRequestPtr &req, const std::function &callback); + void rootPost(const HttpRequestPtr &req, const std::function &callback); }; } // namespace v1 } // namespace api diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index 2a3d86a3..22f459b4 100755 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -112,11 +112,11 @@ void HttpAppFrameworkImpl::setFileTypes(const std::vector &types) void HttpAppFrameworkImpl::initRegex() { std::string regString; - for (auto &binder : _ctrlVector) + for (auto &router : _ctrlVector) { std::regex reg("\\(\\[\\^/\\]\\*\\)"); - std::string tmp = std::regex_replace(binder.pathParameterPattern, reg, "[^/]*"); - binder._regex = std::regex(binder.pathParameterPattern, std::regex_constants::icase); + std::string tmp = std::regex_replace(router.pathParameterPattern, reg, "[^/]*"); + router._regex = std::regex(router.pathParameterPattern, std::regex_constants::icase); regString.append("(").append(tmp).append(")|"); } if (regString.length() > 0) @@ -239,23 +239,52 @@ void HttpAppFrameworkImpl::addHttpPath(const std::string &path, paras = results.suffix(); } } - struct CtrlBinder _binder; - _binder.parameterPlaces = std::move(places); - _binder.queryParametersPlaces = std::move(parametersPlaces); - _binder.binderPtr = binder; - _binder.filtersName = filters; - _binder.pathParameterPattern = std::regex_replace(originPath, regex, "([^/]*)"); + auto pathParameterPattern = std::regex_replace(originPath, regex, "([^/]*)"); + auto binderInfo = CtrlBinderPtr(new CtrlBinder); + binderInfo->filtersName = filters; + binderInfo->binderPtr = binder; + binderInfo->parameterPlaces = std::move(places); + binderInfo->queryParametersPlaces = std::move(parametersPlaces); + { + std::lock_guard 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) { - _binder._validMethodsFlags.resize(Invalid, 0); 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 guard(_ctrlMutex); - _ctrlVector.push_back(std::move(_binder)); + _ctrlVector.push_back(std::move(router)); } } 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()) { size_t ctlIndex = i - 1; - auto &binder = _ctrlVector[ctlIndex]; + auto &router = _ctrlVector[ctlIndex]; //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()); - if (binder._validMethodsFlags[req->method()] == 0) - { - //Invalid Http Method - auto res = drogon::HttpResponse::newHttpResponse(); - res->setStatusCode(HttpResponse::k405MethodNotAllowed); - callback(res); - return; - } + //Invalid Http Method + auto res = drogon::HttpResponse::newHttpResponse(); + 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; { - std::lock_guard guard(*(binder.binderMtx)); - responsePtr = binder.responsePtr.lock(); + std::lock_guard guard(*(binder->binderMtx)); + responsePtr = binder->responsePtr.lock(); } if (responsePtr) { @@ -1103,28 +1129,28 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s return; } - std::vector params(binder.parameterPlaces.size()); + std::vector params(binder->parameterPlaces.size()); 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++) { - size_t place = binder.parameterPlaces[j - 1]; + 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) + if (binder->queryParametersPlaces.size() > 0) { auto qureyPara = req->getParameters(); for (auto parameter : qureyPara) { - if (binder.queryParametersPlaces.find(parameter.first) != - binder.queryParametersPlaces.end()) + if (binder->queryParametersPlaces.find(parameter.first) != + binder->queryParametersPlaces.end()) { - auto place = binder.queryParametersPlaces.find(parameter.first)->second; + auto place = binder->queryParametersPlaces.find(parameter.first)->second; if (place > params.size()) params.resize(place); params[place - 1] = parameter.second; @@ -1138,7 +1164,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s 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; auto newResp = resp; if (resp->expiredTime() >= 0) @@ -1147,9 +1173,9 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, const s std::dynamic_pointer_cast(resp)->makeHeaderString(); { auto &binderIterm = _ctrlVector[ctlIndex]; - std::lock_guard guard(*(binderIterm.binderMtx)); + std::lock_guard guard(*(binder->binderMtx)); _responseCacheMap->insert(binderIterm.pathParameterPattern, resp, resp->expiredTime()); - binderIterm.responsePtr = resp; + binder->responsePtr = resp; } } if (needSetJsessionid) diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index 456d0474..f0eb637d 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -152,7 +152,7 @@ class HttpAppFrameworkImpl : public HttpAppFramework const std::string &session_id, const std::function &missCallback); // - struct ControllerAndFiltersName + struct SimpleControllerRouterItem { std::string controllerName; std::vector filtersName; @@ -161,29 +161,33 @@ class HttpAppFrameworkImpl : public HttpAppFramework std::weak_ptr responsePtr; std::mutex _mutex; }; - std::unordered_map _simpCtrlMap; + std::unordered_map _simpCtrlMap; std::mutex _simpCtrlMutex; - struct WSCtrlAndFiltersName + struct WebSocketControllerRouterItem { WebSocketControllerBasePtr controller; std::vector filtersName; }; - std::unordered_map _websockCtrlMap; + std::unordered_map _websockCtrlMap; std::mutex _websockCtrlMutex; struct CtrlBinder { - std::string pathParameterPattern; - std::vector parameterPlaces; - std::map queryParametersPlaces; internal::HttpBinderBasePtr binderPtr; std::vector filtersName; + std::vector parameterPlaces; + std::map queryParametersPlaces; std::unique_ptr binderMtx = std::unique_ptr(new std::mutex); std::weak_ptr responsePtr; - std::vector _validMethodsFlags; - std::regex _regex; }; - std::vector _ctrlVector; + typedef std::shared_ptr CtrlBinderPtr; + struct HttpControllerRouterItem + { + std::string pathParameterPattern; + std::regex _regex; + CtrlBinderPtr _binders[Invalid]; //The enum value Invalid is the http methods number + }; + std::vector _ctrlVector; std::mutex _ctrlMutex; std::regex _ctrlRegex;