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)

    Request body



70
71
72
73
74
75
76
77
78
79
# File 'lib/google/apis/core/http_command.rb', line 70

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 = Hash.new
  self.body = body
  self.query = {}
  self.params = {}
end

Instance Attribute Details

#body#read

Request body

Returns:

  • (#read)


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

def body
  @body
end

#connectionHTTPClient

HTTP Client

Returns:

  • (HTTPClient)


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

def connection
  @connection
end

#headerHash

HTTP headers

Returns:

  • (Hash)


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

def header
  @header
end

#methodsymbol

HTTP method

Returns:

  • (symbol)


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

def method
  @method
end

#optionsGoogle::Apis::RequestOptions

Request options



34
35
36
# File 'lib/google/apis/core/http_command.rb', line 34

def options
  @options
end

#paramsHash

Path params for URL Template

Returns:

  • (Hash)


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

def params
  @params
end

#queryHash

Query params

Returns:

  • (Hash)


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

def query
  @query
end

#urlString, Addressable::URI

HTTP request URL

Returns:

  • (String, Addressable::URI)


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

def url
  @url
end

Instance Method Details

#allow_form_encoding?Boolean

Returns:

  • (Boolean)


320
321
322
# File 'lib/google/apis/core/http_command.rb', line 320

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

#apply_request_options(req_header)

This method returns an undefined value.

Update the request with any specified options.

Parameters:

  • header (Hash)

    HTTP headers



311
312
313
314
315
316
317
318
# File 'lib/google/apis/core/http_command.rb', line 311

def apply_request_options(req_header)
  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)
end

#authorization_refreshable?Boolean

Check if attached credentials can be automatically refreshed

Returns:

  • (Boolean)


133
134
135
# File 'lib/google/apis/core/http_command.rb', line 133

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 (Hash) (defaults to: nil)

    HTTP response headers

  • body (String) (defaults to: nil)

    HTTP response body

  • message (String) (defaults to: nil)

    Error message text

Raises:



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/google/apis/core/http_command.rb', line 202

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 429
    message ||= 'Rate limit exceeded'
    raise Google::Apis::RateLimitError.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)


236
237
238
# File 'lib/google/apis/core/http_command.rb', line 236

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)

    True if error should be raised again after handling

Yields:

  • (nil, err)

    if block given

Raises:

  • (StandardError)

    if no block



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/google/apis/core/http_command.rb', line 259

def error(err, rethrow: false, &block)
  logger.debug { sprintf('Error - %s', PP.pp(err, '')) }
  if err.is_a?(HTTPClient::BadResponseError)
    begin
      res = err.res
      check_status(res.status.to_i, res.header, res.body)
    rescue Google::Apis::Error => e
      err = e
    end
  elsif err.is_a?(HTTPClient::TimeoutError) || err.is_a?(SocketError)
    err = Google::Apis::TransmissionError.new(err)
  end
  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 (HTTPClient)

    HTTP client

Yields:

  • (result, err)

    Result or error if block supplied

Returns:

  • (Object)

Raises:



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

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, Signet::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 (Hash)

    Response headers

  • body (String, #read)

    Response body

Returns:

  • (Object)

    Response object

Raises:



182
183
184
185
# File 'lib/google/apis/core/http_command.rb', line 182

def process_response(status, header, body)
  check_status(status, header, body)
  decode_response_body(header['Content-Type'].first, 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



245
246
247
248
249
# File 'lib/google/apis/core/http_command.rb', line 245

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