Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #7544 (closed defect: fixed)

Opened 1 year ago

Last modified 1 year ago

[PATCH] Routing - Allow the use of escaped, reserved URI characters

Reported by: chrisroos Assigned to: bitsweat
Priority: normal Milestone: 1.x
Component: ActionPack Version: edge
Severity: normal Keywords: routing
Cc: bitsweat, begemot

Description

Routing should ignore delimiter characters in the reserved set (see section 2.2) if they are escaped.

Given the route ':controller/:action/:id', I would expect '/foo/bar/baz%2F123' to be parsed as {:controller => 'foo', :action => 'bar', :id => 'baz/123'}.

Instead, baz%2F123 is first unescaped (leaving us with '/foo/bar/baz/123'), causing the route recognition to fail.

This patch adds tests and fixes the routing implementation.

Attachments

routing.patch (5.0 kB) - added by chrisroos on 02/12/07 23:20:21.
routing.1.patch (4.6 kB) - added by chrisroos on 02/14/07 17:01:30.

Change History

02/12/07 23:20:21 changed by chrisroos

  • attachment routing.patch added.

02/12/07 23:25:52 changed by chrisroos

It should be noted that these changes broke, and I therefore had to change, one assertion in one test:

test_recognize_with_encoded_id_and_regex

This will break any applications that rely on the previous implementation.

(follow-up: ↓ 3 ) 02/13/07 00:34:27 changed by bitsweat

  • cc set to bitsweat.

Please use URI.escape/unescape for the path instead of CGI.

(in reply to: ↑ 2 ) 02/13/07 08:16:35 changed by chrisroos

Replying to bitsweat:

Please use URI.escape/unescape for the path instead of CGI.

I'm afraid URI.escape won't do. URI.escape only escapes unsafe characters. A forward slash (et al) is not unsafe. I believe, however, that we want to force it to be escaped when it appears as a path segment. Hence the use of CGI.escape.

02/13/07 08:18:25 changed by chrisroos

Sorry. I intended to add examples to that reply, and forgot.

> require 'uri'
=> true

> URI.escape('foo/bar')
=> "foo/bar"

> require 'cgi'
=> true

> CGI.escape('foo/bar')
=> "foo%2Fbar"

02/13/07 09:14:17 changed by bitsweat

Doh. CGI.escape encodes + as a space which breaks others. That's why we switched trunk to URI.escape path params and CGI.escape query params. Unforunately it's not so cut & dried.

02/13/07 09:28:31 changed by chrisroos

Hmm. I kinda suspected as much (what with me having to change the assertions in one of the existing tests!)

You think we can treat space/+ as a special case? If so, I can revert the test I changed and rework the patch.

Is there any further background on the space/+ issue I can take into account?

02/14/07 17:00:48 changed by chrisroos

Ok, so I've amended the patch to treat + as a special case. I reverted the one original test that I changed (test_recognize_with_encoded_id_and_regex) and all now passes.

02/14/07 17:01:30 changed by chrisroos

  • attachment routing.1.patch added.

02/21/07 10:05:36 changed by bitsweat

  • status changed from new to closed.
  • resolution set to fixed.

04/20/07 08:07:27 changed by begemot

  • priority changed from normal to high.
  • status changed from closed to reopened.
  • resolution deleted.
  • severity changed from normal to major.

Please rollback this patch. The existing behaviour was correct. After the change it is impossible to tell '+' from ' ' inside a parameter. E.g. something that looks like "A+%2B+B" in a url becomes "A+++B" in the params[]. It also breaks assert_route when escaped characters are present.

Example routes.rb:

map.test '/test/:name/:action/:id', :controller => 'users', :requirements => { :name => /[\/]+/ }

Example tests:

def test_routing_1

assert_routing "/test/john/show", :name => 'john', :controller => 'users', :action => 'show'

end def test_routing_2

assert_routing "/test/joh+n/show", :name => 'joh n', :controller => 'users', :action => 'show'

end def test_routing_3

assert_routing "/test/joh+%2b+n/show", :name => 'joh + n', :controller => 'users', :action => 'show'

end

Failures: test_routing_2(RoutesTest) The recognized options <{"name"=>"joh+n", "action"=>"show", "controller"=>"users"}> did not match <{"name"=>"joh n", "action"=>"show", "controller"=>"users"}>, difference: <{"name"=>"joh n"}>

test_routing_3(RoutesTest) The recognized options <{"name"=>"joh+++n", "action"=>"show", "controller"=>"users"}> did not match <{"name"=>"joh + n", "action"=>"show", "controller"=>"users"}>, difference: <{"name"=>"joh + n"}>

04/20/07 08:10:30 changed by begemot

  • cc changed from bitsweat to bitsweat, begemot.

05/14/07 10:29:47 changed by bitsweat

  • owner changed from core to bitsweat.
  • priority changed from high to normal.
  • status changed from reopened to new.
  • severity changed from major to normal.

I've revisited this; neither solution looks correct. CGI.escape escapes too much; URI.escape escapes too little.

According to RFC 2396 section 3.3,

      pchar         = unreserved | escaped |
                      ":" | "@" | "&" | "=" | "+" | "$" | ","

05/14/07 11:14:34 changed by bitsweat

  • status changed from new to closed.
  • resolution set to fixed.

(In [6730]) Rationalize route path escaping according to RFC 2396 section 3.3. Closes #7544, #8307.