1 module hunt.http.routing.impl.AbstractRegexMatcher; 2 3 import hunt.http.routing.Matcher; 4 import hunt.http.routing.Router; 5 6 import hunt.collection; 7 import hunt.Exceptions; 8 9 import hunt.logging; 10 11 import std.conv; 12 import std.regex; 13 14 15 /** 16 * 17 */ 18 abstract class AbstractRegexMatcher : Matcher { 19 20 protected Map!(RegexRule, Set!Router) _regexMap; 21 22 protected static class RegexRule { 23 string rule; 24 Regex!char pattern; 25 26 protected this(string rule) { 27 this.rule = rule; 28 pattern = regex(rule); 29 } 30 31 override 32 bool opEquals(Object o) { 33 if (this is o) return true; 34 RegexRule regexRule = cast(RegexRule) o; 35 if(regexRule is null) return false; 36 return rule == regexRule.rule; 37 } 38 39 override 40 size_t toHash() @trusted nothrow { 41 return hashOf(rule); 42 } 43 } 44 45 protected Map!(RegexRule, Set!(Router)) regexMap() { 46 if (_regexMap is null) { 47 _regexMap = new HashMap!(RegexRule, Set!(Router))(); 48 } 49 return _regexMap; 50 } 51 52 override 53 void add(string rule, Router router) { 54 // regexMap().computeIfAbsent(new RegexRule(rule), k -> new HashSet<>()).add(router); 55 auto r = new RegexRule(rule); 56 if(regexMap().containsKey(r)) 57 { 58 regexMap()[r].add(router); 59 } 60 else 61 { 62 auto hs = new HashSet!(Router)(); 63 hs.add(router); 64 regexMap().put(r, hs); 65 } 66 } 67 68 override 69 MatchResult match(string value) { 70 if (_regexMap is null) { 71 return null; 72 } 73 74 Set!Router routers = new HashSet!Router(); 75 Map!(Router, Map!(string, string)) parameters = new HashMap!(Router, Map!(string, string))(); 76 77 foreach(RegexRule rule, Set!Router routerSet; _regexMap) 78 { 79 // tracef("v=%s, pattern=%s", value, rule.rule); 80 RegexMatch!string m = matchAll(value, rule.pattern); 81 82 if (m.empty) 83 continue; 84 85 routers.addAll(routerSet); 86 87 Map!(string, string) param = new HashMap!(string, string)(); 88 foreach(Captures!string item; m) 89 { 90 // tracef("front:%s, length:%d", item.front, item.length); 91 for (size_t i = 1; i <item.length; i++) { 92 // tracef("%d => %s", i, item[i]); 93 param.put("group" ~ i.to!string(), item[i]); 94 } 95 } 96 97 if (!param.isEmpty()) { 98 foreach(router; routerSet) 99 parameters.put(router, param); 100 } 101 } 102 if (routers.isEmpty()) { 103 return null; 104 } else { 105 return new MatchResult(routers, parameters, getMatchType()); 106 } 107 } 108 109 110 MatchType getMatchType() { implementationMissing(); return MatchType.PATH; } 111 112 }