diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/retry_errors.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/retry_errors.rb index 41ffee47b6b..a4755a9577e 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/retry_errors.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/retry_errors.rb @@ -118,7 +118,6 @@ def retry_request(context, error) delay_retry(context) context.retries += 1 context.config.credentials.refresh! if error.expired_credentials? - context.http_request.body.rewind context.http_response.reset call(context) end @@ -129,8 +128,7 @@ def delay_retry(context) def should_retry?(context, error) retryable?(context, error) and - context.retries < retry_limit(context) and - response_truncatable?(context) + context.retries < retry_limit(context) end def retryable?(context, error) @@ -149,10 +147,6 @@ def retry_limit(context) context.config.retry_limit end - def response_truncatable?(context) - context.http_response.body.respond_to?(:truncate) - end - end def add_handlers(handlers, config) diff --git a/gems/aws-sdk-core/lib/seahorse/client/http/response.rb b/gems/aws-sdk-core/lib/seahorse/client/http/response.rb index e39a68e1ffa..bad38553dfe 100644 --- a/gems/aws-sdk-core/lib/seahorse/client/http/response.rb +++ b/gems/aws-sdk-core/lib/seahorse/client/http/response.rb @@ -152,7 +152,6 @@ def on_error(&callback) def reset @status_code = 0 @headers.clear - @body.truncate(0) @error = nil end diff --git a/gems/aws-sdk-core/lib/seahorse/client/net_http/handler.rb b/gems/aws-sdk-core/lib/seahorse/client/net_http/handler.rb index 0208b3a84dd..8ce4026fc4d 100644 --- a/gems/aws-sdk-core/lib/seahorse/client/net_http/handler.rb +++ b/gems/aws-sdk-core/lib/seahorse/client/net_http/handler.rb @@ -44,7 +44,7 @@ class InvalidHttpVerbError < StandardError; end # @param [RequestContext] context # @return [Response] def call(context) - transmit(context.config, context.http_request, context.http_response) + transmit(context.config, context.http_request, context.http_response, context) Response.new(context: context) end @@ -69,7 +69,7 @@ def error_message(req, error) # @param [Http::Request] req # @param [Http::Response] resp # @return [void] - def transmit(config, req, resp) + def transmit(config, req, resp, context) session(config, req) do |http| http.request(build_net_request(req)) do |net_resp| @@ -77,10 +77,23 @@ def transmit(config, req, resp) headers = extract_headers(net_resp) bytes_received = 0 + context.bytes_written ||= 0 resp.signal_headers(status_code, headers) net_resp.read_body do |chunk| + if bytes_received < context.bytes_written + chunk_index = context.bytes_written - bytes_received + next_chunk = chunk.byteslice(chunk_index..-1) + else + next_chunk = chunk + end + + if next_chunk + resp.signal_data(next_chunk) + + context.bytes_written += next_chunk.bytesize + end + bytes_received += chunk.bytesize - resp.signal_data(chunk) end complete_response(req, resp, bytes_received) diff --git a/gems/aws-sdk-core/lib/seahorse/client/request_context.rb b/gems/aws-sdk-core/lib/seahorse/client/request_context.rb index 4298e3ff199..b73fff2bb80 100644 --- a/gems/aws-sdk-core/lib/seahorse/client/request_context.rb +++ b/gems/aws-sdk-core/lib/seahorse/client/request_context.rb @@ -47,6 +47,9 @@ def initialize(options = {}) # @return [Integer] attr_accessor :retries + # @return [Integer] + attr_accessor :bytes_written + # @return [Hash] attr_reader :metadata diff --git a/gems/aws-sdk-core/spec/aws/plugins/retry_errors_spec.rb b/gems/aws-sdk-core/spec/aws/plugins/retry_errors_spec.rb index 829b07c6c6a..b74ef2743d0 100644 --- a/gems/aws-sdk-core/spec/aws/plugins/retry_errors_spec.rb +++ b/gems/aws-sdk-core/spec/aws/plugins/retry_errors_spec.rb @@ -217,28 +217,6 @@ def handle(send_handler = nil, &block) expect(resp.context.retries).to eq(3) end - it 'rewinds the request body before each retry attempt' do - body = resp.context.http_request.body - expect(body).to receive(:rewind).exactly(3).times - resp.error = RetryErrorsSvc::Errors::RequestLimitExceeded.new(nil,nil) - handle { |context| resp } - end - - it 'truncates the response body before each retry attempt' do - body = double('truncatable-body', pos: 100, truncate: 0) - resp.context.http_response.body = body - expect(body).to receive(:truncate).with(0).exactly(3).times - resp.error = RetryErrorsSvc::Errors::RequestLimitExceeded.new(nil,nil) - handle { |context| resp } - end - - it 'skips retry if un-truncatable response body has received data' do - resp.context.http_response.body = double('write-once-body', pos: 100) - resp.error = RetryErrorsSvc::Errors::RequestLimitExceeded.new(nil,nil) - handle { |context| resp } - expect(resp.context.retries).to eq(0) - end - it 'retries if creds expire and are refreshable' do expect(credentials).to receive(:refresh!).exactly(3).times resp.error = RetryErrorsSvc::Errors::AuthFailure.new(nil,nil) diff --git a/gems/aws-sdk-core/spec/seahorse/client/net_http/handler_spec.rb b/gems/aws-sdk-core/spec/seahorse/client/net_http/handler_spec.rb index 8431ca50c8d..e0f6b5d4945 100644 --- a/gems/aws-sdk-core/spec/seahorse/client/net_http/handler_spec.rb +++ b/gems/aws-sdk-core/spec/seahorse/client/net_http/handler_spec.rb @@ -251,6 +251,22 @@ def endpoint expect(resp_body.read).to eq('response-body') end + it 'populates part of response body that has not been written yet' do + context.bytes_written = 9 + stub_request(:any, endpoint).to_return(body: 'response-body') + resp_body = make_request.context.http_response.body + resp_body.rewind + expect(resp_body.read).to eq('body') + end + + it 'does not populate part of response body that has already been written' do + context.bytes_written = 15 + stub_request(:any, endpoint).to_return(body: 'response-body') + resp_body = make_request.context.http_response.body + resp_body.rewind + expect(resp_body.read).to eq('') + end + it 'wraps errors with a NetworkingError' do stub_request(:any, endpoint).to_raise(EOFError) resp = make_request