azure-core-0.1.2/0000755000175000017500000000000012730534277013026 5ustar debiandebianazure-core-0.1.2/.gitignore0000755000175000017500000000045012730534277015020 0ustar debiandebian.rvmrc *.gem *.rbc *.swp *.tmproj *~ .\#* tags /pkg /doc Gemfile.lock nbproject/* *.gem .idea .project .bundle .config .yardoc _yardoc coverage doc/ lib/bundler/man pkg rdoc .DS_Store .ruby-version .env *.pem !service_management/azure/test/fixtures/management_certificate.pem *.publishsettings azure-core-0.1.2/Gemfile0000755000175000017500000000143512730534277014327 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- source 'https://rubygems.org' gemspecazure-core-0.1.2/Rakefile0000755000175000017500000000262212730534277014500 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'rake/testtask' require 'rubygems/package_task' gem_spec = eval(File.read('./azure-core.gemspec')) Gem::PackageTask.new(gem_spec) do |pkg| pkg.need_zip = false pkg.need_tar = false end namespace :test do Rake::TestTask.new :unit do |t| t.pattern = 'test/unit/**/*_test.rb' t.verbose = true t.libs = %w(lib test) end namespace :unit do def component_task(component) Rake::TestTask.new component do |t| t.pattern = "test/unit/#{component}/**/*_test.rb" t.verbose = true t.libs = %w(lib test) end end component_task :core end end task :test => %w(test:unit) task :default => :test azure-core-0.1.2/azure-core.gemspec0000755000175000017500000000400212730534277016446 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'date' require File.expand_path('../lib/azure/core/version', __FILE__) Gem::Specification.new do |s| s.name = 'azure-core' s.version = Azure::Core::Version s.authors = ['Microsoft Corporation', 'AppFog'] s.email = 'azureruby@microsoft.com' s.description = 'Microsoft Azure Client Core Library for Ruby SDK' s.summary = 'Core library to be consumed by Ruby SDK gems' s.homepage = 'http://github.com/Azure/azure-ruby-asm-core' s.license = 'Apache License, Version 2.0' s.files = `git ls-files`.split("\n").reject { |f| f.start_with?("test/unit") } s.required_ruby_version = '>= 1.9.3' s.add_runtime_dependency('faraday', '~> 0.9') s.add_runtime_dependency('faraday_middleware', '~> 0.10') s.add_runtime_dependency('nokogiri', '~> 1.6') s.add_development_dependency('dotenv', '~> 2.0') s.add_development_dependency('minitest', '~> 5') s.add_development_dependency('minitest-reporters', '~> 1') s.add_development_dependency('mocha', '~> 1.0') s.add_development_dependency('rake', '~> 10.0') s.add_development_dependency('timecop', '~> 0.7') s.add_development_dependency('bundler', '~> 1.11') end azure-core-0.1.2/test/0000755000175000017500000000000012730534277014005 5ustar debiandebianazure-core-0.1.2/test/test_helper.rb0000755000175000017500000000203012730534277016646 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'dotenv' Dotenv.load require 'minitest/autorun' require 'mocha/mini_test' require 'minitest/reporters' # Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new require 'timecop' require 'logger' require 'stringio' Dir['./test/support/**/*.rb'].each { |dep| require dep }azure-core-0.1.2/test/fixtures/0000755000175000017500000000000012730534277015656 5ustar debiandebianazure-core-0.1.2/test/fixtures/http_error.xml0000755000175000017500000000037412730534277020577 0ustar debiandebian TableAlreadyExists The table specified already exists. azure-core-0.1.2/test/support/0000755000175000017500000000000012730534277015521 5ustar debiandebianazure-core-0.1.2/test/support/fixtures.rb0000755000175000017500000000304212730534277017721 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/http/retry_policy" require "pathname" module Azure module Core Fixtures = Hash.new do |hash, fixture| if path = Fixtures.xml?(fixture) hash[fixture] = path.read elsif path = Fixtures.file?(fixture) hash[fixture] = path end end def Fixtures.root Pathname("../../fixtures").expand_path(__FILE__) end def Fixtures.file?(fixture) path = root.join(fixture) path.file? && path end def Fixtures.xml?(fixture) file?("#{fixture}.xml") end class FixtureRetryPolicy < Azure::Core::Http::RetryPolicy def initialize super &:should_retry? end def should_retry?(response, retry_data) retry_data[:error].inspect.include?('Error: Retry') end end end end azure-core-0.1.2/lib/0000755000175000017500000000000012730534277013574 5ustar debiandebianazure-core-0.1.2/lib/azure/0000755000175000017500000000000012730534277014722 5ustar debiandebianazure-core-0.1.2/lib/azure/core.rb0000755000175000017500000000253012730534277016202 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'rubygems' require 'nokogiri' require 'faraday' require 'faraday_middleware' module Azure module Core autoload :Utility, 'azure/core/utility' autoload :Logger, 'azure/core/utility' autoload :Error, 'azure/core/error' autoload :Service, 'azure/core/service' autoload :FilteredService, 'azure/core/filtered_service' autoload :SignedService, 'azure/core/signed_service' autoload :Default, 'azure/core/default' end end azure-core-0.1.2/lib/azure/http_response_helper.rb0000644000175000017500000000325112730534277021504 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module HttpResponseHelper # Sends request to HTTP server and returns a Faraday::Response # @param method [Symbol] The HTTP method to use (:get, :post, :put, :del, etc...) # @param url [URI] The URI of the HTTP endpoint to query # @param conn [Net::HTTP] http agent for a given uri # @param headers [String] The request headers # @param body [String] The request body #returns Faraday::Response def set_up_response(method, url, conn, headers ,body) conn.run_request(method, url, nil, nil) do |req| req.body = body if body req.headers = headers if headers unless headers.nil? keep_alive = headers['Keep-Alive'] || headers['keep-alive'] req.options[:timeout] = keep_alive.split('=').last.to_i unless keep_alive.nil? end req.options[:open_timeout] ||= 60 end end end endazure-core-0.1.2/lib/azure/core/0000755000175000017500000000000012730534277015652 5ustar debiandebianazure-core-0.1.2/lib/azure/core/utility.rb0000755000175000017500000001331712730534277017712 0ustar debiandebian#------------------------------------------------------------------------- # Copyright 2013 Microsoft Open Technologies, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'ipaddr' if RUBY_VERSION.to_f < 2.0 begin require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32|mingw32/ rescue LoadError puts 'WARNING: Output will look weird on Windows unless'\ ' you install the "win32console" gem.' end end module Azure module Error # Azure Error class Error < Azure::Core::Error attr_reader :description attr_reader :status_code attr_reader :type def initialize(type, status, description) @type = type @status_code = status @description = description super("#{type} (#{status_code}): #{description}") end end end module Core module Utility def random_string(str = 'azure', no_of_char = 5) str + (0...no_of_char).map { ('a'..'z').to_a[rand(26)] }.join end def xml_content(xml, key, default = '') content = default node = xml.at_css(key) content = node.text if node content end def locate_file(name) if File.exist? name name elsif File.exist?(File.join(ENV['HOME'], name)) File.join(ENV['HOME'], name) else Azure::Loggerx.error_with_exit "Unable to find #{name} file " end end def export_der(cert, key, pass = nil, name = nil) pkcs12 = OpenSSL::PKCS12.create(pass, name, key, cert) Base64.encode64(pkcs12.to_der) rescue Exception => e puts e.message abort end def export_fingerprint(certificate) Digest::SHA1.hexdigest(certificate.to_der) end def enable_winrm?(winrm_transport) (!winrm_transport.nil? && (winrm_transport.select { |x| x.downcase == 'http' || x.downcase == 'https' }.size > 0)) end def get_certificate(private_key_file) rsa = OpenSSL::PKey.read File.read(private_key_file) cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = 0 name = OpenSSL::X509::Name.new([['CN', 'Azure Management Certificate']]) cert.subject = cert.issuer = name cert.not_before = Time.now cert.not_after = cert.not_before + (60*60*24*365) cert.public_key = rsa.public_key cert.sign(rsa, OpenSSL::Digest::SHA1.new) cert end def initialize_external_logger(logger) Loggerx.initialize_external_logger(logger) end end # Logger module Logger class << self attr_accessor :logger def info(msg) if logger.nil? puts msg.bold.white else logger.info(msg) end end def error_with_exit(msg) if logger.nil? puts msg.bold.red else logger.error(msg) end raise msg.bold.red end def warn(msg) if logger.nil? puts msg.yellow else logger.warn(msg) end msg end def error(msg) if logger.nil? puts msg.bold.red else logger.error(msg) end msg end def exception_message(msg) if logger.nil? puts msg.bold.red else logger.warn(msg) end raise msg.bold.red end def success(msg) msg_with_new_line = msg + "\n" if logger.nil? print msg_with_new_line.green else logger.info(msg) end end def initialize_external_logger(logger) @logger = logger end end end end end class String { reset: 0, bold: 1, dark: 2, underline: 4, blink: 5, orange: 6, negative: 7, black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37, }.each do |key, value| define_method key do "\e[#{value}m" + self + "\e[0m" end end end # Code validate private/public IP acceptable ranges. class IPAddr PRIVATE_RANGES = [ IPAddr.new('10.0.0.0/8'), IPAddr.new('172.16.0.0/12'), IPAddr.new('192.168.0.0/16') ] def private? return false unless self.ipv4? PRIVATE_RANGES.each do |ipr| return true if ipr.include?(self) end false end def public? !private? end class << self def validate_ip_and_prefix(ip, cidr) if cidr.to_s.empty? raise "Cidr is missing for IP '#{ip}'." elsif valid?(ip) raise "Ip address '#{ip}' is invalid." elsif !IPAddr.new(ip).private? raise "Ip Address #{ip} must be private." end end def validate_address_space(ip) if ip.split('/').size != 2 raise "Cidr is invalid for IP #{ip}." elsif valid?(ip) raise "Address space '#{ip}' is invalid." end end def address_prefix(ip, cidr) ip + '/' + cidr.to_s end def valid?(ip) (IPAddr.new(ip) rescue nil).nil? end end end Azure::Loggerx = Azure::Core::Logger azure-core-0.1.2/lib/azure/core/default.rb0000755000175000017500000000164312730534277017632 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core module Default # Default User Agent header string USER_AGENT = "Azure-Core/#{Azure::Core::Version}".freeze end end end azure-core-0.1.2/lib/azure/core/auth/0000755000175000017500000000000012730534277016613 5ustar debiandebianazure-core-0.1.2/lib/azure/core/auth/shared_key_lite.rb0000755000175000017500000000327612730534277022306 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/auth/shared_key" module Azure module Core module Auth class SharedKeyLite < SharedKey # The name of the strategy. # # @return [String] def name 'SharedKeyLite' end # Generate the string to sign. # # @param method [Symbol] The HTTP request method. # @param uri [URI] The URI of the request we're signing. # @param headers [Hash] A Hash of HTTP request headers. # # Returns a plain text string. def signable_string(method, uri, headers) [ method.to_s.upcase, headers.fetch('Content-MD5', ''), headers.fetch('Content-Type', ''), headers.fetch('Date') { raise IndexError, 'Headers must include Date' }, canonicalized_headers(headers), canonicalized_resource(uri) ].join("\n") end end end end end azure-core-0.1.2/lib/azure/core/auth/signer.rb0000755000175000017500000000325112730534277020433 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'openssl' require 'base64' module Azure module Core module Auth # Utility class to sign strings with HMAC-256 and then encode the # signed string using Base64. class Signer # The access key for the account attr :access_key # Initialize the Signer. # # @param access_key [String] The access_key encoded in Base64. def initialize(access_key) if access_key.nil? raise ArgumentError, 'Signing key must be provided' end @access_key = Base64.strict_decode64(access_key) end # Generate an HMAC signature. # # @param body [String] The string to sign. # # @return [String] a Base64 String signed with HMAC. def sign(body) signed = OpenSSL::HMAC.digest('sha256', access_key, body) Base64.strict_encode64(signed) end end end end end azure-core-0.1.2/lib/azure/core/auth/authorizer.rb0000755000175000017500000000261512730534277021343 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/configuration" module Azure module Core module Auth class Authorizer # Public: Signs an HTTP request before it's made, by adding the # Authorization header # # request - An Azure::Core::HttpRequest that hasn't been signed # signer - A signing strategy, such as Azure::Table::Auth::SharedKey # # Returns the modified request def sign(request, signer) signature = signer.sign(request.method, request.uri, request.headers) request.headers['Authorization'] = "#{signer.name} #{signature}" request end end end end end azure-core-0.1.2/lib/azure/core/auth/shared_key.rb0000755000175000017500000001064512730534277021267 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'cgi' require 'azure/core/auth/signer' module Azure module Core module Auth class SharedKey < Signer # The Azure account's name. attr :account_name # Initialize the Signer. # # @param account_name [String] The account name. Defaults to the one in the # global configuration. # @param access_key [String] The access_key encoded in Base64. Defaults to the # one in the global configuration. def initialize(account_name=Azure.storage_account_name, access_key=Azure.storage_access_key) @account_name = account_name super(access_key) end # The name of the strategy. # # @return [String] def name 'SharedKey' end # Create the signature for the request parameters # # @param method [Symbol] HTTP request method. # @param uri [URI] URI of the request we're signing. # @param headers [Hash] HTTP request headers. # # @return [String] base64 encoded signature def sign(method, uri, headers) "#{account_name}:#{super(signable_string(method, uri, headers))}" end # Sign the request # # @param req [Azure::Core::Http::HttpRequest] HTTP request to sign # # @return [Azure::Core::Http::HttpRequest] def sign_request(req) req.headers['Authorization'] = "#{name} #{sign(req.method, req.uri, req.headers)}" req end # Generate the string to sign. # # @param method [Symbol] HTTP request method. # @param uri [URI] URI of the request we're signing. # @param headers [Hash] HTTP request headers. # # @return [String] def signable_string(method, uri, headers) [ method.to_s.upcase, headers.fetch('Content-Encoding', ''), headers.fetch('Content-Language', ''), headers.fetch('Content-Length', ''), headers.fetch('Content-MD5', ''), headers.fetch('Content-Type', ''), headers.fetch('Date', ''), headers.fetch('If-Modified-Since', ''), headers.fetch('If-Match', ''), headers.fetch('If-None-Match', ''), headers.fetch('If-Unmodified-Since', ''), headers.fetch('Range', ''), canonicalized_headers(headers), canonicalized_resource(uri) ].join("\n") end # Calculate the Canonicalized Headers string for a request. # # @param headers [Hash] HTTP request headers. # # @return [String] a string with the canonicalized headers. def canonicalized_headers(headers) headers = headers.map { |k,v| [k.to_s.downcase, v] } headers.select! { |k,v| k =~ /^x-ms-/ } headers.sort_by! { |(k,v)| k } headers.map! { |k,v| '%s:%s' % [k, v] } headers.map! { |h| h.gsub(/\s+/, ' ') }.join("\n") end # Calculate the Canonicalized Resource string for a request. # # @param uri [URI] URI of the request we're signing. # # @return [String] a string with the canonicalized resource. def canonicalized_resource(uri) resource = '/' + account_name + (uri.path.empty? ? '/' : uri.path) params = CGI.parse(uri.query.to_s).map { |k,v| [k.downcase, v] } params.sort_by! { |k,v| k } params.map! { |k,v| '%s:%s' % [k, v.map(&:strip).sort.join(',')] } [resource, *params].join("\n") end end end end end azure-core-0.1.2/lib/azure/core/service.rb0000755000175000017500000000323612730534277017646 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/http/http_request' module Azure module Core # A base class for Service implementations class Service # Create a new instance of the Service # # @param host [String] The hostname. (optional, Default empty) # @param options [Hash] options including {:client} (optional, Default {}) def initialize(host='', options = {}) @host = host @client = options[:client] || Azure end attr_accessor :host, :client def call(method, uri, body=nil, headers={}) request = Core::Http::HttpRequest.new(method, uri, body: body, headers: headers, client: @client) yield request if block_given? request.call end def generate_uri(path='', query={}) uri = URI.parse(File.join(host, path)) uri.query = URI.encode_www_form(query) unless query == nil or query.empty? uri end end end endazure-core-0.1.2/lib/azure/core/signed_service.rb0000755000175000017500000000360312730534277021175 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/filtered_service' require 'azure/core/http/signer_filter' require 'azure/core/auth/shared_key' module Azure module Core # A base class for Service implementations class SignedService < FilteredService # Create a new instance of the SignedService # # @param signer [Azure::Core::Auth::Signer]. An implementation of Signer used for signing requests. (optional, Default=Azure::Core::Auth::SharedKey.new) # @param account_name [String] The account name (optional, Default=Azure.config.storage_account_name) # @param options [Hash] options def initialize(signer=nil, account_name=nil, options={}) super('', options) signer ||= Core::Auth::SharedKey.new(client.storage_account_name, client.storage_access_key) @account_name = account_name || client.storage_account_name @signer = signer filters.unshift Core::Http::SignerFilter.new(signer) if signer end attr_accessor :account_name attr_accessor :signer def call(method, uri, body=nil, headers=nil) super(method, uri, body, headers) end end end endazure-core-0.1.2/lib/azure/core/filtered_service.rb0000755000175000017500000000305312730534277021521 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/service' module Azure module Core # A base class for Service implementations class FilteredService < Service # Create a new instance of the FilteredService # # @param host [String] The hostname. (optional, Default empty) # @param options [Hash] options including {:client} (optional, Default {}) def initialize(host='', options={}) super @filters = [] end attr_accessor :filters def call(method, uri, body=nil, headers=nil) super(method, uri, body, headers) do |request| filters.each { |filter| request.with_filter filter } if filters end end def with_filter(filter=nil, &block) filter = filter || block filters.push filter if filter end end end endazure-core-0.1.2/lib/azure/core/error.rb0000755000175000017500000000167212730534277017341 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core # Superclass for errors generated from this library, so people can # just rescue this for generic error handling class Error < StandardError;end end end azure-core-0.1.2/lib/azure/core/version.rb0000755000175000017500000000216112730534277017667 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core class Version MAJOR = 0 unless defined? MAJOR MINOR = 1 unless defined? MINOR UPDATE = 2 unless defined? UPDATE PRE = nil unless defined? PRE class << self # @return [String] def to_s [MAJOR, MINOR, UPDATE].join('.') + (PRE.nil? ? '' : "-#{PRE}") end end end end end azure-core-0.1.2/lib/azure/core/http/0000755000175000017500000000000012730534277016631 5ustar debiandebianazure-core-0.1.2/lib/azure/core/http/http_error.rb0000755000175000017500000000567712730534277021370 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/error' require 'nokogiri' module Azure module Core module Http # Public: Class for handling all HTTP response errors class HTTPError < Azure::Core::Error attr :uri # Public: The HTTP status code of this error # # Returns a Fixnum attr :status_code # Public: The type of error # # http://msdn.microsoft.com/en-us/library/azure/dd179357 # # Returns a String attr :type # Public: Description of the error # # Returns a String attr :description # Public: Detail of the error # # Returns a String attr :detail # Public: Initialize an error # # http_response - An Azure::Core::HttpResponse def initialize(http_response) @http_response = http_response @uri = http_response.uri @status_code = http_response.status_code parse_response super("#{type} (#{status_code}): #{description}") end # Extract the relevant information from the response's body. If the response # body is not an XML, we return an 'Unknown' error with the entire body as # the description # # Returns nothing def parse_response if @http_response.body && @http_response.body.include?('<') document = Nokogiri.Slop(@http_response.body) @type = document.css('code').first.text if document.css('code').any? @type = document.css('Code').first.text if document.css('Code').any? @description = document.css('message').first.text if document.css('message').any? @description = document.css('Message').first.text if document.css('Message').any? # service bus uses detail instead of message @detail = document.css('detail').first.text if document.css('detail').any? @detail = document.css('Detail').first.text if document.css('Detail').any? else @type = 'Unknown' if @http_response.body @description = "#{@http_response.body.strip}" end end end end end end end azure-core-0.1.2/lib/azure/core/http/http_request.rb0000755000175000017500000001374712730534277021724 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'digest/md5' require 'base64' require 'net/http' require 'time' require 'azure/core/version' require 'azure/core/http/http_response' require 'azure/core/http/retry_policy' require 'azure/core/default' require 'azure/http_response_helper' module Azure module Core module Http # Represents a HTTP request can perform synchronous queries to a # HTTP server, returning a HttpResponse class HttpRequest include Azure::HttpResponseHelper alias_method :_method, :method # The HTTP method to use (:get, :post, :put, :delete, etc...) attr_accessor :method # The URI of the HTTP endpoint to query attr_accessor :uri # The header values as a Hash attr_accessor :headers # The body of the request (IO or String) attr_accessor :body # Azure client which contains configuration context and http agents # @return [Azure::Client] attr_accessor :client # The http filter attr_accessor :has_retry_filter # Public: Create the HttpRequest # # @param method [Symbol] The HTTP method to use (:get, :post, :put, :del, etc...) # @param uri [URI] The URI of the HTTP endpoint to query # @param options_or_body [Hash|IO|String] The request options including {:client, :body} or raw body only def initialize(method, uri, options_or_body = {}) options ||= unless options_or_body.is_a?(Hash) {body: options_or_body} end || options_or_body || {} @method = method @uri = if uri.is_a?(String) URI.parse(uri) else uri end @client = options[:client] || Azure self.headers = default_headers(options[:current_time] || Time.now.httpdate).merge(options[:headers] || {}) self.body = options[:body] end # Public: Applies a HttpFilter to the HTTP Pipeline # # filter - Any object that responds to .call(req, _next) and # returns a HttpResponse eg. HttpFilter, Proc, # lambda, etc. (optional) # # &block - An inline block may be used instead of a filter # # example: # # request.with_filter do |req, _next| # _next.call # end # # NOTE: # # The code block provided must call _next or the filter pipeline # will not complete and the HTTP request will never execute # def with_filter(filter=nil, &block) filter = filter || block if filter @has_retry_filter = filter.is_a? Azure::Core::Http::RetryPolicy original_call = self._method(:call) # support 1.8.7 (define_singleton_method doesn't exist until 1.9.1) filter_call = Proc.new do filter.call(self, original_call) end k = class << self; self; end if k.method_defined? :define_singleton_method self.define_singleton_method(:call, filter_call) else k.send(:define_method, :call, filter_call) end end end # Build a default headers Hash def default_headers(current_time) {}.tap do |def_headers| def_headers['User-Agent'] = Azure::Core::Default::USER_AGENT def_headers['x-ms-date'] = current_time def_headers['x-ms-version'] = '2014-02-14' def_headers['DataServiceVersion'] = '1.0;NetFx' def_headers['MaxDataServiceVersion'] = '2.0;NetFx' def_headers['Content-Type'] = 'application/atom+xml; charset=utf-8' end end def http_setup http = @client.agents(uri) unless headers.nil? keep_alive = headers['Keep-Alive'] || headers['keep-alive'] http.read_timeout = keep_alive.split('=').last.to_i unless keep_alive.nil? end http end def body=(body) @body = body apply_body_headers end # Sends request to HTTP server and returns a HttpResponse # # @return [HttpResponse] def call conn = http_setup res = conn.run_request(method.to_sym, uri, nil, nil) do |req| req.body = body if body req.headers = headers if headers end response = HttpResponse.new(res) response.uri = uri raise response.error if !response.success? && !@has_retry_filter response end private def apply_body_headers if body if IO === body headers['Content-Length'] = body.size.to_s headers['Content-MD5'] = Digest::MD5.file(body.path).base64digest unless headers['Content-MD5'] else headers['Content-Length'] = body.bytesize.to_s headers['Content-MD5'] = Base64.strict_encode64(Digest::MD5.digest(body)) unless headers['Content-MD5'] end else headers['Content-Length'] = '0' end end end end end end azure-core-0.1.2/lib/azure/core/http/signer_filter.rb0000755000175000017500000000224612730534277022021 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/http/http_filter' module Azure module Core module Http # A HttpFilter implementation that creates a authorization signature which is added to the request headers class SignerFilter < HttpFilter def initialize(signer) @signer = signer end def call(req, _next) @signer.sign_request(req) _next.call end end end end end azure-core-0.1.2/lib/azure/core/http/http_response.rb0000755000175000017500000000576112730534277022067 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/http/http_error' module Azure module Core module Http # A small proxy to clean up the API of Net::HTTPResponse. class HttpResponse # Public: Initialize a new response. # # http_response - A Net::HTTPResponse. def initialize(http_response, uri='') @http_response = http_response @uri = uri end attr_accessor :uri # Public: Get the response body. # # Returns a String. def body @http_response.body end # Public: Get the response status code. # # Returns a Fixnum. def status_code @http_response.status end # Public: Check if this response was successful. A request is considered # successful if the response is in the 200 - 399 range. # # Returns nil|false. def success? @http_response.success? end # Public: Get all the response headers as a Hash. # # Returns a Hash. def headers @http_response.headers end # Public: Get an error that wraps this HTTP response, as long as this # response was unsuccessful. This method will return nil if the # response was successful. # # Returns an Azure::Core::Http::HTTPError. def exception HTTPError.new(self) unless success? end alias_method :error, :exception # TODO: This needs to be deleted and HttpError needs to be refactored to not rely on HttpResponse. # The dependency on knowing the internal structure of HttpResponse breaks good design principles. # The only reason this class exists is because the HttpError parses the HttpResponse to produce an error msg. class MockResponse def initialize(code, body, headers) @status = code @body = body @headers = headers @headers.each { |k,v| @headers[k] = [v] unless v.respond_to? first } end attr_accessor :status attr_accessor :body attr_accessor :headers def to_hash @headers end end end end end end azure-core-0.1.2/lib/azure/core/http/debug_filter.rb0000755000175000017500000000275112730534277021621 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/http/http_filter" module Azure module Core module Http # A HttpFilter implementation that displays information about the request and response for debugging class DebugFilter < HttpFilter def call(req, _next) puts "--REQUEST-BEGIN---------------------------" puts "method:", req.method, "uri:", req.uri, "headers:", req.headers, "body:", req.body puts "--REQUEST-END---------------------------" r = _next.call puts "--RESPONSE-BEGIN---------------------------" puts "status_code:", r.status_code, "headers:", r.headers, "body:", r.body puts "--RESPONSE-END---------------------------" r end end end end endazure-core-0.1.2/lib/azure/core/http/http_filter.rb0000755000175000017500000000423312730534277021507 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core module Http # A filter which can modify the HTTP pipeline both before and # after requests/responses. Multiple filters can be nested in a # "Russian Doll" model to create a compound HTTP pipeline class HttpFilter # Initialize a HttpFilter # # &block - An inline block which implements the filter. # # The inline block should take parameters |request, _next| where # request is a HttpRequest and _next is an object that implements # a method .call which returns an HttpResponse. The block passed # to the constructor should also return HttpResponse, either as # the result of calling _next.call or by customized logic. # def initialize(&block) @block = block end # Executes the filter # # request - HttpRequest. The request # _next - An object that implements .call (no params) # # NOTE: _next is a either a subsequent HttpFilter wrapped in a # closure, or the HttpRequest object's call method. Either way, # it must have it's .call method executed within each filter to # complete the pipeline. _next.call should return an HttpResponse # and so should this Filter. def call(request, _next) @block ? @block.call(request, _next) : _next.call end end end end endazure-core-0.1.2/lib/azure/core/http/retry_policy.rb0000755000175000017500000000531012730534277021704 0ustar debiandebian#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/http/http_filter" module Azure module Core module Http # A HttpFilter implementation that handles retrying based on a # specific policy when HTTP layer errors occur class RetryPolicy < HttpFilter def initialize(&block) @block = block end attr_accessor :retry_data # Overrides the base class implementation of call to implement # a retry loop that uses should_retry? to determine when to # break the loop # # req - HttpRequest. The HTTP request # _next - HttpFilter. The next filter in the pipeline def call(req, _next) retry_data = {} response = nil begin response = _next.call rescue retry_data[:error] = $! end while should_retry?(response, retry_data) if retry_data.has_key?(:error) raise retry_data[:error] else response end end # Determines if the HTTP request should continue retrying # # response - HttpResponse. The response from the active request # retry_data - Hash. Stores stateful retry data # # The retry_data is a Hash which can be used to store # stateful data about the request execution context (such as an # incrementing counter, timestamp, etc). The retry_data object # will be the same instance throughout the lifetime of the request. # # If an inline block was passed to the constructor, that block # will be used here and should return true to retry the job, or # false to stop exit. If an inline block was not passed to the # constructor the method returns false. # # Alternatively, a subclass could override this method. def should_retry?(response, retry_data) @block ? @block.call(response, retry_data) : false end end end end endazure-core-0.1.2/README.md0000755000175000017500000000125712730534277014315 0ustar debiandebian# Azure::Core [![Build Status](https://travis-ci.org/Azure/azure-ruby-asm-core.png?branch=master)](https://travis-ci.org/Azure/azure-ruby-asm-core) This project provides a Ruby package with core functionality consumed by Azure SDK gems. ## Installation Add this line to your application's Gemfile: ```ruby gem 'azure-core' ``` And then execute: $ bundle Or install it yourself as: $ gem install azure-core ## Usage ```ruby require 'azure/core' ``` ## Development After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests. ## Provide Feedback If you encounter any bugs with the library please file an issue. azure-core-0.1.2/.travis.yml0000755000175000017500000000172112730534277015143 0ustar debiandebiansudo: false language: ruby rvm: - 2.0.0 - 2.1.5 - 2.2.0 - 2.3.0 before_install: gem install bundler -v 1.11.2 script: - bundle install && bundle exec rake test:unit deploy: provider: rubygems api_key: secure: EN/hvsyyZq4bOxJgJXVP8AttRsn9ajYrtsg47bVcPHtSXP52mT1r800FC50l1V1MoeNPrgjO8WjVY37rR/FerDsdt0rujakfseKOpCeosAX8hbJ2zVcyOnU16TmkNUAqKKprHkvw/8dnNEYmeyUo+VZmizxVhieur8yitKWiP08Ab1ehA8sDfcGsusnE/Las7fyiiCqMfFQJsJWJimIXNYF6pGZs+6l1YE2sH5S4wKLf09+jhP4WZ6nXcYlyUViLqieMx3US1a9jVV534QSIVYk7Z8PdP4eJm4P46UJ1YPc85DceLAZh2dno5l+Eyk16UYBgPichWEqQf3+0SaNKxNDkNYmXPkxNbajIKFLAsTs7CBwhwK3CxfgDok2P3jcB9iJg3ZlWFD6fMxr1Tca1cEkLpxj8S7peB4St0AwVeaEXfUHIDHb706PbOOoy5BOuK+aDotz0/sHQTOHSAPD4IhZ3+GKCkV4NOV2fxKTWXYK1NSx76jyBW3gnSsy9OWKhKxEXaVLB3J1i5dKUw1l4YBJuRATw2GbimMqQf0EpXukXE/fKugU4+EQUZwoIe85GrjaJrU/LXMpp8lBoh5dPZOxtEXGp6cJWcl239FUVSY17Wf/H8cTpahhNR+PNHUyavC2syPOqxrzNKmfNN3bWFm6iJkYCNI2bFxpUB/Ky+Vc= gem: azure-core on: tags: true repo: Azure/azure-ruby-asm-core azure-core-0.1.2/ChangeLog.md0000644000175000017500000000070212730534277015176 0ustar debiandebian# 2016.5.16 - azure-core gem @version 0.1.2 * Return response instead of raising exception when there is a retry filter [#8](https://github.com/Azure/azure-ruby-asm-core/pull/8) ## 2016.4.18 - azure-core gem @version 0.1.1 * Can not upload file with spaces [#360](https://github.com/Azure/azure-sdk-for-ruby/issues/360) # 2016.4.14 - azure-core gem @version 0.1.0 * Initial release, splitting code from 'azure' gem to its own separate gem for core.