SNode.C
Loading...
Searching...
No Matches
express::dispatcher Namespace Reference

Classes

class  ApplicationDispatcher
 
class  MiddlewareDispatcher
 
class  RouterDispatcher
 

Functions

std::vector< std::string > explode (const std::string &input, char delim)
 
const std::regex & pathRegex ()
 
std::smatch matchResult (const std::string &cpath)
 
bool hasResult (const std::string &cpath)
 
void setParams (const std::string &cpath, Request &req)
 
std::unordered_map< std::string, std::string > parseQuery (std::string_view qs)
 
std::pair< std::regex, std::vector< std::string > > compileParamRegex (std::string_view mountPath, bool isPrefix, bool strictRouting, bool caseInsensitive)
 
bool querySupersetMatches (const std::unordered_map< std::string, std::string > &rq, const std::unordered_map< std::string, std::string > &need)
 
bool boundaryPrefix (std::string_view path, std::string_view base, bool caseInsensitive)
 
bool equalPath (std::string_view a, std::string_view b, bool caseInsensitive)
 
std::string_view trimOneTrailingSlash (std::string_view s)
 
void splitPathAndQuery (std::string_view url, std::string_view &path, std::string_view &query)
 
bool ieq (char a, char b)
 
template<typename RequestLike >
bool matchAndFillParams (const std::regex &rx, const std::vector< std::string > &names, std::string_view reqPath, RequestLike &req)
 

Function Documentation

◆ boundaryPrefix()

bool express::dispatcher::boundaryPrefix ( std::string_view  path,
std::string_view  base,
bool  caseInsensitive 
)

Definition at line 233 of file regex_utils.cpp.

233 {
234 // Normalize: an empty base is equivalent to "/"
235 if (base.empty()) {
236 base = "/";
237 }
238
239 // Special case: base "/" matches any absolute path
240 if (base.size() == 1 && base[0] == '/') {
241 return !path.empty() && path.front() == '/';
242 }
243
244 // Base longer than path cannot match
245 if (base.size() > path.size()) {
246 return false;
247 }
248
249 auto eq = [&](char a, char b) {
250 return !caseInsensitive ? (a == b)
251 : (std::tolower(static_cast<unsigned char>(a)) == std::tolower(static_cast<unsigned char>(b)));
252 };
253
254 // Check prefix characters
255 for (size_t i = 0; i < base.size(); ++i) {
256 if (!eq(path[i], base[i])) {
257 return false;
258 }
259 }
260
261 // Boundary: either exact match, or next char is a '/'
262 return (path.size() == base.size()) || (path[base.size()] == '/');
263 }

Referenced by express::dispatcher::MiddlewareDispatcher::dispatch(), and express::dispatcher::RouterDispatcher::dispatch().

Here is the caller graph for this function:

◆ compileParamRegex()

std::pair< std::regex, std::vector< std::string > > express::dispatcher::compileParamRegex ( std::string_view  mountPath,
bool  isPrefix,
bool  strictRouting,
bool  caseInsensitive 
)

Definition at line 156 of file regex_utils.cpp.

156 {
157 std::string pat;
158 pat.reserve(mountPath.size() * 2);
159 std::vector<std::string> names;
160 pat += '^';
161
162 const char* s = mountPath.data();
163 const char* e = s + mountPath.size();
164 while (s < e) {
165 if (*s == ':') {
166 ++s;
167 const char* nstart = s;
168 while (s < e && (std::isalnum(static_cast<unsigned char>(*s)) > 0 || *s == '_' || *s == '-')) {
169 ++s;
170 }
171 std::string name(nstart, s);
172 std::string custom;
173 if (s < e && *s == '(') {
174 int depth = 0;
175 const char* rstart = s + 1;
176 ++s;
177 while (s < e) {
178 if (*s == '(') {
179 ++depth;
180 } else if (*s == ')' && depth-- == 0) {
181 break;
182 }
183 ++s;
184 }
185 custom.assign(rstart, s);
186 if (s < e && *s == ')') {
187 ++s;
188 }
189 }
190 names.push_back(std::move(name));
191 if (!custom.empty()) {
192 pat += '(';
193 pat += custom;
194 pat += ')';
195 } else {
196 pat += "([^/]+)";
197 } // default: single segment
198 } else {
199 static const std::string meta = R"(\.^$|()[]{}*+?!)";
200 if (meta.find(*s) != std::string::npos) {
201 pat += '\\';
202 }
203 pat += *s;
204 ++s;
205 }
206 }
207
208 if (isPrefix) {
209 pat += "(?:/|$)"; // boundary
210 } else {
211 if (!strictRouting) {
212 pat += "/?"; // allow single trailing slash
213 }
214 pat += '$';
215 }
216
217 auto flags = std::regex::ECMAScript | (!caseInsensitive ? std::regex::flag_type{} : std::regex::icase);
218
219 return {std::regex(pat, flags), std::move(names)};
220 }

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), express::dispatcher::MiddlewareDispatcher::dispatch(), and express::dispatcher::RouterDispatcher::dispatch().

