class Canistor::Handler

AWS-SDK compatible handler to mock S3 interaction.

Public Instance Methods

call(context) click to toggle source

@param [RequestContext] context @return [Response]

# File lib/canistor/handler.rb, line 17
def call(context)
  log(context.config, context.http_request)
  handle(
    context,
    Canistor::Authorization.new(context.http_request.headers['Authorization']),
    Canistor::Subject.new(context.http_request.endpoint)
  )
  Seahorse::Client::Response.new(context: context)
end

Private Instance Methods

handle(context, authorization, subject) click to toggle source

Mocks interaction with S3 using the library request context, authorization from headers, and subject based on the request URI.

When a bucket can be found the request will be forwarded to the Canistor::Store::Bucket object for futher handling.

Stubbed error reponses and error conditions are handled by rendering the correct responses or raising an exception.

# File lib/canistor/handler.rb, line 37
def handle(context, authorization, subject)
  Canistor.take_fail(:fatal) do
    return Canistor::ErrorHandler.trigger_fatal_error(context)
  end
  Canistor.take_fail(:bad_request) do
    return Canistor::ErrorHandler.serve_bad_request(context)
  end
  Canistor.take_fail(:reset_connection) do
    return Canistor::ErrorHandler.trigger_reset_connection(context)
  end
  Canistor.take_fail(:internal_server_error) do
    return Canistor::ErrorHandler.serve_internal_error(context)
  end
  if credentials = Canistor.find_credentials(authorization)
    if authorization.valid_signature?(context.http_request, credentials)
      if bucket = Canistor.find_bucket(subject.region, subject.bucket)
        # The AWS client has an optimization where it waits for a 100
        # Continue status code before sending the request body.
        if context.http_request.headers['expect'] == '100-continue'
          Canistor::ErrorHandler.serve_continue(context)
        end
        method = context.http_request.http_method.to_s.downcase
        bucket.send(
          method,
          context,
          authorization.access_key_id,
          subject
        )
      else
        Canistor::ErrorHandler.serve_no_such_bucket(context, subject)
      end
    else
      Canistor::ErrorHandler.serve_signature_does_not_match(
        context,
        authorization
      )
    end
  else
    Canistor::ErrorHandler.serve_invalid_access_key(context, authorization)
  end
ensure
  context.http_response.signal_done
end
log(config, request) click to toggle source
# File lib/canistor/handler.rb, line 81
def log(config, request)
  headers = request.headers.to_hash.slice('content-length', 'content-type')
  params = CGI::parse(request.endpoint.query.to_s)
  Canistor.logger.debug(
    '[Canistor::S3] ' + config.region + ' ' + request.http_method + ' ' +
    request.endpoint.path.to_s +
    (headers.empty? ? '' : ' ' + headers.inspect) +
    (params.empty? ? '' : ' ' + params.inspect)
  ) if Canistor.logger
end