提交 02482671 编写于 作者: A Andrew White

Merge pull request #9700 from senny/6513_integration_test_headers

rework passing headers and env variables in integration tests
## Rails 4.0.0 (unreleased) ##
* `ActionDispatch::IntegrationTest` allows headers and rack env
variables to be passed when performing requests.
Fixes #6513.
Example:
get "/success", {}, "HTTP_REFERER" => "http://test.com/",
"Host" => "http://test.com"
*Yves Senn*
* Http::Headers respects headers that are not prefixed with HTTP_
*Yves Senn*
* Fix incorrectly appended square brackets to a multiple select box
if an explicit name has been given and it already ends with "[]"
......
module ActionDispatch
module Http
class Headers
CGI_VARIABLES = %w(
CONTENT_TYPE CONTENT_LENGTH
HTTPS AUTH_TYPE GATEWAY_INTERFACE
PATH_INFO PATH_TRANSLATED QUERY_STRING
REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER
REQUEST_METHOD SCRIPT_NAME
SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE
)
HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
include Enumerable
attr_reader :env
def initialize(env = {})
@headers = env
@env = {}
merge!(env)
end
def [](key)
@env[env_name(key)]
end
def [](header_name)
@headers[env_name(header_name)]
def []=(key, value)
@env[env_name(key)] = value
end
def []=(k,v); @headers[k] = v; end
def key?(k); @headers.key? k; end
def key?(key); @env.key? key; end
alias :include? :key?
def fetch(header_name, *args, &block)
@headers.fetch env_name(header_name), *args, &block
def fetch(key, *args, &block)
@env.fetch env_name(key), *args, &block
end
def each(&block)
@headers.each(&block)
@env.each(&block)
end
private
def merge(headers_or_env)
headers = Http::Headers.new(env.dup)
headers.merge!(headers_or_env)
headers
end
# Converts a HTTP header name to an environment variable name if it is
# not contained within the headers hash.
def env_name(header_name)
@headers.include?(header_name) ? header_name : cgi_name(header_name)
def merge!(headers_or_env)
headers_or_env.each do |key, value|
self[env_name(key)] = value
end
end
def cgi_name(k)
"HTTP_#{k.upcase.gsub(/-/, '_')}"
private
def env_name(key)
key = key.to_s
if key =~ HTTP_HEADER
key = key.upcase.tr('-', '_')
key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
end
key
end
end
end
......
......@@ -17,7 +17,7 @@ module RequestHelpers
# a Hash, or a String that is appropriately encoded
# (<tt>application/x-www-form-urlencoded</tt> or
# <tt>multipart/form-data</tt>).
# - +headers+: Additional headers to pass, as a Hash. The headers will be
# - +headers_or_env+: Additional headers to pass, as a Hash. The headers will be
# merged into the Rack env hash.
#
# This method returns a Response object, which one can use to
......@@ -28,44 +28,44 @@ module RequestHelpers
#
# You can also perform POST, PATCH, PUT, DELETE, and HEAD requests with
# +#post+, +#patch+, +#put+, +#delete+, and +#head+.
def get(path, parameters = nil, headers = nil)
process :get, path, parameters, headers
def get(path, parameters = nil, headers_or_env = nil)
process :get, path, parameters, headers_or_env
end
# Performs a POST request with the given parameters. See +#get+ for more
# details.
def post(path, parameters = nil, headers = nil)
process :post, path, parameters, headers
def post(path, parameters = nil, headers_or_env = nil)
process :post, path, parameters, headers_or_env
end
# Performs a PATCH request with the given parameters. See +#get+ for more
# details.
def patch(path, parameters = nil, headers = nil)
process :patch, path, parameters, headers
def patch(path, parameters = nil, headers_or_env = nil)
process :patch, path, parameters, headers_or_env
end
# Performs a PUT request with the given parameters. See +#get+ for more
# details.
def put(path, parameters = nil, headers = nil)
process :put, path, parameters, headers
def put(path, parameters = nil, headers_or_env = nil)
process :put, path, parameters, headers_or_env
end
# Performs a DELETE request with the given parameters. See +#get+ for
# more details.
def delete(path, parameters = nil, headers = nil)
process :delete, path, parameters, headers
def delete(path, parameters = nil, headers_or_env = nil)
process :delete, path, parameters, headers_or_env
end
# Performs a HEAD request with the given parameters. See +#get+ for more
# details.
def head(path, parameters = nil, headers = nil)
process :head, path, parameters, headers
def head(path, parameters = nil, headers_or_env = nil)
process :head, path, parameters, headers_or_env
end
# Performs a OPTIONS request with the given parameters. See +#get+ for
# more details.
def options(path, parameters = nil, headers = nil)
process :options, path, parameters, headers
def options(path, parameters = nil, headers_or_env = nil)
process :options, path, parameters, headers_or_env
end
# Performs an XMLHttpRequest request with the given parameters, mirroring
......@@ -74,11 +74,11 @@ def options(path, parameters = nil, headers = nil)
# The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or
# +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart
# string; the headers are a hash.
def xml_http_request(request_method, path, parameters = nil, headers = nil)
headers ||= {}
headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
headers['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
process(request_method, path, parameters, headers)
def xml_http_request(request_method, path, parameters = nil, headers_or_env = nil)
headers_or_env ||= {}
headers_or_env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
headers_or_env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
process(request_method, path, parameters, headers_or_env)
end
alias xhr :xml_http_request
......@@ -95,40 +95,40 @@ def follow_redirect!
# redirect. Note that the redirects are followed until the response is
# not a redirect--this means you may run into an infinite loop if your
# redirect loops back to itself.
def request_via_redirect(http_method, path, parameters = nil, headers = nil)
process(http_method, path, parameters, headers)
def request_via_redirect(http_method, path, parameters = nil, headers_or_env = nil)
process(http_method, path, parameters, headers_or_env)
follow_redirect! while redirect?
status
end
# Performs a GET request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
def get_via_redirect(path, parameters = nil, headers = nil)
request_via_redirect(:get, path, parameters, headers)
def get_via_redirect(path, parameters = nil, headers_or_env = nil)
request_via_redirect(:get, path, parameters, headers_or_env)
end
# Performs a POST request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
def post_via_redirect(path, parameters = nil, headers = nil)
request_via_redirect(:post, path, parameters, headers)
def post_via_redirect(path, parameters = nil, headers_or_env = nil)
request_via_redirect(:post, path, parameters, headers_or_env)
end
# Performs a PATCH request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
def patch_via_redirect(path, parameters = nil, headers = nil)
request_via_redirect(:patch, path, parameters, headers)
def patch_via_redirect(path, parameters = nil, headers_or_env = nil)
request_via_redirect(:patch, path, parameters, headers_or_env)
end
# Performs a PUT request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
def put_via_redirect(path, parameters = nil, headers = nil)
request_via_redirect(:put, path, parameters, headers)
def put_via_redirect(path, parameters = nil, headers_or_env = nil)
request_via_redirect(:put, path, parameters, headers_or_env)
end
# Performs a DELETE request, following any subsequent redirect.
# See +request_via_redirect+ for more information.
def delete_via_redirect(path, parameters = nil, headers = nil)
request_via_redirect(:delete, path, parameters, headers)
def delete_via_redirect(path, parameters = nil, headers_or_env = nil)
request_via_redirect(:delete, path, parameters, headers_or_env)
end
end
......@@ -268,8 +268,8 @@ def _mock_session
end
# Performs the actual request.
def process(method, path, parameters = nil, rack_env = nil)
rack_env ||= {}
def process(method, path, parameters = nil, headers_or_env = nil)
rack_env = Http::Headers.new(headers_or_env || {}).env
if path =~ %r{://}
location = URI.parse(path)
https! URI::HTTPS === location if location.scheme
......
......@@ -573,6 +573,21 @@ def test_failed_get
def test_generate_url_without_controller
assert_equal 'http://www.example.com/foo', url_for(:controller => "foo")
end
def test_pass_headers
get "/success", {}, "Referer" => "http://www.example.com/foo", "Host" => "http://nohost.com"
assert_equal "http://nohost.com", @request.env["HTTP_HOST"]
assert_equal "http://www.example.com/foo", @request.env["HTTP_REFERER"]
end
def test_pass_env
get "/success", {}, "HTTP_REFERER" => "http://test.com/", "HTTP_HOST" => "http://test.com"
assert_equal "http://test.com", @request.env["HTTP_HOST"]
assert_equal "http://test.com/", @request.env["HTTP_REFERER"]
end
end
class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
......
require 'abstract_unit'
require "abstract_unit"
class HeaderTest < ActiveSupport::TestCase
def setup
setup do
@headers = ActionDispatch::Http::Headers.new(
"HTTP_CONTENT_TYPE" => "text/plain"
"CONTENT_TYPE" => "text/plain",
"HTTP_REFERER" => "/some/page"
)
end
def test_each
test "#new with mixed headers and env" do
headers = ActionDispatch::Http::Headers.new(
"Content-Type" => "application/json",
"HTTP_REFERER" => "/some/page",
"Host" => "http://test.com")
assert_equal({"CONTENT_TYPE" => "application/json",
"HTTP_REFERER" => "/some/page",
"HTTP_HOST" => "http://test.com"}, headers.env)
end
test "#env returns the headers as env variables" do
assert_equal({"CONTENT_TYPE" => "text/plain",
"HTTP_REFERER" => "/some/page"}, @headers.env)
end
test "#each iterates through the env variables" do
headers = []
@headers.each { |pair| headers << pair }
assert_equal [["HTTP_CONTENT_TYPE", "text/plain"]], headers
assert_equal [["CONTENT_TYPE", "text/plain"],
["HTTP_REFERER", "/some/page"]], headers
end
test "set new headers" do
@headers["Host"] = "127.0.0.1"
assert_equal "127.0.0.1", @headers["Host"]
assert_equal "127.0.0.1", @headers["HTTP_HOST"]
end
test "headers can contain numbers" do
@headers["Content-MD5"] = "Q2hlY2sgSW50ZWdyaXR5IQ=="
assert_equal "Q2hlY2sgSW50ZWdyaXR5IQ==", @headers["Content-MD5"]
assert_equal "Q2hlY2sgSW50ZWdyaXR5IQ==", @headers["HTTP_CONTENT_MD5"]
end
test "set new env variables" do
@headers["HTTP_HOST"] = "127.0.0.1"
assert_equal "127.0.0.1", @headers["Host"]
assert_equal "127.0.0.1", @headers["HTTP_HOST"]
end
def test_setter
@headers['foo'] = "bar"
assert_equal "bar", @headers['foo']
test "key?" do
assert @headers.key?("CONTENT_TYPE")
assert @headers.include?("CONTENT_TYPE")
end
def test_key?
assert @headers.key?('HTTP_CONTENT_TYPE')
assert @headers.include?('HTTP_CONTENT_TYPE')
test "fetch with block" do
assert_equal "omg", @headers.fetch("notthere") { "omg" }
end
def test_fetch_with_block
assert_equal 'omg', @headers.fetch('notthere') { 'omg' }
test "accessing http header" do
assert_equal "/some/page", @headers["Referer"]
assert_equal "/some/page", @headers["referer"]
assert_equal "/some/page", @headers["HTTP_REFERER"]
end
test "content type" do
test "accessing special header" do
assert_equal "text/plain", @headers["Content-Type"]
assert_equal "text/plain", @headers["content-type"]
assert_equal "text/plain", @headers["CONTENT_TYPE"]
assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"]
end
test "fetch" do
assert_equal "text/plain", @headers.fetch("content-type", nil)
assert_equal "not found", @headers.fetch('not-found', 'not found')
assert_equal "not found", @headers.fetch("not-found", "not found")
end
test "#merge! headers with mutation" do
@headers.merge!("Host" => "http://example.test",
"Content-Type" => "text/html")
assert_equal({"HTTP_HOST" => "http://example.test",
"CONTENT_TYPE" => "text/html",
"HTTP_REFERER" => "/some/page"}, @headers.env)
end
test "#merge! env with mutation" do
@headers.merge!("HTTP_HOST" => "http://first.com",
"CONTENT_TYPE" => "text/html")
assert_equal({"HTTP_HOST" => "http://first.com",
"CONTENT_TYPE" => "text/html",
"HTTP_REFERER" => "/some/page"}, @headers.env)
end
test "merge without mutation" do
combined = @headers.merge("HTTP_HOST" => "http://example.com",
"CONTENT_TYPE" => "text/html")
assert_equal({"HTTP_HOST" => "http://example.com",
"CONTENT_TYPE" => "text/html",
"HTTP_REFERER" => "/some/page"}, combined.env)
assert_equal({"CONTENT_TYPE" => "text/plain",
"HTTP_REFERER" => "/some/page"}, @headers.env)
end
test "env variables with . are not modified" do
headers = ActionDispatch::Http::Headers.new
headers.merge! "rack.input" => "",
"rack.request.cookie_hash" => "",
"action_dispatch.logger" => ""
assert_equal(["action_dispatch.logger",
"rack.input",
"rack.request.cookie_hash"], headers.env.keys.sort)
end
test "symbols are treated as strings" do
headers = ActionDispatch::Http::Headers.new(:SERVER_NAME => "example.com",
"HTTP_REFERER" => "/",
:Host => "test.com")
assert_equal "example.com", headers["SERVER_NAME"]
assert_equal "/", headers[:HTTP_REFERER]
assert_equal "test.com", headers["HTTP_HOST"]
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册