lib/httpclient.rb in httpclient-2.5.1 vs lib/httpclient.rb in httpclient-2.5.2

- old
+ new

@@ -322,10 +322,12 @@ # HTTPClient::WWWAuth:: WWW authentication handler. attr_reader :www_auth # How many times get_content and post_content follows HTTP redirect. # 10 by default. attr_accessor :follow_redirect_count + # Base url of resources. + attr_accessor :base_url # Set HTTP version as a String:: 'HTTP/1.0' or 'HTTP/1.1' attr_proxy(:protocol_version, true) # Connect timeout in sec. attr_proxy(:connect_timeout, true) @@ -360,31 +362,40 @@ # Default User-Agent header DEFAULT_AGENT_NAME = 'HTTPClient/1.0' # Creates a HTTPClient instance which manages sessions, cookies, etc. # - # HTTPClient.new takes 3 optional arguments for proxy url string, - # User-Agent String and From header String. User-Agent and From are embedded - # in HTTP request Header if given. No User-Agent and From header added - # without setting it explicitly. + # HTTPClient.new takes optional arguments as a Hash. + # * :proxy - proxy url string + # * :agent_name - User-Agent String + # * :from - from header String + # * :base_url - base URL of resources + # * :force_basic_auth - flag for sending Authorization header w/o gettin 401 first + # User-Agent and From are embedded in HTTP request Header if given. + # From header is not set without setting it explicitly. # # proxy = 'http://myproxy:8080' # agent_name = 'MyAgent/0.1' # from = 'from@example.com' # HTTPClient.new(proxy, agent_name, from) # - # You can use a keyword argument style Hash. Keys are :proxy, :agent_name - # and :from. + # After you set base_url, all resources you pass to get, post and other + # methods are recognized to be prefixed with base_url. Say base_url is + # 'https://api.example.com/v1, get('/users') is the same as + # get('https://api.example.com/v1/users') internally. You can also pass + # full URL from 'http://' even after setting base_url. # - # HTTPClient.new(:agent_name => 'MyAgent/0.1') def initialize(*args) - proxy, agent_name, from = keyword_argument(args, :proxy, :agent_name, :from) + proxy, agent_name, from, base_url, force_basic_auth = + keyword_argument(args, :proxy, :agent_name, :from, :base_url, :force_basic_auth) @proxy = nil # assigned later. @no_proxy = nil @no_proxy_regexps = [] + @base_url = base_url @www_auth = WWWAuth.new @proxy_auth = ProxyAuth.new + @www_auth.basic_auth.force_auth = @proxy_auth.basic_auth.force_auth = force_basic_auth @request_filter = [@proxy_auth, @www_auth] @debug_dev = nil @redirect_uri_callback = method(:default_redirect_uri_callback) @test_loopback_response = [] @session_manager = SessionManager.new(self) @@ -507,18 +518,18 @@ # clnt.set_auth('http://www.example.com/foo/', 'foo_user', 'passwd') # clnt.set_auth('http://www.example.com/bar/', 'bar_user', 'passwd') # # Calling this method resets all existing sessions. def set_auth(domain, user, passwd) - uri = urify(domain) + uri = to_resource_url(domain) @www_auth.set_auth(uri, user, passwd) reset_all end # Deprecated. Use set_auth instead. def set_basic_auth(domain, user, passwd) - uri = urify(domain) + uri = to_resource_url(domain) @www_auth.basic_auth.set(uri, user, passwd) reset_all end # Sets credential for Proxy authentication. @@ -529,10 +540,18 @@ def set_proxy_auth(user, passwd) @proxy_auth.set_auth(user, passwd) reset_all end + # Turn on/off the BasicAuth force flag. Generally HTTP client must + # send Authorization header after it gets 401 error from server from + # security reason. But in some situation (e.g. API client) you might + # want to send Authorization from the beginning. + def force_basic_auth=(force_basic_auth) + @www_auth.basic_auth.force_auth = @proxy_auth.basic_auth.force_auth = force_basic_auth + end + # Sets the filename where non-volatile Cookies be saved by calling # save_cookie_store. # This method tries to load and managing Cookies from the specified file. # # Calling this method resets all existing sessions. @@ -776,11 +795,11 @@ if method == :propfind header ||= PROPFIND_DEFAULT_EXTHEADER else header ||= {} end - uri = urify(uri) + uri = to_resource_url(uri) if block if block.arity == 1 filtered_block = proc { |res, str| block.call(str) } @@ -796,19 +815,17 @@ end # Sends HEAD request in async style. See request_async for arguments. # It immediately returns a HTTPClient::Connection instance as a result. def head_async(uri, *args) - query, header = keyword_argument(args, :query, :header) - request_async(:head, uri, query, nil, header || {}) + request_async2(:head, uri, argument_to_hash(args, :query, :header)) end # Sends GET request in async style. See request_async for arguments. # It immediately returns a HTTPClient::Connection instance as a result. def get_async(uri, *args) - query, header = keyword_argument(args, :query, :header) - request_async(:get, uri, query, nil, header || {}) + request_async2(:get, uri, argument_to_hash(args, :query, :header)) end # Sends POST request in async style. See request_async for arguments. # It immediately returns a HTTPClient::Connection instance as a result. def post_async(uri, *args) @@ -864,11 +881,11 @@ # Sends a request in async style. request method creates new Thread for # HTTP connection and returns a HTTPClient::Connection instance immediately. # # Arguments definition is the same as request. def request_async(method, uri, query = nil, body = nil, header = {}) - uri = urify(uri) + uri = to_resource_url(uri) do_request_async(method, uri, query, body, header) end # new method that has same signature as 'request' def request_async2(method, uri, *args) @@ -879,18 +896,18 @@ if method == :propfind header ||= PROPFIND_DEFAULT_EXTHEADER else header ||= {} end - uri = urify(uri) + uri = to_resource_url(uri) do_request_async(method, uri, query, body, header) end # Resets internal session for the given URL. Keep-alive connection for the # site (host-port pair) is disconnected if exists. def reset(uri) - uri = urify(uri) + uri = to_resource_url(uri) @session_manager.reset(uri) end # Resets all of internal sessions. Keep-alive connections are disconnected. def reset_all @@ -963,12 +980,12 @@ break rescue RetryableResponse retry_count -= 1 end end - rescue Exception - conn.push $! + rescue Exception => e + conn.push e end } conn.async_thread = t conn end @@ -990,11 +1007,11 @@ def getenv(name) ENV[name.downcase] || ENV[name.upcase] end def follow_redirect(method, uri, query, body, header, &block) - uri = urify(uri) + uri = to_resource_url(uri) if block filtered_block = proc { |r, str| block.call(str) if r.ok? } end @@ -1198,7 +1215,16 @@ @debug_dev << res end def set_encoding(str, encoding) str.force_encoding(encoding) if encoding + end + + def to_resource_url(uri) + u = urify(uri) + if @base_url && u.scheme.nil? && u.host.nil? + urify(@base_url + uri) + else + u + end end end