Skip to content
This repository
Browse code

Prevent conflict between mime types and Object methods

Assuming the type ":touch", Collector.new was calling
send(:touch), which instead of triggering method_missing
and generating a new collector method, actually
invoked the private method `touch` inherited from
Object.

By generating the method for each mime type as it
is registered, the private methods on Object can
never be reached by `send`, because the `Collector`
will have them before `send` is called on it.

To do this, a callback mechanism was added to Mime::Type

This allows someone to add a callback for whenever
a new mime type is registered. The callback then
gets called with the new mime as a parameter.

This is then used in AbstractController::Collector
to generate new collector methods after each mime
is registered.
  • Loading branch information...
commit 021f3d24f32dbad98c72cd5c36ff0b511be07a64 1 parent 07314e6
Mircea Pricop authored July 06, 2012 mircea committed July 06, 2012
4  actionpack/lib/abstract_controller/collector.rb
@@ -16,6 +16,10 @@ def #{sym}(*args, &block)                # def html(*args, &block)
16 16
       generate_method_for_mime(mime)
17 17
     end
18 18
 
  19
+    Mime::Type.register_callback do |mime|
  20
+      generate_method_for_mime(mime) unless self.instance_methods.include?(mime.to_sym)
  21
+    end
  22
+
19 23
   protected
20 24
 
21 25
     def method_missing(symbol, &block)
13  actionpack/lib/action_dispatch/http/mime_type.rb
@@ -58,6 +58,8 @@ class Type
58 58
     cattr_reader :browser_generated_types
59 59
     attr_reader :symbol
60 60
 
  61
+    @register_callbacks = []
  62
+
61 63
     # A simple helper class used in parsing the accept header
62 64
     class AcceptItem #:nodoc:
63 65
       attr_accessor :order, :name, :q
@@ -89,6 +91,10 @@ class << self
89 91
       TRAILING_STAR_REGEXP = /(text|application)\/\*/
90 92
       PARAMETER_SEPARATOR_REGEXP = /;\s*\w+="?\w+"?/
91 93
 
  94
+      def register_callback(&block)
  95
+        @register_callbacks << block
  96
+      end
  97
+
92 98
       def lookup(string)
93 99
         LOOKUP[string]
94 100
       end
@@ -106,10 +112,15 @@ def register_alias(string, symbol, extension_synonyms = [])
106 112
       def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)
107 113
         Mime.const_set(symbol.upcase, Type.new(string, symbol, mime_type_synonyms))
108 114
 
109  
-        SET << Mime.const_get(symbol.upcase)
  115
+        new_mime = Mime.const_get(symbol.upcase)
  116
+        SET << new_mime
110 117
 
111 118
         ([string] + mime_type_synonyms).each { |str| LOOKUP[str] = SET.last } unless skip_lookup
112 119
         ([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = SET.last }
  120
+
  121
+        @register_callbacks.each do |callback|
  122
+          callback.call(new_mime)
  123
+        end
113 124
       end
114 125
 
115 126
       def parse(accept_header)
4  actionpack/test/controller/mime_responds_test.rb
@@ -505,7 +505,7 @@ def test_invalid_format
505 505
 end
506 506
 
507 507
 class RespondWithController < ActionController::Base
508  
-  respond_to :html, :json
  508
+  respond_to :html, :json, :touch
509 509
   respond_to :xml, :except => :using_resource_with_block
510 510
   respond_to :js,  :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ]
511 511
 
@@ -623,12 +623,14 @@ def setup
623 623
     super
624 624
     @request.host = "www.example.com"
625 625
     Mime::Type.register_alias('text/html', :iphone)
  626
+    Mime::Type.register_alias('text/html', :touch)
626 627
     Mime::Type.register('text/x-mobile', :mobile)
627 628
   end
628 629
 
629 630
   def teardown
630 631
     super
631 632
     Mime::Type.unregister(:iphone)
  633
+    Mime::Type.unregister(:touch)
632 634
     Mime::Type.unregister(:mobile)
633 635
   end
634 636
 
14  actionpack/test/dispatch/mime_type_test.rb
@@ -118,6 +118,20 @@ class MimeTypeTest < ActiveSupport::TestCase
118 118
     end
119 119
   end
120 120
 
  121
+  test "register callbacks" do
  122
+    begin
  123
+      registered_mimes = []
  124
+      Mime::Type.register_callback do |mime|
  125
+        registered_mimes << mime
  126
+      end
  127
+
  128
+      Mime::Type.register("text/foo", :foo)
  129
+      assert_equal registered_mimes, [Mime::FOO]
  130
+    ensure
  131
+      Mime::Type.unregister(:FOO)
  132
+    end
  133
+  end
  134
+
121 135
   test "custom type with extension aliases" do
122 136
     begin
123 137
       Mime::Type.register "text/foobar", :foobar, [], [:foo, "bar"]

0 notes on commit 021f3d2

Please sign in to comment.
Something went wrong with that request. Please try again.