提交 86754a8f 编写于 作者: K Kasper Timm Hansen

Use accept header instead of mangling request path.

Instead of appending a format to the request, it's much better
to just pass a more appropriate accept header. Rails will figure
out the format from that instead.

This allows devs to use `:as` on routes that don't have a format.

Introduce an `IdentityEncoder` to avoid `if request_encoder`,
essentially a better version of the purpose of the `WWWFormEncoder`.
One that makes conceptual sense on GET requests too.

Fixes #27144.
上级 49aa974e
......@@ -211,7 +211,7 @@ def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: n
end
if path =~ %r{://}
path = build_expanded_path(path, request_encoder) do |location|
path = build_expanded_path(path) do |location|
https! URI::HTTPS === location if location.scheme
if url_host = location.host
......@@ -220,8 +220,6 @@ def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: n
host! url_host
end
end
elsif as
path = build_expanded_path(path, request_encoder)
end
hostname, port = host.split(":")
......@@ -239,7 +237,7 @@ def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: n
"HTTP_HOST" => host,
"REMOTE_ADDR" => remote_addr,
"CONTENT_TYPE" => request_encoder.content_type,
"HTTP_ACCEPT" => accept
"HTTP_ACCEPT" => request_encoder.accept_header || accept
}
wrapped_headers = Http::Headers.from_hash({})
......@@ -291,10 +289,10 @@ def build_full_uri(path, env)
"#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}"
end
def build_expanded_path(path, request_encoder)
def build_expanded_path(path)
location = URI.parse(path)
yield location if block_given?
path = request_encoder.append_format_to location.path
path = location.path
location.query ? "#{path}?#{location.query}" : path
end
end
......
module ActionDispatch
class RequestEncoder # :nodoc:
@encoders = {}
class IdentityEncoder
def content_type; end
def accept_header; end
def encode_params(params); params; end
def response_parser; -> body { body }; end
end
@encoders = { identity: IdentityEncoder.new }
attr_reader :response_parser
def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false)
def initialize(mime_name, param_encoder, response_parser = nil)
@mime = Mime[mime_name]
unless @mime
......@@ -12,21 +19,15 @@ def initialize(mime_name, param_encoder, response_parser, url_encoded_form = fal
"unregistered MIME Type: #{mime_name}. See `Mime::Type.register`."
end
@url_encoded_form = url_encoded_form
@path_format = ".#{@mime.symbol}" unless @url_encoded_form
@response_parser = response_parser || -> body { body }
@param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc
@response_parser = response_parser || -> body { body }
@param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc
end
def append_format_to(path)
if @url_encoded_form
path
else
path + @path_format
end
def content_type
@mime.to_s
end
def content_type
def accept_header
@mime.to_s
end
......@@ -40,7 +41,7 @@ def self.parser(content_type)
end
def self.encoder(name)
@encoders[name] || WWWFormEncoder
@encoders[name] || @encoders[:identity]
end
def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil)
......@@ -48,7 +49,5 @@ def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil)
end
register_encoder :json, response_parser: -> body { JSON.parse(body) }
WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true)
end
end
......@@ -930,6 +930,10 @@ def test_cookies_set_in_setup_are_persisted_through_the_session
class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest
class FooController < ActionController::Base
def foos
render plain: "ok"
end
def foos_json
render json: params.permit(:foo)
end
......@@ -958,13 +962,30 @@ def test_standard_json_encoding_works
def test_encoding_as_json
post_to_foos as: :json do
assert_response :success
assert_match "foos_json.json", request.path
assert_equal "application/json", request.content_type
assert_equal "application/json", request.accepts.first.to_s
assert_equal :json, request.format.ref
assert_equal({ "foo" => "fighters" }, request.request_parameters)
assert_equal({ "foo" => "fighters" }, response.parsed_body)
end
end
def test_doesnt_mangle_request_path
with_routing do |routes|
routes.draw do
ActiveSupport::Deprecation.silence do
post ":action" => FooController
end
end
post "/foos"
assert_equal "/foos", request.path
post "/foos_json", as: :json
assert_equal "/foos_json", request.path
end
end
def test_encoding_as_without_mime_registration
assert_raise ArgumentError do
ActionDispatch::IntegrationTest.register_encoder :wibble
......@@ -979,8 +1000,10 @@ def test_registering_custom_encoder
post_to_foos as: :wibble do
assert_response :success
assert_match "foos_wibble.wibble", request.path
assert_equal "/foos_wibble", request.path
assert_equal "text/wibble", request.content_type
assert_equal "text/wibble", request.accepts.first.to_s
assert_equal :wibble, request.format.ref
assert_equal Hash.new, request.request_parameters # Unregistered MIME Type can't be parsed.
assert_equal "ok", response.parsed_body
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册