Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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 mirceapricop authored mircea committed
4 actionpack/lib/abstract_controller/collector.rb
View
@@ -16,6 +16,10 @@ def #{sym}(*args, &block) # def html(*args, &block)
generate_method_for_mime(mime)
end
+ Mime::Type.register_callback do |mime|
+ generate_method_for_mime(mime) unless self.instance_methods.include?(mime.to_sym)
+ end
+
protected
def method_missing(symbol, &block)
13 actionpack/lib/action_dispatch/http/mime_type.rb
View
@@ -58,6 +58,8 @@ class Type
cattr_reader :browser_generated_types
attr_reader :symbol
+ @register_callbacks = []
+
# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
attr_accessor :order, :name, :q
@@ -89,6 +91,10 @@ class << self
TRAILING_STAR_REGEXP = /(text|application)\/\*/
PARAMETER_SEPARATOR_REGEXP = /;\s*\w+="?\w+"?/
+ def register_callback(&block)
+ @register_callbacks << block
+ end
+
def lookup(string)
LOOKUP[string]
end
@@ -106,10 +112,15 @@ def register_alias(string, symbol, extension_synonyms = [])
def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)
Mime.const_set(symbol.upcase, Type.new(string, symbol, mime_type_synonyms))
- SET << Mime.const_get(symbol.upcase)
+ new_mime = Mime.const_get(symbol.upcase)
+ SET << new_mime
([string] + mime_type_synonyms).each { |str| LOOKUP[str] = SET.last } unless skip_lookup
([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = SET.last }
+
+ @register_callbacks.each do |callback|
+ callback.call(new_mime)
+ end
end
def parse(accept_header)
4 actionpack/test/controller/mime_responds_test.rb
View
@@ -505,7 +505,7 @@ def test_invalid_format
end
class RespondWithController < ActionController::Base
- respond_to :html, :json
+ respond_to :html, :json, :touch
respond_to :xml, :except => :using_resource_with_block
respond_to :js, :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ]
@@ -623,12 +623,14 @@ def setup
super
@request.host = "www.example.com"
Mime::Type.register_alias('text/html', :iphone)
+ Mime::Type.register_alias('text/html', :touch)
Mime::Type.register('text/x-mobile', :mobile)
end
def teardown
super
Mime::Type.unregister(:iphone)
+ Mime::Type.unregister(:touch)
Mime::Type.unregister(:mobile)
end
14 actionpack/test/dispatch/mime_type_test.rb
View
@@ -118,6 +118,20 @@ class MimeTypeTest < ActiveSupport::TestCase
end
end
+ test "register callbacks" do
+ begin
+ registered_mimes = []
+ Mime::Type.register_callback do |mime|
+ registered_mimes << mime
+ end
+
+ Mime::Type.register("text/foo", :foo)
+ assert_equal registered_mimes, [Mime::FOO]
+ ensure
+ Mime::Type.unregister(:FOO)
+ end
+ end
+
test "custom type with extension aliases" do
begin
Mime::Type.register "text/foobar", :foobar, [], [:foo, "bar"]
Please sign in to comment.
Something went wrong with that request. Please try again.