8 class ConnectionError
< StandardError
# :nodoc:
11 def initialize(response
, message
= nil)
17 "Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
21 # Raised when a Timeout::Error occurs.
22 class TimeoutError
< ConnectionError
23 def initialize(message
)
26 def to_s
; @message ;end
30 class Redirection
< ConnectionError
# :nodoc:
31 def to_s
; response
['Location'] ? "#{super} => #{response['Location']}" : super; end
35 class ClientError
< ConnectionError
; end # :nodoc:
38 class BadRequest
< ClientError
; end # :nodoc
41 class UnauthorizedAccess
< ClientError
; end # :nodoc
44 class ForbiddenAccess
< ClientError
; end # :nodoc
47 class ResourceNotFound
< ClientError
; end # :nodoc:
50 class ResourceConflict
< ClientError
; end # :nodoc:
53 class ServerError
< ConnectionError
; end # :nodoc:
55 # 405 Method Not Allowed
56 class MethodNotAllowed
< ClientError
# :nodoc:
58 @response['Allow'].split(',').map
{ |verb
| verb
.strip
.downcase
.to_sym
}
62 # Class to handle connections to remote web services.
63 # This class is used by ActiveResource::Base to interface with REST
67 HTTP_FORMAT_HEADER_NAMES
= { :get => 'Accept',
68 :put => 'Content-Type',
69 :post => 'Content-Type',
73 attr_reader
:site, :user, :password, :timeout
82 # The +site+ parameter is required and will set the +site+
83 # attribute to the URI for the remote resource service.
84 def initialize(site
, format
= ActiveResource
::Formats[:xml])
85 raise ArgumentError
, 'Missing site URI' unless site
86 @user = @password = nil
91 # Set URI for remote service.
93 @site = site
.is_a
?(URI
) ? site
: URI
.parse(site
)
94 @user = URI
.decode(@site.user
) if @site.user
95 @password = URI
.decode(@site.password
) if @site.password
98 # Set user for remote service.
103 # Set password for remote service.
104 def password
=(password
)
108 # Set the number of seconds after which HTTP requests to the remote service should time out.
109 def timeout
=(timeout
)
113 # Execute a GET request.
114 # Used to get (find) resources.
115 def get(path
, headers
= {})
116 format
.decode(request(:get, path
, build_request_headers(headers
, :get)).body
)
119 # Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
120 # Used to delete resources.
121 def delete(path
, headers
= {})
122 request(:delete, path
, build_request_headers(headers
, :delete))
125 # Execute a PUT request (see HTTP protocol documentation if unfamiliar).
126 # Used to update resources.
127 def put(path
, body
= '', headers
= {})
128 request(:put, path
, body
.to_s
, build_request_headers(headers
, :put))
131 # Execute a POST request.
132 # Used to create new resources.
133 def post(path
, body
= '', headers
= {})
134 request(:post, path
, body
.to_s
, build_request_headers(headers
, :post))
137 # Execute a HEAD request.
138 # Used to obtain meta-information about resources, such as whether they exist and their size (via response headers).
139 def head(path
, headers
= {})
140 request(:head, path
, build_request_headers(headers
))
145 # Makes request to remote service.
146 def request(method
, path
, *arguments
)
147 logger
.info
"#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}" if logger
149 time
= Benchmark
.realtime
{ result
= http
.send(method
, path
, *arguments
) }
150 logger
.info
"--> %d %s (%d %.2fs)" % [result
.code
, result
.message
, result
.body
? result
.body
.length
: 0, time
] if logger
151 handle_response(result
)
152 rescue Timeout
::Error => e
153 raise TimeoutError
.new(e
.message
)
156 # Handles response and error codes from remote service.
157 def handle_response(response
)
158 case response
.code
.to_i
160 raise(Redirection
.new(response
))
164 raise(BadRequest
.new(response
))
166 raise(UnauthorizedAccess
.new(response
))
168 raise(ForbiddenAccess
.new(response
))
170 raise(ResourceNotFound
.new(response
))
172 raise(MethodNotAllowed
.new(response
))
174 raise(ResourceConflict
.new(response
))
176 raise(ResourceInvalid
.new(response
))
178 raise(ClientError
.new(response
))
180 raise(ServerError
.new(response
))
182 raise(ConnectionError
.new(response
, "Unknown response code: #{response.code}"))
186 # Creates new Net::HTTP instance for communication with
187 # remote service and resources.
189 http
= Net
::HTTP.new(@site.host
, @site.port
)
190 http
.use_ssl
= @site.is_a
?(URI
::HTTPS)
191 http
.verify_mode
= OpenSSL
::SSL::VERIFY_NONE if http
.use_ssl
192 http
.read_timeout
= @timeout if @timeout # If timeout is not set, the default Net::HTTP timeout (60s) is used.
197 @default_header ||= {}
200 # Builds headers for request to remote service.
201 def build_request_headers(headers
, http_method
=nil)
202 authorization_header
.update(default_header
).update(http_format_header(http_method
)).update(headers
)
205 # Sets authorization header
206 def authorization_header
207 (@user || @password ? { 'Authorization' => 'Basic ' + ["#{@user}:#{ @password}"].pack('m').delete("\r\n") } : {})
210 def http_format_header(http_method
)
211 {HTTP_FORMAT_HEADER_NAMES
[http_method
] => format
.mime_type
}