google-apis-core 0.18.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adcaaf904d1c4e3e203b45c527c259c1be63aa675402247297a96ca087b5e14a
4
- data.tar.gz: 6bafca376fc6569b0e8ff19071c1729e83310f55d3cb3b99e11d5440448ffd83
3
+ metadata.gz: 2e4864fdbdd96f55fa077d183ac6c25f87d16509b48bd270803c73f81d4fa47b
4
+ data.tar.gz: 869598753c71741fcd2a4f474b464a609d6fcb2b6513c9c87d75ff1365192d07
5
5
  SHA512:
6
- metadata.gz: 4a24caabd4a3bfc09f9de6be416165fa6aa4b90f89b7ecf4f948801cba266c81e497f773fe25740a723056db708342a28eb36584a11dc43a436ca90e2eb95234
7
- data.tar.gz: 4da89f87e45e5edf5c359aef57878e044c90411638c899744efe5235215fa576b2cd3eb46fa61b1678a4b57dda521b6f9fb386c8868a3b9118ddc494757f8a9a
6
+ metadata.gz: 4bfce12bdbf8dd48e4856b77902d7fef1343ae940400e56090b1d946ed26e786b1f39ae17f3aa60dfc63e3594411c48eb5711957ad7a0f55c136fab03e45edb8
7
+ data.tar.gz: 21c7758ca4994eef7b077b19b10affcc112a909834f3b7dc5b346df42712ea3d68cccabf8131c869410ce3091f679509f39f834d5f05fbb31ea8c14ec40d8a45
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Release History
2
2
 
