mirror of
https://github.com/drogonframework/drogon.git
synced 2025-09-22 00:00:33 -04:00
Add the OPTIONS method for CORS
This commit is contained in:
parent
2d9ca5ae5f
commit
d5e8bd0b73
@ -10,9 +10,9 @@ class TestController : public drogon::HttpSimpleController<TestController>
|
||||
PATH_LIST_BEGIN
|
||||
//list path definations here;
|
||||
//PATH_ADD("/path","filter1","filter2",...);
|
||||
PATH_ADD("/");
|
||||
PATH_ADD("/", Get);
|
||||
PATH_ADD("/Test", "nonFilter");
|
||||
PATH_ADD("/tpost", Post);
|
||||
PATH_ADD("/tpost", Post, Options);
|
||||
PATH_ADD("/slow", "TimeFilter", Get);
|
||||
PATH_LIST_END
|
||||
TestController()
|
||||
|
@ -9,5 +9,6 @@ class TestViewCtl : public drogon::HttpSimpleController<TestViewCtl>
|
||||
//list path definations here;
|
||||
//PATH_ADD("/path","filter1","filter2",...);
|
||||
PATH_ADD("/view");
|
||||
PATH_ADD("/", Post);
|
||||
PATH_LIST_END
|
||||
};
|
||||
|
@ -10,11 +10,12 @@ class ApiTest : public drogon::HttpController<ApiTest>
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
//use METHOD_ADD to add your custom processing function here;
|
||||
METHOD_ADD(ApiTest::rootGet, "", "TimeFilter", Get, "drogon::LocalHostFilter", "drogon::IntranetIpFilter");
|
||||
METHOD_ADD(ApiTest::rootPost, "", Post);
|
||||
METHOD_ADD(ApiTest::rootGet, "", "TimeFilter", Get, Options, "drogon::LocalHostFilter", "drogon::IntranetIpFilter");
|
||||
METHOD_ADD(ApiTest::rootPost, "", Post, Options);
|
||||
METHOD_ADD(ApiTest::get, "/get/{2}/{1}", Get); //path is /api/v1/apitest/get/{arg2}/{arg1}
|
||||
METHOD_ADD(ApiTest::your_method_name, "/{1}/List?P2={2}", Get); //path is /api/v1/apitest/{arg1}/list
|
||||
METHOD_ADD(ApiTest::staticApi, "/static", Get, Post);
|
||||
METHOD_ADD(ApiTest::staticApi, "/static", Get, Options); //CORS
|
||||
METHOD_ADD(ApiTest::staticApi, "/static", Post, Put, Delete);
|
||||
METHOD_ADD(ApiTest::get2, "/get/{1}", Get); //path is /api/v1/apitest/get/{arg1}
|
||||
ADD_METHOD_TO(ApiTest::get2, "/absolute/{1}", Get); //path is /absolute/{arg1}
|
||||
METHOD_ADD(ApiTest::jsonTest, "/json", Post);
|
||||
@ -29,6 +30,7 @@ class ApiTest : public drogon::HttpController<ApiTest>
|
||||
void rootPost(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||
void jsonTest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||
void formTest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||
|
||||
public:
|
||||
ApiTest()
|
||||
{
|
||||
|
@ -199,6 +199,130 @@ void doTest(const HttpClientPtr &client, std::promise<int> &pro, bool isHttps =
|
||||
}
|
||||
});
|
||||
|
||||
/// 4. Http OPTIONS Method
|
||||
req = HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Options);
|
||||
req->setPath("/tpost");
|
||||
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
|
||||
if (result == ReqResult::Ok)
|
||||
{
|
||||
//LOG_DEBUG << resp->getBody();
|
||||
auto allow = resp->getHeader("allow");
|
||||
if (resp->statusCode() == k200OK && allow.find("POST") != std::string::npos)
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
req = HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Options);
|
||||
req->setPath("/api/v1/apitest");
|
||||
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
|
||||
if (result == ReqResult::Ok)
|
||||
{
|
||||
//LOG_DEBUG << resp->getBody();
|
||||
auto allow = resp->getHeader("allow");
|
||||
if (resp->statusCode() == k200OK && allow == "OPTIONS,GET,HEAD,POST")
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
req = HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Options);
|
||||
req->setPath("/slow");
|
||||
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
|
||||
if (result == ReqResult::Ok)
|
||||
{
|
||||
if (resp->statusCode() == k403Forbidden)
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
req = HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Options);
|
||||
req->setPath("/*");
|
||||
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
|
||||
if (result == ReqResult::Ok)
|
||||
{
|
||||
//LOG_DEBUG << resp->getBody();
|
||||
auto allow = resp->getHeader("allow");
|
||||
if (resp->statusCode() == k200OK && allow == "GET,HEAD,POST,PUT,DELETE,OPTIONS")
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
req = HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Options);
|
||||
req->setPath("/api/v1/apitest/static");
|
||||
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
|
||||
if (result == ReqResult::Ok)
|
||||
{
|
||||
//LOG_DEBUG << resp->getBody();
|
||||
auto allow = resp->getHeader("allow");
|
||||
if (resp->statusCode() == k200OK && allow == "OPTIONS,GET,HEAD")
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
/// 4. Test HttpController
|
||||
req = HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Post);
|
||||
|
@ -106,6 +106,7 @@ enum HttpMethod
|
||||
Head,
|
||||
Put,
|
||||
Delete,
|
||||
Options,
|
||||
Invalid
|
||||
};
|
||||
|
||||
|
@ -526,7 +526,6 @@ void HttpAppFrameworkImpl::onConnection(const TcpConnectionPtr &conn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HttpAppFrameworkImpl::setUploadPath(const std::string &uploadPath)
|
||||
{
|
||||
assert(!uploadPath.empty());
|
||||
@ -555,24 +554,16 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
|
||||
{
|
||||
LOG_TRACE << "new request:" << req->peerAddr().toIpPort() << "->" << req->localAddr().toIpPort();
|
||||
LOG_TRACE << "Headers " << req->methodString() << " " << req->path();
|
||||
|
||||
#if 0
|
||||
const std::map<std::string, std::string>& headers = req->headers();
|
||||
for (std::map<std::string, std::string>::const_iterator it = headers.begin();
|
||||
it != headers.end();
|
||||
++it) {
|
||||
LOG_TRACE << it->first << ": " << it->second;
|
||||
}
|
||||
|
||||
LOG_TRACE<<"cookies:";
|
||||
auto cookies = req->cookies();
|
||||
for(auto it=cookies.begin();it!=cookies.end();++it)
|
||||
{
|
||||
LOG_TRACE<<it->first<<"="<<it->second;
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_TRACE << "http path=" << req->path();
|
||||
if (req->method() == Options && (req->path() == "*" || req->path() == "/*"))
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setContentTypeCode(ContentType::CT_TEXT_PLAIN);
|
||||
resp->addHeader("ALLOW", "GET,HEAD,POST,PUT,DELETE,OPTIONS");
|
||||
resp->setExpiredTime(0);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
// LOG_TRACE << "query: " << req->query() ;
|
||||
|
||||
std::string sessionId = req->getCookie("JSESSIONID");
|
||||
|
@ -101,7 +101,7 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
|
||||
}
|
||||
}
|
||||
auto pathParameterPattern = std::regex_replace(originPath, regex, "([^/]*)");
|
||||
auto binderInfo = CtrlBinderPtr(new CtrlBinder);
|
||||
auto binderInfo = std::make_shared<CtrlBinder>();
|
||||
binderInfo->_filterNames = filters;
|
||||
binderInfo->_binderPtr = binder;
|
||||
binderInfo->_parameterPlaces = std::move(places);
|
||||
@ -117,10 +117,13 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
|
||||
for (auto const &method : validMethods)
|
||||
{
|
||||
router._binders[method] = binderInfo;
|
||||
if (method == Options)
|
||||
binderInfo->_isCORS = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
binderInfo->_isCORS = true;
|
||||
for (int i = 0; i < Invalid; i++)
|
||||
router._binders[i] = binderInfo;
|
||||
}
|
||||
@ -136,10 +139,13 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
|
||||
for (auto const &method : validMethods)
|
||||
{
|
||||
router._binders[method] = binderInfo;
|
||||
if (method == Options)
|
||||
binderInfo->_isCORS = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
binderInfo->_isCORS = true;
|
||||
for (int i = 0; i < Invalid; i++)
|
||||
router._binders[i] = binderInfo;
|
||||
}
|
||||
@ -176,7 +182,14 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
|
||||
{
|
||||
//Invalid Http Method
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(k405MethodNotAllowed);
|
||||
if (req->method() != Options)
|
||||
{
|
||||
res->setStatusCode(k405MethodNotAllowed);
|
||||
}
|
||||
else
|
||||
{
|
||||
res->setStatusCode(k403Forbidden);
|
||||
}
|
||||
callback(res);
|
||||
return;
|
||||
}
|
||||
@ -222,6 +235,33 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
|
||||
bool needSetJsessionid,
|
||||
std::string &&sessionId)
|
||||
{
|
||||
if (req->method() == Options)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setContentTypeCode(ContentType::CT_TEXT_PLAIN);
|
||||
std::string methods = "OPTIONS,";
|
||||
if (routerItem._binders[Get] && routerItem._binders[Get]->_isCORS)
|
||||
{
|
||||
methods.append("GET,HEAD,");
|
||||
}
|
||||
if (routerItem._binders[Post] && routerItem._binders[Post]->_isCORS)
|
||||
{
|
||||
methods.append("POST,");
|
||||
}
|
||||
if (routerItem._binders[Put] && routerItem._binders[Put]->_isCORS)
|
||||
{
|
||||
methods.append("PUT,");
|
||||
}
|
||||
if (routerItem._binders[Delete] && routerItem._binders[Delete]->_isCORS)
|
||||
{
|
||||
methods.append("DELETE,");
|
||||
}
|
||||
methods.resize(methods.length() - 1);
|
||||
resp->addHeader("ALLOW", methods);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpResponsePtr &responsePtr = ctrlBinderPtr->_responsePtrMap[req->getLoop()];
|
||||
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
|
||||
{
|
||||
@ -240,6 +280,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> params(ctrlBinderPtr->_parameterPlaces.size());
|
||||
std::smatch r;
|
||||
if (std::regex_match(req->path(), r, routerItem._regex))
|
||||
|
@ -51,6 +51,7 @@ class HttpControllersRouter : public trantor::NonCopyable
|
||||
std::vector<size_t> _parameterPlaces;
|
||||
std::map<std::string, size_t> _queryParametersPlaces;
|
||||
std::map<trantor::EventLoop *,std::shared_ptr<HttpResponse>> _responsePtrMap;
|
||||
bool _isCORS = false;
|
||||
};
|
||||
typedef std::shared_ptr<CtrlBinder> CtrlBinderPtr;
|
||||
struct HttpControllerRouterItem
|
||||
@ -58,7 +59,7 @@ class HttpControllersRouter : public trantor::NonCopyable
|
||||
std::string _pathParameterPattern;
|
||||
std::string _pathPattern;
|
||||
std::regex _regex;
|
||||
CtrlBinderPtr _binders[Invalid]; //The enum value Invalid is the http methods number
|
||||
CtrlBinderPtr _binders[Invalid]={nullptr}; //The enum value Invalid is the http methods number
|
||||
};
|
||||
std::vector<HttpControllerRouterItem> _ctrlVector;
|
||||
std::mutex _ctrlMutex;
|
||||
|
@ -113,6 +113,9 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
|
||||
case Delete:
|
||||
output->append("DELETE ");
|
||||
break;
|
||||
case Options:
|
||||
output->append("OPTIONS ");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -109,6 +109,16 @@ class HttpRequestImpl : public HttpRequest
|
||||
_method = Invalid;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (m == "OPTIONS")
|
||||
{
|
||||
_method = Options;
|
||||
}
|
||||
else
|
||||
{
|
||||
_method = Invalid;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_method = Invalid;
|
||||
break;
|
||||
@ -161,6 +171,9 @@ class HttpRequestImpl : public HttpRequest
|
||||
case Delete:
|
||||
result = "DELETE";
|
||||
break;
|
||||
case Options:
|
||||
result = "OPTIONS";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -384,7 +397,7 @@ class HttpRequestImpl : public HttpRequest
|
||||
|
||||
virtual const std::string &matchedPathPattern() const override
|
||||
{
|
||||
if(_matchedPathPattern.empty())
|
||||
if (_matchedPathPattern.empty())
|
||||
return _path;
|
||||
return _matchedPathPattern;
|
||||
}
|
||||
|
@ -118,8 +118,8 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_response->statusCode() == k101SwitchingProtocols &&
|
||||
_response->getHeaderBy("upgrade") == "websocket")
|
||||
if (_response->statusCode() == k204NoContent || (_response->statusCode() == k101SwitchingProtocols &&
|
||||
_response->getHeaderBy("upgrade") == "websocket"))
|
||||
{
|
||||
//The Websocket response may not have a content-length header.
|
||||
_state = HttpResponseParseState::kGotAll;
|
||||
|
@ -53,22 +53,30 @@ void HttpSimpleControllersRouter::registerHttpSimpleController(const std::string
|
||||
}
|
||||
auto &item = _simpCtrlMap[path];
|
||||
item._controllerName = ctrlName;
|
||||
item._filterNames = filters;
|
||||
item._validMethodsFlags.clear(); //There may be old data, first clear
|
||||
auto binder = std::make_shared<CtrlBinder>();
|
||||
binder->_filterNames = filters;
|
||||
auto &_object = DrClassMap::getSingleInstance(ctrlName);
|
||||
auto controller = std::dynamic_pointer_cast<HttpSimpleControllerBase>(_object);
|
||||
binder->_controller = controller;
|
||||
if (validMethods.size() > 0)
|
||||
{
|
||||
item._validMethodsFlags.resize(Invalid, 0);
|
||||
for (auto const &method : validMethods)
|
||||
{
|
||||
item._validMethodsFlags[method] = 1;
|
||||
item._binders[method] = binder;
|
||||
if (method == Options)
|
||||
{
|
||||
binder->_isCORS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto controller = item._controller;
|
||||
if (!controller)
|
||||
else
|
||||
{
|
||||
auto &_object = DrClassMap::getSingleInstance(ctrlName);
|
||||
controller = std::dynamic_pointer_cast<HttpSimpleControllerBase>(_object);
|
||||
item._controller = controller;
|
||||
//All HTTP methods are valid
|
||||
for (size_t i = 0; i < Invalid; i++)
|
||||
{
|
||||
item._binders[i] = binder;
|
||||
}
|
||||
binder->_isCORS = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,47 +91,77 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
|
||||
if (iter != _simpCtrlMap.end())
|
||||
{
|
||||
auto &ctrlInfo = iter->second;
|
||||
if (!ctrlInfo._validMethodsFlags.empty())
|
||||
auto &binder = ctrlInfo._binders[req->method()];
|
||||
if (!binder)
|
||||
{
|
||||
assert(ctrlInfo._validMethodsFlags.size() > req->method());
|
||||
if (ctrlInfo._validMethodsFlags[req->method()] == 0)
|
||||
//Invalid Http Method
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
if (req->method() != Options)
|
||||
{
|
||||
//Invalid Http Method
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(k405MethodNotAllowed);
|
||||
callback(res);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
res->setStatusCode(k403Forbidden);
|
||||
}
|
||||
callback(res);
|
||||
return;
|
||||
}
|
||||
auto &filters = ctrlInfo._filters;
|
||||
auto &filters = ctrlInfo._binders[req->method()]->_filters;
|
||||
if (!filters.empty())
|
||||
{
|
||||
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
|
||||
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
|
||||
FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &ctrlInfo]() mutable {
|
||||
doControllerHandler(ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
|
||||
FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder]() mutable {
|
||||
doControllerHandler(binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
doControllerHandler(ctrlInfo, req, std::move(callback), needSetJsessionid, std::move(sessionId));
|
||||
doControllerHandler(binder, ctrlInfo, req, std::move(callback), needSetJsessionid, std::move(sessionId));
|
||||
}
|
||||
return;
|
||||
}
|
||||
_httpCtrlsRouter.route(req, std::move(callback), needSetJsessionid, std::move(sessionId));
|
||||
}
|
||||
|
||||
void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem &item,
|
||||
void HttpSimpleControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const SimpleControllerRouterItem &routerItem,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
bool needSetJsessionid,
|
||||
std::string &&sessionId)
|
||||
{
|
||||
const std::string &ctrlName = item._controllerName;
|
||||
auto &controller = item._controller;
|
||||
auto &controller = ctrlBinderPtr->_controller;
|
||||
if (controller)
|
||||
{
|
||||
HttpResponsePtr &responsePtr = item._responsePtrMap[req->getLoop()];
|
||||
if (req->method() == Options)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setContentTypeCode(ContentType::CT_TEXT_PLAIN);
|
||||
std::string methods = "OPTIONS,";
|
||||
if (routerItem._binders[Get] && routerItem._binders[Get]->_isCORS)
|
||||
{
|
||||
methods.append("GET,HEAD,");
|
||||
}
|
||||
if (routerItem._binders[Post] && routerItem._binders[Post]->_isCORS)
|
||||
{
|
||||
methods.append("POST,");
|
||||
}
|
||||
if (routerItem._binders[Put] && routerItem._binders[Put]->_isCORS)
|
||||
{
|
||||
methods.append("PUT,");
|
||||
}
|
||||
if (routerItem._binders[Delete] && routerItem._binders[Delete]->_isCORS)
|
||||
{
|
||||
methods.append("DELETE,");
|
||||
}
|
||||
methods.resize(methods.length() - 1);
|
||||
resp->addHeader("ALLOW", methods);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
HttpResponsePtr &responsePtr = ctrlBinderPtr->_responsePtrMap[req->getLoop()];
|
||||
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
|
||||
{
|
||||
//use cached response!
|
||||
@ -142,7 +180,7 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
|
||||
}
|
||||
else
|
||||
{
|
||||
controller->asyncHandleHttpRequest(req, [=, callback = std::move(callback), &item, sessionId = std::move(sessionId)](const HttpResponsePtr &resp) {
|
||||
controller->asyncHandleHttpRequest(req, [=, callback = std::move(callback), &ctrlBinderPtr, sessionId = std::move(sessionId)](const HttpResponsePtr &resp) {
|
||||
auto newResp = resp;
|
||||
if (resp->expiredTime() >= 0)
|
||||
{
|
||||
@ -151,12 +189,12 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
|
||||
auto loop = req->getLoop();
|
||||
if (loop->isInLoopThread())
|
||||
{
|
||||
item._responsePtrMap[loop] = resp;
|
||||
ctrlBinderPtr->_responsePtrMap[loop] = resp;
|
||||
}
|
||||
else
|
||||
{
|
||||
loop->queueInLoop([loop, resp, &item]() {
|
||||
item._responsePtrMap[loop] = resp;
|
||||
loop->queueInLoop([loop, resp, &ctrlBinderPtr]() {
|
||||
ctrlBinderPtr->_responsePtrMap[loop] = resp;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -178,6 +216,7 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string &ctrlName = routerItem._controllerName;
|
||||
LOG_ERROR << "can't find controller " << ctrlName;
|
||||
auto res = drogon::HttpResponse::newNotFoundResponse();
|
||||
if (needSetJsessionid)
|
||||
@ -192,10 +231,17 @@ void HttpSimpleControllersRouter::init(const std::vector<trantor::EventLoop *> &
|
||||
for (auto &iter : _simpCtrlMap)
|
||||
{
|
||||
auto &item = iter.second;
|
||||
item._filters = FiltersFunction::createFilters(item._filterNames);
|
||||
for (auto ioloop : ioLoops)
|
||||
for (size_t i = 0; i < Invalid; i++)
|
||||
{
|
||||
item._responsePtrMap[ioloop] = std::shared_ptr<HttpResponse>();
|
||||
auto &binder = item._binders[i];
|
||||
if(binder)
|
||||
{
|
||||
binder->_filters = FiltersFunction::createFilters(binder->_filterNames);
|
||||
for (auto ioloop : ioLoops)
|
||||
{
|
||||
binder->_responsePtrMap[ioloop] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -34,38 +34,44 @@ class HttpAppFrameworkImpl;
|
||||
class HttpControllersRouter;
|
||||
class HttpSimpleControllersRouter : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit HttpSimpleControllersRouter(HttpControllersRouter &httpCtrlRouter)
|
||||
: _httpCtrlsRouter(httpCtrlRouter) {}
|
||||
void registerHttpSimpleController(const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<any> &filtersAndMethods);
|
||||
void route(const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
bool needSetJsessionid,
|
||||
std::string &&sessionId);
|
||||
void init(const std::vector<trantor::EventLoop *> &ioLoops);
|
||||
public:
|
||||
explicit HttpSimpleControllersRouter(HttpControllersRouter &httpCtrlRouter)
|
||||
: _httpCtrlsRouter(httpCtrlRouter) {}
|
||||
void registerHttpSimpleController(const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<any> &filtersAndMethods);
|
||||
void route(const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
bool needSetJsessionid,
|
||||
std::string &&sessionId);
|
||||
void init(const std::vector<trantor::EventLoop *> &ioLoops);
|
||||
|
||||
private:
|
||||
HttpControllersRouter &_httpCtrlsRouter;
|
||||
struct SimpleControllerRouterItem
|
||||
{
|
||||
std::string _controllerName;
|
||||
std::vector<std::string> _filterNames;
|
||||
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
|
||||
std::vector<int> _validMethodsFlags;
|
||||
std::shared_ptr<HttpSimpleControllerBase> _controller;
|
||||
std::map<trantor::EventLoop *, std::shared_ptr<HttpResponse>> _responsePtrMap;
|
||||
//std::atomic<bool> _mutex = ATOMIC_VAR_INIT(false);
|
||||
//std::atomic_flag _mutex = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap;
|
||||
std::mutex _simpCtrlMutex;
|
||||
private:
|
||||
HttpControllersRouter &_httpCtrlsRouter;
|
||||
|
||||
void doControllerHandler(SimpleControllerRouterItem &item,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
bool needSetJsessionid,
|
||||
std::string &&sessionId);
|
||||
struct CtrlBinder
|
||||
{
|
||||
std::shared_ptr<HttpSimpleControllerBase> _controller;
|
||||
std::vector<std::string> _filterNames;
|
||||
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
|
||||
std::map<trantor::EventLoop *, std::shared_ptr<HttpResponse>> _responsePtrMap;
|
||||
bool _isCORS = false;
|
||||
};
|
||||
typedef std::shared_ptr<CtrlBinder> CtrlBinderPtr;
|
||||
|
||||
struct SimpleControllerRouterItem
|
||||
{
|
||||
std::string _controllerName;
|
||||
CtrlBinderPtr _binders[Invalid] = {nullptr};
|
||||
};
|
||||
std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap;
|
||||
std::mutex _simpCtrlMutex;
|
||||
|
||||
void doControllerHandler(const CtrlBinderPtr &ctrlBinderPtr,
|
||||
const SimpleControllerRouterItem &routerItem,
|
||||
const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
bool needSetJsessionid,
|
||||
std::string &&sessionId);
|
||||
};
|
||||
} // namespace drogon
|
||||
|
Loading…
x
Reference in New Issue
Block a user