comparison piecrust/routing.py @ 380:f33712c4cfab

routing: Fix bugs with matching URLs with correct route but missing metadata. When matching a route like `/foo/%slug%` against an URL like `/foo`, the route will (correctly) return a match, but it will be completely missing the `slug` metadata, resulting in problems elsewhere. This change makes it so that any missing route metadata will be filled in with an empty string. And because this means generated URLs may differ from the incoming URL when using trailing slashes (`/foo/` _vs._ `/foo`), we make the assert in the chef server handle those discrepancies.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 10 May 2015 00:34:21 -0700
parents 4b1019bb2533
children dc0988d937b3
comparison
equal deleted inserted replaced
379:d40b744a9d99 380:f33712c4cfab
88 return self.source.realm 88 return self.source.realm
89 89
90 def matchesMetadata(self, route_metadata): 90 def matchesMetadata(self, route_metadata):
91 return self.required_route_metadata.issubset(route_metadata.keys()) 91 return self.required_route_metadata.issubset(route_metadata.keys())
92 92
93 def matchUri(self, uri): 93 def matchUri(self, uri, strict=False):
94 if not uri.startswith(self.uri_root): 94 if not uri.startswith(self.uri_root):
95 raise Exception("The given URI is not absolute: %s" % uri) 95 raise Exception("The given URI is not absolute: %s" % uri)
96 uri = uri[len(self.uri_root):] 96 uri = uri[len(self.uri_root):]
97 97
98 if not self.pretty_urls: 98 if not self.pretty_urls:
99 uri = ugly_url_cleaner.sub('', uri) 99 uri = ugly_url_cleaner.sub('', uri)
100 elif self.trailing_slash: 100 elif self.trailing_slash:
101 uri = uri.rstrip('/') 101 uri = uri.rstrip('/')
102 102
103 route_metadata = None
103 m = self.uri_re.match(uri) 104 m = self.uri_re.match(uri)
104 if m: 105 if m:
105 return m.groupdict() 106 route_metadata = m.groupdict()
106 if self.uri_re_no_path: 107 if self.uri_re_no_path:
107 m = self.uri_re_no_path.match(uri) 108 m = self.uri_re_no_path.match(uri)
108 if m: 109 if m:
109 return m.groupdict() 110 route_metadata = m.groupdict()
110 return None 111 if route_metadata is None:
112 return None
113
114 if not strict:
115 # When matching URIs, if the URI is a match but is missing some
116 # metadata, fill those up with empty strings. This can happen if,
117 # say, a route's pattern is `/foo/%slug%`, and we're matching an
118 # URL like `/foo`.
119 matched_keys = set(route_metadata.keys())
120 missing_keys = self.required_route_metadata - matched_keys
121 for k in missing_keys:
122 route_metadata[k] = ''
123
124 return route_metadata
111 125
112 def getUri(self, route_metadata, *, sub_num=1, provider=None): 126 def getUri(self, route_metadata, *, sub_num=1, provider=None):
113 route_metadata = copy.deepcopy(route_metadata) 127 route_metadata = copy.deepcopy(route_metadata)
114 if provider: 128 if provider:
115 route_metadata.update(provider.getRouteMetadata()) 129 route_metadata.update(provider.getRouteMetadata())