Jump To Content

LearnHub




Dealing with Microsoft Office Protocol Discovery in Rails

Opening hyperlinks the 'Microsoft Way'

When you embed a link in a Microsoft word document, Word will use "Microsoft Office Protocol Discovery" to determine if the document can be edited by Word (via DAV for example). This can result in some strange emails littering your inbox if you are running a Ruby on Rails based site with exception notifier.

For example:


A ActionController::NotImplemented occurred in application#index:

 Only  requests are allowed.
 [RAILS_ROOT]/vendor/rails/actionpack/lib/action_controller/routing/route_set.rb:389:in `recognize_path'

-------------------------------
Environment:
-------------------------------

 * CONTENT_LENGTH         : 0
 * HTTP_CONTENT_LENGTH    : 0
 * HTTP_USER_AGENT        : Microsoft Office Protocol Discovery
 * HTTP_VERSION           : HTTP/1.1
 * REQUEST_METHOD         : OPTIONS
 * REQUEST_URI            : /static/

By default RoR routing will route GET, PUT, POST, DELETE and HEAD request methods, but Office is using OPTIONS, which is described in RFC 2616

I suppose that this is useful if you are running an intranet site, but in that case you're likely using something like Sharepoint, not a custom RoR application. These requests can be served by setting up a catch all route that will intercept any OPTIONS requests, and then return an appropriate header. Since we don't support any of the features that Office is looking for, a simple 200 status will suffice.

You can serve these requests from whichever controller you feel is appropriate. In my case I'll use a controller called 'index'

In config/routes.rb

map.connect '*path', 
            :controller => 'index', 
            :action => 'options_for_mopd', 
            :conditions => {:method => :options}
In app/controllers/index_controller.rb

  def options_for_mopd
    render :nothing => true, :status => 200
  end
Rails doesn't support the OPTIONS HTTP verb, so we'll have to monkey patch to add it. In lib/extra_http_verbs.rb

module ActionController
  module Routing
    HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
  end
end

Make sure to require lib/extra_http_verbs.rb in an initializer.

Testing it is rather easy, even though RoR doesn't have a function defined for OPTIONS like it does for GET, POST, PUT, DELETE and HEAD. In test/functional/index_controller_test.rb


  def test_options_for_mopd
    get :options_for_mopd, {}, :REQUEST_METHOD => 'OPTIONS'
    assert_response :success
  end

For more information about Microsoft Office Protocol Discovery, see this knowledge base article


  1. Carsten saidThu, 12 Jun 2008 18:17:41 -0000 ( Link )

    Cool Wes, I was getting sick of those exceptions!

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  2. jwallace41 saidThu, 26 Jun 2008 04:29:25 -0000 ( Link )

    Two things. I think it should be ‘path’ instead of ‘path’ and to test that it actually works, you can use curl which is available on every platform pretty much for free.

    Here’s the curl command: curl -X OPTIONS http://:/

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  3. jwallace41 saidTue, 01 Jul 2008 10:39:06 -0000 ( Link )

    Heh, I’m glad you were able to figure out my post even with the HTML interpolation. :) For anyone else who comes along, the curl command example is: curl -X OPTIONS http://host:port/path/whatever/that/is

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  4. jwallace41 saidTue, 01 Jul 2008 10:59:56 -0000 ( Link )

    I’ve run across another issue with this solution and have yet to solve it. Basically, any URI that is invalid generates an exception in my app. For example: http://localhost:3000/asdf/sf/adfs/ads/f <—obviously invalid

    This occurs because of http://github.com/rails/rails/commit/dcaa074abf5691a933b9c55159cc7d98a02b3b2f and more information may be found at http://dev.rubyonrails.org/ticket/6953. My expectation is that since the first route doesn’t match that the matching attempts would continue through the routes file irrespective of the HTTP method.

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  5. wmoxam saidWed, 02 Jul 2008 19:08:55 -0000 ( Link )

    Hrmm, I’m going to have to rethink this.

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  6. eddm saidTue, 05 Aug 2008 20:55:32 -0000 ( Link )

    How about rendering a 404 status in index#options_for_mopd ? It might tell anything that is sending OPTIONS requests to stop it and give up.

    However, I may be full of crap and this might not work. :)

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  7. clinton saidWed, 06 Aug 2008 05:21:38 -0000 ( Link )

    I’m returning HTTP 405 – Method Not Allowed. Hopefully Microsoft Office will take the hint.

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  8. smulube saidThu, 26 Feb 2009 12:40:26 -0000 ( Link )

    For what it’s worth, I actually tackled these annoying exceptions caused by MS Office in a slightly different way. Instead of your ingenious rails monkey patching, it occurred to me that I might be able to filter out these OPTIONS requests before they even reach rails.

    At the moment I am still using Nginx in front of a cluster of Thin instances (haven’t yet switched to Phusion Passenger, which seems to be the new hotness), and Nginx has a HttpRewriteModule which lets me say this:

    if ($request_method = OPTIONS) {
        return 204;
    }

    So any OPTIONS request that comes in is handled by Nginx without incurring any application overhead at the Rails end, and I don’t get those annoying exception reports all the time.

    I haven’t looked into how you’d do this with Apache, but I’m sure there must be a similar way of doing this, which would also avoid messing with Rails code.

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  9. smulube saidThu, 26 Feb 2009 12:47:54 -0000 ( Link )

    sorry, double post caused by sign up weirdness…

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  10. jwallace41 saidSat, 28 Feb 2009 02:02:33 -0000 ( Link )

    We moved away from ExceptionNotifier some time ago and have just been ignoring this error in our Hoptoad error lists for some time now.

    But this week I ran across binary logic’s fork of hoptoad_notifier and incorporated his change into my own up to date fork of hoptoad_notifier.

    http://github.com/wallace/hoptoad_notifier/commit/6b7a1b27eeabf058a25ea4f11c38838f53131a98

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  11. jwallace41 saidSat, 28 Feb 2009 02:15:45 -0000 ( Link )

    Of course, the error still occurs, it just isn’t reported in hoptoad. Furthermore, to test use curl -X OPTIONS -A “Microsoft Data Access Internet Publishing Provider DAV 1.1” http://host/path/here

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  12. codeofficer saidThu, 12 Mar 2009 03:12:13 -0000 ( Link )

    FYI, if you’re using Rails 2.3, I just coded up a rack based gem you can use in your apps to divert these request, returning a status 200 before it even hits your rails stack. No more exceptions :)

    http://github.com/CodeOfficer/rack-options-request/tree/master

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  13. codeofficer saidSun, 12 Apr 2009 02:56:48 -0000 ( Link )

    good point, I’ll make the change :)

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  14. obelix74 saidThu, 11 Jun 2009 17:02:59 -0000 ( Link )

    Thanks for the post. It doesn’t quite work.

    /usr/local/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/routing.rb:270: warning: already initialized constant HTTP_METHODS /usr/local/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/routing/builder.rb:187:in `validate_route_conditions’: Invalid HTTP method specified in route conditions: {:method=>:options} (ArgumentError)

    Server dies here.

    Actions
    Vote
    Current Rating
    0
    Rate Up
    Rate Down
    No Votes

    Post Comments

  15. andyt saidThu, 03 Sep 2009 15:20:25 -0000 ( Link )

    The following mod_rewrite rule will do the job, and save all kinds of Rails freakery:

    RewriteCond %{REQUEST_METHOD} ^OPTIONS RewriteRule .* – [R=405,L]

    Actions
    Vote
    Current Rating
    1
    Rate Up
    Rate Down
    1 Total Vote

    Post Comments

Your Comment
Textile is Enabled (View Reference)