Skip to content

Commit

Permalink
like :request_headers, env[:response_headers] is now case-insensitive
Browse files Browse the repository at this point in the history
  • Loading branch information
mislav committed Mar 26, 2011
1 parent 50da503 commit 8dccfc6
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 94 deletions.
6 changes: 2 additions & 4 deletions lib/faraday/adapter/action_dispatch.rb
Expand Up @@ -21,10 +21,8 @@ def call(env)
super
@session.__send__(env[:method], env[:url].request_uri, env[:body], env[:request_headers])
resp = @session.response
env.update \
:status => resp.status,
:response_headers => resp.headers,
:body => resp.body
env.update :status => resp.status, :body => resp.body
env[:response_headers].update resp.headers
@app.call env
end
end
Expand Down
10 changes: 2 additions & 8 deletions lib/faraday/adapter/excon.rb
Expand Up @@ -21,14 +21,8 @@ def call(env)
:headers => env[:request_headers],
:body => env[:body]

env.update \
:status => resp.status.to_i,
:response_headers => {},
:body => resp.body

resp.headers.each do |key, value|
env[:response_headers][key.downcase] = value
end
env.update :status => resp.status.to_i, :body => resp.body
env[:response_headers].update resp.headers

@app.call env
rescue ::Excon::Errors::SocketError
Expand Down
9 changes: 2 additions & 7 deletions lib/faraday/adapter/net_http.rb
Expand Up @@ -53,15 +53,10 @@ def call(env)
raise Error::ConnectionFailed, $!
end

response_headers = {}
http_response.each_header do |key, value|
response_headers[key] = value
env[:response_headers][key] = value
end

env.update \
:status => http_response.code.to_i,
:response_headers => response_headers,
:body => http_response.body
env.update :status => http_response.code.to_i, :body => http_response.body

@app.call env
end
Expand Down
6 changes: 2 additions & 4 deletions lib/faraday/adapter/patron.rb
Expand Up @@ -25,10 +25,8 @@ def call(env)
raise Error::ConnectionFailed, $!
end

env.update \
:status => response.status,
:response_headers => response.headers.inject({}) { |memo, (k, v)| memo[k.downcase] = v; memo },
:body => response.body
env.update :status => response.status, :body => response.body
env[:response_headers].update response.headers

@app.call env
end
Expand Down
15 changes: 2 additions & 13 deletions lib/faraday/adapter/typhoeus.rb
Expand Up @@ -31,10 +31,8 @@ def call(env)

is_parallel = !!env[:parallel_manager]
req.on_complete do |resp|
env.update \
:status => resp.code,
:response_headers => parse_response_headers(resp.headers),
:body => resp.body
env.update :status => resp.code, :body => resp.body
env[:response_headers].parse resp.headers
env[:response].finish(env) if is_parallel
end

Expand All @@ -46,15 +44,6 @@ def call(env)
rescue Errno::ECONNREFUSED
raise Error::ConnectionFailed, $!
end

def parse_response_headers(header_string)
return {} unless header_string && !header_string.empty?
Hash[*header_string.split(/\r\n/).
tap { |a| a.shift }. # drop the HTTP status line
map { |h| h.split(/:\s+/,2) }. # split key and value
reject { |(k, v)| k.nil? }. # Ignore blank lines
map { |(k, v)| [k.downcase, v] }.flatten]
end
end
end
end
2 changes: 1 addition & 1 deletion lib/faraday/connection.rb
Expand Up @@ -22,7 +22,7 @@ def initialize(url = nil, options = {})
options = url
url = options[:url]
end
@headers = HeaderHash.new
@headers = Headers.new
@params = {}
@options = options[:request] || {}
@ssl = options[:ssl] || {}
Expand Down
1 change: 1 addition & 0 deletions lib/faraday/request.rb
Expand Up @@ -73,6 +73,7 @@ def to_env_hash(connection, request_method)
:body => body,
:url => connection.build_url(path, env_params),
:request_headers => env_headers,
:response_headers => Utils::Headers.new,
:parallel_manager => connection.parallel_manager,
:request => connection.options.merge(:proxy => connection.proxy),
:ssl => connection.ssl}
Expand Down
47 changes: 30 additions & 17 deletions lib/faraday/utils.rb
Expand Up @@ -6,18 +6,36 @@ module Utils
extend Rack::Utils
extend self

