summary refs log tree commit
diff options
context:
space:
mode:
authorRyan Tomayko <rtomayko@gmail.com>2009-01-15 05:46:21 -0800
committerRyan Tomayko <rtomayko@gmail.com>2009-12-22 14:35:48 -0800
commitaea2d608fe592a665741087a8d6d31fcf26848ec (patch)
tree64757c1156f3ea0db2e1cc940574a126766bcb6e
parent1ffa95c55394c862798727ac8b203ecedda8842a (diff)
downloadrack-aea2d608fe592a665741087a8d6d31fcf26848ec.tar.gz
Use Content-Type to determine POST params parsing [#20]
Reverts the hard test for a 'PUT' request method (8d01dc0) and
uses the Content-Type to determine whether to read into the
request body. The Request#POST method parses the request body
if (and only if) either of the following conditions are met:

1. The request's Content-Type is application/x-www-form-urlencoded
   or multipart/form-data. Note: the REQUEST_METHOD is ignored in
   this case.

2. The original REQUEST_METHOD is 'POST' and no Content-Type header
   was specified in the request. Note that we use the REQUEST_METHOD
   value before any modifications by the MethodOverride middleware.

This is very similar to how this worked prior to 8d01dc0 but
narrows the 'no Content-Type' special case to apply only to
POST requests. A PUT request with no Content-Type header would
trigger parsing before - with this change only POST requests
with no Content-Type trigger parsing.
-rw-r--r--lib/rack/request.rb14
-rw-r--r--test/spec_rack_request.rb26
2 files changed, 30 insertions, 10 deletions
diff --git a/lib/rack/request.rb b/lib/rack/request.rb
index 957abbb5..b3de1ce4 100644
--- a/lib/rack/request.rb
+++ b/lib/rack/request.rb
@@ -90,7 +90,6 @@ module Rack
     # one of the media types presents in this list will not be eligible
     # for form-data / param parsing.
     FORM_DATA_MEDIA_TYPES = [
-      nil,
       'application/x-www-form-urlencoded',
       'multipart/form-data'
     ]
@@ -104,12 +103,17 @@ module Rack
     ]
 
     # Determine whether the request body contains form-data by checking
-    # the request media_type against registered form-data media-types:
-    # "application/x-www-form-urlencoded" and "multipart/form-data". The
+    # the request Content-Type for one of the media-types:
+    # "application/x-www-form-urlencoded" or "multipart/form-data". The
     # list of form-data media types can be modified through the
     # +FORM_DATA_MEDIA_TYPES+ array.
+    #
+    # A request body is also assumed to contain form-data when no
+    # Content-Type header is provided and the request_method is POST.
     def form_data?
-      FORM_DATA_MEDIA_TYPES.include?(media_type)
+      type = media_type
+      meth = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD']
+      (meth == 'POST' && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type)
     end
 
     # Determine whether the request body contains data by checking
@@ -158,7 +162,7 @@ module Rack
 
     # The union of GET and POST data.
     def params
-      self.put? ? self.GET : self.GET.update(self.POST)
+      self.GET.update(self.POST)
     rescue EOFError => e
       self.GET
     end
diff --git a/test/spec_rack_request.rb b/test/spec_rack_request.rb
index f0e1a5ca..fcdeb484 100644
--- a/test/spec_rack_request.rb
+++ b/test/spec_rack_request.rb
@@ -66,9 +66,11 @@ context "Rack::Request" do
     lambda { req.POST }.should.raise(RuntimeError)
   end
 
-  specify "can parse POST data" do
+  specify "can parse POST data when method is POST and no Content-Type given" do
     req = Rack::Request.new \
-      Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla")
+      Rack::MockRequest.env_for("/?foo=quux",
+        "REQUEST_METHOD" => 'POST',
+        :input => "foo=bar&quux=bla")
     req.content_type.should.be.nil
     req.media_type.should.be.nil
     req.query_string.should.equal "foo=quux"
@@ -77,7 +79,7 @@ context "Rack::Request" do
     req.params.should.equal "foo" => "bar", "quux" => "bla"
   end
 
-  specify "can parse POST data with explicit content type" do
+  specify "can parse POST data with explicit content type regardless of method" do
     req = Rack::Request.new \
       Rack::MockRequest.env_for("/",
         "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
@@ -92,6 +94,7 @@ context "Rack::Request" do
   specify "does not parse POST data when media type is not form-data" do
     req = Rack::Request.new \
       Rack::MockRequest.env_for("/?foo=quux",
+        "REQUEST_METHOD" => 'POST',
         "CONTENT_TYPE" => 'text/plain;charset=utf-8',
         :input => "foo=bar&quux=bla")
     req.content_type.should.equal 'text/plain;charset=utf-8'
@@ -102,6 +105,16 @@ context "Rack::Request" do
     req.body.read.should.equal "foo=bar&quux=bla"
   end
 
+  specify "can parse POST data on PUT when media type is form-data" do
+    req = Rack::Request.new \
+      Rack::MockRequest.env_for("/?foo=quux",
+        "REQUEST_METHOD" => 'PUT',
+        "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
+        :input => "foo=bar&quux=bla")
+    req.POST.should.equal "foo" => "bar", "quux" => "bla"
+    req.body.read.should.equal "foo=bar&quux=bla"
+  end
+
   specify "rewinds input after parsing POST data" do
     input = StringIO.new("foo=bar&quux=bla")
     req = Rack::Request.new \
@@ -114,7 +127,8 @@ context "Rack::Request" do
 
   specify "cleans up Safari's ajax POST body" do
     req = Rack::Request.new \
-      Rack::MockRequest.env_for("/", :input => "foo=bar&quux=bla\0")
+      Rack::MockRequest.env_for("/",
+        'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
     req.POST.should.equal "foo" => "bar", "quux" => "bla"
   end
 
@@ -173,7 +187,9 @@ context "Rack::Request" do
 
   specify "can cache, but invalidates the cache" do
     req = Rack::Request.new \
-      Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla")
+      Rack::MockRequest.env_for("/?foo=quux",
+        "CONTENT_TYPE" => "application/x-www-form-urlencoded",
+        :input => "foo=bar&quux=bla")
     req.GET.should.equal "foo" => "quux"
     req.GET.should.equal "foo" => "quux"
     req.env["QUERY_STRING"] = "bla=foo"