Sorry, I didn't explain my situation clearly enough. I want the "testname" 
in the example to actually be considered as a single URL segment. These 
strings come from a database and represent a single resource, and I can't 
control what they contain. Normally they don't have slashes in, but 
occasionally they do, and I want the system to continue to work whether or 
not they contain slashes.

For what it's worth, I've worked around the problem with a custom request 
subclass that does the extra escaping. It only works for my specific usage, 
but that's good enough for me :-). A proper fix (assuming it really is a 
bug) would probably involve changing pyramid.traversal.quote_path_segment 
to handle this case. This would also be necessary for traversal if a 
resource's __name__ contained a slash.

from pyramid.request import Request
from pyramid.events import subscriber

class MyRequest(Request):
    def route_url(self, *args, **kwargs):
        result = super(MyRequest, self).route_url(*args, **kwargs)
        # Escape %2F (slash) by percent-encoding the percent.
        # When the URL is followed, the outer layer of escaping will be
        # removed, leaving %2F in the matchdict.
        return result.replace('%2F', '%252F')

    def fixmatchdict(self):
        matchdict = self.matchdict
        if matchdict:
            for key, value in matchdict.items():
                if isinstance(value, basestring):
                    matchdict[key] = value.replace('%2F', '/')


# The ContextFound event fires after the URL has been processed
# but before any view code runs, so is a convenient place for us
# to unescape slashes in the matchdict
@subscriber('pyramid.events.ContextFound')
def contextfound(event):
    event.request.fixmatchdict()


While reading the source, I noticed the documentation for 
pyramid.traversal.quote_path_segment which says:

   The return value for each segment passed to this
   function is cached in a module-scope dictionary for
   speed: the cached version is returned when possible
   rather than recomputing the quoted version.  No cache
   emptying is ever done for the lifetime of an
   application, however.  If you pass arbitrary
   user-supplied strings to this function (as opposed to
   some bounded set of values from a 'working set' known to
   your application), it may become a memory leak.


https://github.com/Pylons/pyramid/blob/1.4/pyramid/traversal.py#L549


As far as I can tell, if you are generating URLs based on strings from a 
database, whether with traversal or url dispatch, that cache will end up 
containing every string from your database that ever gets used during URL 
generation. I know the docstring for quote_path_segment warns about this, 
but I don't think that warning ever makes it as far as the main docs... 
(Also, URL generation using strings from a database seems like a fairly 
reasonable thing to want to do)

Simon

On Thursday, February 21, 2013 3:29:02 PM UTC, Blaise Laflamme wrote:

> The {pattern} notation represents a segment in a URL which is separated by 
> slashes. If you want to use multiple segments you should define them 
> separately, ie /{one}/{two} or use the /path/to/*remainder notation to 
> catch everything remaining. To generate a URL you can provide a tuple or a 
> string, i.e.: request.route_url('test', testname='path/to/resource') or 
> request.route_url('test', testname=('path', 'to', 'resource')). Any value 
> you pass in your patterns will be url-quoted.
>
> On Thursday, 21 February 2013 08:11:28 UTC-5, Simon King wrote:
>>
>> Hi all,
>>
>> I'm not sure if this would be considered a bug, but I'm having trouble 
>> generating URLs using request.route_url, when my replacement values 
>> themselves contain slashes. For example, if I had the following route 
>> defined:
>>
>>   config.add_route('test', '/tests/{testname}/')
>>
>> and I generate a route like this:
>>
>>   request.route_url('test', testname='one/two')
>>
>> ...the resulting URL will look something like:
>>
>>   http://localhost/tests/one%2Ftwo/
>>
>> However, if I try to visit this URL, it is treated exactly the same as:
>>
>>   http://localhost/tests/one/two/
>>
>> ...so the route doesn't match. I suspect that as far as HTTP is concerned 
>> those 2 URLs are equivalent, so my workaround will have to be escaping my 
>> replacement values before creating URLs, and unescaping them in my views.
>>
>> Could this be considered a bug in route_url, that it generates URLs that 
>> don't roundtrip correctly? And could it be fixed by adding special handling 
>> of the "/" character in the generator and the matcher?
>>
>> Thanks,
>>
>> Simon
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/pylons-discuss?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to