HEADERS = Hash.new do |h, k|
if k.respond_to?(:to_str)
k
else
k.to_s.split('_'). # :user_agent => %w(user agent)
each { |w| w.capitalize! }. # => %w(User Agent)
join('-') # => "User-Agent"
class Headers < HeaderHash
# symbol -> string mapper + cache
KeyMap = Hash.new do |map, key|
map[key] = if key.respond_to?(:to_str) then key
else
key.to_s.split('_'). # :user_agent => %w(user agent)
each { |w| w.capitalize! }. # => %w(User Agent)
join('-') # => "User-Agent"
end
end
KeyMap[:etag] = "ETag"

def [](k)
super(KeyMap[k])
end
end

HEADERS.merge! :etag => "ETag"
HEADERS.values.each { |v| v.freeze }
def []=(k, v)
super(KeyMap[k], v)
end

alias_method :update, :merge!

def parse(header_string)
return unless header_string && !header_string.empty?
header_string.split(/\r\n/).
tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line
map { |h| h.split(/:\s+/, 2) }.reject { |(k, v)| k.nil? }. # split key and value, ignore blank lines
each { |(k, v)| self[k] = v }
end
end

# Make Rack::Utils build_query method public.
public :build_query
Expand Down Expand Up @@ -54,15 +72,10 @@ def merge_params(existing_params, new_params)
end
end

# Turns headers keys and values into strings. Look up symbol keys in the
# the HEADERS hash.
#
# h = merge_headers(HeaderHash.new, :content_type => 'text/plain')
# h['Content-Type'] # = 'text/plain'
#
# Turns headers keys and values into strings
def merge_headers(existing_headers, new_headers)
new_headers.each do |key, value|
existing_headers[HEADERS[key]] = value.to_s
existing_headers[key] = value.to_s
end
end

Expand Down
4 changes: 3 additions & 1 deletion test/adapters/live_test.rb
Expand Up @@ -26,7 +26,9 @@ class LiveTest < Faraday::TestCase
end

define_method "test_#{adapter}_GET_retrieves_the_response_headers" do
assert_match /text\/html/, create_connection(adapter).get('hello_world').headers['content-type']
response = create_connection(adapter).get('hello_world')
assert_match /text\/html/, response.headers['Content-Type'], 'original case fail'
assert_match /text\/html/, response.headers['content-type'], 'lowercase fail'
end

define_method "test_#{adapter}_POST_send_url_encoded_params" do
Expand Down
33 changes: 0 additions & 33 deletions test/adapters/typhoeus_test.rb

This file was deleted.

43 changes: 37 additions & 6 deletions test/env_test.rb
@@ -1,15 +1,13 @@
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))

class TestEnv < Faraday::TestCase
class EnvTest < Faraday::TestCase
def setup
@conn = Faraday.new :url => 'http://sushi.com/api', :headers => {'Mime-Version' => '1.0'}
@conn.options[:timeout] = 3
@conn.options[:open_timeout] = 5
@conn.ssl[:verify] = false
@conn.proxy 'http://proxy.com'
@input = {
:body => 'abc',
:headers => {'Server' => 'Faraday'}}
@input = { :body => 'abc' }
@env = env_for @conn do |req|
req.url 'foo.json', 'a' => 1
req['Server'] = 'Faraday'
Expand All @@ -26,8 +24,15 @@ def test_request_create_stores_addressable_uri
end

def test_request_create_stores_headers
assert_kind_of Rack::Utils::HeaderHash, @env[:request_headers]
assert_equal @input[:headers].merge('Mime-Version' => '1.0'), @env[:request_headers]
headers = @env[:request_headers]
assert_equal '1.0', headers['mime-version']
assert_equal 'Faraday', headers['server']
end

def test_response_headers_case_insensitive
headers = @env[:response_headers]
headers['Content-Type'] = 'application/json'
assert_equal 'application/json', headers['content-type']
end

def test_request_create_stores_body
Expand All @@ -54,3 +59,29 @@ def env_for(connection)
env_setup.to_env_hash(connection, :get)
end
end

class HeadersTest < Faraday::TestCase
def setup
@headers = Faraday::Utils::Headers.new
end

def test_parse_response_headers_leaves_http_status_line_out
@headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
assert_equal %w(Content-Type), @headers.keys
end

def test_parse_response_headers_parses_lower_cased_header_name_and_value
@headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
assert_equal 'text/html', @headers['content-type']
end

def test_parse_response_headers_parses_lower_cased_header_name_and_value_with_colon
@headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://sushi.com/\r\n\r\n")
assert_equal 'http://sushi.com/', @headers['location']
end

def test_parse_response_headers_parses_blank_lines
@headers.parse("HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n")
assert_equal 'text/html', @headers['content-type']
end
end

0 comments on commit 8dccfc6

Please sign in to comment.