From 228bac1cfb10055e876e7d0f86811ad261e87813 Mon Sep 17 00:00:00 2001 From: An Tao Date: Thu, 17 Oct 2019 17:12:52 +0800 Subject: [PATCH] Make user can use any string as a placeholder's name in routing patterns (#282) --- examples/simple_example/api_v1_ApiTest.h | 4 +- lib/src/HttpControllersRouter.cc | 187 +++++++++++++++++++++-- 2 files changed, 173 insertions(+), 18 deletions(-) diff --git a/examples/simple_example/api_v1_ApiTest.h b/examples/simple_example/api_v1_ApiTest.h index 4ff50b60..c80467a2 100644 --- a/examples/simple_example/api_v1_ApiTest.h +++ b/examples/simple_example/api_v1_ApiTest.h @@ -18,10 +18,10 @@ class ApiTest : public drogon::HttpController "drogon::IntranetIpFilter"); METHOD_ADD(ApiTest::rootPost, "", Post, Options); METHOD_ADD(ApiTest::get, - "/get/{2}/{1}", + "/get/{2:p2}/{1}", Get); // path is /api/v1/apitest/get/{arg2}/{arg1} METHOD_ADD(ApiTest::your_method_name, - "/{1}/List?P2={2}", + "/{PI}/List?P2={}", Get); // path is /api/v1/apitest/{arg1}/list METHOD_ADD(ApiTest::staticApi, "/static", Get, Options); // CORS METHOD_ADD(ApiTest::staticApi, "/static", Post, Put, Delete); diff --git a/lib/src/HttpControllersRouter.cc b/lib/src/HttpControllersRouter.cc index b3715a69..9c401f32 100644 --- a/lib/src/HttpControllersRouter.cc +++ b/lib/src/HttpControllersRouter.cc @@ -19,6 +19,7 @@ #include "StaticFileRouter.h" #include "HttpAppFrameworkImpl.h" #include "FiltersFunction.h" +#include using namespace drogon; @@ -98,7 +99,7 @@ void HttpControllersRouter::addHttpPath( std::vector places; std::string tmpPath = path; std::string paras = ""; - std::regex regex = std::regex("\\{([0-9]+)\\}"); + std::regex regex = std::regex("\\{([^/]*)\\}"); std::smatch results; auto pos = tmpPath.find('?'); if (pos != std::string::npos) @@ -107,39 +108,193 @@ void HttpControllersRouter::addHttpPath( tmpPath = tmpPath.substr(0, pos); } std::string originPath = tmpPath; + size_t placeIndex = 1; while (std::regex_search(tmpPath, results, regex)) { if (results.size() > 1) { - size_t place = (size_t)std::stoi(results[1].str()); - if (place > binder->paramCount() || place == 0) + auto result = results[1].str(); + if (!result.empty() && + std::all_of(result.begin(), result.end(), [](const char c) { + return std::isdigit(c); + })) { - LOG_ERROR << "parameter placeholder(value=" << place - << ") out of range (1 to " << binder->paramCount() - << ")"; - exit(0); + size_t place = (size_t)std::stoi(result); + if (place > binder->paramCount() || place == 0) + { + LOG_ERROR << "Parameter placeholder(value=" << place + << ") out of range (1 to " << binder->paramCount() + << ")"; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + if (!std::all_of(places.begin(), + places.end(), + [place](size_t i) { return i != place; })) + { + LOG_ERROR << "Parameter placeholders are duplicated: index=" + << place; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + places.push_back(place); } - places.push_back(place); + else + { + std::regex regNumberAndName("([0-9]+):.*"); + std::smatch regexResult; + if (std::regex_match(result, regexResult, regNumberAndName)) + { + assert(regexResult.size() == 2 && regexResult[1].matched); + auto num = regexResult[1].str(); + size_t place = (size_t)std::stoi(num); + if (place > binder->paramCount() || place == 0) + { + LOG_ERROR << "Parameter placeholder(value=" << place + << ") out of range (1 to " + << binder->paramCount() << ")"; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + if (!std::all_of(places.begin(), + places.end(), + [place](size_t i) { return i != place; })) + { + LOG_ERROR + << "Parameter placeholders are duplicated: index=" + << place; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + places.push_back(place); + } + else + { + if (!std::all_of(places.begin(), + places.end(), + [placeIndex](size_t i) { + return i != placeIndex; + })) + { + LOG_ERROR + << "Parameter placeholders are duplicated: index=" + << placeIndex; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + places.push_back(placeIndex); + } + } + ++placeIndex; } tmpPath = results.suffix(); } std::map parametersPlaces; if (!paras.empty()) { - std::regex pregex("([^&]*)=\\{([0-9]+)\\}&*"); + std::regex pregex("([^&]*)=\\{([^&]*)\\}&*"); while (std::regex_search(paras, results, pregex)) { if (results.size() > 2) { - size_t place = (size_t)std::stoi(results[2].str()); - if (place > binder->paramCount() || place == 0) + auto result = results[2].str(); + if (!result.empty() && + std::all_of(result.begin(), result.end(), [](const char c) { + return std::isdigit(c); + })) { - LOG_ERROR << "parameter placeholder(value=" << place - << ") out of range (1 to " << binder->paramCount() - << ")"; - exit(0); + size_t place = (size_t)std::stoi(result); + if (place > binder->paramCount() || place == 0) + { + LOG_ERROR << "Parameter placeholder(value=" << place + << ") out of range (1 to " + << binder->paramCount() << ")"; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + if (!std::all_of(places.begin(), + places.end(), + [place](size_t i) { + return i != place; + }) || + !all_of(parametersPlaces.begin(), + parametersPlaces.end(), + [place](const std::pair + &item) { + return item.second != place; + })) + { + LOG_ERROR << "Parameter placeholders are " + "duplicated: index=" + << place; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + parametersPlaces[results[1].str()] = place; } - parametersPlaces[results[1].str()] = place; + else + { + std::regex regNumberAndName("([0-9]+):.*"); + std::smatch regexResult; + if (std::regex_match(result, regexResult, regNumberAndName)) + { + assert(regexResult.size() == 2 && + regexResult[1].matched); + auto num = regexResult[1].str(); + size_t place = (size_t)std::stoi(num); + if (place > binder->paramCount() || place == 0) + { + LOG_ERROR << "Parameter placeholder(value=" << place + << ") out of range (1 to " + << binder->paramCount() << ")"; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + if (!std::all_of(places.begin(), + places.end(), + [place](size_t i) { + return i != place; + }) || + !all_of(parametersPlaces.begin(), + parametersPlaces.end(), + [place](const std::pair + &item) { + return item.second != place; + })) + { + LOG_ERROR << "Parameter placeholders are " + "duplicated: index=" + << place; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + parametersPlaces[results[1].str()] = place; + } + else + { + if (!std::all_of(places.begin(), + places.end(), + [placeIndex](size_t i) { + return i != placeIndex; + }) || + !all_of(parametersPlaces.begin(), + parametersPlaces.end(), + [placeIndex]( + const std::pair + &item) { + return item.second != placeIndex; + })) + { + LOG_ERROR << "Parameter placeholders are " + "duplicated: index=" + << placeIndex; + LOG_ERROR << "Path pattern: " << path; + exit(1); + } + parametersPlaces[results[1].str()] = placeIndex; + } + } + ++placeIndex; } paras = results.suffix(); }