33module Grape
44 module Middleware
55 class Formatter < Base
6- CHUNKED = 'chunked'
7- FORMAT = 'format'
86
97 def default_options
108 {
@@ -69,34 +67,27 @@ def ensure_content_type(headers)
6967 end
7068 end
7169
72- def request
73- @request ||= Rack ::Request . new ( env )
74- end
75-
76- # store read input in env['api.request.input']
7770 def read_body_input
78- return unless
79- ( request . post? || request . put? || request . patch? || request . delete? ) &&
80- ( !request . form_data? || !request . media_type ) &&
81- !request . parseable_data? &&
82- ( request . content_length . to_i . positive? || request . env [ Grape ::Http ::Headers ::HTTP_TRANSFER_ENCODING ] == CHUNKED )
83-
84- return unless ( input = env [ Rack ::RACK_INPUT ] )
71+ input = rack_request . body # reads RACK_INPUT
72+ return if input . nil?
73+ return unless read_body_input?
8574
8675 input . try ( :rewind )
8776 body = env [ Grape ::Env ::API_REQUEST_INPUT ] = input . read
8877 begin
89- read_rack_input ( body ) if body && ! body . empty?
78+ read_rack_input ( body )
9079 ensure
9180 input . try ( :rewind )
9281 end
9382 end
9483
95- # store parsed input in env['api.request.body']
9684 def read_rack_input ( body )
97- fmt = request . media_type ? mime_types [ request . media_type ] : options [ :default_format ]
85+ return if body . empty?
86+
87+ media_type = rack_request . media_type
88+ fmt = media_type ? mime_types [ media_type ] : options [ :default_format ]
9889
99- throw :error , status : 415 , message : "The provided content-type '#{ request . media_type } ' is not supported." unless content_type_for ( fmt )
90+ throw :error , status : 415 , message : "The provided content-type '#{ media_type } ' is not supported." unless content_type_for ( fmt )
10091 parser = Grape ::Parser . parser_for fmt , options [ :parsers ]
10192 if parser
10293 begin
@@ -119,8 +110,21 @@ def read_rack_input(body)
119110 end
120111 end
121112
113+ # this middleware will not try to format the following content-types since Rack already handles them
114+ # when calling Rack's `params` function
115+ # - application/x-www-form-urlencoded
116+ # - multipart/form-data
117+ # - multipart/related
118+ # - multipart/mixed
119+ def read_body_input?
120+ ( rack_request . post? || rack_request . put? || rack_request . patch? || rack_request . delete? ) &&
121+ !( rack_request . form_data? && rack_request . content_type ) &&
122+ !rack_request . parseable_data? &&
123+ ( rack_request . content_length . to_i . positive? || rack_request . env [ Grape ::Http ::Headers ::HTTP_TRANSFER_ENCODING ] == 'chunked' )
124+ end
125+
122126 def negotiate_content_type
123- fmt = format_from_extension || format_from_params || options [ :format ] || format_from_header || options [ :default_format ]
127+ fmt = format_from_extension || query_params [ 'format' ] || options [ :format ] || format_from_header || options [ :default_format ]
124128 if content_type_for ( fmt )
125129 env [ Grape ::Env ::API_FORMAT ] = fmt . to_sym
126130 else
@@ -129,18 +133,14 @@ def negotiate_content_type
129133 end
130134
131135 def format_from_extension
132- request_path = request . path . try ( :scrub )
136+ request_path = rack_request . path . try ( :scrub )
133137 dot_pos = request_path . rindex ( '.' )
134138 return unless dot_pos
135139
136140 extension = request_path [ dot_pos + 1 ..]
137141 extension if content_type_for ( extension )
138142 end
139143
140- def format_from_params
141- Rack ::Utils . parse_nested_query ( env [ Rack ::QUERY_STRING ] ) [ FORMAT ]
142- end
143-
144144 def format_from_header
145145 accept_header = env [ Grape ::Http ::Headers ::HTTP_ACCEPT ] . try ( :scrub )
146146 return if accept_header . blank?
0 commit comments