Skip to content

Commit

Permalink
Use real Net::HTTPResponse subclasses for test responses
Browse files Browse the repository at this point in the history
  • Loading branch information
drbrain committed Apr 8, 2011
1 parent 2fae93f commit d51470f
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 66 deletions.
109 changes: 62 additions & 47 deletions lib/mechanize.rb
Expand Up @@ -264,7 +264,7 @@ def auth(user, password)

# Fetches the URL passed in and returns a page.
def get(options, parameters = [], referer = nil)
verb = :get
method = :get

unless options.is_a? Hash
url = options
Expand All @@ -277,7 +277,7 @@ def get(options, parameters = [], referer = nil)
parameters = options[:params] || []
referer = options[:referer]
headers = options[:headers]
verb = options[:verb] || verb
method = options[:verb] || method
end

unless referer
Expand All @@ -299,7 +299,7 @@ def get(options, parameters = [], referer = nil)

# fetch the page
headers ||= {}
page = fetch_page url, verb, headers, parameters, referer
page = fetch_page url, method, headers, parameters, referer
add_to_history(page)
yield page if block_given?
page
Expand Down Expand Up @@ -712,8 +712,8 @@ def response_read response, request

body.rewind

raise Mechanize::ResponseCodeError, response unless
Net::HTTPResponse::CODE_TO_OBJ[response.code.to_s]
raise Mechanize::ResponseCodeError, response if
Net::HTTPUnknownResponse === response

content_length = response.content_length

Expand Down Expand Up @@ -767,6 +767,51 @@ def response_read response, request
end
end

def response_redirect response, method, page, redirects
case @redirect_ok
when true, :all
# shortcut
when false, nil
return page
when :permanent
return page if response_class != Net::HTTPMovedPermanently
end

log.info("follow redirect to: #{response['Location']}") if log

from_uri = page.uri

raise RedirectLimitReachedError.new(page, redirects) if
redirects + 1 > redirection_limit

redirect_method = method == :head ? :head : :get

page = fetch_page(response['Location'].to_s, redirect_method, {}, [],
page, redirects + 1)

@history.push(page, from_uri)

return page
end

def response_authenticate(response, page, uri, request, headers, params,
referer)
raise ResponseCodeError, page unless @user || @password
raise ResponseCodeError, page if @auth_hash.has_key?(uri.host)

if response['www-authenticate'] =~ /Digest/i
@auth_hash[uri.host] = :digest
if response['server'] =~ /Microsoft-IIS/
@auth_hash[uri.host] = :iis_digest
end
@digest = response['www-authenticate']
else
@auth_hash[uri.host] = :basic
end

fetch_page(uri, request.method.downcase.to_sym, headers, params, referer)
end

private

def resolve(url, referer = current_page())
Expand Down Expand Up @@ -872,53 +917,23 @@ def fetch_page uri, method = :get, headers = {}, params = [],

response_cookies response, uri, page

res_klass = Net::HTTPResponse::CODE_TO_OBJ[response.code.to_s]

meta = response_follow_meta_refresh response, uri, page, redirects
return meta if meta

return page if res_klass <= Net::HTTPSuccess

if res_klass == Net::HTTPNotModified
case response
when Net::HTTPSuccess, Mechanize::FileResponse
page
when Net::HTTPNotModified
log.debug("Got cached page") if log
return visited_page(uri) || page
elsif res_klass <= Net::HTTPRedirection
case redirect_ok
when true, :all
# shortcut
when false, nil
return page
when :permanent
return page if res_klass != Net::HTTPMovedPermanently
end
log.info("follow redirect to: #{ response['Location'] }") if log
from_uri = page.uri
raise RedirectLimitReachedError.new(page, redirects) if
redirects + 1 > redirection_limit
redirect_method = method == :head ? :head : :get
page = fetch_page(response['Location'].to_s, redirect_method, {}, [],
page, redirects + 1)

@history.push(page, from_uri)
return page
elsif res_klass <= Net::HTTPUnauthorized
raise ResponseCodeError, page unless @user || @password
raise ResponseCodeError, page if @auth_hash.has_key?(uri.host)
if response['www-authenticate'] =~ /Digest/i
@auth_hash[uri.host] = :digest
if response['server'] =~ /Microsoft-IIS/
@auth_hash[uri.host] = :iis_digest
end
@digest = response['www-authenticate']
else
@auth_hash[uri.host] = :basic
end

return fetch_page(uri, request.method.downcase.to_sym, headers, params,
referer)
visited_page(uri) || page
when Net::HTTPRedirection
response_redirect response, method, page, redirects
when Net::HTTPUnauthorized
response_authenticate(response, page, uri, request, headers, params,
referer)
else
raise ResponseCodeError.new(page), "Unhandled response"
end

raise ResponseCodeError.new(page), "Unhandled response"
end

def add_to_history(page)
Expand Down
32 changes: 28 additions & 4 deletions test/helper.rb
Expand Up @@ -97,14 +97,37 @@ def request(request, *data, &block)
end

res['Content-Type'] ||= 'text/html'
res['Content-Length'] ||= res.body.length.to_s
res.code ||= "200"

