[offtopic] HTTP Authentication in Safari is broken for RESTful Rails

There's currently a bug in Safari, or more likely somewhere in the OS X HTTP API that breaks HTTP Authentication when there is a semicolon in the path part of the URL. This means it's impossible to use HTTP Authentication when you're building a RESTful Rails app that needs to work in Safari.

More details can be found at http://bugs.webkit.org/show_bug.cgi?id=10073

There's a test page at http://onautopilot.com/test;webkit that should ask you for a username and a password.

Right now this still seems to be broken in Leopard. It would be great if somebody who knows the right people inside Apple could try to raise awareness of this issue. It would be somewhat ironic if Leopard Server ships with Rails while this is still broken.

Kind regards,
Thijs

I stumbled across this in September, and it required this ugly, ugly work around:
http://toolmantim.com/article/2006/9/19/safari_urls_the_semi_colon_and_one_night_in_paris

Thanks for raising the issue properly and trying to get it addressed.

-- tim

Great idea to try escaping the semicolon!
For those interested, you can work around this issue by adding the following to your ApplicationController in app/controllers/application.rb:

   # make HTTP Authentication work on Safari for RESTful Rails
   alias_method :orig_url_for, :url_for
   def url_for(options = {}, *parameters_for_method_reference)
     result = orig_url_for(options, parameters_for_method_reference)
     if request.env['HTTP_USER_AGENT'].to_s.include? 'AppleWebKit'
       result.is_a?(String) ? result.gsub(';', '%3B') : result
     else
       result
     end
   end

Kind regards,
Thijs

Very nice, Thijs. A minor nitpick, and nothing to do with the actual solution: when overriding a method in a subclass, you can just call 'super' to get at the original. You don't actually need to alias the original. The alias trick is only needed when you are altering a method of the current class. For instance, if you were monkeypatching a new url_for implementation into ActionController::Base itself, you'd need to use alias there to preserve the original url_for.

- Jamis Buck
jamis@37signals.com

Thanks Thijs, updated accordingly (with slightly cleaner code):
http://toolmantim.com/article/2006/9/19/safari_urls_the_semi_colon_and_one_night_in_paris

-- tim

At first I tried to call super as Tim did, but I ended up with an url without the ';edit' part while using the url helpers generated by ActionController::Resources.

I've looked into this again and it seems that I need to explicitly pass the parameters to super to make it work. Like this:

   def url_for(options = {}, *parameters_for_method_reference)
     result = super(options, parameters_for_method_reference)
     if request.env['HTTP_USER_AGENT'].to_s.include? 'AppleWebKit'
       result.is_a?(String) ? result.gsub(';','%3B') : result
     else
       result
     end
   end

My understanding of super was that it passed the original method's parameters, but maybe not in this case.

Kind regards,
Thijs

PGP.sig (186 Bytes)