1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00
fog--fog/lib/fog/atmos/storage.rb
Paul Thornthwaite 7ee3535d99 [core] Replace Fog::Connection with stable version
Fog::Connection mixed in XML parsing via the `parser` argument which
wasn't much use for the majority of APIs using JSON.

This adds the deprecation warning and attempts to update providers to
the correct version of Connection that they need.

Either the cleaner `Fog::Core::Connection` or if reliant on the XML
parsing still `Fog::XML::SAXParserConnection`

The SAX parser will be moving to `fog/xml` fairly soon.
2014-02-25 21:42:34 +00:00

186 lines
5.4 KiB
Ruby

require 'fog/atmos/core'
module Fog
module Storage
class Atmos < Fog::Service
requires :atmos_storage_endpoint,
:atmos_storage_secret,
:atmos_storage_token
recognizes :persistent
model_path 'fog/atmos/models/storage'
model :directory
collection :directories
model :file
collection :files
request_path 'fog/atmos/requests/storage'
# request :delete_container
request :get_namespace
request :head_namespace
request :post_namespace
request :put_namespace
request :delete_namespace
module Utils
ENDPOINT_REGEX = /(https*):\/\/([a-zA-Z0-9\.\-]+)(:[0-9]+)?(\/.*)?/
def ssl?
protocol = @endpoint.match(ENDPOINT_REGEX)[1]
raise ArgumentError, 'Invalid endpoint URL' if protocol.nil?
return true if protocol == 'https'
return false if protocol == 'http'
raise ArgumentError, "Unknown protocol #{protocol}"
end
def port
port = @endpoint.match(ENDPOINT_REGEX)[3]
return ssl? ? 443 : 80 if port.nil?
port.split(':')[1].to_i
end
def host
@endpoint.match(ENDPOINT_REGEX)[2]
end
def api_path
@endpoint.match(ENDPOINT_REGEX)[4]
end
def setup_credentials(options)
@storage_token = options[:atmos_storage_token]
@storage_secret = options[:atmos_storage_secret]
@storage_secret_decoded = Base64.decode64(@storage_secret)
@endpoint = options[:atmos_storage_endpoint]
@prefix = self.ssl? ? 'https' : 'http'
@storage_host = self.host
@storage_port = self.port
@api_path = self.api_path
end
end
class Mock
include Utils
def initialize(options={})
setup_credentials(options)
end
def request(options)
raise "Atmos Storage mocks not implemented"
end
end
class Real
include Utils
def initialize(options={})
setup_credentials(options)
@connection_options = options[:connection_options] || {}
@hmac = Fog::HMAC.new('sha1', @storage_secret_decoded)
@persistent = options.fetch(:persistent, false)
@connection = Fog::Core::Connection.new("#{@prefix}://#{@storage_host}:#{@storage_port}",
@persistent, @connection_options)
end
def uid
@storage_token#.split('/')[-1]
end
def sign(string)
value = @hmac.sign(string)
Base64.encode64( value ).chomp()
end
def reload
@connection.reset
end
def request(params, &block)
req_path = params[:path]
# Force set host and port
params.merge!({
:host => @storage_host,
:path => "#{@api_path}/rest/#{params[:path]}",
})
# Set default method and headers
params = {:method => 'GET', :headers => {}}.merge params
params[:headers]["Content-Type"] ||= "application/octet-stream"
# Add request date
params[:headers]["date"] = Time.now().httpdate()
params[:headers]["x-emc-uid"] = @storage_token
# Build signature string
signstring = ""
signstring += params[:method]
signstring += "\n"
signstring += params[:headers]["Content-Type"]
signstring += "\n"
if( params[:headers]["range"] )
signstring += params[:headers]["range"]
end
signstring += "\n"
signstring += params[:headers]["date"]
signstring += "\n"
signstring += "/rest/" + URI.unescape( req_path ).downcase
query_str = params[:query].map{|k,v| "#{k}=#{v}"}.join('&')
signstring += '?' + query_str unless query_str.empty?
signstring += "\n"
customheaders = {}
params[:headers].each { |key,value|
case key
when 'x-emc-date', 'x-emc-signature'
#skip
when /^x-emc-/
customheaders[ key.downcase ] = value
end
}
header_arr = customheaders.sort()
header_arr.each { |key,value|
# Values are lowercase and whitespace-normalized
signstring += key + ":" + value.strip.chomp.squeeze( " " ) + "\n"
}
digest = @hmac.sign(signstring.chomp())
signature = Base64.encode64( digest ).chomp()
params[:headers]["x-emc-signature"] = signature
params.delete(:host) #invalid excon request parameter
parse = params.delete(:parse)
begin
response = @connection.request(params, &block)
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::Storage::Atmos::NotFound.slurp(error)
else
error
end
end
unless response.body.empty?
if parse
document = Fog::ToHashDocument.new
parser = Nokogiri::XML::SAX::PushParser.new(document)
parser << response.body
parser.finish
response.body = document.body
end
end
response
end
end
end
end
end