Testing the new router

233 views
Skip to first unread message

Kenneth Lundström

unread,
Jan 16, 2011, 4:57:01 PM1/16/11
to web...@googlegroups.com
Hello,

how do I test the new router that Jonathan has made.

I renamed the routes.examples.py to routes.py and edited it. No mather
what I write in it gets used. I tried to find the answer in all posts on
the mailinglist but no success.


Kenneth

Jonathan Lundell

unread,
Jan 16, 2011, 5:26:10 PM1/16/11
to web...@googlegroups.com
On Jan 16, 2011, at 1:57 PM, Kenneth Lundström wrote:
>
> how do I test the new router that Jonathan has made.
>
> I renamed the routes.examples.py to routes.py and edited it. No mather what I write in it gets used. I tried to find the answer in all posts on the mailinglist but no success.

Start with router.example.py instead. The key to using the new router is to define a dict named 'routers'. There's more documentation in the file, and I'll repost some examples below.

Post your routes.py here, along with a description of what you intend that it does (if it's not obvious).

======

Suppose you've written an app, named it 'myapp', and want to make it the default, with its name always removed. Your default controller is still 'default', and you want to remove its name from user-visible URLs as well. Here's what you put in routes.py:

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

That's it. And it's smart enough to know how to do the right thing with URLs like:

http://domain.com/myapp/default/myapp
or http://domain.com/myapp/myapp/index

...where normal shortening would be ambiguous.


If you have two applications, myapp and myapp2, you'll get the same effect, and additionally myapp2's default controller will be stripped from the URL whenever it's safe (which is mostly all the time).

Another case. Suppose you want to support URL-based languages, where your URLs look like this:

http://myapp/en/some/path

or (rewritten)

http://en/some/path

Here's how:

routers = dict(
BASE = dict( default_application='myapp' ),
myapp = dict( languages=['en', 'it', 'jp'], default_language='en' ),
)

Now an incoming URL like this:

http:/domain.com/it/some/path

will be routed to /myapp/some/path, and request.uri_language will be set to 'it', so you can force the translation. You can also have language-specific static files.

http://domain.com/it/static/filename

will be mapped to:

applications/myapp/static/it/filename

...if that file exists. If it doesn't, then URLs like:

http://domain.com/it/static/base.css

...will still map to:

applications/myapp/static/base.css

(because there is no static/it/base.css)

So you can now have language-specific static files, including images, if you need to.


Domain mapping is supported as well.

routers = dict(
BASE = dict(
domains = {
'domain1.com' : 'app1',
'domain2.com' : 'app2',
}
),
)

does what you'd expect.

routers = dict(
BASE = dict(
domains = {
'domain.com:80' : 'app/insecure',
'domain.com:443' : 'app/secure',
}
),
)

...maps http://domain.com accesses to app's controller named 'insecure', while https accesses go to the 'secure' controller. Or you can map different ports to different apps, in the obvious way.


There's more, but mostly everything happens automatically, and there's no need to dig into the details of configuration unless there's some non-standard thing you need. There's a bit more documentation in router.example.py.

Kenneth Lundström

unread,
Jan 16, 2011, 5:42:29 PM1/16/11
to web...@googlegroups.com
> Start with router.example.py instead. The key to using the new router
is to define a dict named 'routers'. There's more documentation in the
file, and I'll repost some examples below.

> Post your routes.py here, along with a description of what you intend
that it does (if it's not obvious).

I just added:

routers = dict(
BASE = dict(
domains = {

'economy.nudata.fi' : 'economy',
'testing.nudata.fi' : 'testapplication',
}
),
)

but if if go to economy.nudata.fi I get to welcome.


Kenneth

Jonathan Lundell

unread,
Jan 16, 2011, 6:10:13 PM1/16/11
to web...@googlegroups.com
On Jan 16, 2011, at 2:42 PM, Kenneth Lundström wrote:
>
> I just added:
>
> routers = dict(
> BASE = dict(
> domains = {
> 'economy.nudata.fi' : 'economy',
> 'testing.nudata.fi' : 'testapplication',
> }
> ),
> )
>
> but if if go to economy.nudata.fi I get to welcome.

Are you running the current trunk? There hasn't been a release with the new router yet. Try adding the abc line below (note the comma); you should get a complaint about an unknown key.

routers = dict(
BASE = dict(

abc = None,

Jonathan Lundell

unread,
Jan 16, 2011, 6:11:43 PM1/16/11
to web...@googlegroups.com
On Jan 16, 2011, at 2:42 PM, Kenneth Lundström wrote:
>
> > Start with router.example.py instead. The key to using the new router is to define a dict named 'routers'. There's more documentation in the file, and I'll repost some examples below.
>
> > Post your routes.py here, along with a description of what you intend that it does (if it's not obvious).
>
> I just added:
>
> routers = dict(
> BASE = dict(
> domains = {
> 'economy.nudata.fi' : 'economy',
> 'testing.nudata.fi' : 'testapplication',
> }
> ),
> )
>
> but if if go to economy.nudata.fi I get to welcome.

One more question: does this work OK with the old routing logic?

Kenneth Lundström

unread,
Jan 16, 2011, 6:26:28 PM1/16/11
to web...@googlegroups.com
> Are you running the current trunk? There hasn't been a release with
the new router yet. Try adding the abc line below (note the comma); you
should get a complaint about an unknown key.

I�m running the newest Nightly Built?

> One more question: does this work OK with the old routing logic?

I have not used any routing logic so far?


Kenneth

Jonathan Lundell

unread,
Jan 16, 2011, 7:27:30 PM1/16/11
to web...@googlegroups.com
On Jan 16, 2011, at 3:26 PM, Kenneth Lundström wrote:
>
> > Are you running the current trunk? There hasn't been a release with the new router yet. Try adding the abc line below (note the comma); you should get a complaint about an unknown key.
>
> I´m running the newest Nightly Built?
>
> > One more question: does this work OK with the old routing logic?
>
> I have not used any routing logic so far?

I'm not sure what's in the nightly build. The abc= line should tell us something, and I can give you a little more debugging depending on what it says.

What's your environment? Host system, server configuration, etc? There are some configurations (like mod_proxy) where you have to do domain-based routing at the server rather than web2py, I think.

Kenneth Lundström

unread,
Jan 16, 2011, 7:39:18 PM1/16/11
to web...@googlegroups.com
> I'm not sure what's in the nightly build. The abc= line should tell
us something, and I can give you a little more debugging depending on
what it says.

abc gave nothing, it loaded welcome without any errors, or were should I
see any complaints about an unknown key?

I�m running on linux, CentOS, MySQL, mod_wsgi, Apache.

I guess I have to give trunk a go, never used Mercurial so it�ll be an
experiment.


Kenneth

Jonathan Lundell

unread,
Jan 16, 2011, 7:54:27 PM1/16/11
to web...@googlegroups.com
On Jan 16, 2011, at 4:39 PM, Kenneth Lundström wrote:
>
> > I'm not sure what's in the nightly build. The abc= line should tell us something, and I can give you a little more debugging depending on what it says.
>
> abc gave nothing, it loaded welcome without any errors, or were should I see any complaints about an unknown key?
>
> I´m running on linux, CentOS, MySQL, mod_wsgi, Apache.
>
> I guess I have to give trunk a go, never used Mercurial so it´ll be an experiment.

Yes, you should get a syntax error:

raise SyntaxError, "unknown key '%s' in router '%s'" % (key, app)

In this case: "unknown key 'abc' in router 'BASE'"

I'll download the currently nightly and take a look.

Jonathan Lundell

unread,
Jan 16, 2011, 7:58:22 PM1/16/11
to web...@googlegroups.com
On Jan 16, 2011, at 4:39 PM, Kenneth Lundström wrote:
>
> > I'm not sure what's in the nightly build. The abc= line should tell us something, and I can give you a little more debugging depending on what it says.

The nightly is pretty old.

Massimo?

Kenneth Lundström

unread,
Jan 16, 2011, 8:08:35 PM1/16/11
to web...@googlegroups.com
> The nightly is pretty old.

Where can you see if my upgrading to a trunk version worked? I did a hg
clone https://web..... and then copied everything to my web2py folder.

Earlier I edited the routes file, now I noticed a new file named
router.examples.py. I added those lines to it. But can�t any errors and
welcome app is always loaded,


Kenneth


Matt

unread,
Jan 16, 2011, 8:11:27 PM1/16/11
to web2py-users
Hi Jonathan,

I'm also trying to use the new routing approach and I'm having a
little trouble with static files.

In my app's static directory I have sub folders (containing files)
like this:

/static/css/base.css
/static/images/logo.png
/static/js/jquery.js

I'm using the most minimal routing:

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

routes_onerror = [(r'*/*', r'/error')]

Now when I try and request certain files I seem to get very unexpected
results....

When I try:

http://localhost:8000/css/base.css

it works.

however when I request an invalid link like:

http://localhost:8000/css/base2.css

It doesn't raise a 404 as I'd expect.

Also for some reason I can't seem to use:

http://localhost:8000/static/css/base.css (gives a 403 error and
doesn't redirect to error).

But I have to use 'static' for javascript files:

http://localhost:8000/static/js/jquery.js

As

http://localhost:8000/js/jquery.js gives an error and redirects to :

http://localhost:8000/error?code=400&ticket=None&requested_uri=/js/jquery.js&request_url=/js/jquery.js

Any suggestions?

Thanks in advance,
Matt

Jonathan Lundell

unread,
Jan 16, 2011, 8:14:54 PM1/16/11
to web...@googlegroups.com

So far so good. You need to copy your router file to routes.py, though.

If you cp router.example.py to routes.py and then replace the routers dict with yours, that should be a good start.

Jonathan Lundell

unread,
Jan 16, 2011, 8:19:27 PM1/16/11
to web...@googlegroups.com
Thanks for the report, Matt.

On Jan 16, 2011, at 5:11 PM, Matt wrote:
>
> Hi Jonathan,
>
> I'm also trying to use the new routing approach and I'm having a
> little trouble with static files.
>
> In my app's static directory I have sub folders (containing files)
> like this:
>
> /static/css/base.css
> /static/images/logo.png
> /static/js/jquery.js
>
> I'm using the most minimal routing:
>
> routers = dict(
> BASE = dict(
> default_application = 'app',
> ),
> )
>
> routes_onerror = [(r'*/*', r'/error')]
>
> Now when I try and request certain files I seem to get very unexpected
> results....
>
> When I try:
>
> http://localhost:8000/css/base.css
>
> it works.

OK, I wouldn't expect that to work.

Your app name is 'app', right?

>
> however when I request an invalid link like:
>
> http://localhost:8000/css/base2.css
>
> It doesn't raise a 404 as I'd expect.
>
> Also for some reason I can't seem to use:
>
> http://localhost:8000/static/css/base.css (gives a 403 error and
> doesn't redirect to error).
>
> But I have to use 'static' for javascript files:
>
> http://localhost:8000/static/js/jquery.js
>
> As
>
> http://localhost:8000/js/jquery.js gives an error and redirects to :
>
> http://localhost:8000/error?code=400&ticket=None&requested_uri=/js/jquery.js&request_url=/js/jquery.js
>
> Any suggestions?

I'll investigate, using your parameters. Can't promise to get to it tonight, though.

Kenneth Lundström

unread,
Jan 16, 2011, 8:27:17 PM1/16/11
to web...@googlegroups.com
> So far so good. You need to copy your router file to routes.py, though.

> If you cp router.example.py to routes.py and then replace the routers dict with yours, that should be a good start.

I copied the file, changed ownership, permissions, but nothing. Not until I restarted Apache was the routes.py noticed and used. Now my econopy.nudata.fi goes to economy application the way I wanted.

Thank you,


Kenneth

Jonathan Lundell

unread,
Jan 16, 2011, 8:29:44 PM1/16/11
to web...@googlegroups.com

Ah, great.

Restarting Apache probably restarted web2py as well, which is necessary for a new routes.py.


Matt

unread,
Jan 16, 2011, 8:44:14 PM1/16/11
to web2py-users
Hi Jonathan,

Thanks for your quick response. Yes the application is 'app'.

Sure, that would be great.

Cheers,
Matt
> >http://localhost:8000/static/css/base.css(gives a 403 error and
> > doesn't redirect to error).
>
> > But I have to use 'static' for javascript files:
>
> >http://localhost:8000/static/js/jquery.js
>
> > As
>
> >http://localhost:8000/js/jquery.js gives an error and redirects to :
>
> >http://localhost:8000/error?code=400&ticket=None&requested_uri=/js/jq...

Jonathan Lundell

unread,
Jan 17, 2011, 11:56:51 AM1/17/11
to web...@googlegroups.com
On Jan 16, 2011, at 5:44 PM, Matt wrote:
>
> Hi Jonathan,
>
> Thanks for your quick response. Yes the application is 'app'.
>
> Sure, that would be great.

I've been looking at this, and a couple of things aren't making sense to me. Your configuration sounds fine, at least what I see of it. I've been testing it like this:

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

app = dict(
controllers = ['default', 'error', 'appadmin'],
),
)

routes_onerror = [(r'*/*', r'/error')]

...because I don't have an application installed named 'app'; this tells the router logic to pretend there's such an app, with the indicated controllers (if the controller list is different, please let me know, but it shouldn't much affect things).

You wrote that this works:

http://localhost:8000/css/base.css

...but it really shouldn't, since there's no way for the router to recognize the URL as a static file. I'd expect it to be rewritten as:

http://localhost:8000/app/css/base.css

...that is, treating 'css' as a controller. I would expect this to work:

http://localhost:8000/static/css/base.css

So I'm wondering first if you're running the current trunk (last few days, anyway). If not, the 'routers=' entry will be ignored.

Second, it would be helpful to turn on router logging. To do so, copy logging.example.conf to logging.conf, and then edit the rewrite logger and console handler to log debug messages:

[logger_rewrite]
level=DEBUG
qualname=web2py.rewrite
handlers=consoleHandler
propagate=0

...

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

(If you're not able to log to the console, you'll have to do more configuration work to log elsewhere.)

Another thing to try, and I recommend this for anyone doing routing, is to customize the doctest in routes.py for your own routing policy. Try replacing the existing doctest with this (if this doesn't work, please send me your routes.py privately and I'll edit it myself and send it back). You run the doctest at the cli:

python routes.py

>>> import os
>>> import gluon.main
>>> from gluon.rewrite import load, filter_url, filter_err, get_effective_router, try_redirect_on_error
>>> load(routes=os.path.basename(__file__))

>>> filter_url('http://localhost:8000/css/base.css', router='app')
'app'
>>> os.path.relpath(filter_url('http://domain.com/favicon.ico'))
'applications/app/static/favicon.ico'
>>> filter_url('http://domain.com/abc')
'/app/default/abc'
>>> filter_url('http://localhost:8000/css/base.css')
"/app/default/css ['base.css']"
>>> os.path.relpath(filter_url('http://domain.com/static/css/base.css'))
'applications/app/static/css/base.css'

>>> from gluon.http import HTTP
>>> from gluon.storage import Storage
>>> http = HTTP(400, 'original http message', Location='some/location')
>>> request = Storage()
>>> request.env = Storage()
>>> request.application = 'app'
>>> request.env.request_uri = 'request_uri'
>>> request.url = 'request.url'
>>> http = try_redirect_on_error(http, request)
>>> (http.status, http.body, http.headers.get('Location'))
(303, 'You are being redirected <a href="/error?code=400&ticket=None&requested_uri=request_uri&request_url=request.url">here</a>', '/error?code=400&ticket=None&requested_uri=request_uri&request_url=request.url')

>>> filter_url('https://domain.com/app/ctr/fcn', out=True)
'/ctr/fcn'
>>> filter_url('https://domain.com/welcome/ctr/fcn', out=True)
'/welcome/ctr/fcn'
>>> filter_url('https://domain.com/app/default/fcn', out=True)
'/fcn'
>>> filter_url('https://domain.com/app/default/index', out=True)
'/'
>>> filter_url('https://domain.com/app/appadmin/index', out=True)
'/appadmin'
>>> filter_url('http://domain.com/app/default/fcn?query', out=True)
'/fcn?query'
>>> filter_url('http://domain.com/app/default/fcn#anchor', out=True)
'/fcn#anchor'
>>> filter_url('http://domain.com/app/default/fcn?query#anchor', out=True)
'/fcn?query#anchor'

>>> filter_err(200)
200
>>> filter_err(399)
399
>>> filter_err(404)
'/error?code=404&ticket=tkt'

Martín Mulone

unread,
Jan 17, 2011, 12:38:27 PM1/17/11
to web...@googlegroups.com
return LOAD('plugin_comments','comments.load',args=[tablename, record_id, page],ajax=True)
  File "/home/martin/Repositorios/google_appengine/web2py/gluon/compileapp.py", line 145, in __call__
    extension=extension)
  File "/home/martin/Repositorios/google_appengine/web2py/gluon/html.py", line 262, in URL
    acf = rewrite.map_url_out(application, controller, function, args, r or _request)
  File "/home/martin/Repositorios/google_appengine/web2py/gluon/rewrite.py", line 867, in map_url_out
    map = MapUrlOut(application, controller, function, args, request)
  File "/home/martin/Repositorios/google_appengine/web2py/gluon/rewrite.py", line 722, in __init__
    self.domain_application = self.request.env.domain_application
AttributeError: 'NoneType' object has no attribute 'env'

I start to test, but I have this error In GAE

2011/1/17 Jonathan Lundell <jlun...@pobox.com>



--
Pablo Martín Mulone (mar...@tecnodoc.com.ar)
Paraná, Entre Ríos, Argentina (CP 3100).

My blog: http://martin.tecnodoc.com.ar
Expert4Solution Profile: http://www.experts4solutions.com/e4s/default/expert/6


Jonathan Lundell

unread,
Jan 17, 2011, 1:04:39 PM1/17/11
to web...@googlegroups.com
On Jan 17, 2011, at 9:38 AM, Martín Mulone wrote:
> return LOAD('plugin_comments','comments.load',args=[tablename, record_id, page],ajax=True)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/compileapp.py", line 145, in __call__
> extension=extension)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/html.py", line 262, in URL
> acf = rewrite.map_url_out(application, controller, function, args, r or _request)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/rewrite.py", line 867, in map_url_out
> map = MapUrlOut(application, controller, function, args, request)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/rewrite.py", line 722, in __init__
> self.domain_application = self.request.env.domain_application
> AttributeError: 'NoneType' object has no attribute 'env'
>
> I start to test, but I have this error In GAE
>

Thanks, Martín. Is this the current trunk?

What's happening is that LOAD is calling URL in a peculiar way (Massimo, would you take a look, please?). It's making this call:

html.URL(request.application,c,f, args=args,vars=vars,extension=extension)

...which means that URL isn't able to pass request on to the URL rewriter.

As a temporary workaround, you can do the URL rewriting yourself by adding a url= argument to your LOAD call:

..., url=URL(r=request, c='plugin_comments', f='comments.load', args=[tablename, record_id, page])

in which case you don't have to pass those args to LOAD (but I think it does no harm).


Massimo, I think that LOAD's call to html.URL needs to include request, or else simply call URL, which will take care of it automatically. Do you see any reason not to do that? (This will be a non-problem once we have request-scope globals available in gluon.)

Martín Mulone

unread,
Jan 17, 2011, 1:07:10 PM1/17/11
to web...@googlegroups.com
yes is trunk

2011/1/17 Jonathan Lundell <jlun...@pobox.com>

Jonathan Lundell

unread,
Jan 17, 2011, 1:15:53 PM1/17/11
to web...@googlegroups.com
On Jan 17, 2011, at 10:07 AM, Martín Mulone wrote:
yes is trunk

OK, either try the workaround (url=) or if you want to wait, we'll get LOAD fixed in the trunk (might take a day or two).

Jonathan Lundell

unread,
Jan 17, 2011, 1:49:47 PM1/17/11
to web...@googlegroups.com
On Jan 17, 2011, at 10:07 AM, Martín Mulone wrote:
> yes is trunk

If you'd like to try a likely fix to LOAD, you can make this change. In gluon.compileapp.LoadFactory, you'll see this line toward the end:

url = url or html.URL(request.application,c,
f, args=args,vars=vars,
extension=extension)

Just add r=request:

url = url or html.URL(request.application,c,
f, args=args,vars=vars, r=request,
extension=extension)

Jonathan Lundell

unread,
Jan 17, 2011, 2:18:21 PM1/17/11
to web...@googlegroups.com
On Jan 17, 2011, at 10:49 AM, Jonathan Lundell wrote:
>
> On Jan 17, 2011, at 10:07 AM, Martín Mulone wrote:
>> yes is trunk
>
> If you'd like to try a likely fix to LOAD, you can make this change. In gluon.compileapp.LoadFactory, you'll see this line toward the end:
>
> url = url or html.URL(request.application,c,
> f, args=args,vars=vars,
> extension=extension)
>
> Just add r=request:
>
> url = url or html.URL(request.application,c,
> f, args=args,vars=vars, r=request,
> extension=extension)

I just noticed that this pattern appears twice. Martín, I think you're using the second one, but it shouldn't hurt to patch both.

Jonathan Lundell

unread,
Jan 17, 2011, 7:21:17 PM1/17/11
to web...@googlegroups.com
On Jan 17, 2011, at 9:38 AM, Martín Mulone wrote:
> return LOAD('plugin_comments','comments.load',args=[tablename, record_id, page],ajax=True)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/compileapp.py", line 145, in __call__
> extension=extension)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/html.py", line 262, in URL
> acf = rewrite.map_url_out(application, controller, function, args, r or _request)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/rewrite.py", line 867, in map_url_out
> map = MapUrlOut(application, controller, function, args, request)
> File "/home/martin/Repositorios/google_appengine/web2py/gluon/rewrite.py", line 722, in __init__
> self.domain_application = self.request.env.domain_application
> AttributeError: 'NoneType' object has no attribute 'env'
>
> I start to test, but I have this error In GAE
>

Hopefully this is now fixed in the trunk. I wasn't able to test it, but at the very least it should do no harm, and it should fix this particular problem.

Matt

unread,
Jan 17, 2011, 9:03:54 PM1/17/11
to web2py-users
Hi Jonathan,

As it turns out I'd mistakenly left a handler in my app.yaml that was
causing the problem.

Really sorry to have wasted your time on this.

Otherwise the new routing code seems to be working really well. Much
simpler which is fantastic!

Thanks again for your help,
Matt

Jonathan Lundell

unread,
Jan 17, 2011, 10:53:55 PM1/17/11
to web...@googlegroups.com
On Jan 17, 2011, at 6:03 PM, Matt wrote:
>
> As it turns out I'd mistakenly left a handler in my app.yaml that was
> causing the problem.
>
> Really sorry to have wasted your time on this.
>
> Otherwise the new routing code seems to be working really well. Much
> simpler which is fantastic!

Don't worry about it; I'm happy it's working for you.

Tom Atkins

unread,
Feb 2, 2011, 10:52:09 AM2/2/11
to web...@googlegroups.com
Thanks for your work on the new routers Jonathan - it makes life much easier.

Quick question, say I have:

routers = dict(
  BASE  = dict(
      domains = {
          'domain1.com' : 'app1',
          'domain2.com' : 'app2',
      }
  ),
)

But would also like www.domain1.com to map to app1 but also change the URL to domain1.com (stripping the www part) what is the best way to achieve that?

Ideally I'd like it to work the same way as this .htaccess:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

This silently redirects to the non www domain and sends a 301 to any search engines to make it clear that the only site is at domain1.com (nothing at www.domain1.com).

Thanks in advance.

Jonathan Lundell

unread,
Feb 2, 2011, 11:43:54 AM2/2/11
to web...@googlegroups.com

If possible, it's better to do the redirection through .htaccess. It's more efficient, since web2py never has to run.

This should also work, if you don't really need the redirect, so it's also efficient:

routers = dict(
BASE = dict(
domains = {
'domain1.com' : 'app1',

'www.domain1.com' : 'app1',


'domain2.com' : 'app2',
}
),
)

My impression is that search engines (Google anyway) are fairly smart about encountering the same content at related domains, and IIRC Google has a protocol for telling them which address is preferred.


If you still want to do it through web2py, I think I'd do the rewrite as above (for both domain1 and www.domain1) and in models/0redirect.py (or at any rate, before any other application code runs), something like:

if request.env.http_host == 'www.domain1.com':
redirect("http://domain1.com%s" % request.env.request_uri, 301)

or more generally:

redirects = {
'www.domain1.com' : 'domain1.com',
...
}

if request.env.http_host in redirects:
scheme = request.env.get('wsgi_url_scheme', 'http').lower()
uri = "%s://%s%s" % (scheme, redirects[request.env.http_host], request.env.request_uri)
redirect(uri, 301)

None of that is tested, and you'd want to check it all, including appropriate escaping (if it's not done already). But you get the idea. It also doesn't take port overrides into consideration.

Tom Atkins

unread,
Feb 2, 2011, 12:17:33 PM2/2/11
to web...@googlegroups.com
Thanks for the quick reply! Your suggestion works fine.  Perfect for my low traffic server with lots of small sites.  I'll look into getting Apache to manage redirects if (when!) it gets busier.

The redirect is useful as if a user comes to the www. version of the site and then to the no www version they lose their session as the cookies don't match.  With your suggestion the session is maintained regardless of the URL entered.

Jonathan Lundell

unread,
Feb 2, 2011, 12:26:35 PM2/2/11
to web...@googlegroups.com
On Feb 2, 2011, at 9:17 AM, Tom Atkins wrote:
Thanks for the quick reply! Your suggestion works fine.  Perfect for my low traffic server with lots of small sites.  I'll look into getting Apache to manage redirects if (when!) it gets busier.

The redirect is useful as if a user comes to the www. version of the site and then to the no www version they lose their session as the cookies don't match.  With your suggestion the session is maintained regardless of the URL entered.

I'm glad to here it. Did you use the short version or the long version?

If you used the short version, would you mind trying out the long version and letting us know how it works? I'd like to include the technique in the documentation.

BTW, this technique (or something very like it) should work fine with the regex-based rewrite logic; the request.env values that we're using are basically http request header items, slightly cleaned up.

Tom Atkins

unread,
Feb 2, 2011, 1:18:17 PM2/2/11
to web...@googlegroups.com
Initially I tried the short version.  Just tried the long version and it works too - impressively no typos in your untested code!  Both also work nicely for http and https.

What are the pros and cons of the short v long version?

Jonathan Lundell

unread,
Feb 2, 2011, 1:27:42 PM2/2/11
to web...@googlegroups.com
On Feb 2, 2011, at 10:18 AM, Tom Atkins wrote:
Initially I tried the short version.  Just tried the long version and it works too - impressively no typos in your untested code!  Both also work nicely for http and https.

What are the pros and cons of the short v long version?

The long version seems useful if you had more than one or two domains that you needed to redirect, and it retains the incoming http vs https scheme. Other than that, they should be equivalent. 

Of course, you could also implement it with regular expressions, sort of along the lines of the Apache rewrite module, though that seems like overkill for most requirements.

Tom Atkins

unread,
Feb 2, 2011, 2:16:15 PM2/2/11
to web...@googlegroups.com
On 2 February 2011 18:27, Jonathan Lundell <jlun...@pobox.com> wrote:

The long version seems useful if you had more than one or two domains that you needed to redirect

Of course - realised that just after I posted the question!
 
, and it retains the incoming http vs https scheme. 

Yes - what I said previously was wrong - only the long version work for hhtps as well.

All very useful and exactly what I was looking.  Many thanks! 
Reply all
Reply to author
Forward
0 new messages