routes_onerror bug

25 views
Skip to first unread message

Anthony

unread,
Nov 18, 2011, 1:16:51 PM11/18/11
to web2py-d...@googlegroups.com
See https://groups.google.com/d/topic/web2py/guc_tkj6b7s/discussion. It looks like routes_onerror can enter an infinite loop when there are URL rewrites involved. Here's the current code from try_rewrite_on_error() in rewrite.py:

    else:
        path_info = '/' + path_info.lstrip('/') # add leading '/' if missing
        if path_info != environ['PATH_INFO']:
            # rewrite request, call wsgibase recursively, avoid loop
            environ['PATH_INFO'] = path_info
            environ['QUERY_STRING'] = query_string
            return None, environ

In the above, path_info is the error handler path given in routes_onerror in routes.py. To avoid an infinite loop, the code checks to make sure path_info is not the same as environ['PATH_INFO'] (i.e., the URL that raised the error). If not, it then sets environ['PATH_INFO'] to the error handler path, and when the function is returned in wsgibase, wsgibase gets called recursively with the new path. The problem is, early in the recursive call to wsgibase, the new environ['PATH_INFO'] gets rewritten according to the routes_in rules. As a result, when the above 'if' clause is reached again, path_info does not match environ['PATH_INFO'], even though they do represent the same URL, so you get a loop.

The code below attempts a fix by first rewriting path_info before comparing it to environ['PATH_INFO']. The fix works in the case referenced in the above linked discussion, but I'm not sure this is the best approach, or whether it breaks something else. Massimo, Jonathan, perhaps you could have a look and see if there is a better alternative.

    else:
        error_raising_path = environ['PATH_INFO']
        # Rewrite routes_onerror path.
        path_info = '/' + path_info.lstrip('/') # add leading '/' if missing                    
        environ['PATH_INFO'] = path_info
        error_handling_path = url_in(request, environ)[1]['PATH_INFO']
        # Avoid infinite loop.
        if error_handling_path != error_raising_path:
            # wsgibase will be called recursively with the routes_onerror path.
            environ['QUERY_STRING'] = query_string
            return None, environ

Patch file is attached.

Anthony
try_rewrite_on_error_2011-11-18.patch

Anthony

unread,
Nov 18, 2011, 11:52:31 PM11/18/11
to web2py-d...@googlegroups.com
    else:
        error_raising_path = environ['PATH_INFO']
        # Rewrite routes_onerror path.
        path_info = '/' + path_info.lstrip('/') # add leading '/' if missing                    
        environ['PATH_INFO'] = path_info
        error_handling_path = url_in(request, environ)[1]['PATH_INFO']
        # Avoid infinite loop.
        if error_handling_path != error_raising_path:
            # wsgibase will be called recursively with the routes_onerror path.
            environ['QUERY_STRING'] = query_string
            return None, environ

Oops, there's a line missing from the above -- right after the "# wsgibase..." comment should be the following line:

            environ['PATH_INFO'] = path_info 

Note, it's correct in the patch file, just missing from my post text.

Anthony
Reply all
Reply to author
Forward
0 new messages