URL

The URL function is one of the most important functions in web2py. It generates internal URL paths for the actions and the static files.

Here is an example:

  1. URL('f')

is mapped into

  1. /[application]/[controller]/f

Notice that the output of the URL function depends on the name of the current application, the calling controller, and other parameters. web2py supports URL mapping and reverse URL mapping. URL mapping allows you to redefine the format of external URLs. If you use the URL function to generate all the internal URLs, then additions or changes to URL mappings will prevent broken links within the web2py application.

You can pass additional parameters to the URL function, i.e., extra terms in the URL path (args) and URL query variables (vars):

  1. URL('f', args=['x', 'y'], vars=dict(z='t'))

is mapped into

  1. /[application]/[controller]/f/x/y?z=t

The args attributes are automatically parsed, decoded, and finally stored in request.args by web2py. Similarly, the vars are parsed, decoded, and then stored in request.vars. args and vars provide the basic mechanism by which web2py exchanges information with the client’s browser.

If args contains only one element, there is no need to pass it in a list.

You can also use the URL function to generate URLs to actions in other controllers and other applications:

  1. URL('a', 'c', 'f', args=['x', 'y'], vars=dict(z='t'))

is mapped into

  1. /a/c/f/x/y?z=t

It is also possible to specify application, controller and function using named arguments:

  1. URL(a='a', c='c', f='f')

If the application name a is missing the current app is assumed.

  1. URL('c', 'f')

If the controller name c is missing, the current one is assumed.

  1. URL('f')

Instead of passing the name of a controller function it is also possible to pass the function itself

  1. URL(f)

For the reasons mentioned above, you should always use the URL function to generate URLs of static files for your applications. Static files are stored in the application’s static subfolder (that’s where they go when uploaded using the administrative interface). web2py provides a virtual ‘static’ controller whose job is to retrieve files from the static subfolder, determine their content-type, and stream the file to the client. The following example generates the URL for the static file “image.png”:

  1. URL('static', 'image.png')

is mapped into

  1. /[application]/static/image.png

If the static file is in a subfolder within the static folder, you can include the subfolder(s) as part of the filename. For example, to generate:

  1. /[application]/static/images/icons/arrow.png

one should use:

  1. URL('static', 'images/icons/arrow.png')

You do not need to encode/escape the args and vars arguments; this is done automatically for you.

By default, the extension corresponding to the current request (which can be found in request.extension) is appended to the function, unless request.extension is html, the default. This can be overridden by explicitly including an extension as part of the function name URL(f='name.ext') or with the extension argument:

  1. URL(..., extension='css')

The current extension can be explicitly suppressed:

  1. URL(..., extension=False)

Absolute urls

By default, URL generates relative URLs. However, you can also generate absolute URLs by specifying the scheme and host arguments (this is useful, for example, when inserting URLs in email messages):

  1. URL(..., scheme='http', host='www.mysite.com')

You can automatically include the scheme and host of the current request by simply setting the arguments to True.

  1. URL(..., scheme=True, host=True)

The URL function also accepts a port argument to specify the server port if necessary.

Digitally signed urls

When generating a URL, you have the option to digitally sign it. This will append a _signature GET variable that can be verified by the server. This can be done in two ways.

You can pass to the URL function the following arguments:

  • hmac_key: the key for signing the URL (a string)
  • salt: an optional string to salt the data before signing
  • hash_vars: an optional list of names of variables from the URL query string (i.e., GET variables) to be included in the signature. It can also be set to True (the default) to include all variables, or False to include none of the variables.

Here is an example of usage:

  1. KEY = 'mykey'
  2. def one():
  3. return dict(link=URL('two', vars=dict(a=123), hmac_key=KEY))
  4. def two():
  5. if not URL.verify(request, hmac_key=KEY): raise HTTP(403)
  6. # do something
  7. return locals()

This makes the action two accessible only via a digitally signed URL. A digitally signed URL looks like this:

  1. /welcome/default/two?a=123&_signature=4981bc70e13866bb60e52a09073560ae822224e9

Note, the digital signature is verified via the URL.verify function. URL.verify also takes the hmac_key, salt, and hash_vars arguments described above, and their values must match the values that were passed to the URL function when the digital signature was created in order to verify the URL.

A second and more sophisticated but more common use of digitally signed URLs is in conjunction with Auth. This is best explained with an example:

  1. @auth.requires_login()
  2. def one():
  3. return dict(link=URL('two', vars=dict(a=123), user_signature=True)
  4. @auth.requires_signature()
  5. def two():
  6. # do something
  7. return locals()

In this case the hmac_key is automatically generated and shared within the session. This allows action two to delegate any access control to action one. If the link is generated and signed, it is valid; else it is not. If the link is stolen by another user, the link will be invalid.

It is good practice to always digitally sign Ajax callbacks. If you use the web2py LOAD function, it has a user_signature argument too that can be used for this purpose:

  1. {{=LOAD('default', 'two', vars=dict(a=123), ajax=True, user_signature=True)}}