mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00

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.
186 lines
5.4 KiB
Ruby
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
|