A more readable version of this here: http://stackoverflow.com/questions/4009082/rails-3-http-extensions-webdav-and-rack-app-mounting Hello, 1 The following is more to point out to the code devs an issue of rails that can be percieved as a flaw. 2 And also me asking some oppinions from people who know better. I want to add WebDAV to my Rails 3 App with Warden authentication. My warden middleware is injected via Devise. > http://github.com/chrisroberts/dav4rack http://github.com/hassox/warden http://github.com/plataformatec/devise I cannot mount DAV4Rack handlers from inside rails app (routes), like this: # in routes.rb mount DAV4Rack::Handler.new( :root => Rails.root.to_s, # <= it''s just an example :root_uri_path => ''/webdav'', :resource_class => Dav::DocumentResource # <= my custom resource, you could use FileResource from dav4rack ), :at => "/webdav" because rails validates HTTP verbs (GET POST PUT ..), and webdav uses HTTP extensions like PROPFIND that do not validate, throwing the following exception: ActionController::UnknownHttpMethod (PROPFIND, accepted HTTP methods are get, head, put, post, delete, and options) This validation takes place in ActionDispatch: /usr/local/lib/ruby/gems/1.9.1/gems/actionpack-3.0.0/lib/ action_dispatch/http/request.rb +56 +72 in (56) "def request_method" and (72) "def method" Sample code from ActionDispatch that does the validation, to make things clear: def method @method ||= begin method = env["rack.methodoverride.original_method"] || env[''REQUEST_METHOD''] HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") method end end To add DAV4Rack handlers to the rails app I have to mount the handler outside of ActionDispatch, at rack level, like this: # config.ru require ::File.expand_path(''../config/environment'', __FILE__) require ''dav4rack/interceptor'' require ''dav/document_resource'' app = Rack::Builder.new{ map ''/webdav/'' do run DAV4Rack::Handler.new( :root => Rails.root.to_s, :root_uri_path => ''/webdav'', :resource_class => Dav::DocumentResource ) end map ''/'' do use DAV4Rack::Interceptor, :mappings => { ''/webdav/'' => { :resource_class => Dav::DocumentResource }, } run Pmp::Application end }.to_app run app Now I have Webdav support in my application. But It still needs authentication, and for that I''d like to use warden. # in document_resource.rb def check_authentication puts request.env[''warden''] # nil :( end Warden is nil because my DAV4Rack::Handler is mounted above the session and warden middleware. Using "rake middleware" to inspect my stack I can see the following: > rake middleware use ActionDispatch::Static use Rack::Lock use ActiveSupport::Cache::Strategy::LocalCache use Rack::Runtime use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::RemoteIp use Rack::Sendfile use ActionDispatch::Callbacks use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ParamsParser use Rack::MethodOverride use ActionDispatch::Head use ActionDispatch::BestStandardsSupport use Warden::Manager run Pmp::Application.routes I believe that by wrapping "Pmp::Application.routes" with DAV handler (just like I do above for "Pmp::Application" in config.ru) will inject my webdav handler in the stack at the right place to satisfy the two conditions: 1. Be above ActionDispatch method validation code, to avoid ActionController::UnknownHttpMethod 2. Be below session and Warden::Manager so I can use warden authentication. How to do that? Looking at "rake middleware" otput it seems obvious to override the "Pmp::Application.routes" method: # in my app at APP_ROOT/config/application.rb # override the routes method inherited from Rails::Application#routes def routes routes_app = super app = Rack::Builder.new { map ''/webdav/'' do run DAV4Rack::Handler.new( :root => Rails.root.to_s, :root_uri_path => ''/webdav'', :resource_class => Dav::DocumentResource ) end map ''/'' do use DAV4Rack::Interceptor, :mappings => { ''/webdav/'' => { :resource_class => Dav::DocumentResource }, } run routes_app end }.to_app class << app; self end.class_eval do attr_accessor :routes_app def method_missing(sym, *args, &block) routes_app.send sym, *args, &block end end app.routes_app = routes_app app end Because our replacing rack application "app" will be asked a few methods down the chain, that we do not implement, we delegate theese to the old original application "routes_app" with a little method_missing magic. And voila: evrything is working! Great success. Only one problem: I don''t like it. There must be a better way to do all this enveloping, other than overriding routes method. ### THE BIG QUESTION: IS THERE A BETTER WAY TO ADD A RACK APP JUST ABOVE THE "Pmp::Application#routes" APP BY MEANS OF RACK MOUNT OR OTHER ??? ### THE BIG CONCLUSION 1. The "mount" semantics in routes.rb should be rack-level (not rails/ railtie/whatever), to allow, in this way, hadling of HTTP extensions, or at least have a method for this case "mount_rack" -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.