lib/unwind.rb in unwind-0.9.3 vs lib/unwind.rb in unwind-0.9.4
- old
+ new
@@ -1,65 +1,114 @@
require "unwind/version"
require 'faraday'
module Unwind
- class TooManyRedirects < StandardError; end
- class MissingRedirectLocation < StandardError; end
+ class TooManyRedirects < StandardError; end
+ class MissingRedirectLocation < StandardError; end
- class RedirectFollower
+ class RedirectFollower
- attr_reader :final_url, :original_url, :redirect_limit, :response, :redirects
+ attr_reader :final_url, :original_url, :redirect_limit, :response, :redirects
- def initialize(original_url, limit=5)
- @original_url, @redirect_limit = original_url, limit
- @redirects = []
- end
+ def initialize(original_url, limit=5)
+ @original_url, @redirect_limit = original_url, limit
+ @redirects = []
+
+ end
- def redirected?
- !(self.final_url == self.original_url)
- end
+ def redirected?
+ !(self.final_url == self.original_url)
+ end
- def resolve(current_url=nil)
+ def resolve(current_url=nil, options={})
- ok_to_continue?
+ ok_to_continue?
- current_url ||= self.original_url
- response = Faraday.get(current_url)
+ current_url ||= self.original_url
+ #adding this header because we really only care about resolving the url
+ headers = (options || {}).merge({"accept-encoding" => "none"})
+ response = Faraday.get(current_url, headers)
- if [301, 302, 307].include?(response.status)
- @redirects << current_url.to_s
- @redirect_limit -= 1
- resolve redirect_url(response).normalize
- else
- @final_url = current_url.to_s
- @response = response
- self
- end
- end
+ if [301, 302, 303].include?(response.status)
+ @redirects << current_url.to_s
+ @redirect_limit -= 1
+ resolve(redirect_url(response).normalize, apply_cookie(response, headers))
+ else
+ @final_url = current_url.to_s
+ @response = response
+ self
+ end
+ end
- def self.resolve(original_url, limit=5)
- new(original_url, limit).resolve
- end
+ def self.resolve(original_url, limit=5)
+ new(original_url, limit).resolve
+ end
- private
+ private
- def ok_to_continue?
- raise TooManyRedirects if redirect_limit < 0
- end
- def redirect_url(response)
- if response['location'].nil?
- body_match = response.body.match(/<a href=\"([^>]+)\">/i)
- raise MissingRedirectLocation unless body_match
- Addressable::URI.parse(body_match[0])
- else
- redirect_uri = Addressable::URI.parse(response['location'])
- redirect_uri.relative? ? response.env[:url].join(response['location']) : redirect_uri
- end
- end
-
+ def ok_to_continue?
+ raise TooManyRedirects if redirect_limit < 0
+ end
- end
+ def redirect_url(response)
+ if response['location'].nil?
+ body_match = response.body.match(/<a href=\"([^>]+)\">/i)
+ raise MissingRedirectLocation unless body_match
+ Addressable::URI.parse(body_match[0])
+ else
+ redirect_uri = Addressable::URI.parse(response['location'])
+ redirect_uri.relative? ? response.env[:url].join(response['location']) : redirect_uri
+ end
+ end
+
+ def apply_cookie(response, headers)
+ if response.status == 302 && response['set-cookie']
+ headers.merge(:cookie => CookieHash.to_cookie_string(response['set-cookie']))
+ else
+ #todo: should we delete the cookie at this point if it exists?
+ headers
+ end
+ end
+
+ end
+
+ #borrowed (stolen) from HTTParty with minor updates
+ #to handle all cookies existing in a single string
+ class CookieHash < Hash
+
+ CLIENT_COOKIES = %w{path expires domain path secure httponly}
+
+ def add_cookies(value)
+ case value
+ when Hash
+ merge!(value)
+ when String
+ value = value.gsub(/expires=[\w,\s-:]+;/i, '')
+ value = value.gsub(/httponly[\,\;]*/i, '')
+ value.split(/[;,]\s/).each do |cookie|
+ array = cookie.split('=')
+ self[array[0].strip.to_sym] = array[1]
+ end
+ else
+ raise "add_cookies only takes a Hash or a String"
+ end
+ end
+
+ def to_cookie_string
+ delete_if { |k, v| CLIENT_COOKIES.include?(k.to_s.downcase) }.collect { |k, v| "#{k}=#{v}" }.join("; ")
+ end
+
+ def self.to_cookie_string(*cookie_strings)
+ h = CookieHash.new
+ cookie_strings.each do |cs|
+ h.add_cookies(cs)
+ end
+
+ h.to_cookie_string
+ end
+ end
+
end