Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way of allowing encoded slashes in a URL segment in Rails 3?

What I want

I want to pass a URL segment with an encoded slash.


The Problem

  • Running locally on Thin, it works
  • Running on the server on Passenger/Nginx/Rack, it breaks
  • Something decodes the slash before it reaches Rails

My Question

  • What's the best way of allowing parameters to have slashes?

What I've Tried

  • Changing a '/' for a special character at the boundary - '!' for example. This is messy and causes other issues in other areas of the app
  • Changing Nginx config as per https://serverfault.com/questions/459369/disabling-url-decoding-in-nginx-proxy
  • Found this for Passenger: https://golem.ph.utexas.edu/wiki/instiki/show/Run+on+Port+80
  • This indicates that PassengerAllowEncodedSlashes on might solve this issue but hesitant to do this in case it affects security

The Detail

routes.rb

get '/api/shops/:city', to: 'shops#index', constraints: /[0-9A-Za-z\-\.\%\s]+/

Form

The user can select their area from a dropdown:

London/Dover
Glasgow/Edinburgh

On Submit

We hit the API with: /api/shops/London%2FDover

We encode the slash when building the url for obvious reasons.

This works...

Running locally on Rails on Thin.

The URL is recognised by the routes, the slash is decoded inside Rails and inside our application we have London/Dover as a parameter.

This breaks...

Running on the server on Nginx, Passenger and Rack.

The slash is decoded before it hits Rails.

/api/shops/London/Dover isn't a route so responds with a 404.

Versions

  • Passenger 3.0.2
  • Nginx 1.2.9
  • Rack 1.2 (Release 1.5)
  • Rails 3.2.17
like image 429
John Gallagher Avatar asked Oct 21 '25 10:10

John Gallagher


1 Answers

We faced the same problem. We tried encoding the string using CGI::escape , URI::encode, ERB::Util::url_encode, but nothing worked on server with passenger and nginx. The solution that worked for us was to modify the route to use wild card character, known as "Route Globbing". Refer this link : http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments

So, in your case, the route becomes

`get '/api/shops/*city', to: 'shops#index', constraints: /[0-9A-Za-z\-\.\%\s]+/ `

instead of get '/api/shops/:city', to: 'shops#index', constraints: /[0-9A-Za-z\-\.\%\s]+/.

Notice the wild card character in the route before parameter "city".

like image 64
Isha Aggarwal Avatar answered Oct 24 '25 01:10

Isha Aggarwal