From: Aki Tuomi Date: Wed, 23 Aug 2023 17:13:11 +0000 (+0300) Subject: ext/yahttp: Move route matching to separate function X-Git-Tag: auth-4.9.0-alpha1~42^2~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a0281be936f92db399f92889e3015cf3b09aa975;p=thirdparty%2Fpdns.git ext/yahttp: Move route matching to separate function --- diff --git a/ext/yahttp/yahttp/router.cpp b/ext/yahttp/yahttp/router.cpp index 83465e318a..e123b38479 100644 --- a/ext/yahttp/yahttp/router.cpp +++ b/ext/yahttp/yahttp/router.cpp @@ -5,8 +5,6 @@ #include "router.hpp" namespace YaHTTP { - typedef funcptr::tuple TDelim; - // router is defined here. YaHTTP::Router Router::router; @@ -24,86 +22,103 @@ namespace YaHTTP { routes.push_back(funcptr::make_tuple(method2, url, handler, name)); }; - RoutingResult Router::route(Request *req, THandlerFunction& handler) { - std::map params; - int pos1,pos2; - bool matched = false; - bool seen = false; - std::string rname; - - // iterate routes - for(TRouteList::iterator i = routes.begin(); !matched && i != routes.end(); i++) { - int k1,k2,k3; - std::string pname; - std::string method, url; - funcptr::tie(method, url, handler, rname) = *i; - matched = false; - - // see if we can't match the url - params.clear(); - // simple matcher func - for(k1=0, k2=0; k1 < static_cast(url.size()) && k2 < static_cast(req->url.path.size()); ) { - if (url[k1] == '<') { - pos1 = k2; - k3 = k1+1; + bool Router::match(const std::string& route, const URL& requrl, std::map ¶ms) { + size_t rpos = 0; + size_t upos = 0; + size_t npos = 0; + size_t nstart = 0; + size_t nend = 0; + std::string pname; + for(; rpos < route.size() && upos < requrl.path.size(); ) { + if (route[rpos] == '<') { + nstart = upos; + npos = rpos+1; // start of parameter - while(k1 < static_cast(url.size()) && url[k1] != '>') k1++; - pname = std::string(url.begin()+k3, url.begin()+k1); + while(rpos < route.size() && route[rpos] != '>') { + rpos++; + } + pname = std::string(route.begin()+static_cast(npos), route.begin()+static_cast(rpos)); // then we also look it on the url - if (pname[0]=='*') { + if (pname[0] == '*') { pname = pname.substr(1); // this matches whatever comes after it, basically end of string - pos2 = req->url.path.size(); - matched = true; - if (pname != "") - params[pname] = funcptr::tie(pos1,pos2); - k1 = url.size(); - k2 = req->url.path.size(); + nend = requrl.path.size(); + if (!pname.empty()) { + params[pname] = funcptr::tie(nstart,nend); + } + rpos = route.size(); + upos = requrl.path.size(); break; } else { - // match until url[k1] - while(k2 < static_cast(req->url.path.size()) && req->url.path[k2] != url[k1+1]) k2++; - pos2 = k2; - params[pname] = funcptr::tie(pos1,pos2); + // match until url[upos] or next / if pattern is at end + while (upos < requrl.path.size()) { + if (route[rpos+1] == '\0' && requrl.path[upos] == '/') { + break; + } + if (requrl.path[upos] == route[rpos+1]) { + break; + } + upos++; + } + nend = upos; + params[pname] = funcptr::tie(nstart, nend); } - k2--; + upos--; } - else if (url[k1] != req->url.path[k2]) { + else if (route[rpos] != requrl.path[upos]) { break; } - k1++; k2++; + rpos++; upos++; } + return route[rpos] == requrl.path[upos]; + } - // ensure. - if (url[k1] != req->url.path[k2]) - matched = false; - else - matched = true; + RoutingResult Router::route(Request *req, THandlerFunction& handler) { + std::map params; + bool matched = false; + bool seen = false; + std::string rname; + + // iterate routes + for (auto& route: routes) { + std::string method; + std::string url; + funcptr::tie(method, url, handler, rname) = route; - if (matched && method.empty() == false && req->method != method) { + // see if we can't match the url + params.clear(); + // simple matcher func + matched = match(url, req->url, params); + + if (matched && !method.empty() && req->method != method) { // method did not match, record it though so we can return correct result matched = false; seen = true; continue; } + if (matched) { + break; + } } if (!matched) { - if (seen) + if (seen) { return RouteNoMethod; + } // no route return RouteNotFound; } req->parameters.clear(); - for(std::map::iterator i = params.begin(); i != params.end(); i++) { - int p1,p2; - funcptr::tie(p1,p2) = i->second; - std::string value(req->url.path.begin() + p1, req->url.path.begin() + p2); + for (const auto& param: params) { + int nstart = 0; + int nend = 0; + funcptr::tie(nstart, nend) = param.second; + std::string value(req->url.path.begin() + nstart, req->url.path.begin() + nend); value = Utility::decodeURL(value); - req->parameters[i->first] = std::move(value); + req->parameters[param.first] = std::move(value); } req->routeName = std::move(rname); diff --git a/ext/yahttp/yahttp/router.hpp b/ext/yahttp/yahttp/router.hpp index 0261bd4cd5..c9332078d0 100644 --- a/ext/yahttp/yahttp/router.hpp +++ b/ext/yahttp/yahttp/router.hpp @@ -34,6 +34,7 @@ namespace YaHTTP { typedef funcptr::function THandlerFunction; //!< Handler function pointer typedef funcptr::tuple TRoute; //!< Route tuple (method, urlmask, handler, name) typedef std::vector TRouteList; //!< List of routes in order of evaluation + typedef funcptr::tuple TDelim; /*! Implements simple router. @@ -53,6 +54,7 @@ is consumed but not stored. Note that only path is matched, scheme, host and url RoutingResult route(Request *req, THandlerFunction& handler); // urlFor(const std::string &name, const strstr_map_t& arguments); //& params); //& params) { return router.match(route, requrl, params); }; static RoutingResult Route(Request *req, THandlerFunction& handler) { return router.route(req, handler); }; //url.path, returns RouteFound if route is found and method matches, RouteNoMethod if route is seen but method did match, and RouteNotFound if not found. static void PrintRoutes(std::ostream &os) { router.printRoutes(os); }; //