3
+ ### 1.0.0 (2025-08-03)
4
+
5
+ This is a major release that replaces the underlying httpclient library with Faraday ([#23524](https://github.com/googleapis/google-api-ruby-client/issues/23524)). This will ensure the client libraries are on a more stable and better maintained foundation moving forward.
6
+
7
+ For most users, this change should be transparent. However, if your application depends on the httpclient interfaces, you can retain compatibility with httpclient by pinning the `google-apis-core` gem to `~> 0.18` in your Gemfile. Httpclient-based versions of this gem will remain on the 0.x release train, while Faraday-based versions will occupy the 1.x release train. We will push critical fixes and security updates to both branches for one year until August 2026, but new feature work will take place only on the 1.x branch.
8
+
3
9
  ### 0.18.0 (2025-05-22)
4
10
 
5
11
  #### Features
data/OVERVIEW.md CHANGED
@@ -4,6 +4,24 @@ This library includes common base classes and dependencies used by legacy REST
4
4
  clients for Google APIs. It is used by client libraries, but you should not
5
5
  need to install it by itself.
6
6
 
7
+ ## Usage
8
+
9
+ In most cases, this library is installed automatically as a dependency of
10
+ another library. For example, if you install the
11
+ [google-apis-drive_v3](https://rubygems.org/gems/google-apis-drive_v3) client
12
+ library, it will bring in the latest `google-apis-core` as a dependency. Thus,
13
+ in most cases, you do not need to add `google-apis-core` to your Gemfile
14
+ directly.
15
+
16
+ Earlier (0.x) versions of this library utilized the legacy
17
+ [httpclient](https://rubygems.org/gems/httpclient) gem and made some of its
18
+ interfaces available for advanced use cases. Version 1.0 and later of this
19
+ library replaced httpclient with [faraday](https://rubygems.org/gems/faraday).
20
+ If your application makes use of the httpclient interfaces (this is rare), you
21
+ should pin `google-apis-core` to a 0.x version in your Gemfile. For example:
22
+
23
+ gem "google-apis-core", "~> 0.18"
24
+
7
25
  ## Documentation
8
26
 
9
27
  More detailed descriptions of the Google legacy REST clients are available in two documents.
@@ -18,13 +18,13 @@ require 'google/apis'
18
18
  require 'google/apis/core/version'
19
19
  require 'google/apis/core/api_command'
20
20
  require 'google/apis/core/batch'
21
+ require 'google/apis/core/faraday_integration'
21
22
  require 'google/apis/core/upload'
22
23
  require 'google/apis/core/storage_upload'
23
24
  require 'google/apis/core/download'
24
25
  require 'google/apis/core/storage_download'
25
26
  require 'google/apis/options'
26
27
  require 'googleauth'
27
- require 'httpclient'
28
28
 
29
29
  module Google
30
30
  module Apis
@@ -149,8 +149,8 @@ module Google
149
149
  # @return [Addressable::URI]
150
150
  attr_accessor :batch_path
151
151
 
152
- # HTTP client
153
- # @return [HTTPClient]
152
+ # Faraday HTTP connection
153
+ # @return [Faraday::Connection]
154
154
  attr_writer :client
155
155
 
156
156
  # General settings
@@ -263,8 +263,8 @@ module Google
263
263
  batch_command.execute(client)
264
264
  end
265
265
 
266
- # Get the current HTTP client
267
- # @return [HTTPClient]
266
+ # Get the current HTTP connection
267
+ # @return [Faraday::Connection]
268
268
  def client
269
269
  @client ||= new_client
270
270
  end
@@ -376,7 +376,7 @@ module Google
376
376
  command = make_storage_upload_command(:delete, 'b/{bucket}/o', options)
377
377
  command.upload_id = upload_id
378
378
  command.params['bucket'] = bucket unless bucket.nil?
379
- command.delete_upload = options[:delete_upload] unless options[:delete_upload].nil?
379
+ command.delete_upload = true
380
380
  execute_or_queue_command(command)
381
381
  end
382
382
 
@@ -542,39 +542,22 @@ module Google
542
542
  Thread.current[:google_api_batch_service] = nil
543
543
  end
544
544
 
545
- # Create a new HTTP client
546
- # @return [HTTPClient]
545
+ # Create a new HTTP connection
546
+ # @return [Faraday::Connection]
547
547
  def new_client
548
- client = ::HTTPClient.new
549
-
550
- if client_options.transparent_gzip_decompression
551
- client.transparent_gzip_decompression = client_options.transparent_gzip_decompression
552
- end
553
-
554
- client.proxy = client_options.proxy_url if client_options.proxy_url
555
-
556
- if client_options.open_timeout_sec
557
- client.connect_timeout = client_options.open_timeout_sec
558
- end
559
-
560
- if client_options.read_timeout_sec
561
- client.receive_timeout = client_options.read_timeout_sec
548
+ options = {}
549
+ request_options = {params_encoder: Faraday::FlatParamsEncoder}
550
+ options[:proxy] = {uri: client_options.proxy_url} if client_options.proxy_url
551
+ request_options[:open_timeout] = client_options.open_timeout_sec if client_options.open_timeout_sec
552
+ request_options[:read_timeout] = client_options.read_timeout_sec if client_options.read_timeout_sec
553
+ request_options[:write_timeout] = client_options.send_timeout_sec if client_options.send_timeout_sec
554
+ options[:request] = request_options unless request_options.empty?
555
+ options[:headers] = { 'User-Agent' => user_agent }
556
+
557
+ Faraday.new options do |faraday|
558
+ faraday.response :logger, Google::Apis.logger if client_options.log_http_requests
559
+ faraday.response :follow_redirects_google_apis_core, limit: 5
562
560
  end
563
-
564
- if client_options.send_timeout_sec
565
- client.send_timeout = client_options.send_timeout_sec
566
- end
567
-
568
- client.follow_redirect_count = 5
569
- client.default_header = { 'User-Agent' => user_agent }
570
-
571
- client.debug_dev = logger if client_options.log_http_requests
572
-
573
- # Make HttpClient use system default root CA path
574
- # https://github.com/nahi/httpclient/issues/445
575
- client.ssl_config.clear_cert_store
576
- client.ssl_config.cert_store.set_default_paths
577
- client
578
561
  end
579
562
 
580
563
 
@@ -82,7 +82,7 @@ module Google
82
82
  parts.each_index do |index|
83
83
  response = deserializer.to_http_response(parts[index])
84
84
  outer_header = response.shift
85
- call_id = header_to_id(outer_header['Content-ID'].first) || index
85
+ call_id = header_to_id(Array(outer_header['Content-ID']).first) || index
86
86
  call, callback = @calls[call_id]
87
87
  begin
88
88
  result = call.process_response(*response) unless call.nil?
@@ -211,14 +211,14 @@ module Google
211
211
 
212
212
  protected
213
213
 
214
- # Auxiliary method to split the header from the body in an HTTP response.
214
+ # Auxiliary method to split the headers from the body in an HTTP response.
215
215
  #
216
216
  # @param [String] response
217
217
  # the response to parse.
218
- # @return [Array<(HTTP::Message::Headers, String)>]
219
- # the header and the body, separately.
218
+ # @return [Array<(Hash{String=>Array<String>}, String)>]
219
+ # the headers and the body, separately.
220
220
  def split_header_and_body(response)
221
- header = HTTP::Message::Headers.new
221
+ headers = {}
222
222
  payload = response.lstrip
223
223
  while payload
224
224
  line, payload = payload.split(/\n/, 2)
@@ -226,9 +226,9 @@ module Google
226
226
  break if line.empty?
227
227
  match = /\A([^:]+):\s*/.match(line)
228
228
  fail BatchError, sprintf('Invalid header line in response: %s', line) if match.nil?
229
- header[match[1]] = match.post_match
229
+ (headers[match[1]] ||= []) << match.post_match
230
230
  end
231
- [header, payload]
231
+ [headers, payload]
232
232
  end
233
233
  end
234
234
  end
@@ -23,6 +23,8 @@ module Google
23
23
  # Streaming/resumable media download support
24
24
  class DownloadCommand < ApiCommand
25
25
  RANGE_HEADER = 'Range'
26
+
27
+ # @deprecated No longer used
26
28
  OK_STATUS = [200, 201, 206]
27
29
 
28
30
  # File or IO to write content to
@@ -61,8 +63,7 @@ module Google
61
63
  # of file content.
62
64
  #
63
65
  # @private
64
- # @param [HTTPClient] client
65
- # HTTP client
66
+ # @param [Faraday::Connection] client Faraday connection
66
67
  # @yield [result, err] Result or error if block supplied
67
68
  # @return [Object]
68
69
  # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
@@ -78,39 +79,39 @@ module Google
78
79
  request_header[RANGE_HEADER] = sprintf('bytes=%d-', @offset)
79
80
  end
80
81
 
81
- http_res = client.get(url.to_s,
82
- query: query,
83
- header: request_header,
84
- follow_redirect: true) do |res, chunk|
85
- status = res.http_header.status_code.to_i
86
- next unless OK_STATUS.include?(status)
82
+ http_res = client.get(url.to_s, query, request_header) do |request|
83
+ request.options.on_data = proc do |chunk, _size, res|
84
+ status = res.status.to_i
85
+ next if chunk.nil? || (status >= 300 && status < 400)
87
86
 
88
- download_offset ||= (status == 206 ? @offset : 0)
89
- download_offset += chunk.bytesize
87
+ # HTTP 206 is Partial Content
88
+ download_offset ||= (status == 206 ? @offset : 0)
89
+ download_offset += chunk.bytesize
90
90
 
91
- if download_offset - chunk.bytesize == @offset
92
- next_chunk = chunk
93
- else
94
- # Oh no! Requested a chunk, but received the entire content
95
- chunk_index = @offset - (download_offset - chunk.bytesize)
96
- next_chunk = chunk.byteslice(chunk_index..-1)
97
- next if next_chunk.nil?
98
- end
91
+ if download_offset - chunk.bytesize == @offset
92
+ next_chunk = chunk
93
+ else
94
+ # Oh no! Requested a chunk, but received the entire content
95
+ chunk_index = @offset - (download_offset - chunk.bytesize)
96
+ next_chunk = chunk.byteslice(chunk_index..-1)
97
+ next if next_chunk.nil?
98
+ end
99
99
 
100
- # logger.debug { sprintf('Writing chunk (%d bytes, %d total)', chunk.length, bytes_read) }
101
- @download_io.write(next_chunk)
100
+ # logger.debug { sprintf('Writing chunk (%d bytes, %d total)', chunk.length, bytes_read) }
101
+ @download_io.write(next_chunk)
102
102
 
103
- @offset += next_chunk.bytesize
103
+ @offset += next_chunk.bytesize
104
+ end
104
105
  end
105
106
 
106
- @download_io.flush if @download_io.respond_to?(:flush)
107
+ @download_io.flush if @download_io.respond_to?(:flush)
107
108
 
108
109
  if @close_io_on_finish
109
110
  result = nil
110
111
  else
111
112
  result = @download_io
112
113
  end
113
- check_status(http_res.status.to_i, http_res.header, http_res.body)
114
+ check_status(http_res.status.to_i, http_res.headers, http_res.body)
114
115
  success(result, &block)
115
116
  rescue => e
116
117
  @download_io.flush if @download_io.respond_to?(:flush)
@@ -0,0 +1,47 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "faraday"
16
+ require "faraday/follow_redirects"
17
+
18
+ module Google
19
+ module Apis
20
+ module Core
21
+ # Customized version of the FollowRedirects middleware that does not
22
+ # trigger on 308. HttpCommand wants to handle 308 itself for resumable
23
+ # uploads.
24
+ class FollowRedirectsMiddleware < Faraday::FollowRedirects::Middleware
25
+ def follow_redirect?(env, response)
26
+ super && response.status != 308
27
+ end
28
+ end
29
+
30
+ Faraday::Response.register_middleware(follow_redirects_google_apis_core: FollowRedirectsMiddleware)
31
+
32
+ # Customized subclass of Faraday::Response with additional capabilities
33
+ # needed by older versions of some downstream dependencies.
34
+ class Response < Faraday::Response
35
+ # Compatibility alias.
36
+ # Earlier versions based on the old `httpclient` gem used `HTTP::Message`,
37
+ # which defined the `header` field that some clients, notably
38
+ # google-cloud-storage, depend on.
39
+ # Faraday's `headers` isn't an exact replacement because its values are
40
+ # single strings whereas `HTTP::Message` values are arrays, but
41
+ # google-cloud-storage already passes the result through `Array()` so this
42
+ # should work sufficiently.
43
+ alias header headers
44
+ end
45
+ end
46
+ end
47
+ end
@@ -17,6 +17,7 @@ require 'addressable/template'
17
17
  require 'google/apis/options'
18
18
  require 'google/apis/errors'
19
19
  require 'retriable'
20
+ require 'google/apis/core/faraday_integration'
20
21
  require 'google/apis/core/logging'
21
22
  require 'pp'
22
23
 
@@ -59,8 +60,8 @@ module Google
59
60
  # @return [symbol]
60
61
  attr_accessor :method
61
62
 
62
- # HTTP Client
63
- # @return [HTTPClient]
63
+ # Faraday connection
64
+ # @return [Faraday::Connection]
64
65
  attr_accessor :connection
65
66
 
66
67
  # Query params
@@ -96,8 +97,8 @@ module Google
96
97
 
97
98
  # Execute the command, retrying as necessary
98
99
  #
99
- # @param [HTTPClient] client
100
- # HTTP client
100
+ # @param [Faraday::Connection] client
101
+ # Faraday connection
101
102
  # @yield [result, err] Result or error if block supplied
102
103
  # @return [Object]
103
104
  # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
@@ -181,7 +182,7 @@ module Google
181
182
  @form_encoded = false
182
183
  end
183
184
 
184
- self.body = '' unless self.body
185
+ self.body = '' if self.body.nil? && [:post, :put, :patch].include?(method)
185
186
  end
186
187
 
187
188
  # Release any resources used by this command
@@ -205,7 +206,7 @@ module Google
205
206
  # @raise [Google::Apis::AuthorizationError] Authorization is required
206
207
  def process_response(status, header, body)
207
208
  check_status(status, header, body)
208
- decode_response_body(header['Content-Type'].first, body)
209
+ decode_response_body(Array(header['Content-Type']).first, body)
209
210
  end
210
211
 
211
212
  # Check the response and raise error if needed
@@ -284,17 +285,10 @@ module Google
284
285
  # @raise [StandardError] if no block
285
286
  def error(err, rethrow: false, &block)
286
287
  logger.debug { sprintf('Error - %s', PP.pp(err, +'')) }
287
- if err.is_a?(HTTPClient::BadResponseError)
288
- begin
289
- res = err.res
290
- raise Google::Apis::TransmissionError.new(err) if res.nil?
291
- check_status(res.status.to_i, res.header, res.body)
292
- rescue Google::Apis::Error => e
293
- err = e
294
- end
295
- elsif err.is_a?(HTTPClient::TimeoutError) ||
288
+ if err.is_a?(Faraday::FollowRedirects::RedirectLimitReached)
289
+ err = Google::Apis::RedirectError.new(err)
290
+ elsif err.is_a?(Faraday::Error) ||
296
291
  err.is_a?(SocketError) ||
297
- err.is_a?(HTTPClient::KeepAliveDisconnected) ||
298
292
  err.is_a?(Errno::ECONNREFUSED) ||
299
293
  err.is_a?(Errno::ETIMEDOUT) ||
300
294
  err.is_a?(Errno::ECONNRESET)
@@ -307,8 +301,8 @@ module Google
307
301
  # Execute the command once.
308
302
  #
309
303
  # @private
310
- # @param [HTTPClient] client
311
- # HTTP client
304
+ # @param [Faraday::Connection] client
305
+ # Faraday connection
312
306
  # @return [Object]
313
307
  # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
314
308
  # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
@@ -320,15 +314,11 @@ module Google
320
314
  request_header = header.dup
321
315
  apply_request_options(request_header)
322
316
 
323
- @http_res = client.request(method.to_s.upcase,
324
- url.to_s,
325
- query: nil,
326
- body: body,
327
- header: request_header,
328
- follow_redirect: true)
317
+ @http_res = client.run_request(method, url.to_s, body, request_header)
318
+
329
319
  logger.debug { @http_res.status }
330
320
  logger.debug { safe_single_line_representation @http_res }
331
- response = process_response(@http_res.status.to_i, @http_res.header, @http_res.body)
321
+ response = process_response(@http_res.status.to_i, @http_res.headers, @http_res.body)
332
322
  success(response)
333
323
  rescue => e
334
324
  logger.debug { sprintf('Caught error %s', e) }
@@ -410,9 +400,14 @@ module Google
410
400
  @opencensus_span.put_attribute "http.host", url.host.to_s
411
401
  @opencensus_span.put_attribute "http.method", method.to_s.upcase
412
402
  @opencensus_span.put_attribute "http.path", url.path.to_s
413
- if body.respond_to? :bytesize
414
- @opencensus_span.put_message_event \
415
- OpenCensus::Trace::SpanBuilder::SENT, 1, body.bytesize
403
+ sent_size =
404
+ if body.respond_to? :bytesize
405
+ body.bytesize
406
+ elsif body.nil?
407
+ 0
408
+ end
409
+ if sent_size
410
+ @opencensus_span.put_message_event OpenCensus::Trace::SpanBuilder::SENT, 1, sent_size
416
411
  end
417
412
 
418
413
  formatter = OpenCensus::Trace.config.http_formatter
@@ -30,8 +30,7 @@ module Google
30
30
  # here too.
31
31
  #
32
32
  # @private
33
- # @param [HTTPClient] client
34
- # HTTP client
33
+ # @param [Faraday::Connection] client Faraday connection
35
34
  # @yield [result, err] Result or error if block supplied
36
35
  # @return [Object]
37
36
  # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
@@ -47,41 +46,45 @@ module Google
47
46
  request_header[RANGE_HEADER] = sprintf('bytes=%d-', @offset)
48
47
  end
49
48
 
50
- http_res = client.get(url.to_s,
51
- query: query,
52
- header: request_header,
53
- follow_redirect: true) do |res, chunk|
54
- status = res.http_header.status_code.to_i
55
- next unless OK_STATUS.include?(status)
49
+ http_res = client.get(url.to_s, query, request_header) do |request|
50
+ request.options.on_data = proc do |chunk, _size, res|
51
+ status = res.status.to_i
52
+ next if chunk.nil? || (status >= 300 && status < 400)
56
53
 
57
- download_offset ||= (status == 206 ? @offset : 0)
58
- download_offset += chunk.bytesize
54
+ download_offset ||= (status == 206 ? @offset : 0)
55
+ download_offset += chunk.bytesize
59
56
 
60
- if download_offset - chunk.bytesize == @offset
61
- next_chunk = chunk
62
- else
63
- # Oh no! Requested a chunk, but received the entire content
64
- chunk_index = @offset - (download_offset - chunk.bytesize)
65
- next_chunk = chunk.byteslice(chunk_index..-1)
66
- next if next_chunk.nil?
67
- end
57
+ if download_offset - chunk.bytesize == @offset
58
+ next_chunk = chunk
59
+ else
60
+ # Oh no! Requested a chunk, but received the entire content
61
+ chunk_index = @offset - (download_offset - chunk.bytesize)
62
+ next_chunk = chunk.byteslice(chunk_index..-1)
63
+ next if next_chunk.nil?
64
+ end
68
65
 
69
- # logger.debug { sprintf('Writing chunk (%d bytes, %d total)', chunk.length, bytes_read) }
70
- @download_io.write(next_chunk)
66
+ # logger.debug { sprintf('Writing chunk (%d bytes, %d total)', chunk.length, bytes_read) }
67
+ @download_io.write(next_chunk)
71
68
 
72
- @offset += next_chunk.bytesize
69
+ @offset += next_chunk.bytesize
70
+ end
73
71
  end
74
72
 
75
- @download_io.flush if @download_io.respond_to?(:flush)
73
+ @download_io.flush if @download_io.respond_to?(:flush)
76
74
 
77
75
  if @close_io_on_finish
78
76
  result = nil
79
77
  else
80
78
  result = @download_io
81
79
  end
82
- check_status(http_res.status.to_i, http_res.header, http_res.body)
83
- # In case of file download in storage, we need to respond back with http
84
- # header along with the actual object.
80
+ check_status(http_res.status.to_i, http_res.headers, http_res.body)
81
+ # In case of file download in storage, we need to respond back with
82
+ # the http response object along with the result IO object, because
83
+ # google-cloud-storage uses the HTTP info.
84
+ # Also, older versions of google-cloud-storage assume this object
85
+ # conforms to the old httpclient response API instead of the Faraday
86
+ # response API. Return a subclass that provides the needed methods.
87
+ http_res = Core::Response.new http_res.env
85
88
  success([result, http_res], &block)
86
89
  rescue => e
87
90
  @download_io.flush if @download_io.respond_to?(:flush)
@@ -94,8 +94,7 @@ module Google
94
94
 
95
95
  # Execute the command, retrying as necessary
96
96
  #
97
- # @param [HTTPClient] client
98
- # HTTP client
97
+ # @param [Faraday::Connection] client Faraday connection
99
98
  # @yield [result, err] Result or error if block supplied
100
99
  # @return [Object]
101
100
  # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
@@ -138,11 +137,10 @@ module Google
138
137
  request_header[CONTENT_TYPE_HEADER] = JSON_CONTENT_TYPE
139
138
  request_header[UPLOAD_CONTENT_TYPE_HEADER] = upload_content_type unless upload_content_type.nil?
140
139
 
141
- response = client.post(url.to_s, query: request_query,
142
- body: body,
143
- header: request_header,
144
- follow_redirect: true)
145
- result = process_response(response.status_code, response.header, response.body)
140
+ response = client.post(url.to_s, body, request_header) do |request|
141
+ request.params.replace(request_query)
142
+ end
143
+ result = process_response(response.status.to_i, response.headers, response.body)
146
144
  success(result)
147
145
  rescue => e
148
146
  error(e, rethrow: true)
@@ -166,8 +164,7 @@ module Google
166
164
 
167
165
  # Send the actual content
168
166
  #
169
- # @param [HTTPClient] client
170
- # HTTP client
167
+ # @param [Faraday::Connection] client Faraday connection
171
168
  # @return [HTTP::Message]
172
169
  # @raise [Google::Apis::ServerError] Unable to send the request
173
170
  def send_upload_command(client)
@@ -178,7 +175,7 @@ module Google
178
175
 
179
176
  request_header = header.dup
180
177
  request_header[CONTENT_RANGE_HEADER] = get_content_range_header current_chunk_size
181
- request_header[CONTENT_LENGTH_HEADER] = current_chunk_size
178
+ request_header[CONTENT_LENGTH_HEADER] = current_chunk_size.to_s
182
179
  chunk_body =
183
180
  if @upload_chunk_size == 0
184
181
  upload_io
@@ -186,10 +183,10 @@ module Google
186
183
  StringIO.new(upload_io.read(current_chunk_size))
187
184
  end
188
185
 
189
- response = client.put(@upload_url, body: chunk_body, header: request_header, follow_redirect: true)
186
+ response = client.put(@upload_url, chunk_body, request_header)
190
187
 
191
- result = process_response(response.status_code, response.header, response.body)
192
- @upload_incomplete = false if response.status_code.eql? OK_STATUS
188
+ result = process_response(response.status.to_i, response.headers, response.body)
189
+ @upload_incomplete = false if response.status.to_i.eql? OK_STATUS
193
190
  @offset += current_chunk_size if @upload_incomplete
194
191
  success(result)
195
192
  rescue => e
@@ -214,7 +211,8 @@ module Google
214
211
  # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
215
212
  # @raise [Google::Apis::AuthorizationError] Authorization is required
216
213
  def process_response(status, header, body)
217
- @upload_url = header[LOCATION_HEADER].first unless header[LOCATION_HEADER].empty?
214
+ location_header = Array(header[LOCATION_HEADER])
215
+ @upload_url = location_header.first unless location_header.empty?
218
216
  super(status, header, body)
219
217
  end
220
218
 
@@ -224,7 +222,7 @@ module Google
224
222
  request_header[CONTENT_RANGE_HEADER] = "bytes */#{upload_io.size}"
225
223
  request_header[CONTENT_LENGTH_HEADER] = '0'
226
224
  # Initiating call
227
- response = client.put(@upload_url, header: request_header, follow_redirect: true)
225
+ response = client.put(@upload_url, "", request_header)
228
226
  handle_resumable_upload_http_response_codes(response)
229
227
  end
230
228
 
@@ -234,25 +232,25 @@ module Google
234
232
  request_header = header.dup
235
233
  request_header[CONTENT_LENGTH_HEADER] = '0'
236
234
  # Initiating call
237
- response = client.delete(@upload_url, header: request_header, follow_redirect: true)
235
+ response = client.delete(@upload_url, nil, request_header)
238
236
  handle_resumable_upload_http_response_codes(response)
239
237
 
240
- if !@upload_incomplete && (400..499).include?(response.code.to_i)
238
+ if !@upload_incomplete && (400..499).include?(response.status.to_i)
241
239
  @close_io_on_finish = true
242
240
  true # method returns true if upload is successfully cancelled
243
241
  else
244
- logger.debug { sprintf("Failed to cancel upload session. Response: #{response.code} - #{response.body}") }
242
+ logger.debug { sprintf("Failed to cancel upload session. Response: #{response.status.to_i} - #{response.body}") }
245
243
  end
246
244
 
247
245
  end
248
246
 
249
247
  def handle_resumable_upload_http_response_codes(response)
250
- code = response.code.to_i
248
+ code = response.status.to_i
251
249
 
252
250
  case code
253
251
  when 308
254
252
  if response.headers['Range']
255
- range = response.headers['Range']
253
+ range = Array(response.headers['Range']).first
256
254
  @offset = range.split('-').last.to_i + 1
257
255
  logger.debug { sprintf("Upload is incomplete. Bytes uploaded so far: #{range}") }
258
256
  else
@@ -266,7 +264,7 @@ module Google
266
264
  # Upload is complete.
267
265
  @upload_incomplete = false
268
266
  else
269
- logger.debug { sprintf("Unexpected response: #{response.code} - #{response.body}") }
267
+ logger.debug { sprintf("Unexpected response: #{response.status.to_i} - #{response.body}") }
270
268
  @upload_incomplete = true
271
269
  end
272
270
  end
@@ -30,6 +30,7 @@ module Google
30
30
  UPLOAD_CONTENT_TYPE_HEADER = 'X-Goog-Upload-Header-Content-Type'
31
31
  UPLOAD_CONTENT_LENGTH = 'X-Goog-Upload-Header-Content-Length'
32
32
  CONTENT_TYPE_HEADER = 'Content-Type'
33
+ CONTENT_LENGTH_HEADER = "Content-Length"
33
34
 
34
35
  # File name or IO containing the content to upload
35
36
  # @return [String, File, #read]
@@ -159,9 +160,11 @@ module Google
159
160
  # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
160
161
  # @raise [Google::Apis::AuthorizationError] Authorization is required
161
162
  def process_response(status, header, body)
162
- @offset = Integer(header[BYTES_RECEIVED_HEADER].first) unless header[BYTES_RECEIVED_HEADER].empty?
163
- @upload_url = header[UPLOAD_URL_HEADER].first unless header[UPLOAD_URL_HEADER].empty?
164
- upload_status = header[UPLOAD_STATUS_HEADER].first
163
+ bytes_received_header = Array(header[BYTES_RECEIVED_HEADER])
164
+ @offset = Integer(bytes_received_header.first) unless bytes_received_header.empty?
165
+ upload_url_header = Array(header[UPLOAD_URL_HEADER])
166
+ @upload_url = upload_url_header.first unless upload_url_header.empty?
167
+ upload_status = Array(header[UPLOAD_STATUS_HEADER]).first
165
168
  logger.debug { sprintf('Upload status %s', upload_status) }
166
169
  if upload_status == STATUS_ACTIVE
167
170
  @state = :active
@@ -184,19 +187,14 @@ module Google
184
187
  request_header[UPLOAD_CONTENT_LENGTH] = upload_io.size.to_s
185
188
  request_header[UPLOAD_CONTENT_TYPE_HEADER] = upload_content_type
186
189
 
187
- client.request(method.to_s.upcase,
188
- url.to_s, query: nil,
189
- body: body,
190
- header: request_header,
191
- follow_redirect: true)
190
+ client.run_request(method, url.to_s, body, request_header)
192
191
  rescue => e
193
192
  raise Google::Apis::ServerError, e.message
194
193
  end
195
194
 
196
195
  # Query for the status of an incomplete upload
197
196
  #
198
- # @param [HTTPClient] client
199
- # HTTP client
197
+ # @param [Faraday::Connection] client Faraday connection
200
198
  # @return [HTTP::Message]
201
199
  # @raise [Google::Apis::ServerError] Unable to send the request
202
200
  def send_query_command(client)
@@ -206,14 +204,13 @@ module Google
206
204
  apply_request_options(request_header)
207
205
  request_header[UPLOAD_COMMAND_HEADER] = QUERY_COMMAND
208
206
 
209
- client.post(@upload_url, body: '', header: request_header, follow_redirect: true)
207
+ client.post(@upload_url, '', request_header)
210
208
  end
211
209
 
212
210
 
213
211
  # Send the actual content
214
212
  #
215
- # @param [HTTPClient] client
216
- # HTTP client
213
+ # @param [Faraday::Connection] client Faraday connection
217
214
  # @return [HTTP::Message]
218
215
  # @raise [Google::Apis::ServerError] Unable to send the request
219
216
  def send_upload_command(client)
@@ -228,16 +225,16 @@ module Google
228
225
  request_header[UPLOAD_COMMAND_HEADER] = UPLOAD_COMMAND
229
226
  request_header[UPLOAD_OFFSET_HEADER] = @offset.to_s
230
227
  request_header[CONTENT_TYPE_HEADER] = upload_content_type
228
+ request_header[CONTENT_LENGTH_HEADER] = (upload_io.size - @offset).to_s
231
229
 
232
- client.post(@upload_url, body: content, header: request_header, follow_redirect: true)
230
+ client.post(@upload_url, content, request_header)
233
231
  end
234
232
 
235
233
  # Execute the upload request once. This will typically perform two HTTP requests -- one to initiate or query
236
234
  # for the status of the upload, the second to send the (remaining) content.
237
235
  #
238
236
  # @private
239
- # @param [HTTPClient] client
240
- # HTTP client
237
+ # @param [Faraday::Connection] client Faraday connection
241
238
  # @yield [result, err] Result or error if block supplied
242
239
  # @return [Object]
243
240
  # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
@@ -247,16 +244,16 @@ module Google
247
244
  case @state
248
245
  when :start
249
246
  response = send_start_command(client)
250
- result = process_response(response.status_code, response.header, response.body)
247
+ result = process_response(response.status.to_i, response.headers, response.body)
251
248
  when :active
252
249
  response = send_query_command(client)
253
- result = process_response(response.status_code, response.header, response.body)
250
+ result = process_response(response.status.to_i, response.headers, response.body)
254
251
  when :cancelled, :final
255
252
  error(@last_error, rethrow: true, &block)
256
253
  end
257
254
  if @state == :active
258
255
  response = send_upload_command(client)
259
- result = process_response(response.status_code, response.header, response.body)
256
+ result = process_response(response.status.to_i, response.headers, response.body)
260
257
  end
261
258
 
262
259
  success(result, &block) if @state == :final
@@ -16,7 +16,7 @@ module Google
16
16
  module Apis
17
17
  module Core
18
18
  # Core version
19
- VERSION = "0.18.0".freeze
19
+ VERSION = "1.0.0".freeze
20
20
  end
21
21
  end
22
22
  end
@@ -61,7 +61,7 @@ module Google
61
61
  # @!attribute [rw] read_timeout_sec
62
62
  # @return [Integer] How long, in seconds, before receiving data times out
63
63
  # @!attribute [rw] transparent_gzip_decompression
64
- # @return [Boolean] True if gzip compression needs to be enabled
64
+ # @return [Boolean] DEPRECATED. Gzip decompression is now always on.
65
65
  # Get the default options
66
66
  # @return [Google::Apis::ClientOptions]
67
67
  def self.default
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-apis-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google LLC
@@ -27,104 +27,92 @@ dependencies:
27
27
  name: retriable
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '2.0'
33
- - - "<"
30
+ - - "~>"
34
31
  - !ruby/object:Gem::Version
35
- version: 4.a
32
+ version: '3.1'
36
33
  type: :runtime
37
34
  prerelease: false
38
35
  version_requirements: !ruby/object:Gem::Requirement
39
36
  requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: '2.0'
43
- - - "<"
37
+ - - "~>"
44
38
  - !ruby/object:Gem::Version
45
- version: 4.a
39
+ version: '3.1'
46
40
  - !ruby/object:Gem::Dependency
47
41
  name: addressable
48
42
  requirement: !ruby/object:Gem::Requirement
49
43
  requirements:
50
44
  - - "~>"
51
45
  - !ruby/object:Gem::Version
52
- version: '2.5'
46
+ version: '2.8'
53
47
  - - ">="
54
48
  - !ruby/object:Gem::Version
55
- version: 2.5.1
49
+ version: 2.8.7
56
50
  type: :runtime
57
51
  prerelease: false
58
52
  version_requirements: !ruby/object:Gem::Requirement
59
53
  requirements:
60
54
  - - "~>"
61
55
  - !ruby/object:Gem::Version
62
- version: '2.5'
56
+ version: '2.8'
63
57
  - - ">="
64
58
  - !ruby/object:Gem::Version
65
- version: 2.5.1
59
+ version: 2.8.7
66
60
  - !ruby/object:Gem::Dependency
67
61
  name: mini_mime
68
62
  requirement: !ruby/object:Gem::Requirement
69
63
  requirements:
70
64
  - - "~>"
71
65
  - !ruby/object:Gem::Version
72
- version: '1.0'
66
+ version: '1.1'
73
67
  type: :runtime
74
68
  prerelease: false
75
69
  version_requirements: !ruby/object:Gem::Requirement
76
70
  requirements:
77
71
  - - "~>"
78
72
  - !ruby/object:Gem::Version
79
- version: '1.0'
73
+ version: '1.1'
80
74
  - !ruby/object:Gem::Dependency
81
75
  name: googleauth
82
76
  requirement: !ruby/object:Gem::Requirement
83
77
  requirements:
84
78
  - - "~>"
85
79
  - !ruby/object:Gem::Version
86
- version: '1.9'
80
+ version: '1.14'
87
81
  type: :runtime
88
82
  prerelease: false
89
83
  version_requirements: !ruby/object:Gem::Requirement
90
84
  requirements:
91
85
  - - "~>"
92
86
  - !ruby/object:Gem::Version
93
- version: '1.9'
87
+ version: '1.14'
94
88
  - !ruby/object:Gem::Dependency
95
- name: httpclient
89
+ name: faraday
96
90
  requirement: !ruby/object:Gem::Requirement
97
91
  requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- version: 2.8.3
101
- - - "<"
92
+ - - "~>"
102
93
  - !ruby/object:Gem::Version
103
- version: 3.a
94
+ version: '2.13'
104
95
  type: :runtime
105
96
  prerelease: false
106
97
  version_requirements: !ruby/object:Gem::Requirement
107
98
  requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: 2.8.3
111
- - - "<"
99
+ - - "~>"
112
100
  - !ruby/object:Gem::Version
113
- version: 3.a
101
+ version: '2.13'
114
102
  - !ruby/object:Gem::Dependency
115
- name: mutex_m
103
+ name: faraday-follow_redirects
116
104
  requirement: !ruby/object:Gem::Requirement
117
105
  requirements:
118
- - - ">="
106
+ - - "~>"
119
107
  - !ruby/object:Gem::Version
120
- version: '0'
108
+ version: '0.3'
121
109
  type: :runtime
122
110
  prerelease: false
123
111
  version_requirements: !ruby/object:Gem::Requirement
124
112
  requirements:
125
- - - ">="
113
+ - - "~>"
126
114
  - !ruby/object:Gem::Version
127
- version: '0'
115
+ version: '0.3'
128
116
  email: googleapis-packages@google.com
129
117
  executables: []
130
118
  extensions: []
@@ -147,6 +135,7 @@ files:
147
135
  - lib/google/apis/core/batch.rb
148
136
  - lib/google/apis/core/composite_io.rb
149
137
  - lib/google/apis/core/download.rb
138
+ - lib/google/apis/core/faraday_integration.rb
150
139
  - lib/google/apis/core/hashable.rb
151
140
  - lib/google/apis/core/http_command.rb
152
141
  - lib/google/apis/core/json_representation.rb
@@ -164,7 +153,7 @@ licenses:
164
153
  metadata:
165
154
  bug_tracker_uri: https://github.com/googleapis/google-api-ruby-client/issues
166
155
  changelog_uri: https://github.com/googleapis/google-api-ruby-client/tree/main/google-apis-core/CHANGELOG.md
167
- documentation_uri: https://googleapis.dev/ruby/google-apis-core/v0.18.0
156
+ documentation_uri: https://googleapis.dev/ruby/google-apis-core/v1.0.0
168
157
  source_code_uri: https://github.com/googleapis/google-api-ruby-client/tree/main/google-apis-core
169
158
  rdoc_options: []
170
159
  require_paths: