Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow regex in routes #1062

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 34 additions & 34 deletions source/vibe/http/router.d
Original file line number Diff line number Diff line change
Expand Up @@ -362,45 +362,45 @@ unittest {
private enum maxRouteParameters = 64;

private struct Route {
import std.regex;
HTTPMethod method;
string pattern;
Regex!char pattern;
HTTPServerRequestDelegate cb;

this(HTTPMethod method, string url_match, HTTPServerRequestDelegate cb){
/***
* Convert the url_match into a regex before storing to minimize compiles.
* The regex should preserve variable names that start with ":".
* The regex will be terminated by any "*" within the string,
* so if the "*" was intended as a regex "*",
* use the regex version of this method instead.
***/
this.method = method;
this.cb = cb;
this.pattern = regex(replaceAll!(p => "(P<"~p[1]~">(?!/).*)")("^" ~ replaceFirst(url_match, regex(r"\*.*"), ""), regex(":((?!/).+)")));
}

this(HTTPMethod method, Regex!char url_match, HTTPServerRequestDelegate cb){
this.method = method;
this.cb = cb;
this.pattern = url_match;
}

bool matches(string url, ref string[string] params)
const {
size_t i, j;

// store parameters until a full match is confirmed
import std.typecons;
Tuple!(string, string)[maxRouteParameters] tmpparams;
size_t tmppparams_length = 0;

for (i = 0, j = 0; i < url.length && j < pattern.length;) {
if (pattern[j] == '*') {
foreach (t; tmpparams[0 .. tmppparams_length])
params[t[0]] = t[1];
return true;
}
if (url[i] == pattern[j]) {
i++;
j++;
} else if(pattern[j] == ':') {
j++;
string name = skipPathNode(pattern, j);
string match = skipPathNode(url, i);
assert(tmppparams_length < maxRouteParameters, "Maximum number of route parameters exceeded.");
tmpparams[tmppparams_length++] = tuple(name, match);
} else return false;
}

if ((j < pattern.length && pattern[j] == '*') || (i == url.length && j == pattern.length)) {
foreach (t; tmpparams[0 .. tmppparams_length])
params[t[0]] = t[1];
return true;
}

return false;
}
/***
* Runs the regex stored in this.pattern against the url.
* If it matches, populate params with any captures returned by the regex,
* including named captures.
***/
Captures!(string) cap = url.matchFirst(this.pattern);
if (!cap.length) return false;
assert(cap.length < maxRouteParameters, "Maximum number of route parameters exceeded.");
foreach(n; this.pattern.namedCaptures)
params[n] = cap[n];
params ~= cap[1..$];
return true;
}
}


Expand Down