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']

Roundup Issue Tracker: http://roundup-tracker.org/