Here is the caller graph for this function:

◆ equalPath()

bool express::dispatcher::equalPath ( std::string_view  a,
std::string_view  b,
bool  caseInsensitive 
)

Definition at line 265 of file regex_utils.cpp.

265 {
266 if (a.size() != b.size()) {
267 return false;
268 }
269 for (size_t i = 0; i < a.size(); ++i) {
270 if (!caseInsensitive ? (a[i] != b[i]) : !ieq(a[i], b[i])) {
271 return false;
272 }
273 }
274 return true;
275 }

References ieq().

Referenced by express::dispatcher::ApplicationDispatcher::dispatch().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ explode()

std::vector< std::string > express::dispatcher::explode ( const std::string &  input,
char  delim 
)

Definition at line 54 of file regex_utils.cpp.

54 {
55 std::vector<std::string> result;
56 std::string current;
57 int parenDepth = 0;
58
59 for (const char ch : input) {
60 if (ch == '(') {
61 parenDepth++;
62 current += ch;
63 } else if (ch == ')') {
64 parenDepth--;
65 current += ch;
66 } else if (ch == delim && parenDepth == 0) {
67 result.push_back(current);
68 current.clear();
69 } else {
70 current += ch;
71 }
72 }
73
74 if (!current.empty()) {
75 result.push_back(current);
76 }
77
78 return result;
79 }

Referenced by setParams().

Here is the caller graph for this function:

◆ hasResult()

bool express::dispatcher::hasResult ( const std::string &  cpath)

Definition at line 96 of file regex_utils.cpp.

96 {
97 std::smatch smatch;
98
99 return std::regex_search(cpath, smatch, pathRegex());
100 }
const std::regex & pathRegex()

References pathRegex().

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), and express::dispatcher::MiddlewareDispatcher::dispatch().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ieq()

bool express::dispatcher::ieq ( char  a,
char  b 
)
inline

Definition at line 84 of file regex_utils.h.

84 {
85 return std::tolower(static_cast<unsigned char>(a)) == std::tolower(static_cast<unsigned char>(b));
86 }

Referenced by equalPath().

Here is the caller graph for this function:

◆ matchAndFillParams()

template<typename RequestLike >
bool express::dispatcher::matchAndFillParams ( const std::regex &  rx,
const std::vector< std::string > &  names,
std::string_view  reqPath,
RequestLike &  req 
)
inline

Definition at line 108 of file regex_utils.h.

108 {
109 std::cmatch m;
110 if (!std::regex_search(reqPath.begin(), reqPath.end(), m, rx)) {
111 return false;
112 }
113 const size_t g = (!m.empty()) ? (m.size() - 1) : 0;
114 const size_t n = std::min(names.size(), g);
115 for (size_t i = 0; i < n; ++i) {
116 req.params[names[i]] = m[i + 1].str();
117 }
118 return true;
119 }

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), and express::dispatcher::RouterDispatcher::dispatch().

Here is the caller graph for this function:

◆ matchResult()

std::smatch express::dispatcher::matchResult ( const std::string &  cpath)

Definition at line 88 of file regex_utils.cpp.

88 {
89 std::smatch smatch;
90
91 std::regex_search(cpath, smatch, pathRegex());
92
93 return smatch;
94 }

References pathRegex().

Referenced by setParams().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parseQuery()

std::unordered_map< std::string, std::string > express::dispatcher::parseQuery ( std::string_view  qs)

Definition at line 129 of file regex_utils.cpp.

