class Aws::S3::Plugins::S3Signer::BucketRegionErrorHandler

This handler detects when a request fails because of a mismatched bucket region. It follows up by making a request to determine the correct region, then finally a version 4 signed request against the correct regional endpoint.

Public Instance Methods

call(context) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 129
def call(context)
  response = @handler.call(context)
  handle_region_errors(response)
end

Private Instance Methods

custom_endpoint?(resp) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 163
def custom_endpoint?(resp)
  resolved_suffix = Aws::Partitions::EndpointProvider.dns_suffix_for(
    resp.context.config.region
  )
  !resp.context.http_request.endpoint.hostname.include?(resolved_suffix)
end
fips_region?(resp) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 159
def fips_region?(resp)
  resp.context.http_request.endpoint.host.include?('fips')
end
get_region_and_retry(context) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 146
def get_region_and_retry(context)
  actual_region = context.http_response.headers['x-amz-bucket-region']
  actual_region ||= region_from_body(context.http_response.body_contents)
  update_bucket_cache(context, actual_region)
  log_warning(context, actual_region)
  resign_with_new_region(context, actual_region)
  @handler.call(context)
end
handle_region_errors(response) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 136
def handle_region_errors(response)
  if wrong_sigv4_region?(response) &&
     !fips_region?(response) &&
     !custom_endpoint?(response)
    get_region_and_retry(response.context)
  else
    response
  end
end
log_warning(context, actual_region) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 205
def log_warning(context, actual_region)
  msg = "S3 client configured for #{context.config.region.inspect} " \
        "but the bucket #{context.params[:bucket].inspect} is in " \
        "#{actual_region.inspect}; Please configure the proper region " \
        "to avoid multiple unnecessary redirects and signing attempts\n"
  if (logger = context.config.logger)
    logger.warn(msg)
  else
    warn(msg)
  end
end
region_from_body(body) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 196
def region_from_body(body)
  region = body.match(/<Region>(.+?)<\/Region>/)[1]
  if region.nil? || region == ''
    raise "couldn't get region from body: #{body}"
  else
    region
  end
end
resign_with_new_region(context, actual_region) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 176
def resign_with_new_region(context, actual_region)
  context.http_response.body.truncate(0)
  context.http_request.endpoint.host = S3Signer.new_hostname(
    context, actual_region
  )
  context.metadata[:redirect_region] = actual_region
  # if it's an ARN, use the service in the ARN
  if (arn = context.metadata[:s3_arn])
    service = arn[:arn].service
  end
  Aws::Plugins::SignatureV4.apply_signature(
    context: context,
    signer: S3Signer.build_v4_signer(
      service: service || 's3',
      region: actual_region,
      credentials: context.config.credentials
    )
  )
end
update_bucket_cache(context, actual_region) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 155
def update_bucket_cache(context, actual_region)
  S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
end
wrong_sigv4_region?(resp) click to toggle source
# File lib/aws-sdk-s3/plugins/s3_signer.rb, line 170
def wrong_sigv4_region?(resp)
  resp.context.http_response.status_code == 400 &&
    (resp.context.http_response.headers['x-amz-bucket-region'] ||
     resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/))
end