Sublunary Paths

Zope alternatives to GET/POST parameters.

Before you ask, sublunary paths comes from a poem by Philip Larkin (it’s Many famous feet have trod, partway down that page). It has nothing much to do with web programming, nor Zope, but every time I see the identifier subpath it reminds me. Besides, I’m sure you appreciate the break from IT once in a while?

A subpath in Zope terms is that part of a URL that comes after the script, method or whatever that’s actually executed. Bear in mind that Zope is all about inheritance and object-orientedness, so if we have a script available at:

http://www.myserver.com/scripts/myScript

…then it’s possible to access it via URLs like:

http://www.myserver.com/scripts/myScript/part1/part2/part3

…and you can consider that the “part3” URL “inherits” myScript.  Those extra parts (in bold) don’t need to refer to actual directories[1]; they can be pretty much aribtrary.  They’re made available in the subpath element of the REQUEST object, and here’s where that comes in handy.

If you point a browser at a URL that results in the contents of a file being returned, then the question arises of what the file name should be.  HTTP allows the server to be specific about the type of the data that’s sent, but there’s facility to supply a suitable name.  This makes sense; naming conventions are extremely varied across platforms, so there’s no guarantee that a given name will be appropriate.  Instead, what usually happens is that the browser deduces a name from the URL.  And here problems may occur.

Consider a URL of the form:

http://www.myserver.com/scripts/downloadFile?customer=144876ab6&transaction=76yghj576xz7

…which downloads a GIF file.  There are browsers in existence[0] that will propose the filename downloadFile?customer=144876ab6&transaction=76yghj576xz7.gif, which is less than useful.  The worst part is that the parameters to the request get added to the filename.  The request could be made as a POST rather than a GET to avoid this, but there’s still no way to specify the filename, meaning that all the files downloaded from this URL may end up with the same name.  Not good, especially if they’re being paid for and later ones overwrite previous ones.

The subpath trick, however, can be used in a couple of ways to work around this.
First, since the subpath is ignored by Zope, it can be used to suggest a filename when a POST request is made:

http://www.myserver.com/scripts/downloadFile/myNewFile.gif

That’s good, but we can go further.  The subpath can be used itself to pass the parameters to the script.  Consider this:

http://www.myserver.com/scripts/downloadFile/customer=144876ab6/transaction=76yghj576xz7/myNewFile.gif

In Python terms, we need to look along the subpath and extract those parameters.  Here’s a suitable method to do it:

#Regular expression to spot parameters of the form  = , where
#value may be empty.
paramRe = re.compile(r"(\w+)\s*=\s*(.*)")
def getParametersFromRequest(self):
    """Extract parameters from the subpath and return them in a dict."""
    params = {}
    #The subpath is a list of path elements; in other words, it's
    #been split by '/' characters for us already.
    for p in self.REQUEST.subpath:
        #Check if it's a parameter.
        m = paramRe.match(p)
        if m:
            #It is a match.  group(1) is the identifier,
            #group(2) is the value, which we strip.
            params[m.group(1)] = m.group(2).strip()
    return params

You can call this from any ExternalMethod or Script (Python), passing either self or the container respectively, and it’ll return a dict of parameters.

[0] This is an issue that crops up a lot on mobile phone browsers, but wget shows it too.
[1] This depends on what it is that you append the subpath to; it works for ExternalMethods, but other types of Zope object require the subdirectories to exist.  Which is a pain.

4 thoughts on “Sublunary Paths

  1. Subpath for PythonScripts

    The cases which “require the subdirectories to exist” are actually examples of “old Jedi acquisition tricks”, rather than true subpath traversal.

    However, it is possible to configure a PythonScript to play with arbitrary subpath traversal. The “Bindings” tab of a PythonScript
    has:

    Subpath

    When the script is published directly from a URL, this is the
    portion of the URL path after the script’s name, split at slash
    separators into a list of strings. Otherwise, it is an empty list.

    Recommended value: traverse_subpath

    PythonScripts have this binding set up by default, which makes the
    subpath available under the name ‘traverse_subpath’ (no need to
    pick it off of the REQUEST.

    Tres Seaver.

    • Re: Subpath for PythonScripts

      Useful that, thanks. I think the code is better using the REQUEST, since that means the same code could run in an ExternalMethod or a Script. Now if we could only do the same with Page Templates…

  2. Not entirely true 😉

    “The request could be made as a POST rather than a GET to avoid this, but there’s still no way to specify the filename, meaning that all the files downloaded from this URL may end up with the same name.”

    …rubbish 😉

    You wanna look at how to use a content-disposition header.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s