Class: CloudFS::RestAdapter::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/cloudfs/client/connection.rb

Overview

Provides RESTful interface

Maintains a persistent instance of class HTTPClient, since HTTPClient instance is MT-safe and can be called from several threads without synchronization after setting up an instance, same behaviour is expected from Connection class.

Examples:

conn = Connection.new
response = conn.request('GET', "https://www.example.com",
	:query => { :a => "b", :c => "d" })
response = conn.request('POST', "https://www.example.com", :body => "a=b&c=d")
response = conn.request('POST', "https://www.example.com",
	:body => { :a => "b", :c => "d"} )

See Also:

Instance Method Summary collapse

Constructor Details

#initialize(**params) ⇒ Connection

Creates Connection instance

Parameters:

  • params (Hash)

    connection configurations

Options Hash (**params):

  • :connect_timeout (Fixnum) — default: 60

    for server handshake, defualts to 60 as per httpclient documentation

  • :send_timeout (Fixnum) — default: 120

    for send request, defaults to 120 sec as per httpclient documentation, set 0 for no timeout

  • :receive_timeout (Fixnum) — default: 60

    timeout for read per block, defaults to 60 sec as per httpclient documentation, set 0 for no timeout

  • :max_retry (Fixnum) — default: 0

    for http 500 level errors

  • :agent_name (String) — default: HTTPClient
  • :debug_dev (#<<) — default: nil

    provide http wire information from httpclient



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/cloudfs/client/connection.rb', line 39

def initialize(** params)
  @persistent_conn = HTTPClient.new
  @persistent_conn.cookie_manager = nil

  connect_timeout, send_timeout, receive_timeout,
      max_retries, debug_dev, agent_name =
      params.values_at(:connect_timeout, :send_timeout, :receive_timeout,
                       :max_retries, :debug_dev, :agent_name)
  @persistent_conn.connect_timeout = connect_timeout if connect_timeout
  @persistent_conn.send_timeout = send_timeout if send_timeout
  @persistent_conn.receive_timeout = receive_timeout if receive_timeout
  @persistent_conn.debug_dev = debug_dev if debug_dev.respond_to?(:<<)
  @persistent_conn.agent_name = agent_name
  @max_retries = max_retries ? max_retries : 0
end

Instance Method Details

#request(method, uri, **params, &block) ⇒ Hash

Sends request to specified url, calls HTTPClient#request, retries http 500 level errors with exponential delay upto max retries

Parameters:

  • method (Symbol)

    (:get, :put, :post, :delete) http verb

  • uri (String, URI)

    represents complete url to web resource

  • params (Hash)

    http request parameters i.e. :headers, :query, :body

Options Hash (**params):

  • :header (Hash)

    http request headers

  • :query (Hash)
  • :body (Array<Hash>, Hash, String)

    {} to post multipart forms, key:value forms, string

Returns:

  • (Hash)

    response hash containing content, content_type and http code { :content => String, :content_type => String, :code => Fixnum }

Raises:

OPTIMIZE:

  • async request support

REVIEW:

  • Behaviour in case of error with follow_redirect set to true with callback block for get: observed is that if server return message as response body in case of error, message is discarded and unable to fetch it. Opened issue#234 on nahi/httpclient github. Currently fetching HTTP::Message#reason if HTTP::Message#content is not available in such case

  • exceptions raised by HTTPClient should not be handled



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/cloudfs/client/connection.rb', line 88

def request(method, uri, ** params, &block)
  method = method.to_s.downcase.to_sym
  req_params = params.reject { |_, v| Utils.is_blank?(v) }

  if method == :get && !params[:header].has_key?(Constants::HEADER_REDIRECT)
    req_params = req_params.merge({follow_redirect: true})
  end

  resp = request_with_retry(method, uri, req_params, &block)

  status = resp.status.to_i
  response = {code: status}
  response[:content] = resp.content
  response[:content_type] = resp.header['Content-Type'].first
  if status < 200 || status >=400 || (resp.redirect? && status != 302)
    message = Utils.is_blank?(resp.content) ? resp.reason : resp.content
    request = set_error_request_context(method, uri, req_params)
    fail Errors::ServerError.new(message, status, response, request)
  end
  response

rescue HTTPClient::TimeoutError
  request = set_error_request_context(method, uri, req_params)
  raise Errors::TimeoutError.new($!, request)
rescue HTTPClient::BadResponseError
  request = set_error_request_context(method, uri, req_params)
  raise Errors::ClientError.new($!, request)
rescue Errno::ECONNREFUSED, EOFError, SocketError
  request = set_error_request_context(method, uri, req_params)
  raise Errors::ConnectionFailed.new($!, request)
end

Disconnects all keep alive connections and intenal sessions



56
57
58
# File 'lib/cloudfs/client/connection.rb', line 56

def unlink
  @persistent_conn.reset_all
end