129 {
130 std::unordered_map<std::string, std::string> m;
131 std::size_t i = 0;
132 while (i < qs.size()) {
133 const std::size_t amp = qs.find('&', i);
134 const std::string_view pair = (amp == std::string_view::npos) ? qs.substr(i) : qs.substr(i, amp - i);
135 const std::size_t eq = pair.find('=');
136 std::string key;
137 std::string val;
138 if (eq == std::string_view::npos) {
139 key.assign(pair);
140 } else {
141 key.assign(pair.substr(0, eq));
142 val.assign(pair.substr(eq + 1));
143 }
144 if (!key.empty()) {
145 m.emplace(std::move(key), std::move(val));
146 }
147 if (amp == std::string_view::npos) {
148 break;
149 }
150 i = amp + 1;
151 }
152 return m;
153 }

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), express::dispatcher::MiddlewareDispatcher::dispatch(), and express::dispatcher::RouterDispatcher::dispatch().

Here is the caller graph for this function:

◆ pathRegex()

const std::regex & express::dispatcher::pathRegex ( )

Definition at line 82 of file regex_utils.cpp.

82 {
83 static const std::regex pathregex(PATH_REGEX);
84
85 return pathregex;
86 }
#define PATH_REGEX

Referenced by hasResult(), and matchResult().

Here is the caller graph for this function:

◆ querySupersetMatches()

bool express::dispatcher::querySupersetMatches ( const std::unordered_map< std::string, std::string > &  rq,
const std::unordered_map< std::string, std::string > &  need 
)

Definition at line 222 of file regex_utils.cpp.

223 {
224 for (const auto& kv : need) {
225 auto it = rq.find(kv.first);
226 if (it == rq.end() || it->second != kv.second) {
227 return false;
228 }
229 }
230 return true;
231 }

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), express::dispatcher::MiddlewareDispatcher::dispatch(), and express::dispatcher::RouterDispatcher::dispatch().

Here is the caller graph for this function:

◆ setParams()

void express::dispatcher::setParams ( const std::string &  cpath,
express::Request req 
)

Definition at line 102 of file regex_utils.cpp.

102 {
103 std::vector<std::string> explodedString = explode(cpath, '/');
104 std::vector<std::string> explodedReqString = explode(req.url, '/');
105
106 for (std::vector<std::string>::size_type i = 0; i < explodedString.size() && i < explodedReqString.size(); i++) {
107 if (!explodedString[i].empty() && explodedString[i].front() == ':') {
108 const std::smatch smatch = matchResult(explodedString[i]);
109 std::string regex = "(.*)";
110
111 if (smatch.size() > 1) {
112 if (smatch[1] != "") {
113 regex = smatch[1];
114 }
115 }
116
117 if (std::regex_match(explodedReqString[i], std::regex(regex))) {
118 std::string attributeName = smatch[0];
119 attributeName.erase(0, 1);
120 attributeName.erase((attributeName.length() - static_cast<std::size_t>(smatch[1].length())),
121 static_cast<std::size_t>(smatch[1].length()));
122
123 req.params[attributeName] = explodedReqString[i];
124 }
125 }
126 }
127 }
std::string url
Definition Request.h:96
std::map< std::string, std::string > params
Definition Request.h:79
std::vector< std::string > explode(const std::string &input, char delim)
std::smatch matchResult(const std::string &cpath)

References explode(), matchResult(), express::Request::params, and express::Request::url.

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), and express::dispatcher::MiddlewareDispatcher::dispatch().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ splitPathAndQuery()

void express::dispatcher::splitPathAndQuery ( std::string_view  url,
std::string_view &  path,
std::string_view &  query 
)

Definition at line 284 of file regex_utils.cpp.

284 {
285 const std::size_t qpos = url.find('?');
286 if (qpos == std::string_view::npos) {
287 path = url;
288 query = {};
289 } else {
290 path = url.substr(0, qpos);
291 query = url.substr(qpos + 1);
292 }
293 }

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), express::dispatcher::MiddlewareDispatcher::dispatch(), and express::dispatcher::RouterDispatcher::dispatch().

Here is the caller graph for this function:

◆ trimOneTrailingSlash()

std::string_view express::dispatcher::trimOneTrailingSlash ( std::string_view  s)

Definition at line 277 of file regex_utils.cpp.

277 {
278 if (s.size() > 1 && s.back() == '/') {
279 return std::string_view(s.data(), s.size() - 1);
280 }
281 return s;
282 }

Referenced by express::dispatcher::ApplicationDispatcher::dispatch(), express::dispatcher::MiddlewareDispatcher::dispatch(), and express::dispatcher::RouterDispatcher::dispatch().

Here is the caller graph for this function: