google-apis-core 1.2.5 → 1.3.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/google/apis/core/http_command.rb +149 -56
- data/lib/google/apis/core/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3732fd02580bd217827d1301e1737b4cf816324234980a06892e12f74970cbf5
|
|
4
|
+
data.tar.gz: ed2a0068e67097f5fe2bf39f80f382d27440bd479e5843df8995d5c85a61112a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4216e6c22892a88e775a7210e2d2be785f6dacff4c5c53f43ede511124b0429117ec95dd92da9d546ab3e922205be2d678a69add9fda4f0cafa53a7108b05e0
|
|
7
|
+
data.tar.gz: d143809acffb08f0a09662825fbe733f33eae474dc16d40a72db64a34cf0d359a3ccb4584221d4dfb5b8e137775af23d31d47d84168d7097feca3c5af3c01e8c
|
data/CHANGELOG.md
CHANGED
|
@@ -31,7 +31,7 @@ module Google
|
|
|
31
31
|
RETRIABLE_ERRORS = [Google::Apis::ServerError,
|
|
32
32
|
Google::Apis::RateLimitError,
|
|
33
33
|
Google::Apis::TransmissionError,
|
|
34
|
-
Google::Apis::RequestTimeOutError]
|
|
34
|
+
Google::Apis::RequestTimeOutError].freeze
|
|
35
35
|
|
|
36
36
|
begin
|
|
37
37
|
require 'opencensus'
|
|
@@ -83,15 +83,15 @@ module Google
|
|
|
83
83
|
self.url = url
|
|
84
84
|
self.url = Addressable::Template.new(url) if url.is_a?(String)
|
|
85
85
|
self.method = method
|
|
86
|
-
self.header =
|
|
86
|
+
self.header = {}
|
|
87
87
|
self.body = body
|
|
88
88
|
self.query = {}
|
|
89
89
|
self.params = {}
|
|
90
90
|
@opencensus_span = nil
|
|
91
91
|
if OPENCENSUS_AVAILABLE
|
|
92
92
|
logger.warn 'OpenCensus support is now deprecated. ' +
|
|
93
|
-
'Please refer https://github.com/googleapis/google-api-ruby-client#tracing for migrating to use OpenTelemetry.'
|
|
94
|
-
|
|
93
|
+
'Please refer https://github.com/googleapis/google-api-ruby-client#tracing for migrating to use OpenTelemetry.'
|
|
94
|
+
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
|
@@ -114,34 +114,30 @@ module Google
|
|
|
114
114
|
release!
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
def do_retry
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if block_given?
|
|
134
|
-
yield result, nil
|
|
135
|
-
end
|
|
136
|
-
end
|
|
117
|
+
def do_retry(func, client)
|
|
118
|
+
Retriable.retriable tries: options.retries + 1,
|
|
119
|
+
max_elapsed_time: options.max_elapsed_time,
|
|
120
|
+
base_interval: options.base_interval,
|
|
121
|
+
max_interval: options.max_interval,
|
|
122
|
+
multiplier: options.multiplier,
|
|
123
|
+
on: RETRIABLE_ERRORS do |try|
|
|
124
|
+
# This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
|
|
125
|
+
# auth to be re-attempted without having to retry all sorts of other failures like
|
|
126
|
+
# NotFound, etc
|
|
127
|
+
auth_tries = (try == 1 && authorization_refreshable? ? 2 : 1)
|
|
128
|
+
Retriable.retriable tries: auth_tries,
|
|
129
|
+
on: [Google::Apis::AuthorizationError, Signet::AuthorizationError, Signet::RemoteServerError, Signet::UnexpectedStatusError],
|
|
130
|
+
on_retry: proc { |*| refresh_authorization } do
|
|
131
|
+
send(func, client).tap do |result|
|
|
132
|
+
yield result, nil if block_given?
|
|
137
133
|
end
|
|
138
134
|
end
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
135
|
+
end
|
|
136
|
+
rescue StandardError => e
|
|
137
|
+
if block_given?
|
|
138
|
+
yield nil, e
|
|
139
|
+
else
|
|
140
|
+
raise e
|
|
145
141
|
end
|
|
146
142
|
end
|
|
147
143
|
|
|
@@ -164,6 +160,7 @@ module Google
|
|
|
164
160
|
#
|
|
165
161
|
# @private
|
|
166
162
|
# @return [void]
|
|
163
|
+
# @raise [Google::Apis::ClientError] If path parameter validation fails.
|
|
167
164
|
def prepare!
|
|
168
165
|
normalize_unicode = true
|
|
169
166
|
if options
|
|
@@ -171,7 +168,10 @@ module Google
|
|
|
171
168
|
query.update(options.query) if options.query
|
|
172
169
|
normalize_unicode = options.normalize_unicode
|
|
173
170
|
end
|
|
174
|
-
|
|
171
|
+
if url.is_a?(Addressable::Template)
|
|
172
|
+
validate_path_parameters!
|
|
173
|
+
self.url = encode_reserved_parameters(url, normalize_unicode).expand(params, nil, normalize_unicode)
|
|
174
|
+
end
|
|
175
175
|
url.query_values = normalize_query_values(query).merge(url.query_values || {})
|
|
176
176
|
|
|
177
177
|
if allow_form_encoding?
|
|
@@ -182,17 +182,16 @@ module Google
|
|
|
182
182
|
@form_encoded = false
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
-
self.body = '' if self.body.nil? && [
|
|
185
|
+
self.body = '' if self.body.nil? && %i[post put patch].include?(method)
|
|
186
186
|
if defined?(::Google::Apis::Core::CompositeIO) && body.is_a?(::Google::Apis::Core::CompositeIO)
|
|
187
|
-
header[
|
|
187
|
+
header['Content-Length'] ||= body.size.to_s
|
|
188
188
|
end
|
|
189
189
|
end
|
|
190
190
|
|
|
191
191
|
# Release any resources used by this command
|
|
192
192
|
# @private
|
|
193
193
|
# @return [void]
|
|
194
|
-
def release
|
|
195
|
-
end
|
|
194
|
+
def release!; end
|
|
196
195
|
|
|
197
196
|
# Check the response and either decode body or raise error
|
|
198
197
|
#
|
|
@@ -298,7 +297,7 @@ module Google
|
|
|
298
297
|
err = Google::Apis::TransmissionError.new(err)
|
|
299
298
|
end
|
|
300
299
|
block.call(nil, err) if block_given?
|
|
301
|
-
|
|
300
|
+
raise err if rethrow || block.nil?
|
|
302
301
|
end
|
|
303
302
|
|
|
304
303
|
# Execute the command once.
|
|
@@ -323,7 +322,7 @@ module Google
|
|
|
323
322
|
logger.debug { safe_single_line_representation @http_res }
|
|
324
323
|
response = process_response(@http_res.status.to_i, @http_res.headers, @http_res.body)
|
|
325
324
|
success(response)
|
|
326
|
-
rescue => e
|
|
325
|
+
rescue StandardError => e
|
|
327
326
|
logger.debug { sprintf('Caught error %s', e) }
|
|
328
327
|
error(e, rethrow: true)
|
|
329
328
|
end
|
|
@@ -343,28 +342,33 @@ module Google
|
|
|
343
342
|
end
|
|
344
343
|
|
|
345
344
|
def allow_form_encoding?
|
|
346
|
-
[
|
|
345
|
+
%i[post put].include?(method) && body.nil?
|
|
347
346
|
end
|
|
348
347
|
|
|
349
348
|
# Set the API version header for the service if not empty.
|
|
350
349
|
# @return [void]
|
|
351
|
-
def set_api_version_header
|
|
350
|
+
def set_api_version_header(api_version)
|
|
352
351
|
self.header['X-Goog-Api-Version'] = api_version unless api_version.empty?
|
|
353
352
|
end
|
|
354
353
|
|
|
355
354
|
private
|
|
356
355
|
|
|
357
356
|
UNSAFE_CLASS_NAMES = [
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
]
|
|
357
|
+
'Google::Apis::CloudkmsV1::DecryptResponse',
|
|
358
|
+
'Google::Apis::SecretmanagerV1::SecretPayload',
|
|
359
|
+
'Google::Apis::SecretmanagerV1beta1::SecretPayload'
|
|
360
|
+
].freeze
|
|
361
|
+
|
|
362
|
+
# Matches the two URI template expressions Discovery documents use: simple ({var})
|
|
363
|
+
# and reserved ({+var}). Group 1 is '+' for reserved expansion, group 2 the name.
|
|
364
|
+
TEMPLATE_VAR_PATTERN = /\{(\+?)(\w+)\}/.freeze
|
|
362
365
|
|
|
363
366
|
module RedactingPPMethods
|
|
364
|
-
def pp_object
|
|
367
|
+
def pp_object(obj)
|
|
365
368
|
return super unless UNSAFE_CLASS_NAMES.include? obj.class.name
|
|
369
|
+
|
|
366
370
|
object_address_group obj do
|
|
367
|
-
text
|
|
371
|
+
text '(fields redacted)'
|
|
368
372
|
end
|
|
369
373
|
end
|
|
370
374
|
end
|
|
@@ -377,16 +381,16 @@ module Google
|
|
|
377
381
|
include RedactingPPMethods
|
|
378
382
|
end
|
|
379
383
|
|
|
380
|
-
def safe_pretty_representation
|
|
381
|
-
out = +
|
|
384
|
+
def safe_pretty_representation(obj)
|
|
385
|
+
out = +''
|
|
382
386
|
printer = RedactingPP.new out, 79
|
|
383
387
|
printer.guard_inspect_key { printer.pp obj }
|
|
384
388
|
printer.flush
|
|
385
389
|
out << "\n"
|
|
386
390
|
end
|
|
387
391
|
|
|
388
|
-
def safe_single_line_representation
|
|
389
|
-
out = +
|
|
392
|
+
def safe_single_line_representation(obj)
|
|
393
|
+
out = +''
|
|
390
394
|
printer = RedactingSingleLine.new out
|
|
391
395
|
printer.guard_inspect_key { printer.pp obj }
|
|
392
396
|
printer.flush
|
|
@@ -400,9 +404,9 @@ module Google
|
|
|
400
404
|
|
|
401
405
|
@opencensus_span = OpenCensus::Trace.start_span url.path.to_s
|
|
402
406
|
@opencensus_span.kind = OpenCensus::Trace::SpanBuilder::CLIENT
|
|
403
|
-
@opencensus_span.put_attribute
|
|
404
|
-
@opencensus_span.put_attribute
|
|
405
|
-
@opencensus_span.put_attribute
|
|
407
|
+
@opencensus_span.put_attribute 'http.host', url.host.to_s
|
|
408
|
+
@opencensus_span.put_attribute 'http.method', method.to_s.upcase
|
|
409
|
+
@opencensus_span.put_attribute 'http.path', url.path.to_s
|
|
406
410
|
sent_size =
|
|
407
411
|
if body.respond_to? :bytesize
|
|
408
412
|
body.bytesize
|
|
@@ -436,7 +440,7 @@ module Google
|
|
|
436
440
|
status = @http_res.status.to_i
|
|
437
441
|
if status > 0
|
|
438
442
|
@opencensus_span.set_status map_http_status status
|
|
439
|
-
@opencensus_span.put_attribute
|
|
443
|
+
@opencensus_span.put_attribute 'http.status_code', status
|
|
440
444
|
end
|
|
441
445
|
end
|
|
442
446
|
|
|
@@ -452,7 +456,7 @@ module Google
|
|
|
452
456
|
@form_encoded
|
|
453
457
|
end
|
|
454
458
|
|
|
455
|
-
def map_http_status
|
|
459
|
+
def map_http_status(http_status)
|
|
456
460
|
case http_status
|
|
457
461
|
when 200..399 then 0 # OK
|
|
458
462
|
when 400 then 3 # INVALID_ARGUMENT
|
|
@@ -468,9 +472,8 @@ module Google
|
|
|
468
472
|
end
|
|
469
473
|
|
|
470
474
|
def normalize_query_values(input)
|
|
471
|
-
input.
|
|
475
|
+
input.each_with_object({}) do |(k, v), h|
|
|
472
476
|
h[k] = normalize_query_value(v)
|
|
473
|
-
h
|
|
474
477
|
end
|
|
475
478
|
end
|
|
476
479
|
|
|
@@ -484,6 +487,96 @@ module Google
|
|
|
484
487
|
v.to_s
|
|
485
488
|
end
|
|
486
489
|
end
|
|
490
|
+
|
|
491
|
+
# Validates user-supplied path parameter values against the URL template specification
|
|
492
|
+
# to prevent directory traversal and parameter injection exploits.
|
|
493
|
+
#
|
|
494
|
+
# Validation rejects only dot segments. Other characters are percent-encoded instead.
|
|
495
|
+
#
|
|
496
|
+
# Validation Mechanism:
|
|
497
|
+
# 1. For simple variables ({var}, standard single-wildcard behavior):
|
|
498
|
+
# - Rejects if the value is exactly '.' or '..'.
|
|
499
|
+
# - Reserved characters such as '/', '?' and '#' are percent-encoded by Addressable.
|
|
500
|
+
# 2. For reserved variables ({+var}, double-wildcard behavior):
|
|
501
|
+
# - Splits the value by slash ('/') and rejects any segment that is exactly '.' or '..'.
|
|
502
|
+
# - Every character except '/' and unreserved characters is percent-encoded by
|
|
503
|
+
# #encode_reserved_parameters.
|
|
504
|
+
#
|
|
505
|
+
# @raise [Google::Apis::ClientError] If any validation check fails.
|
|
506
|
+
def validate_path_parameters!
|
|
507
|
+
template_pattern = url.pattern
|
|
508
|
+
|
|
509
|
+
variables = template_pattern.scan(TEMPLATE_VAR_PATTERN).map do |operator, var_name|
|
|
510
|
+
{ name: var_name, reserved: operator == '+' }
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
variables.each do |v|
|
|
514
|
+
var_name = v[:name]
|
|
515
|
+
var_key = params.key?(var_name) ? var_name : var_name.to_sym
|
|
516
|
+
next unless params.key?(var_key)
|
|
517
|
+
|
|
518
|
+
value = params[var_key].to_s
|
|
519
|
+
|
|
520
|
+
if v[:reserved]
|
|
521
|
+
value.split('/').each do |seg|
|
|
522
|
+
if ['.', '..'].include?(seg)
|
|
523
|
+
raise Google::Apis::ClientError,
|
|
524
|
+
"Value for #{var_name} must not contain segments that are exactly '#{seg}'."
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
elsif ['.', '..'].include?(value)
|
|
528
|
+
raise Google::Apis::ClientError,
|
|
529
|
+
"Invalid value for #{var_name} '#{value}'."
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
# Substitutes percent-encoded values for reserved ({+var}) variables in the template.
|
|
535
|
+
#
|
|
536
|
+
# Addressable leaves reserved characters such as '+', ':', '?' and '#' literal in a
|
|
537
|
+
# reserved expansion, so they would reach the server unencoded. Only '/' and unreserved
|
|
538
|
+
# characters should stay literal, so these values are encoded here and written into the
|
|
539
|
+
# template's literal text, which Addressable passes through untouched when it expands
|
|
540
|
+
# the rest.
|
|
541
|
+
#
|
|
542
|
+
# @param [Addressable::Template] template
|
|
543
|
+
# The URL template.
|
|
544
|
+
# @param [Boolean] normalize_unicode
|
|
545
|
+
# Whether to apply Unicode NFC normalization to the values.
|
|
546
|
+
# @return [Addressable::Template]
|
|
547
|
+
# A template with reserved variables replaced by their encoded values.
|
|
548
|
+
def encode_reserved_parameters(template, normalize_unicode)
|
|
549
|
+
pattern = template.pattern.dup
|
|
550
|
+
template.pattern.scan(TEMPLATE_VAR_PATTERN).each do |operator, var_name|
|
|
551
|
+
next unless operator == '+'
|
|
552
|
+
|
|
553
|
+
var_key = params.key?(var_name) ? var_name : var_name.to_sym
|
|
554
|
+
next unless params.key?(var_key)
|
|
555
|
+
|
|
556
|
+
# The encoded value contains no braces, so the new pattern parses cleanly and the
|
|
557
|
+
# value cannot introduce a template expression of its own.
|
|
558
|
+
pattern = pattern.gsub("{+#{var_name}}", encode_reserved_value(params[var_key], normalize_unicode))
|
|
559
|
+
end
|
|
560
|
+
Addressable::Template.new(pattern)
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
# Percent-encodes every character except '/' and unreserved characters.
|
|
564
|
+
#
|
|
565
|
+
# @param [Object] value
|
|
566
|
+
# The parameter value.
|
|
567
|
+
# @param [Boolean] normalize_unicode
|
|
568
|
+
# Whether to apply Unicode NFC normalization to the value.
|
|
569
|
+
# @return [String]
|
|
570
|
+
# The encoded value.
|
|
571
|
+
def encode_reserved_value(value, normalize_unicode)
|
|
572
|
+
value = value.to_s
|
|
573
|
+
# Addressable only normalizes values left in the mapping, so normalize here to match.
|
|
574
|
+
value = value.unicode_normalize(:nfc) if normalize_unicode
|
|
575
|
+
# Split on '/' and keep empty segments (-1), so slashes stay literal.
|
|
576
|
+
# Each segment is then fully encoded, including '%' itself (as '%25').
|
|
577
|
+
unreserved = Addressable::URI::CharacterClasses::UNRESERVED
|
|
578
|
+
value.split('/', -1).map { |segment| Addressable::URI.encode_component(segment, unreserved) }.join('/')
|
|
579
|
+
end
|
|
487
580
|
end
|
|
488
581
|
end
|
|
489
582
|
end
|
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: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Google LLC
|
|
@@ -167,7 +167,7 @@ licenses:
|
|
|
167
167
|
metadata:
|
|
168
168
|
bug_tracker_uri: https://github.com/googleapis/google-api-ruby-client/issues
|
|
169
169
|
changelog_uri: https://github.com/googleapis/google-api-ruby-client/tree/main/google-apis-core/CHANGELOG.md
|
|
170
|
-
documentation_uri: https://googleapis.dev/ruby/google-apis-core/v1.
|
|
170
|
+
documentation_uri: https://googleapis.dev/ruby/google-apis-core/v1.3.0
|
|
171
171
|
source_code_uri: https://github.com/googleapis/google-api-ruby-client/tree/main/google-apis-core
|
|
172
172
|
rdoc_options: []
|
|
173
173
|
require_paths:
|