lib/active_resource/connection.rb in embark-journey-0.1.8 vs lib/active_resource/connection.rb in embark-journey-0.2.1
- old
+ new
@@ -1,43 +1,45 @@
-require 'active_support/core_ext/benchmark'
-require 'active_support/core_ext/uri'
-require 'active_support/core_ext/object/inclusion'
-require 'net/https'
-require 'date'
-require 'time'
-require 'uri'
+# frozen_string_literal: true
+require "active_support/core_ext/benchmark"
+require "active_support/core_ext/uri"
+require "active_support/core_ext/object/inclusion"
+require "net/https"
+require "date"
+require "time"
+require "uri"
+
module ActiveResource
# Class to handle connections to remote web services.
# This class is used by ActiveResource::Base to interface with REST
# services.
class Connection
-
- HTTP_FORMAT_HEADER_NAMES = { :get => 'Accept',
- :put => 'Content-Type',
- :post => 'Content-Type',
- :patch => 'Content-Type',
- :delete => 'Accept',
- :head => 'Accept'
+ HTTP_FORMAT_HEADER_NAMES = { get: "Accept",
+ put: "Content-Type",
+ post: "Content-Type",
+ patch: "Content-Type",
+ delete: "Accept",
+ head: "Accept"
}
- attr_reader :site, :user, :password, :auth_type, :timeout, :proxy, :ssl_options
- attr_accessor :format
+ attr_reader :site, :user, :password, :bearer_token, :auth_type, :timeout, :open_timeout, :read_timeout, :proxy, :ssl_options
+ attr_accessor :format, :logger
class << self
def requests
@@requests ||= []
end
end
# The +site+ parameter is required and will set the +site+
# attribute to the URI for the remote resource service.
- def initialize(site, format = ActiveResource::Formats::JsonFormat)
- raise ArgumentError, 'Missing site URI' unless site
- @proxy = @user = @password = nil
+ def initialize(site, format = ActiveResource::Formats::JsonFormat, logger: nil)
+ raise ArgumentError, "Missing site URI" unless site
+ @proxy = @user = @password = @bearer_token = nil
self.site = site
self.format = format
+ self.logger = logger
end
# Set URI for remote service.
def site=(site)
@site = site.is_a?(URI) ? site : URI.parse(site)
@@ -50,33 +52,34 @@
def proxy=(proxy)
@proxy = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
end
# Sets the user for remote service.
- def user=(user)
- @user = user
- end
+ attr_writer :user
# Sets the password for remote service.
- def password=(password)
- @password = password
- end
+ attr_writer :password
+ # Sets the bearer token for remote service.
+ attr_writer :bearer_token
+
# Sets the auth type for remote service.
def auth_type=(auth_type)
@auth_type = legitimize_auth_type(auth_type)
end
# Sets the number of seconds after which HTTP requests to the remote service should time out.
- def timeout=(timeout)
- @timeout = timeout
- end
+ attr_writer :timeout
+ # Sets the number of seconds after which HTTP connects to the remote service should time out.
+ attr_writer :open_timeout
+
+ # Sets the number of seconds after which HTTP read requests to the remote service should time out.
+ attr_writer :read_timeout
+
# Hash of options applied to Net::HTTP instance when +site+ protocol is 'https'.
- def ssl_options=(options)
- @ssl_options = options
- end
+ attr_writer :ssl_options
# Executes a GET request.
# Used to get (find) resources.
def get(path, headers = {})
with_auth { request(:get, path, build_request_headers(headers, :get, self.site.merge(path))) }
@@ -88,23 +91,23 @@
with_auth { request(:delete, path, build_request_headers(headers, :delete, self.site.merge(path))) }
end
# Executes a PATCH request (see HTTP protocol documentation if unfamiliar).
# Used to update resources.
- def patch(path, body = '', headers = {})
+ def patch(path, body = "", headers = {})
with_auth { request(:patch, path, body.to_s, build_request_headers(headers, :patch, self.site.merge(path))) }
end
# Executes a PUT request (see HTTP protocol documentation if unfamiliar).
# Used to update resources.
- def put(path, body = '', headers = {})
+ def put(path, body = "", headers = {})
with_auth { request(:put, path, body.to_s, build_request_headers(headers, :put, self.site.merge(path))) }
end
# Executes a POST request.
# Used to create new resources.
- def post(path, body = '', headers = {})
+ def post(path, body = "", headers = {})
with_auth { request(:post, path, body.to_s, build_request_headers(headers, :post, self.site.merge(path))) }
end
# Executes a HEAD request.
# Used to obtain meta-information about resources, such as whether they exist and their size (via response headers).
@@ -127,46 +130,46 @@
raise SSLError.new(e.message)
end
# Handles response and error codes from the remote service.
def handle_response(response)
+
if response.respond_to?(:header) && (response.header["content-encoding"] == 'gzip')
begin
response.instance_variable_set('@body', ActiveSupport::Gzip.decompress(response.body))
rescue Exception => e
raise(BadRequest.new(response))
end
end
-
case response.code.to_i
- when 301, 302, 303, 307
- raise(Redirection.new(response))
- when 200...400
- response
- when 400
- raise(BadRequest.new(response))
- when 401
- raise(UnauthorizedAccess.new(response))
- when 403
- raise(ForbiddenAccess.new(response))
- when 404
- raise(ResourceNotFound.new(response))
- when 405
- raise(MethodNotAllowed.new(response))
- when 409
- raise(ResourceConflict.new(response))
- when 410
- raise(ResourceGone.new(response))
- when 422
- raise(ResourceInvalid.new(response))
- when 401...500
- raise(ClientError.new(response))
- when 500...600
- raise(ServerError.new(response))
- else
- raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
+ when 301, 302, 303, 307
+ raise(Redirection.new(response))
+ when 200...400
+ response
+ when 400
+ raise(BadRequest.new(response))
+ when 401
+ raise(UnauthorizedAccess.new(response))
+ when 403
+ raise(ForbiddenAccess.new(response))
+ when 404
+ raise(ResourceNotFound.new(response))
+ when 405
+ raise(MethodNotAllowed.new(response))
+ when 409
+ raise(ResourceConflict.new(response))
+ when 410
+ raise(ResourceGone.new(response))
+ when 422
+ raise(ResourceInvalid.new(response))
+ when 401...500
+ raise(ClientError.new(response))
+ when 500...600
+ raise(ServerError.new(response))
+ else
+ raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
end
end
# Creates new Net::HTTP instance for communication with the
# remote service and resources.
@@ -174,11 +177,13 @@
configure_http(new_http)
end
def new_http
if @proxy
- Net::HTTP.new(@site.host, @site.port, @proxy.host, @proxy.port, @proxy.user, @proxy.password)
+ user = URI.parser.unescape(@proxy.user) if @proxy.user
+ password = URI.parser.unescape(@proxy.password) if @proxy.password
+ Net::HTTP.new(@site.host, @site.port, @proxy.host, @proxy.port, user, password)
else
Net::HTTP.new(@site.host, @site.port)
end
end
@@ -187,22 +192,21 @@
# Net::HTTP timeouts default to 60 seconds.
if defined? @timeout
https.open_timeout = @timeout
https.read_timeout = @timeout
end
+ https.open_timeout = @open_timeout if defined?(@open_timeout)
+ https.read_timeout = @read_timeout if defined?(@read_timeout)
end
end
def apply_ssl_options(http)
http.tap do |https|
# Skip config if site is already a https:// URI.
if defined? @ssl_options
http.use_ssl = true
- # Default to no cert verification (WTF? FIXME)
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
-
# All the SSL options have corresponding http settings.
@ssl_options.each { |key, value| http.send "#{key}=", value }
end
end
end
@@ -223,22 +227,24 @@
def with_auth
retried ||= false
yield
rescue UnauthorizedAccess => e
raise if retried || auth_type != :digest
- @response_auth_header = e.response['WWW-Authenticate']
+ @response_auth_header = e.response["WWW-Authenticate"]
retried = true
retry
end
def authorization_header(http_method, uri)
if @user || @password
if auth_type == :digest
- { 'Authorization' => digest_auth_header(http_method, uri) }
+ { "Authorization" => digest_auth_header(http_method, uri) }
else
- { 'Authorization' => 'Basic ' + ["#{@user}:#{@password}"].pack('m').delete("\r\n") }
+ { "Authorization" => "Basic " + ["#{@user}:#{@password}"].pack("m").delete("\r\n") }
end
+ elsif @bearer_token
+ { "Authorization" => "Bearer #{@bearer_token}" }
else
{}
end
end
@@ -249,12 +255,12 @@
request_uri << "?#{uri.query}" if uri.query
ha1 = Digest::MD5.hexdigest("#{@user}:#{params['realm']}:#{@password}")
ha2 = Digest::MD5.hexdigest("#{http_method.to_s.upcase}:#{request_uri}")
- params.merge!('cnonce' => client_nonce)
- request_digest = Digest::MD5.hexdigest([ha1, params['nonce'], "0", params['cnonce'], params['qop'], ha2].join(":"))
+ params["cnonce"] = client_nonce
+ request_digest = Digest::MD5.hexdigest([ha1, params["nonce"], "0", params["cnonce"], params["qop"], ha2].join(":"))
"Digest #{auth_attributes_for(uri, request_digest, params)}"
end
def client_nonce
Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535)))
@@ -267,28 +273,31 @@
end
params
end
def auth_attributes_for(uri, request_digest, params)
- [
- %Q(username="#{@user}"),
- %Q(realm="#{params['realm']}"),
- %Q(qop="#{params['qop']}"),
- %Q(uri="#{uri.path}"),
- %Q(nonce="#{params['nonce']}"),
- %Q(nc="0"),
- %Q(cnonce="#{params['cnonce']}"),
- %Q(opaque="#{params['opaque']}"),
- %Q(response="#{request_digest}")].join(", ")
+ auth_attrs =
+ [
+ %Q(username="#{@user}"),
+ %Q(realm="#{params['realm']}"),
+ %Q(qop="#{params['qop']}"),
+ %Q(uri="#{uri.path}"),
+ %Q(nonce="#{params['nonce']}"),
+ 'nc="0"',
+ %Q(cnonce="#{params['cnonce']}"),
+ %Q(response="#{request_digest}")]
+
+ auth_attrs << %Q(opaque="#{params['opaque']}") unless params["opaque"].blank?
+ auth_attrs.join(", ")
end
def http_format_header(http_method)
- {HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type}
+ { HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type }
end
def legitimize_auth_type(auth_type)
return :basic if auth_type.nil?
auth_type = auth_type.to_sym
- auth_type.in?([:basic, :digest]) ? auth_type : :basic
+ auth_type.in?([:basic, :digest, :bearer]) ? auth_type : :basic
end
end
end