help on rewrite

69 views
Skip to first unread message

Niphlod

unread,
Nov 18, 2011, 8:20:38 AM11/18/11
to web2py-users
Hi @all,
I have a small problem with routes.py and the routes_onerror
parameter.

Basically I have one and only application "mounted" in the webserver
and I'd like to strip the "application" part from all urls.

Leave alone the redirections for static folder, favicon, robots,
sitemap etc, this is done wonderfully setting:

routes_in = (
('/(?P<any>.*)', '/appname/\g<any>')
)

routes_out = (
('/appname/(?P<any>.*)', '/\g<any>')
)

Now, let's say I want to display a simple page instead of the default
error page.

routes_onerror = [
('*/*', '/errors/index')
]

Working perfectly fine this one also.
I created a simple "errors" controller, with an "index()" function in
it, and created a view /errors/index.html.

Request.vars is populated accordingly to the errors, so I can change
the content of the page dinamically, there's only a small problem: if
I try to change the response.status code (if there's a 404 Not Found
it's not "polite" to return a 200 OK status) rewrite kicks in and
loops forever.

Any hints on how to achieve the same result with different parameters,
if this is not a bug ?

Anthony

unread,
Nov 18, 2011, 8:56:20 AM11/18/11
to web...@googlegroups.com
What does your /errors/index function look like? Also, is that your exact routes_onerror? I ask because there is a bug (now fixed in trunk) that leads to a loop if your routes_onerror path is missing the leading '/' (i.e., 'errors/index' would create a loop, whereas '/errors/index' would not).

Anthony

Niphlod

unread,
Nov 18, 2011, 9:31:00 AM11/18/11
to web2py-users
Hi Anthony, /errors/index function is a simple:

def index():
#response.status = request.vars.code
return dict(vars=request.vars)

Notice the response.status line commented, it's the one triggering the
loop.
The template is very simple, in fact I simulated all kinds of error
and it gets rendered correctly. It's only setting the status on the
controller (the commented line in the index() function) that triggers
the infinite loop.

routes_onerror is exactly as reported, with the leading '/'.

BTW, I'm using 1.99.2

Anthony

unread,
Nov 18, 2011, 12:50:31 PM11/18/11
to web...@googlegroups.com
Looks like this is a bug. I may have a fix...

Anthony


On Friday, November 18, 2011 9:31:00 AM UTC-5, Niphlod wrote:
Hi Anthony, /errors/index function is a simple:

def index():
    #response.status = request.vars.code
    return dict(vars=request.vars)

Notice the response.status line commented, it's the one triggering the
loop.
The template is very simple, in fact I simulated all kinds of error
and it gets rendered correctly. It's only setting the status on the
controller (the commented line in the index() function) that triggers
the infinite loop.

routes_onerror is exactly as reported, with the leading '/'.

BTW, I'm using 1.99.2

Niphlod

unread,
Nov 18, 2011, 2:20:24 PM11/18/11
to web2py-users
feel free to suggest anything you want, I'm happy to test it
heavily :D

Anthony

unread,
Nov 18, 2011, 2:32:29 PM11/18/11
to web...@googlegroups.com
See https://groups.google.com/d/topic/web2py-developers/JsY5uO02664/discussion.


On Friday, November 18, 2011 2:20:24 PM UTC-5, Niphlod wrote:
feel free to suggest anything you want, I'm happy to test it
heavily :D

Anthony

unread,
Nov 19, 2011, 12:01:49 AM11/19/11
to web...@googlegroups.com
The patch is now in trunk -- please test. If you can, it would be helpful if you could try it out with different types of rewrite rules. Also, try it using the parameter-based rewrite system, as well as with no rewrite rules at all (want to make sure we didn't break anything).

FYI, an easier way to strip the application name from your URLs is to use the parameter-based rewrite system -- put this in routes.py instead of your routes_in, routes_out:

routers = dict(
    BASE = dict(
        default_application = 'appname',
    ),
)

See http://web2py.com/book/default/chapter/04#Parameter-Based-System.

Another option is simply to name your app 'init'.

Anthony

On Friday, November 18, 2011 2:20:24 PM UTC-5, Niphlod wrote:
feel free to suggest anything you want, I'm happy to test it
heavily :D

Niphlod

unread,
Nov 20, 2011, 7:25:59 AM11/20/11
to web2py-users
ok, I'll try to mess it up and see what is working and what is not.

Thanks

Niphlod

Niphlod

unread,
Nov 20, 2011, 8:53:42 AM11/20/11
to web2py-users
so, here's a few tests on the functionality at the current state
(patch applied). Maybe we can sum up a little "recipe" to explain
better
the "interaction" between parameter based and pattern based
rewrite....

These settings for production sites are a real deal, so, here we
are...
The test is a basic app, with an errors/index function expressed as:

def index():
response.status = request.vars.code
return dict(vars=request.vars)

The test is "passed" when:
a) the appname is stripped from the url
b) the error handler doesn't loop forever
c) a request made to http://host.domain/robots.txt returns the
contents of appname/static/robots.txt
d) a request made to http://host.domain/favicon.ico returns the
contents of appname/static/favicon.ico
e) a request made to http://host.domain/sitemap.xml returns the
contents of appname/static/sitemap.xml

