Mercurial > p > roundup > code
comparison roundup/rest.py @ 5851:167ef847fcdf
issue2551053: Fix routing dict in rest.py
The routing dictionary in rest.py used compiled regular expressions as
dictionary keys. This worked most of the time because the regex lib uses
a cache but resulted in duplicate keys in the dictionary in some cases
where a single key should have been used. Thanks to Robert Klonner for
discovering the problem, debugging the root cause and providing a first
proposed fix.
| author | Ralf Schlatterbeck <rsc@runtux.com> |
|---|---|
| date | Tue, 13 Aug 2019 09:46:02 +0200 |
| parents | 9c6617857032 |
| children | 5e8e160fe2a0 |
comparison
equal
deleted
inserted
replaced
| 5850:048ff467add9 | 5851:167ef847fcdf |
|---|---|
| 289 # so /data/<:class>/<:id> will become | 289 # so /data/<:class>/<:id> will become |
| 290 # /data/([charset]+)/([charset]+) | 290 # /data/([charset]+)/([charset]+) |
| 291 # and extract the variable names to a list [(class), (id)] | 291 # and extract the variable names to a list [(class), (id)] |
| 292 func_vars = cls.__var_to_regex.findall(rule) | 292 func_vars = cls.__var_to_regex.findall(rule) |
| 293 rule = re.compile(cls.__var_to_regex.sub(cls.url_to_regex, rule)) | 293 rule = re.compile(cls.__var_to_regex.sub(cls.url_to_regex, rule)) |
| 294 # Save pattern to represent regex in route_map dictionary | |
| 295 # The entries consist of a 2-tuple of the (rule, dictionary) | |
| 296 # where rule is the compiled regex and dictionary contains the | |
| 297 # func_obj dict indexed by method. | |
| 298 pattern = rule.pattern | |
| 294 | 299 |
| 295 # then we decorate it: | 300 # then we decorate it: |
| 296 # route_map[regex][method] = func | 301 # route_map[pattern] = (rule, func_dict) |
| 302 # where func_dict is a dictionary of func_obj (see below) | |
| 303 # indexed by method name | |
| 297 def decorator(func): | 304 def decorator(func): |
| 298 rule_route = cls.__route_map.get(rule, {}) | 305 rule_route = cls.__route_map.get(pattern, (rule, {})) |
| 306 rule_dict = rule_route [1] | |
| 299 func_obj = { | 307 func_obj = { |
| 300 'func': func, | 308 'func': func, |
| 301 'vars': func_vars | 309 'vars': func_vars |
| 302 } | 310 } |
| 303 for method in methods: | 311 for method in methods: |
| 304 rule_route[method] = func_obj | 312 rule_dict[method] = func_obj |
| 305 cls.__route_map[rule] = rule_route | 313 cls.__route_map[pattern] = rule_route |
| 306 return func | 314 return func |
| 307 return decorator | 315 return decorator |
| 308 | 316 |
| 309 @classmethod | 317 @classmethod |
| 310 def execute(cls, instance, path, method, input): | 318 def execute(cls, instance, path, method, input): |
| 316 path = 'rest/' | 324 path = 'rest/' |
| 317 method = method.upper() | 325 method = method.upper() |
| 318 | 326 |
| 319 # find the rule match the path | 327 # find the rule match the path |
| 320 # then get handler match the method | 328 # then get handler match the method |
| 321 for path_regex in cls.__route_map: | 329 for path_regex, funcs in cls.__route_map.values(): |
| 330 # use compiled regex to find rule | |
| 322 match_obj = path_regex.match(path) | 331 match_obj = path_regex.match(path) |
| 323 if match_obj: | 332 if match_obj: |
| 324 try: | 333 try: |
| 325 func_obj = cls.__route_map[path_regex][method] | 334 func_obj = funcs[method] |
| 326 except KeyError: | 335 except KeyError: |
| 327 raise Reject('Method %s not allowed' % method) | 336 raise Reject('Method %s not allowed' % method) |
| 328 | 337 |
| 329 # retrieve the vars list and the function caller | 338 # retrieve the vars list and the function caller |
| 330 list_vars = func_obj['vars'] | 339 list_vars = func_obj['vars'] |