response_klass = Net::HTTPResponse::CODE_TO_OBJ[res.code.to_s]
response = response_klass.new res.http_version, res.code, res.message

res.header.each do |k,v|
v = v.first if v.length == 1
response[k] = v
end

res.cookies.each do |cookie|
res.add_field('Set-Cookie', cookie.to_s)
response.add_field 'Set-Cookie', cookie.to_s
end

response['Content-Type'] ||= 'text/html'
response['Content-Length'] = res['Content-Length'] || res.body.length.to_s

io = StringIO.new(res.body)
response.instance_variable_set :@socket, io
def io.read clen, dest, _
dest << string[0, clen]
end
yield res if block_given?
res

body_exist = request.response_body_permitted? &&
response_klass.body_permitted?

response.instance_variable_set :@body_exist, body_exist

yield response if block_given?

response
end
end

Expand All @@ -118,6 +141,7 @@ class Response
attr_reader :code
attr_accessor :body, :query, :cookies
attr_accessor :query_params, :http_version
attr_accessor :header

def code=(c)
@code = c.to_s
Expand Down
2 changes: 1 addition & 1 deletion test/servlets.rb
Expand Up @@ -9,7 +9,7 @@ class VerbServlet < WEBrick::HTTPServlet::AbstractServlet
%w(HEAD GET POST PUT DELETE).each do |verb|
eval(<<-eomethod)
def do_#{verb}(req, res)
res.body = "method: #{verb}"
res.header['X-Request-Method'] = #{verb.dump}
end
eomethod
end
Expand Down
11 changes: 6 additions & 5 deletions test/test_mechanize.rb
Expand Up @@ -21,7 +21,7 @@ def setup
@uri = URI.parse 'http://example/'
@req = Net::HTTP::Get.new '/'

@res = Net::HTTPResponse.allocate
@res = Net::HTTPOK.allocate
@res.instance_variable_set :@code, 200
@res.instance_variable_set :@header, {}

Expand Down Expand Up @@ -539,14 +539,15 @@ def @res.read_body() end
end

def test_response_read_unknown_code
def @res.read_body() yield 'part' end
@res.instance_variable_set :@code, 9999
res = Net::HTTPUnknownResponse.allocate
res.instance_variable_set :@code, 9999
def res.read_body() yield 'part' end

e = assert_raises Mechanize::ResponseCodeError do
@agent.response_read @res, @req
@agent.response_read res, @req
end

assert_equal @res, e.page
assert_equal res, e.page
end

def test_response_parse
Expand Down
12 changes: 6 additions & 6 deletions test/test_redirect_verb_handling.rb
Expand Up @@ -14,36 +14,36 @@ def test_to_s
def test_head_redirect_results_in_head_request
page = @agent.head('http://localhost/redirect')
assert_equal(page.uri.to_s, 'http://localhost/verb')
assert_equal(page.body, "method: HEAD")
assert_equal 'HEAD', page.header['X-Request-Method']
end

def test_get_takes_a_verb
page = @agent.get(:url => 'http://localhost/redirect', :verb => :head)
assert_equal(page.uri.to_s, 'http://localhost/verb')
assert_equal(page.body, "method: HEAD")
assert_equal 'HEAD', page.header['X-Request-Method']
end

def test_get_redirect_results_in_get_request
page = @agent.get('http://localhost/redirect')
assert_equal(page.uri.to_s, 'http://localhost/verb')
assert_equal(page.body, "method: GET")
assert_equal 'GET', page.header['X-Request-Method']
end

def test_post_redirect_results_in_get_request
page = @agent.post('http://localhost/redirect')
assert_equal(page.uri.to_s, 'http://localhost/verb')
assert_equal(page.body, "method: GET")
assert_equal 'GET', page.header['X-Request-Method']
end

def test_put_redirect_results_in_get_request
page = @agent.put('http://localhost/redirect', 'foo')
assert_equal(page.uri.to_s, 'http://localhost/verb')
assert_equal(page.body, "method: GET")
assert_equal 'GET', page.header['X-Request-Method']
end

def test_delete_redirect_results_in_get_request
page = @agent.delete('http://localhost/redirect')
assert_equal(page.uri.to_s, 'http://localhost/verb')
assert_equal(page.body, "method: GET")
assert_equal 'GET', page.header['X-Request-Method']
end
end
6 changes: 3 additions & 3 deletions test/test_verbs.rb
Expand Up @@ -8,18 +8,18 @@ def setup
def test_put
page = @agent.put('http://localhost/verb', 'foo')
assert_equal 1, @agent.history.length
assert_equal('method: PUT', page.body)
assert_equal 'PUT', page.header['X-Request-Method']
end

def test_delete
page = @agent.delete('http://localhost/verb', { 'q' => 'foo' })
assert_equal 1, @agent.history.length
assert_equal('method: DELETE', page.body)
assert_equal 'DELETE', page.header['X-Request-Method']
end

def test_head
page = @agent.head('http://localhost/verb', { 'q' => 'foo' })
assert_equal 0, @agent.history.length
assert_equal('method: HEAD', page.body)
assert_equal 'HEAD', page.header['X-Request-Method']
end
end

0 comments on commit d51470f

Please sign in to comment.