class Aws::Plugins::S3RequestSigner::BucketRegionErrorHandler

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

def call(context)

def call(context)
  response = @handler.call(context)
  handle_region_errors(response)
end

def get_region_and_retry(context)

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)
  update_region_header(context, actual_region)
  @handler.call(context)
end

def handle_region_errors(response)

def handle_region_errors(response)
  if wrong_sigv4_region?(response)
    get_region_and_retry(response.context)
  else
    response
  end
end

def log_warning(context, actual_region)

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

def region_from_body(body)

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

def update_bucket_cache(context, actual_region)

def update_bucket_cache(context, actual_region)
  S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
end

def update_region_header(context, region)

def update_region_header(context, region)
  context.http_response.body.truncate(0)
  context.http_request.headers.delete('authorization')
  context.http_request.headers.delete('x-amz-security-token')
  context.http_request.endpoint.host = new_hostname(context, region)
  signer = Signers::V4.new(context.config.credentials, 's3', region)
  signer.sign(context.http_request)
end

def wrong_sigv4_region?(resp)

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