Class: Google::Apis::Core::HttpCommand

Inherits:
Object
  • Object
show all
Includes:
Logging
Defined in:
lib/google/apis/core/http_command.rb

Overview

Command for HTTP request/response.

Direct Known Subclasses

ApiCommand, BatchCommand

Constant Summary collapse

RETRIABLE_ERRORS =
[Google::Apis::ServerError, Google::Apis::RateLimitError, Google::Apis::TransmissionError]

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging

#logger

Constructor Details

#initialize(method, url, body: nil) ⇒ HttpCommand

Returns a new instance of HttpCommand.

Parameters:

  • method (symbol)

    HTTP method

  • url (String, Addressable::URI, Addressable::Template)

    HTTP URL or template

  • body (String, #read) (defaults to: nil)

    Request body


73
74
75
76
77
78
79
80
81
82
# File 'lib/google/apis/core/http_command.rb', line 73

def initialize(method, url, body: nil)
  self.options = Google::Apis::RequestOptions.default.dup
  self.url = url
  self.url = Addressable::Template.new(url) if url.is_a?(String)
  self.method = method
  self.header = Hurley::Header.new
  self.body = body
  self.query = {}
  self.params = {}
end

Instance Attribute Details

#body#read

Request body

Returns:

  • (#read)

49
50
51
# File 'lib/google/apis/core/http_command.rb', line 49

def body
  @body
end

#connectionHurley::Client

HTTP Client

Returns:

  • (Hurley::Client)

57
58
59
# File 'lib/google/apis/core/http_command.rb', line 57

def connection
  @connection
end

#headerHurley::Header

HTTP headers

Returns:

  • (Hurley::Header)

45
46
47
# File 'lib/google/apis/core/http_command.rb', line 45

def header
  @header
end

#methodsymbol

HTTP method

Returns:

  • (symbol)

53
54
55
# File 'lib/google/apis/core/http_command.rb', line 53

def method
  @method
end

#optionsGoogle::Apis::RequestOptions

Request options


37
38
39
# File 'lib/google/apis/core/http_command.rb', line 37

def options
  @options
end

#paramsHash

Path params for URL Template

Returns:

  • (Hash)

65
66
67
# File 'lib/google/apis/core/http_command.rb', line 65

def params
  @params
end

#queryHash

Query params

Returns:

  • (Hash)

61
62
63
# File 'lib/google/apis/core/http_command.rb', line 61

def query
  @query
end

#urlString, Addressable::URI

HTTP request URL

Returns:

  • (String, Addressable::URI)

41
42
43
# File 'lib/google/apis/core/http_command.rb', line 41

def url
  @url
end

Instance Method Details

#allow_form_encoding?Boolean

Returns:

  • (Boolean)

309
310
311
# File 'lib/google/apis/core/http_command.rb', line 309

def allow_form_encoding?
  [:post, :put].include?(method) && body.nil?
end

#apply_request_options(req)

This method returns an undefined value.

Update the request with any specified options.

Parameters:

  • req (Hurley::Request)

    HTTP request


298
299
300
301
302
303
304
305
306
307
# File 'lib/google/apis/core/http_command.rb', line 298

def apply_request_options(req)
  if options.authorization.respond_to?(:apply!)
    options.authorization.apply!(req.header)
  elsif options.authorization.is_a?(String)
    req.header[:authorization] = sprintf('Bearer %s', options.authorization)
  end
  req.header.update(header)
  req.options.timeout = options.timeout_sec
  req.options.open_timeout = options.open_timeout_sec
end

#authorization_refreshable?Boolean

Check if attached credentials can be automatically refreshed

Returns:

  • (Boolean)

136
137
138
# File 'lib/google/apis/core/http_command.rb', line 136

def authorization_refreshable?
  options.authorization.respond_to?(:apply!)
end

#check_status(status, header = nil, body = nil, message = nil)

This method returns an undefined value.

Check the response and raise error if needed

Parameters:

  • status (Fixnum)

    HTTP status code of response

  • header (Hurley::Header) (defaults to: nil)

    HTTP response headers

  • body (String) (defaults to: nil)

    HTTP response body

  • message (String) (defaults to: nil)

    Error message text

Raises:


198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/google/apis/core/http_command.rb', line 198

def check_status(status, header = nil, body = nil, message = nil)
  # TODO: 304 Not Modified depends on context...
  case status
  when 200...300
    nil
  when 301, 302, 303, 307
    message ||= sprintf('Redirect to %s', header[:location])
    raise Google::Apis::RedirectError.new(message, status_code: status, header: header, body: body)
  when 401
    message ||= 'Unauthorized'
    raise Google::Apis::AuthorizationError.new(message, status_code: status, header: header, body: body)
  when 304, 400, 402...500
    message ||= 'Invalid request'
    raise Google::Apis::ClientError.new(message, status_code: status, header: header, body: body)
  when 500...600
    message ||= 'Server error'
    raise Google::Apis::ServerError.new(message, status_code: status, header: header, body: body)
  else
    logger.warn(sprintf('Encountered unexpected status code %s', status))
    message ||= 'Unknown error'
    raise Google::Apis::TransmissionError.new(message, status_code: status, header: header, body: body)
  end
end

#decode_response_body(_content_type, body) ⇒ Object

Process the actual response body. Intended to be overridden by subclasses

Parameters:

  • _content_type (String)

    Content type of body

  • body (String, #read)

    Response body

Returns:

  • (Object)

229
230
231
# File 'lib/google/apis/core/http_command.rb', line 229

def decode_response_body(_content_type, body)
  body
end

#error(err, rethrow: false) {|nil, err| ... }

This method returns an undefined value.

Process an error response

Parameters:

  • err (StandardError)

    Error object

  • rethrow (Boolean) (defaults to: false)

    True if error should be raised again after handling

Yields:

  • (nil, err)

    if block given

Raises:

  • (StandardError)

    if no block


252
253
254
255
256
257
# File 'lib/google/apis/core/http_command.rb', line 252

def error(err, rethrow: false, &block)
  logger.debug { sprintf('Error - %s', PP.pp(err, '')) }
  err = Google::Apis::TransmissionError.new(err) if err.is_a?(Hurley::ClientError) || err.is_a?(SocketError)
  block.call(nil, err) if block_given?
  fail err if rethrow || block.nil?
end

#execute(client) {|result, err| ... } ⇒ Object

Execute the command, retrying as necessary

Parameters:

  • client (Hurley::Client)

    HTTP client

Yields:

  • (result, err)

    Result or error if block supplied

Returns:

  • (Object)

Raises:


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
119
120
121
122
123
# File 'lib/google/apis/core/http_command.rb', line 93

def execute(client)
  prepare!
  begin
    Retriable.retriable tries: options.retries + 1,
                        base_interval: 1,
                        multiplier: 2,
                        on: RETRIABLE_ERRORS do |try|
      # This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
      # auth to be re-attempted without having to retry all sorts of other failures like
      # NotFound, etc
      auth_tries = (try == 1 && authorization_refreshable? ? 2 : 1)
      Retriable.retriable tries: auth_tries,
                          on: [Google::Apis::AuthorizationError],
                          on_retry: proc { |*| refresh_authorization } do
        execute_once(client).tap do |result|
          if block_given?
            yield result, nil
          end
        end
      end
    end
  rescue => e
    if block_given?
      yield nil, e
    else
      raise e
    end
  end
ensure
  release!
end

#process_response(status, header, body) ⇒ Object

Check the response and either decode body or raise error

Parameters:

  • status (Fixnum)

    HTTP status code of response

  • header (Hurley::Header)

    Response headers

  • body (String, #read)

    Response body

Returns:

  • (Object)

    Response object

Raises:


178
179
180
181
# File 'lib/google/apis/core/http_command.rb', line 178

def process_response(status, header, body)
  check_status(status, header, body)
  decode_response_body(header[:content_type], body)
end

#success(result) {|result, nil| ... } ⇒ Object

Process a success response

Parameters:

  • result (Object)

    Result object

Yields:

  • (result, nil)

    if block given

Returns:

  • (Object)

    result if no block given


238
239
240
241
242
# File 'lib/google/apis/core/http_command.rb', line 238

def success(result, &block)
  logger.debug { sprintf('Success - %s', PP.pp(result, '')) }
  block.call(result, nil) if block_given?
  result
end