TEST 1:
---routes.py---
default_application = 'appname'
routes_onerror = [
('*/*', '/appname/errors/index')
]

results : a) not working (that's expected), b) working, c), d), e) not
working (expected behaviour)

TEST 2:
---routes.py---
default_application = 'appname'


routers = dict(
BASE = dict(
default_application = 'appname',
),
)

routes_onerror = [


('*/*', '/errors/index')
]

results: a) working, b) working, c) working, d) working, e) not
working

---routes.py---
default_application = 'appname'
routes_in = (
('/robots.txt', '/static/robots.txt'),
('/sitemap.xml', '/static/sitemap.xml'),
('/favicon.ico', '/static/favicon.ico'),
)

routes_out = (
('/static/robots.txt', '/robots.txt'),
('/static/sitemap.xml', '/sitemap.xml'),
('/static/favicon.ico', '/favicon.ico'),
)

routers = dict(
BASE = dict(
default_application = 'appname',
),
)

routes_onerror = [


('*/*', '/errors/index')
]

results: a) working, b) working, c) working, d) working, e) not
working

TEST 3:
---routes.py---
default_application = 'appname'
routes_in = (
('/(?P<any>.*)', '/appname/\g<any>'),
('/favicon.ico', '/appname/static/favicon.ico'),
('/sitemap.xml', '/appname/static/sitemap.xml'),
('/robots.txt', '/appname/static/robots.txt')
)

routes_out = (
('/appname/(?P<any>.*)', '/\g<any>'),
('/appname/static/favicon.ico', '/favicon.ico' ),
('/appname/static/robots.txt', '/robots.txt'),
('/appname/static/sitemap.xml', '/sitemap.xml')
)

routes_onerror = [
('*/*', '/errors/index')
]

results: a) working, b) working, c) working, d) working, e) not
working

TEST 4:
default_application = 'appname'
routes_in = (
('/favicon.ico', '/appname/static/favicon.ico'),
('/robots.txt', '/appname/static/robots.txt'),
('/sitemap.xml', '/appname/static/sitemap.xml'),


('/(?P<any>.*)', '/appname/\g<any>')
)

routes_out = (
('/appname/static/favicon.ico', '/favicon.ico' ),
('/appname/static/robots.txt', '/robots.txt'),
('/appname/static/sitemap.xml', '/sitemap.xml'),


('/appname/(?P<any>.*)', '/\g<any>')
)

results: a) working, b) working, c) working, d) working, e) working

So, to sum up, something I think I have learned from the experience:
- pattern-based and parameter-based aren't meant to use together. With
pattern-based system "root files" as robots.txt and favicon.ico are
handled internally but not sitemap.xml (or anything else)
- routes_onerror seems to work independantly of the "rewrite method"
- in pattern-based system the order matters. This is an expected
behaviour but nonetheless worth to remember. As an example, take TEST
3 and TEST 4... sitemap.xml gets "taken" by the ('/(?P<any>.*)', '/
appname/\g<any>') tuple in TEST 3 before the "exact match".
- parameter-based is really helpful to map domains to apps or if you
have multiple apps but only one "preferred", or with language-based
redirections. With parameter-based system you can access other apps by
"normal" non-rewritten urls. With pattern-based if you want to have a
"default" application you have to map any additional application
specifically.

Anthony

unread,
Nov 20, 2011, 11:14:22 AM11/20/11
to web...@googlegroups.com
OK, so specifically regarding routes_onerror, has the recent patch eliminated the infinite loop problem (and not broken anything else), as far as you can tell?

And yes, the pattern-based and parameter-based systems cannot be mixed -- you must use one or the other. routes_onerror, however, works with either system.

Note, in the parameter-based system, you can do:

routers = dict(
    BASE = dict(
        default_application = 'appname',
        root_static = ['favicon.ico', 'robots.txt', 'sitemap.xml']
    ),
)

to set static files that should be accessible from the root URL.

Anthony

Niphlod

unread,
Nov 20, 2011, 12:01:41 PM11/20/11
to web2py-users
yes, as far as I can tell the patch solved the infinite loop problem.
All other things are working correctly: it did not brake anything as
far as my tests gone.

> > c) a request made tohttp://host.domain/robots.txtreturns the
> > contents of appname/static/robots.txt
> > d) a request made tohttp://host.domain/favicon.icoreturns the
> > contents of appname/static/favicon.ico
> > e) a request made tohttp://host.domain/sitemap.xmlreturns the

Anthony

unread,
Nov 20, 2011, 1:47:49 PM11/20/11
to web...@googlegroups.com
Great. Thanks for checking.


On Sunday, November 20, 2011 12:01:41 PM UTC-5, Niphlod wrote:
yes, as far as I can tell the patch solved the infinite loop problem.
All other things are working correctly: it did not brake anything as
far as my tests gone.
Reply all
Reply to author
Forward
0 new messages