aws-sdk-core 3.240.0 → 3.241.2
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 +15 -0
- data/VERSION +1 -1
- data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +101 -52
- data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +28 -16
- data/lib/aws-sdk-signin/client.rb +1 -1
- data/lib/aws-sdk-signin.rb +1 -1
- data/lib/aws-sdk-sso/client.rb +1 -1
- data/lib/aws-sdk-sso.rb +1 -1
- data/lib/aws-sdk-ssooidc/client.rb +1 -1
- data/lib/aws-sdk-ssooidc.rb +1 -1
- data/lib/aws-sdk-sts/client.rb +1 -1
- data/lib/aws-sdk-sts.rb +1 -1
- data/lib/seahorse/client/net_http/patches.rb +44 -11
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bb055425607f2a8b6ec90788d038eb14f05f611f705797d31acd04abaf429d0
|
|
4
|
+
data.tar.gz: defdafdbb1fad35d409e1562e0e2f8cad977901919655ba7fc31fa6f01a0178f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ef77628a938900170ccc335d06d6236ef0b01f438b1253e44c10002064f5bbff6aef8c223a828aec55cd2e85abcd4afcd5d99c54de1929e0d560ee7e2c0a4c7
|
|
7
|
+
data.tar.gz: 2dd72d4d3542b6798202763f461c1e4d0a39ce285ce03ce409dcbb5bd4168c1c5dddf56fac29f60f9416a3989dabc8595eab4889c11a1b60d377c0d3f7fa2684
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
Unreleased Changes
|
|
2
2
|
------------------
|
|
3
3
|
|
|
4
|
+
3.241.2 (2026-01-07)
|
|
5
|
+
------------------
|
|
6
|
+
|
|
7
|
+
* Issue - Preserve existing Content-Encoding when applying request trailer checksum.
|
|
8
|
+
|
|
9
|
+
3.241.1 (2026-01-06)
|
|
10
|
+
------------------
|
|
11
|
+
|
|
12
|
+
* Issue - Fix memory leak in ClockSkew retry plugin by normalizing endpoints to prevent unlimited hash growth.
|
|
13
|
+
|
|
14
|
+
3.241.0 (2026-01-05)
|
|
15
|
+
------------------
|
|
16
|
+
|
|
17
|
+
* Feature - Improved memory efficiency when calculating request checksums.
|
|
18
|
+
|
|
4
19
|
3.240.0 (2025-12-16)
|
|
5
20
|
------------------
|
|
6
21
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.241.2
|
|
@@ -4,7 +4,8 @@ module Aws
|
|
|
4
4
|
module Plugins
|
|
5
5
|
# @api private
|
|
6
6
|
class ChecksumAlgorithm < Seahorse::Client::Plugin
|
|
7
|
-
|
|
7
|
+
CHECKSUM_CHUNK_SIZE = 1 * 1024 * 1024 # one MB
|
|
8
|
+
DEFAULT_TRAILER_CHUNK_SIZE = 16_384 # 16 KB
|
|
8
9
|
|
|
9
10
|
# determine the set of supported client side checksum algorithms
|
|
10
11
|
# CRC32c requires aws-crt (optional sdk dependency) for support
|
|
@@ -21,6 +22,7 @@ module Aws
|
|
|
21
22
|
end.freeze
|
|
22
23
|
|
|
23
24
|
CRT_ALGORITHMS = %w[CRC32C CRC64NVME].freeze
|
|
25
|
+
DEFAULT_CHECKSUM = 'CRC32'
|
|
24
26
|
|
|
25
27
|
# Priority order of checksum algorithms to validate responses against.
|
|
26
28
|
# Remove any algorithms not supported by client (ie, depending on CRT availability).
|
|
@@ -37,8 +39,6 @@ module Aws
|
|
|
37
39
|
'SHA256' => 44 + 1
|
|
38
40
|
}.freeze
|
|
39
41
|
|
|
40
|
-
DEFAULT_CHECKSUM = 'CRC32'
|
|
41
|
-
|
|
42
42
|
option(:request_checksum_calculation,
|
|
43
43
|
doc_default: 'when_supported',
|
|
44
44
|
doc_type: 'String',
|
|
@@ -162,9 +162,7 @@ module Aws
|
|
|
162
162
|
context[:http_checksum] ||= {}
|
|
163
163
|
|
|
164
164
|
# Set validation mode to enabled when supported.
|
|
165
|
-
if context.config.response_checksum_validation == 'when_supported'
|
|
166
|
-
enable_request_validation_mode(context)
|
|
167
|
-
end
|
|
165
|
+
enable_request_validation_mode(context) if context.config.response_checksum_validation == 'when_supported'
|
|
168
166
|
|
|
169
167
|
@handler.call(context)
|
|
170
168
|
end
|
|
@@ -194,9 +192,7 @@ module Aws
|
|
|
194
192
|
calculate_request_checksum(context, request_algorithm)
|
|
195
193
|
end
|
|
196
194
|
|
|
197
|
-
if should_verify_response_checksum?(context)
|
|
198
|
-
add_verify_response_checksum_handlers(context)
|
|
199
|
-
end
|
|
195
|
+
add_verify_response_checksum_handlers(context) if should_verify_response_checksum?(context)
|
|
200
196
|
|
|
201
197
|
with_metrics(context.config, algorithm) { @handler.call(context) }
|
|
202
198
|
end
|
|
@@ -334,6 +330,13 @@ module Aws
|
|
|
334
330
|
if (algorithm_header = checksum_properties[:request_algorithm_header])
|
|
335
331
|
headers[algorithm_header] = checksum_properties[:algorithm]
|
|
336
332
|
end
|
|
333
|
+
|
|
334
|
+
# Trailer implementation within Mac/JRUBY environment is facing some
|
|
335
|
+
# network issues that will need further investigation:
|
|
336
|
+
# * https://github.com/jruby/jruby-openssl/issues/271
|
|
337
|
+
# * https://github.com/jruby/jruby-openssl/issues/317
|
|
338
|
+
return apply_request_checksum(context, headers, checksum_properties) if defined?(JRUBY_VERSION)
|
|
339
|
+
|
|
337
340
|
case checksum_properties[:in]
|
|
338
341
|
when 'header'
|
|
339
342
|
apply_request_checksum(context, headers, checksum_properties)
|
|
@@ -346,17 +349,18 @@ module Aws
|
|
|
346
349
|
|
|
347
350
|
def apply_request_checksum(context, headers, checksum_properties)
|
|
348
351
|
header_name = checksum_properties[:name]
|
|
349
|
-
body = context.http_request.body_contents
|
|
350
352
|
headers[header_name] = calculate_checksum(
|
|
351
353
|
checksum_properties[:algorithm],
|
|
352
|
-
body
|
|
354
|
+
context.http_request.body
|
|
353
355
|
)
|
|
354
356
|
end
|
|
355
357
|
|
|
356
358
|
def calculate_checksum(algorithm, body)
|
|
357
359
|
digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
|
|
358
360
|
if body.respond_to?(:read)
|
|
361
|
+
body.rewind
|
|
359
362
|
update_in_chunks(digest, body)
|
|
363
|
+
body.rewind
|
|
360
364
|
else
|
|
361
365
|
digest.update(body)
|
|
362
366
|
end
|
|
@@ -365,7 +369,7 @@ module Aws
|
|
|
365
369
|
|
|
366
370
|
def update_in_chunks(digest, io)
|
|
367
371
|
loop do
|
|
368
|
-
chunk = io.read(
|
|
372
|
+
chunk = io.read(CHECKSUM_CHUNK_SIZE)
|
|
369
373
|
break unless chunk
|
|
370
374
|
|
|
371
375
|
digest.update(chunk)
|
|
@@ -377,7 +381,12 @@ module Aws
|
|
|
377
381
|
location_name = checksum_properties[:name]
|
|
378
382
|
|
|
379
383
|
# set required headers
|
|
380
|
-
headers['Content-Encoding'] =
|
|
384
|
+
headers['Content-Encoding'] =
|
|
385
|
+
if headers['Content-Encoding']
|
|
386
|
+
headers['Content-Encoding'] += ', aws-chunked'
|
|
387
|
+
else
|
|
388
|
+
'aws-chunked'
|
|
389
|
+
end
|
|
381
390
|
headers['X-Amz-Content-Sha256'] = 'STREAMING-UNSIGNED-PAYLOAD-TRAILER'
|
|
382
391
|
headers['X-Amz-Trailer'] = location_name
|
|
383
392
|
|
|
@@ -388,13 +397,14 @@ module Aws
|
|
|
388
397
|
unless context.http_request.body.respond_to?(:size)
|
|
389
398
|
raise Aws::Errors::ChecksumError, 'Could not determine length of the body'
|
|
390
399
|
end
|
|
391
|
-
headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
|
|
392
400
|
|
|
393
|
-
context.http_request.body
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
401
|
+
headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
|
|
402
|
+
context.http_request.body =
|
|
403
|
+
AwsChunkedTrailerDigestIO.new(
|
|
404
|
+
io: context.http_request.body,
|
|
405
|
+
algorithm: checksum_properties[:algorithm],
|
|
406
|
+
location_name: location_name
|
|
407
|
+
)
|
|
398
408
|
end
|
|
399
409
|
|
|
400
410
|
def should_verify_response_checksum?(context)
|
|
@@ -417,10 +427,7 @@ module Aws
|
|
|
417
427
|
context[:http_checksum][:validation_list] = validation_list
|
|
418
428
|
|
|
419
429
|
context.http_response.on_headers do |_status, headers|
|
|
420
|
-
header_name, algorithm = response_header_to_verify(
|
|
421
|
-
headers,
|
|
422
|
-
validation_list
|
|
423
|
-
)
|
|
430
|
+
header_name, algorithm = response_header_to_verify(headers, validation_list)
|
|
424
431
|
next unless header_name
|
|
425
432
|
|
|
426
433
|
expected = headers[header_name]
|
|
@@ -466,52 +473,94 @@ module Aws
|
|
|
466
473
|
# Wrapper for request body that implements application-layer
|
|
467
474
|
# chunking with Digest computed on chunks + added as a trailer
|
|
468
475
|
class AwsChunkedTrailerDigestIO
|
|
469
|
-
|
|
476
|
+
CHUNK_OVERHEAD = 4 # "\r\n\r\n"
|
|
477
|
+
HEX_BASE = 16
|
|
470
478
|
|
|
471
|
-
def initialize(
|
|
472
|
-
@io = io
|
|
473
|
-
@location_name = location_name
|
|
474
|
-
@algorithm = algorithm
|
|
475
|
-
@digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
|
|
476
|
-
@
|
|
479
|
+
def initialize(options = {})
|
|
480
|
+
@io = options.delete(:io)
|
|
481
|
+
@location_name = options.delete(:location_name)
|
|
482
|
+
@algorithm = options.delete(:algorithm)
|
|
483
|
+
@digest = ChecksumAlgorithm.digest_for_algorithm(@algorithm)
|
|
484
|
+
@chunk_size = Thread.current[:net_http_override_body_stream_chunk] || DEFAULT_TRAILER_CHUNK_SIZE
|
|
485
|
+
@overhead_bytes = calculate_overhead(@chunk_size)
|
|
486
|
+
@base_chunk_size = @chunk_size - @overhead_bytes
|
|
487
|
+
@encoded_buffer = +''
|
|
488
|
+
@eof = false
|
|
477
489
|
end
|
|
478
490
|
|
|
479
491
|
# the size of the application layer aws-chunked + trailer body
|
|
480
492
|
def size
|
|
481
|
-
# compute the number of chunks
|
|
482
|
-
# a full chunk has 4 + 4 bytes overhead, a partial chunk is len.to_s(16).size + 4
|
|
483
493
|
orig_body_size = @io.size
|
|
484
|
-
n_full_chunks = orig_body_size /
|
|
485
|
-
partial_bytes = orig_body_size %
|
|
486
|
-
|
|
487
|
-
|
|
494
|
+
n_full_chunks = orig_body_size / @base_chunk_size
|
|
495
|
+
partial_bytes = orig_body_size % @base_chunk_size
|
|
496
|
+
|
|
497
|
+
full_chunk_overhead = @base_chunk_size.to_s(HEX_BASE).size + CHUNK_OVERHEAD
|
|
498
|
+
chunked_body_size = n_full_chunks * (@base_chunk_size + full_chunk_overhead)
|
|
499
|
+
unless partial_bytes.zero?
|
|
500
|
+
chunked_body_size += partial_bytes.to_s(HEX_BASE).size + partial_bytes + CHUNK_OVERHEAD
|
|
501
|
+
end
|
|
488
502
|
trailer_size = ChecksumAlgorithm.trailer_length(@algorithm, @location_name)
|
|
489
503
|
chunked_body_size + trailer_size
|
|
490
504
|
end
|
|
491
505
|
|
|
492
506
|
def rewind
|
|
493
507
|
@io.rewind
|
|
508
|
+
@encoded_buffer = +''
|
|
509
|
+
@eof = false
|
|
510
|
+
@digest = ChecksumAlgorithm.digest_for_algorithm(@algorithm)
|
|
494
511
|
end
|
|
495
512
|
|
|
496
|
-
def read(length, buf = nil)
|
|
497
|
-
|
|
498
|
-
if
|
|
499
|
-
|
|
500
|
-
|
|
513
|
+
def read(length = nil, buf = nil)
|
|
514
|
+
return '' if length&.zero?
|
|
515
|
+
return if eof?
|
|
516
|
+
|
|
517
|
+
buf&.clear
|
|
518
|
+
output_buffer = buf || +''
|
|
501
519
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
return StringIO.new(application_chunked).read(application_chunked.size, buf)
|
|
520
|
+
fill_encoded_buffer(length)
|
|
521
|
+
|
|
522
|
+
if length
|
|
523
|
+
output_buffer << @encoded_buffer.slice!(0, length)
|
|
507
524
|
else
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
525
|
+
output_buffer << @encoded_buffer
|
|
526
|
+
@encoded_buffer.clear
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
output_buffer.empty? && eof? ? nil : output_buffer
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def eof?
|
|
533
|
+
@eof && @encoded_buffer.empty?
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
private
|
|
537
|
+
|
|
538
|
+
def calculate_overhead(chunk_size)
|
|
539
|
+
chunk_size.to_s(HEX_BASE).size + CHUNK_OVERHEAD
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
def fill_encoded_buffer(required_length)
|
|
543
|
+
return if required_length && @encoded_buffer.bytesize >= required_length
|
|
544
|
+
|
|
545
|
+
while !@eof && fill_data?(required_length)
|
|
546
|
+
chunk = @io.read(@base_chunk_size)
|
|
547
|
+
if chunk && !chunk.empty?
|
|
548
|
+
@digest.update(chunk)
|
|
549
|
+
@encoded_buffer << "#{chunk.bytesize.to_s(HEX_BASE)}\r\n#{chunk}\r\n"
|
|
550
|
+
else
|
|
551
|
+
@encoded_buffer << "0\r\n#{trailer_string}\r\n\r\n"
|
|
552
|
+
@eof = true
|
|
553
|
+
end
|
|
513
554
|
end
|
|
514
|
-
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
def trailer_string
|
|
558
|
+
{ @location_name => @digest.base64digest }.map { |k, v| "#{k}:#{v}" }.join("\r\n")
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
# Returns true if more data needs to be read into the buffer
|
|
562
|
+
def fill_data?(length)
|
|
563
|
+
length.nil? || @encoded_buffer.bytesize < length
|
|
515
564
|
end
|
|
516
565
|
end
|
|
517
566
|
end
|
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
module Aws
|
|
4
4
|
module Plugins
|
|
5
5
|
module Retries
|
|
6
|
-
|
|
7
6
|
# @api private
|
|
8
7
|
class ClockSkew
|
|
9
|
-
|
|
10
8
|
CLOCK_SKEW_THRESHOLD = 5 * 60 # five minutes
|
|
11
9
|
|
|
12
10
|
def initialize
|
|
@@ -22,9 +20,9 @@ module Aws
|
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
# Gets the clock_correction in seconds to apply to a given endpoint
|
|
25
|
-
# @param endpoint [URI
|
|
23
|
+
# @param endpoint [URI, String]
|
|
26
24
|
def clock_correction(endpoint)
|
|
27
|
-
@mutex.synchronize { @endpoint_clock_corrections[endpoint
|
|
25
|
+
@mutex.synchronize { @endpoint_clock_corrections[normalized_endpoint(endpoint)] }
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
# The estimated skew factors in any clock skew from
|
|
@@ -35,7 +33,7 @@ module Aws
|
|
|
35
33
|
# Estimated Skew should not be used to correct clock skew errors
|
|
36
34
|
# it should only be used to estimate TTL for a request
|
|
37
35
|
def estimated_skew(endpoint)
|
|
38
|
-
@mutex.synchronize { @endpoint_estimated_skews[endpoint
|
|
36
|
+
@mutex.synchronize { @endpoint_estimated_skews[normalized_endpoint(endpoint)] }
|
|
39
37
|
end
|
|
40
38
|
|
|
41
39
|
# Determines whether a request has clock skew by comparing
|
|
@@ -55,9 +53,9 @@ module Aws
|
|
|
55
53
|
endpoint = context.http_request.endpoint
|
|
56
54
|
now_utc = Time.now.utc
|
|
57
55
|
server_time = server_time(context.http_response)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
return unless server_time && (now_utc - server_time).abs > CLOCK_SKEW_THRESHOLD
|
|
57
|
+
|
|
58
|
+
set_clock_correction(normalized_endpoint(endpoint), server_time - now_utc)
|
|
61
59
|
end
|
|
62
60
|
|
|
63
61
|
# Called for every request
|
|
@@ -69,20 +67,35 @@ module Aws
|
|
|
69
67
|
now_utc = Time.now.utc
|
|
70
68
|
server_time = server_time(context.http_response)
|
|
71
69
|
return unless server_time
|
|
70
|
+
|
|
72
71
|
@mutex.synchronize do
|
|
73
|
-
@endpoint_estimated_skews[endpoint
|
|
72
|
+
@endpoint_estimated_skews[normalized_endpoint(endpoint)] = server_time - now_utc
|
|
74
73
|
end
|
|
75
74
|
end
|
|
76
75
|
|
|
77
76
|
private
|
|
78
77
|
|
|
78
|
+
##
|
|
79
|
+
# @param endpoint [URI, String]
|
|
80
|
+
# the endpoint to normalize
|
|
81
|
+
#
|
|
82
|
+
# @return [String]
|
|
83
|
+
# the endpoint's schema, host, and port - without any path or query arguments
|
|
84
|
+
def normalized_endpoint(endpoint)
|
|
85
|
+
uri = endpoint.is_a?(URI::Generic) ? endpoint : URI(endpoint.to_s)
|
|
86
|
+
|
|
87
|
+
return endpoint.to_s unless uri.scheme && uri.host
|
|
88
|
+
|
|
89
|
+
"#{uri.scheme}://#{uri.host}:#{uri.port}"
|
|
90
|
+
rescue URI::InvalidURIError
|
|
91
|
+
endpoint.to_s
|
|
92
|
+
end
|
|
93
|
+
|
|
79
94
|
# @param response [Seahorse::Client::Http::Response:]
|
|
80
95
|
def server_time(response)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
nil
|
|
85
|
-
end
|
|
96
|
+
Time.parse(response.headers['date']).utc
|
|
97
|
+
rescue StandardError
|
|
98
|
+
nil
|
|
86
99
|
end
|
|
87
100
|
|
|
88
101
|
# Sets the clock correction for an endpoint
|
|
@@ -90,11 +103,10 @@ module Aws
|
|
|
90
103
|
# @param correction [Number]
|
|
91
104
|
def set_clock_correction(endpoint, correction)
|
|
92
105
|
@mutex.synchronize do
|
|
93
|
-
@endpoint_clock_corrections[endpoint
|
|
106
|
+
@endpoint_clock_corrections[normalized_endpoint(endpoint)] = correction
|
|
94
107
|
end
|
|
95
108
|
end
|
|
96
109
|
end
|
|
97
110
|
end
|
|
98
111
|
end
|
|
99
112
|
end
|
|
100
|
-
|
data/lib/aws-sdk-signin.rb
CHANGED
data/lib/aws-sdk-sso/client.rb
CHANGED
data/lib/aws-sdk-sso.rb
CHANGED
data/lib/aws-sdk-ssooidc.rb
CHANGED
data/lib/aws-sdk-sts/client.rb
CHANGED
data/lib/aws-sdk-sts.rb
CHANGED
|
@@ -6,28 +6,61 @@ module Seahorse
|
|
|
6
6
|
module Client
|
|
7
7
|
# @api private
|
|
8
8
|
module NetHttp
|
|
9
|
-
|
|
10
9
|
# @api private
|
|
11
10
|
module Patches
|
|
12
|
-
|
|
13
11
|
def self.apply!
|
|
14
|
-
Net::HTTPGenericRequest.prepend(
|
|
12
|
+
Net::HTTPGenericRequest.prepend(RequestPatches)
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
# Patches intended to override Net::HTTP functionality
|
|
16
|
+
module RequestPatches
|
|
17
|
+
# For requests with bodies, Net::HTTP sets a default content type of:
|
|
18
|
+
# 'application/x-www-form-urlencoded'
|
|
19
|
+
# There are cases where we should not send content type at all.
|
|
20
|
+
# Even when no body is supplied, Net::HTTP uses a default empty body
|
|
21
|
+
# and sets it anyway. This patch disables the behavior when a Thread
|
|
22
|
+
# local variable is set.
|
|
23
|
+
# See: https://github.com/ruby/net-http/issues/205
|
|
24
24
|
def supply_default_content_type
|
|
25
25
|
return if Thread.current[:net_http_skip_default_content_type]
|
|
26
26
|
|
|
27
27
|
super
|
|
28
28
|
end
|
|
29
|
-
end
|
|
30
29
|
|
|
30
|
+
# IO.copy_stream is capped at 16KB buffer so this patch intends to
|
|
31
|
+
# increase its chunk size for better performance.
|
|
32
|
+
# Only intended to use for S3 TM implementation.
|
|
33
|
+
# See: https://github.com/ruby/net-http/blob/master/lib/net/http/generic_request.rb#L292
|
|
34
|
+
def send_request_with_body_stream(sock, ver, path, f)
|
|
35
|
+
return super unless (chunk_size = Thread.current[:net_http_override_body_stream_chunk])
|
|
36
|
+
|
|
37
|
+
unless content_length || chunked?
|
|
38
|
+
raise ArgumentError, 'Content-Length not given and Transfer-Encoding is not `chunked`'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
supply_default_content_type
|
|
42
|
+
write_header(sock, ver, path)
|
|
43
|
+
wait_for_continue sock, ver if sock.continue_timeout
|
|
44
|
+
if chunked?
|
|
45
|
+
chunker = Chunker.new(sock)
|
|
46
|
+
RequestIO.custom_stream(f, chunker, chunk_size)
|
|
47
|
+
chunker.finish
|
|
48
|
+
else
|
|
49
|
+
RequestIO.custom_stream(f, sock, chunk_size)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class RequestIO
|
|
54
|
+
def self.custom_stream(src, dst, chunk_size)
|
|
55
|
+
copied = 0
|
|
56
|
+
while (chunk = src.read(chunk_size))
|
|
57
|
+
dst.write(chunk)
|
|
58
|
+
copied += chunk.bytesize
|
|
59
|
+
end
|
|
60
|
+
copied
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
31
64
|
end
|
|
32
65
|
end
|
|
33
66
|
end
|