3434
3535namespace casbin {
3636
37+ namespace {
38+ static const std::regex capturingColonNonSlashRegex (" (.*?):[^/]+(.*?)" );
39+ static const std::regex enclosedPlaceHolderRegex (" (.*?)\\ {[^/]+?\\ }(.*?)" );
40+
41+ std::string PrepareWildCardMatching (const std::string& value) {
42+ static const std::regex pattern (" /\\ *" );
43+ return std::regex_replace (value, pattern, " /.*" );
44+ }
45+
46+ std::string EscapeCurlyBraces (const std::string& value) {
47+ static const std::regex curlyBraceOpenPattern (" \\ {" );
48+ static const std::regex curlyBraceClosePattern (" \\ }" );
49+
50+ std::string intermediate = std::regex_replace (value, curlyBraceOpenPattern, " \\ {" );
51+ return std::regex_replace (intermediate, curlyBraceClosePattern, " \\ }" );
52+ }
53+ }
54+
3755// KeyMatch determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
3856// For example, "/foo/bar" matches "/foo/*"
3957bool KeyMatch (const std::string& key1, const std::string& key2) {
@@ -67,10 +85,9 @@ std::string KeyGet(const std::string& key1, const std::string& key2) {
6785// KeyMatch2 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
6886// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource"
6987bool KeyMatch2 (const std::string& key1, const std::string& key2) {
70- std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
71- k2 = regex_replace (k2, std::regex (" (.*?):[^/]+(.*?)" ), " $1[^/]+$2" );
72- k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
73- k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
88+ std::string k2 = PrepareWildCardMatching (key2);
89+ k2 = std::regex_replace (k2, capturingColonNonSlashRegex, " $1[^/]+$2" );
90+ k2 = EscapeCurlyBraces (k2);
7491
7592 if (!k2.compare (" *" ))
7693 k2 = " (.*)" ;
@@ -82,17 +99,16 @@ bool KeyMatch2(const std::string& key1, const std::string& key2) {
8299// For example, "/resource1" matches "/:resource"
83100// if the path_var == "resource", then "resource1" will be returned
84101std::string KeyGet2 (const std::string& key1, const std::string& key2, const std::string& path_var) {
85- std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
102+ static const std::regex colonAnyButSlashPattern (" :[^/]+" );
103+ std::string k2 = PrepareWildCardMatching (key2);
86104
87105 std::vector<std::string> keys;
88- std::regex keys_regex (" :[^/]+" );
89- for (std::sregex_iterator it (k2.begin (), k2.end (), keys_regex), end_it; it != end_it; ++it) {
106+ for (std::sregex_iterator it (k2.begin (), k2.end (), colonAnyButSlashPattern), end_it; it != end_it; ++it) {
90107 keys.push_back (it->str ());
91108 }
92109
93- k2 = regex_replace (k2, std::regex (" (.*?):[^/]+(.*?)" ), " $1([^/]+)$2" );
94- k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
95- k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
110+ k2 = std::regex_replace (k2, capturingColonNonSlashRegex, " $1([^/]+)$2" );
111+ k2 = EscapeCurlyBraces (k2);
96112 if (!k2.compare (" *" ))
97113 k2 = " (.*)" ;
98114 k2 = " ^" + k2 + " $" ;
@@ -110,10 +126,9 @@ std::string KeyGet2(const std::string& key1, const std::string& key2, const std:
110126// KeyMatch3 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
111127// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}"
112128bool KeyMatch3 (const std::string& key1, const std::string& key2) {
113- std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
114- k2 = regex_replace (k2, std::regex (" (.*?)\\ {[^/]+?\\ }(.*?)" ), " $1[^/]+$2" );
115- k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
116- k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
129+ std::string k2 = PrepareWildCardMatching (key2);
130+ k2 = std::regex_replace (k2, enclosedPlaceHolderRegex, " $1[^/]+$2" );
131+ k2 = EscapeCurlyBraces (k2);
117132
118133 return RegexMatch (key1, " ^" + k2 + " $" );
119134}
@@ -122,17 +137,16 @@ bool KeyMatch3(const std::string& key1, const std::string& key2) {
122137// For example, "project/proj_project1_admin/" matches "project/proj_{project}_admin/"
123138// if the pathVar == "project", then "project1" will be returned
124139std::string KeyGet3 (const std::string& key1, const std::string& key2, const std::string& path_var) {
125- std::string k2 = regex_replace (key2, std::regex (" /\\ *" ), " /.*" );
140+ static const std::regex placeHolderPattern (" \\ {[^/]+?\\ }" );
141+ std::string k2 = PrepareWildCardMatching (key2);
126142
127143 std::vector<std::string> keys;
128- std::regex keys_regex (" \\ {[^/]+?\\ }" );
129- for (std::sregex_iterator it (k2.begin (), k2.end (), keys_regex), end_it; it != end_it; ++it) {
144+ for (std::sregex_iterator it (k2.begin (), k2.end (), placeHolderPattern), end_it; it != end_it; ++it) {
130145 keys.push_back (it->str ());
131146 }
132147
133- k2 = regex_replace (k2, std::regex (" (.*?)\\ {[^/]+?\\ }(.*?)" ), " $1([^/]+?)$2" );
134- k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
135- k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
148+ k2 = std::regex_replace (k2, enclosedPlaceHolderRegex, " $1([^/]+?)$2" );
149+ k2 = EscapeCurlyBraces (k2);
136150 if (!k2.compare (" *" ))
137151 k2 = " (.*)" ;
138152 k2 = " ^" + k2 + " $" ;
@@ -153,16 +167,15 @@ std::string KeyGet3(const std::string& key1, const std::string& key2, const std:
153167// "/parent/123/child/456" does not match "/parent/{id}/child/{id}"
154168// But KeyMatch3 will match both.
155169bool KeyMatch4 (const std::string& key1, const std::string& key2) {
156- std::string k2 = regex_replace (key2, std::regex ( " / \\ * " ), " /.* " );
170+ std::string k2 = PrepareWildCardMatching (key2);
157171
158172 std::vector<std::string> tokens;
159- std::regex tokens_regex (" \\ {([^/]+)\\ }" );
173+ static std::regex tokens_regex (" \\ {([^/]+)\\ }" );
160174 for (std::sregex_iterator it (k2.begin (), k2.end (), tokens_regex), end_it; it != end_it; ++it)
161175 tokens.push_back (it->str ());
162176
163- k2 = regex_replace (k2, std::regex (" (.*?)\\ {[^/]+?\\ }(.*?)" ), " $1([^/]+)$2" );
164- k2 = regex_replace (k2, std::regex (" \\ {" ), " \\ {" );
165- k2 = regex_replace (k2, std::regex (" \\ }" ), " \\ }" );
177+ k2 = std::regex_replace (k2, enclosedPlaceHolderRegex, " $1([^/]+)$2" );
178+ k2 = EscapeCurlyBraces (k2);
166179 k2 = " ^" + k2 + " $" ;
167180 std::smatch matches;
168181 std::regex_match (key1.begin (), key1.end (), matches, std::regex (k2));
@@ -187,7 +200,7 @@ bool KeyMatch4(const std::string& key1, const std::string& key2) {
187200// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
188201bool RegexMatch (const std::string& key1, const std::string& key2) {
189202 std::regex regex_s (key2);
190- return regex_match (key1, regex_s);
203+ return std:: regex_match (key1, regex_s);
191204}
192205
193206// IPMatch determines whether IP address ip1 matches the pattern of IP address ip2, ip2 can be an IP address or a CIDR pattern.
0 commit comments