]> git.openstreetmap.org Git - rails.git/commitdiff
Rework set_default_request_format ast set_request_formats
authorTom Hughes <tom@compton.nu>
Sat, 29 Feb 2020 15:15:02 +0000 (15:15 +0000)
committerTom Hughes <tom@compton.nu>
Sat, 29 Feb 2020 15:28:23 +0000 (15:28 +0000)
Instead of trying to work out the exact format, just figure
out the list of allowed formats and let rails do the rest.

app/controllers/api/map_controller.rb
app/controllers/api/nodes_controller.rb
app/controllers/api/old_controller.rb
app/controllers/api/relations_controller.rb
app/controllers/api/ways_controller.rb
app/controllers/api_controller.rb

index 113554c72fb38ad590fcbfcf869ce8d7a20f4747..1b5150537bccb8299a990d4e0c47b20598a7df53 100644 (file)
@@ -5,7 +5,7 @@ module Api
     before_action :check_api_readable
     around_action :api_call_handle_error, :api_call_timeout
 
-    before_action :set_default_request_format
+    before_action :set_request_formats
 
     # This is probably the most common call of all. It is used for getting the
     # OSM data for a specified bounding box, usually for editing. First the
index 336aebc915793f05f4f7429214cb6ba74b169eb5..9204d96c0250c1901e0c031de81b6df25c6b9971 100644 (file)
@@ -13,7 +13,7 @@ module Api
     before_action :check_api_readable, :except => [:create, :update, :delete]
     around_action :api_call_handle_error, :api_call_timeout
 
-    before_action :set_default_request_format, :except => [:create, :update, :delete]
+    before_action :set_request_formats, :except => [:create, :update, :delete]
 
     # Create a node from XML.
     def create
index f672e7c4960d9c66c1d0e94c9dd2eac272c53a0e..f8e42476f878c11aaa6aac42f81b5f5ddf7d5536 100644 (file)
@@ -16,7 +16,7 @@ module Api
     before_action :lookup_old_element, :except => [:history]
     before_action :lookup_old_element_versions, :only => [:history]
 
-    before_action :set_default_request_format, :except => [:redact]
+    before_action :set_request_formats, :except => [:redact]
 
     def history
       # the .where() method used in the lookup_old_element_versions
index 329c5e29c7fa7adfc504da3ab7efcd719701adc7..28e4a026bc47a820a5eb40faa7aa1c221e6364f6 100644 (file)
@@ -11,7 +11,7 @@ module Api
     before_action :check_api_readable, :except => [:create, :update, :delete]
     around_action :api_call_handle_error, :api_call_timeout
 
-    before_action :set_default_request_format, :except => [:create, :update, :delete]
+    before_action :set_request_formats, :except => [:create, :update, :delete]
 
     def create
       assert_method :put
index a7c876710ce4c8eafbbab30566d63f42a71a48ca..3b58f208b14e729a696a0f7e2e0ba0cd6ada631e 100644 (file)
@@ -11,7 +11,7 @@ module Api
     before_action :check_api_readable, :except => [:create, :update, :delete]
     around_action :api_call_handle_error, :api_call_timeout
 
-    before_action :set_default_request_format, :except => [:create, :update, :delete]
+    before_action :set_request_formats, :except => [:create, :update, :delete]
 
     def create
       assert_method :put
index 64514a4321f8ff3523621fae28b2830f6f3fa6e5..478810dfc21d40448410662adf82179a2e0d60be 100644 (file)
@@ -4,52 +4,45 @@ class ApiController < ApplicationController
   private
 
   ##
-  # Set default request format to xml unless a client requests a specific format,
-  # which can be done via (a) URL suffix and/or (b) HTTP Accept header, where
-  # the URL suffix always takes precedence over the Accept header.
-  def set_default_request_format
+  # Set allowed request formats if no explicit format has been
+  # requested via a URL suffix. Allowed formats are taken from
+  # any HTTP Accept header with XML as the default.
+  def set_request_formats
     unless params[:format]
       accept_header = request.headers["HTTP_ACCEPT"]
-      if accept_header.nil?
-        # e.g. unit tests don't set an Accept: header by default, force XML in this case
-        request.format = "xml"
-        return
-      end
-
-      req_mimetypes = []
-
-      # Some clients (JOSM) send Accept headers which cannot be parsed by Rails, example: *; q=.2
-      # To be fair, JOSM's Accept header doesn't adhere to RFC 7231, section 5.3.1, et al. either
-      # As a workaround for backwards compatibility, we're assuming XML format
-      begin
-        req_mimetypes = Mime::Type.parse(accept_header)
-      rescue Mime::Type::InvalidMimeType
-        request.format = "xml"
-        return
-      end
-
-      # req_mimetypes contains all Accept header MIME types with descending priority
-      req_mimetypes.each do |mime|
-        if mime.symbol == :xml
-          request.format = "xml"
-          break
-        end
-
-        if mime.symbol == :json
-          request.format = "json"
-          break
-        end
 
-        # Any format, not explicitly requesting XML or JSON -> assume XML as default
-        if mime == "*/*"
-          request.format = "xml"
-          break
+      if accept_header
+        # Some clients (such asJOSM) send Accept headers which cannot be
+        # parse by Rails, for example:
+        #
+        #   Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
+        #
+        # where both "*" and ".2" as a quality do not adhere to the syntax
+        # described in RFC 7231, section 5.3.1, etc.
+        #
+        # As a workaround, and for back compatibility, default to XML format.
+        mimetypes = begin
+                      Mime::Type.parse(accept_header)
+                    rescue Mime::Type::InvalidMimeType
+                      Array(Mime[:xml])
+                    end
+
+        # Allow XML and JSON formats, and treat an all formats wildcard
+        # as XML for backwards compatibility - all other formats are discarded
+        # which will result in a 406 Not Acceptable response being sent
+        formats = mimetypes.map do |mime|
+          if mime.symbol == :xml then :xml
+          elsif mime.symbol == :json then :json
+          elsif mime == "*/*" then :xml
+          end
         end
-
-        # In case the client requests some other format besides XML, JSON and */*,
-        # we deliberately don't set request.format. The framework will return an
-        # ActionController::UnknownFormat error to the client later on in this case.
+      else
+        # Default to XML if no accept header was sent - this includes
+        # the unit tests which don't set one by default
+        formats = Array(:xml)
       end
+
+      request.formats = formats.compact
     end
   end