azure-storage-common 1.1.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +5 -5
  2. data/lib/azure/core.rb +47 -0
  3. data/lib/azure/core/auth/authorizer.rb +36 -0
  4. data/lib/azure/core/auth/shared_key.rb +125 -0
  5. data/lib/azure/core/auth/shared_key_lite.rb +48 -0
  6. data/lib/azure/core/auth/signer.rb +51 -0
  7. data/lib/azure/core/default.rb +23 -0
  8. data/lib/azure/core/error.rb +21 -0
  9. data/lib/azure/core/filtered_service.rb +45 -0
  10. data/lib/azure/core/http/debug_filter.rb +36 -0
  11. data/lib/azure/core/http/http_error.rb +135 -0
  12. data/lib/azure/core/http/http_filter.rb +53 -0
  13. data/lib/azure/core/http/http_request.rb +194 -0
  14. data/lib/azure/core/http/http_response.rb +102 -0
  15. data/lib/azure/core/http/retry_policy.rb +84 -0
  16. data/lib/azure/core/http/signer_filter.rb +33 -0
  17. data/lib/azure/core/service.rb +46 -0
  18. data/lib/azure/core/signed_service.rb +45 -0
  19. data/lib/azure/core/utility.rb +244 -0
  20. data/lib/azure/core/version.rb +33 -0
  21. data/lib/azure/http_response_helper.rb +38 -0
  22. data/lib/azure/storage/common.rb +26 -26
  23. data/lib/azure/storage/common/autoload.rb +62 -61
  24. data/lib/azure/storage/common/client.rb +162 -162
  25. data/lib/azure/storage/common/client_options.rb +363 -363
  26. data/lib/azure/storage/common/client_options_error.rb +41 -41
  27. data/lib/azure/storage/common/configurable.rb +212 -212
  28. data/lib/azure/storage/common/core.rb +35 -35
  29. data/lib/azure/storage/common/core/auth/anonymous_signer.rb +43 -43
  30. data/lib/azure/storage/common/core/auth/shared_access_signature.rb +30 -30
  31. data/lib/azure/storage/common/core/auth/shared_access_signature_generator.rb +399 -352
  32. data/lib/azure/storage/common/core/auth/shared_access_signature_signer.rb +57 -57
  33. data/lib/azure/storage/common/core/auth/shared_key.rb +60 -60
  34. data/lib/azure/storage/common/core/auth/token_signer.rb +43 -43
  35. data/lib/azure/storage/common/core/autoload.rb +53 -53
  36. data/lib/azure/storage/common/core/error.rb +43 -43
  37. data/lib/azure/storage/common/core/filter/exponential_retry_filter.rb +64 -64
  38. data/lib/azure/storage/common/core/filter/linear_retry_filter.rb +55 -55
  39. data/lib/azure/storage/common/core/filter/retry_filter.rb +300 -300
  40. data/lib/azure/storage/common/core/http_client.rb +79 -69
  41. data/lib/azure/storage/common/core/sr.rb +85 -85
  42. data/lib/azure/storage/common/core/token_credential.rb +64 -64
  43. data/lib/azure/storage/common/core/utility.rb +255 -255
  44. data/lib/azure/storage/common/default.rb +868 -868
  45. data/lib/azure/storage/common/service/access_policy.rb +37 -37
  46. data/lib/azure/storage/common/service/cors.rb +38 -38
  47. data/lib/azure/storage/common/service/cors_rule.rb +48 -48
  48. data/lib/azure/storage/common/service/enumeration_results.rb +32 -32
  49. data/lib/azure/storage/common/service/geo_replication.rb +40 -40
  50. data/lib/azure/storage/common/service/logging.rb +47 -47
  51. data/lib/azure/storage/common/service/metrics.rb +45 -45
  52. data/lib/azure/storage/common/service/retention_policy.rb +37 -37
  53. data/lib/azure/storage/common/service/serialization.rb +335 -335
  54. data/lib/azure/storage/common/service/signed_identifier.rb +40 -40
  55. data/lib/azure/storage/common/service/storage_service.rb +322 -322
  56. data/lib/azure/storage/common/service/storage_service_properties.rb +48 -48
  57. data/lib/azure/storage/common/service/storage_service_stats.rb +39 -39
  58. data/lib/azure/storage/common/service/user_delegation_key.rb +50 -0
  59. data/lib/azure/storage/common/version.rb +49 -49
  60. metadata +60 -18
@@ -0,0 +1,135 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'azure/core/error'
16
+ require 'nokogiri'
17
+ require 'json'
18
+
19
+ module Azure
20
+ module Core
21
+ module Http
22
+ # Public: Class for handling all HTTP response errors
23
+ class HTTPError < Azure::Core::Error
24
+
25
+ # Public: Detail of the response
26
+ #
27
+ # Returns an Azure::Core::Http::HttpResponse object
28
+ attr :http_response
29
+
30
+ # Public: The request URI
31
+ #
32
+ # Returns a String
33
+ attr :uri
34
+
35
+ # Public: The HTTP status code of this error
36
+ #
37
+ # Returns a Fixnum
38
+ attr :status_code
39
+
40
+ # Public: The type of error
41
+ #
42
+ # http://msdn.microsoft.com/en-us/library/azure/dd179357
43
+ #
44
+ # Returns a String
45
+ attr :type
46
+
47
+ # Public: Description of the error
48
+ #
49
+ # Returns a String
50
+ attr :description
51
+
52
+ # Public: Detail of the error
53
+ #
54
+ # Returns a String
55
+ attr :detail
56
+
57
+ # Public: The header name whose value is invalid
58
+ #
59
+ # Returns a String
60
+ attr :header
61
+
62
+ # Public: The invalid header value
63
+ #
64
+ # Returns a String
65
+ attr :header_value
66
+
67
+ # Public: Initialize an error
68
+ #
69
+ # http_response - An Azure::Core::HttpResponse
70
+ def initialize(http_response)
71
+ @http_response = http_response
72
+ @uri = http_response.uri
73
+ @status_code = http_response.status_code
74
+ parse_response
75
+ # Use reason phrase as the description if description is empty
76
+ @description = http_response.reason_phrase if (@description.nil? || @description.empty?) && http_response.reason_phrase
77
+ super("#{type} (#{status_code}): #{description}")
78
+ end
79
+
80
+ # Extract the relevant information from the response's body. If the response
81
+ # body is not an XML, we return an 'Unknown' error with the entire body as
82
+ # the description
83
+ #
84
+ # Returns nothing
85
+ def parse_response
86
+ if @http_response.body && @http_response.respond_to?(:headers) && @http_response.headers['Content-Type']
87
+ if @http_response.headers['Content-Type'].include?('xml')
88
+ parse_xml_response
89
+ elsif @http_response.headers['Content-Type'].include?('json')
90
+ parse_json_response
91
+ end
92
+ else
93
+ parse_unknown_response
94
+ end
95
+ end
96
+
97
+ def parse_xml_response
98
+ document = Nokogiri.Slop(@http_response.body)
99
+
100
+ @type = document.css('code').first.text if document.css('code').any?
101
+ @type = document.css('Code').first.text if document.css('Code').any?
102
+ @description = document.css('message').first.text if document.css('message').any?
103
+ @description = document.css('Message').first.text if document.css('Message').any?
104
+ @header = document.css('headername').first.text if document.css('headername').any?
105
+ @header = document.css('HeaderName').first.text if document.css('HeaderName').any?
106
+ @header_value = document.css('headervalue').first.text if document.css('headervalue').any?
107
+ @header_value = document.css('HeaderValue').first.text if document.css('HeaderValue').any?
108
+
109
+ # service bus uses detail instead of message
110
+ @detail = document.css('detail').first.text if document.css('detail').any?
111
+ @detail = document.css('Detail').first.text if document.css('Detail').any?
112
+ end
113
+
114
+ def parse_json_response
115
+ odata_error = JSON.parse(@http_response.body)['odata.error']
116
+ @type = odata_error['code']
117
+ @description = odata_error['message']['value']
118
+ end
119
+
120
+ def parse_unknown_response
121
+ @type = 'Unknown'
122
+ if @http_response.body
123
+ @description = "#{@http_response.body.strip}"
124
+ end
125
+ end
126
+
127
+ def inspect
128
+ string = "#<#{self.class.name}:#{self.object_id} "
129
+ fields = self.instance_variables.map{|field| "#{field}: #{self.send(field.to_s.delete("@")).inspect}"}
130
+ string << fields.join(", ") << ">"
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,53 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ module Azure
16
+ module Core
17
+ module Http
18
+ # A filter which can modify the HTTP pipeline both before and
19
+ # after requests/responses. Multiple filters can be nested in a
20
+ # "Russian Doll" model to create a compound HTTP pipeline
21
+ class HttpFilter
22
+
23
+ # Initialize a HttpFilter
24
+ #
25
+ # &block - An inline block which implements the filter.
26
+ #
27
+ # The inline block should take parameters |request, _next| where
28
+ # request is a HttpRequest and _next is an object that implements
29
+ # a method .call which returns an HttpResponse. The block passed
30
+ # to the constructor should also return HttpResponse, either as
31
+ # the result of calling _next.call or by customized logic.
32
+ #
33
+ def initialize(&block)
34
+ @block = block
35
+ end
36
+
37
+ # Executes the filter
38
+ #
39
+ # request - HttpRequest. The request
40
+ # _next - An object that implements .call (no params)
41
+ #
42
+ # NOTE: _next is a either a subsequent HttpFilter wrapped in a
43
+ # closure, or the HttpRequest object's call method. Either way,
44
+ # it must have it's .call method executed within each filter to
45
+ # complete the pipeline. _next.call should return an HttpResponse
46
+ # and so should this Filter.
47
+ def call(request, _next)
48
+ @block ? @block.call(request, _next) : _next.call
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,194 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'digest/md5'
16
+ require 'base64'
17
+ require 'net/http'
18
+ require 'time'
19
+
20
+ require 'azure/core/version'
21
+ require 'azure/core/http/http_response'
22
+ require 'azure/core/http/retry_policy'
23
+ require 'azure/core/default'
24
+ require 'azure/http_response_helper'
25
+
26
+ module Azure
27
+ module Core
28
+ module Http
29
+ # Represents a HTTP request can perform synchronous queries to a
30
+ # HTTP server, returning a HttpResponse
31
+ class HttpRequest
32
+ include Azure::HttpResponseHelper
33
+ alias_method :_method, :method
34
+
35
+ # The HTTP method to use (:get, :post, :put, :delete, etc...)
36
+ attr_accessor :method
37
+
38
+ # The URI of the HTTP endpoint to query
39
+ attr_accessor :uri
40
+
41
+ # The header values as a Hash
42
+ attr_accessor :headers
43
+
44
+ # The body of the request (IO or String)
45
+ attr_accessor :body
46
+
47
+ # Azure client which contains configuration context and http agents
48
+ # @return [Azure::Client]
49
+ attr_accessor :client
50
+
51
+ # The http filter
52
+ attr_accessor :has_retry_filter
53
+
54
+ # Public: Create the HttpRequest
55
+ #
56
+ # @param method [Symbol] The HTTP method to use (:get, :post, :put, :del, etc...)
57
+ # @param uri [URI] The URI of the HTTP endpoint to query
58
+ # @param options_or_body [Hash|IO|String] The request options including {:client, :body} or raw body only
59
+ def initialize(method, uri, options_or_body = {})
60
+ options ||= unless options_or_body.is_a?(Hash)
61
+ {body: options_or_body}
62
+ end || options_or_body || {}
63
+
64
+ @method = method
65
+ @uri = if uri.is_a?(String)
66
+ URI.parse(uri)
67
+ else
68
+ uri
69
+ end
70
+
71
+ @client = options[:client] || Azure
72
+
73
+ self.headers = default_headers(options[:current_time] || Time.now.httpdate).merge(options[:headers] || {})
74
+ self.body = options[:body]
75
+ end
76
+
77
+ # Public: Applies a HttpFilter to the HTTP Pipeline
78
+ #
79
+ # filter - Any object that responds to .call(req, _next) and
80
+ # returns a HttpResponse eg. HttpFilter, Proc,
81
+ # lambda, etc. (optional)
82
+ #
83
+ # options - The options that are used when call Azure::Core::FilteredService.call.
84
+ # It can be used by retry policies to determine changes in the retry.
85
+ #
86
+ # &block - An inline block may be used instead of a filter
87
+ #
88
+ # example:
89
+ #
90
+ # request.with_filter do |req, _next|
91
+ # _next.call
92
+ # end
93
+ #
94
+ # NOTE:
95
+ #
96
+ # The code block provided must call _next or the filter pipeline
97
+ # will not complete and the HTTP request will never execute
98
+ #
99
+ def with_filter(filter=nil, options={}, &block)
100
+ filter = filter || block
101
+ if filter
102
+ is_retry_policy = filter.is_a?(Azure::Core::Http::RetryPolicy)
103
+ filter.retry_data[:request_options] = options if is_retry_policy
104
+ @has_retry_filter ||= is_retry_policy
105
+
106
+ original_call = self._method(:call)
107
+
108
+ # support 1.8.7 (define_singleton_method doesn't exist until 1.9.1)
109
+ filter_call = Proc.new do
110
+ filter.call(self, original_call)
111
+ end
112
+ k = class << self;
113
+ self;
114
+ end
115
+ if k.method_defined? :define_singleton_method
116
+ self.define_singleton_method(:call, filter_call)
117
+ else
118
+ k.send(:define_method, :call, filter_call)
119
+ end
120
+ end
121
+ end
122
+
123
+ # Build a default headers Hash
124
+ def default_headers(current_time)
125
+ {}.tap do |def_headers|
126
+ def_headers['User-Agent'] = Azure::Core::Default::USER_AGENT
127
+ def_headers['x-ms-date'] = current_time
128
+ def_headers['x-ms-version'] = '2014-02-14'
129
+ def_headers['DataServiceVersion'] = '1.0;NetFx'
130
+ def_headers['MaxDataServiceVersion'] = '3.0;NetFx'
131
+ def_headers['Content-Type'] = 'application/atom+xml; charset=utf-8'
132
+ end
133
+ end
134
+
135
+ def http_setup
136
+ @client.agents(uri)
137
+ end
138
+
139
+ def body=(body)
140
+ @body = body
141
+ apply_body_headers
142
+ end
143
+
144
+ # Sends request to HTTP server and returns a HttpResponse
145
+ #
146
+ # @return [HttpResponse]
147
+ def call
148
+ conn = http_setup
149
+ res = set_up_response(method.to_sym, uri, conn, headers ,body)
150
+
151
+ response = HttpResponse.new(res)
152
+ response.uri = uri
153
+ raise response.error if !response.success? && !@has_retry_filter
154
+ response
155
+ end
156
+
157
+ private
158
+
159
+ def apply_body_headers
160
+ return headers['Content-Length'] = '0' unless body
161
+
162
+ return apply_io_headers if IO === body || Tempfile === body
163
+ return apply_string_io_headers if StringIO === body
164
+ return apply_miscellaneous_headers
165
+ end
166
+
167
+ def apply_io_headers
168
+ headers['Content-Length'] = body.size.to_s if body.respond_to?('size')
169
+ if headers['Content-Length'].nil?
170
+ raise ArgumentError, '\'Content-Length\' must be defined if size cannot be obtained from body IO.'
171
+ end
172
+ headers['Content-MD5'] = Digest::MD5.file(body.path).base64digest unless headers['Content-MD5']
173
+ end
174
+
175
+ def apply_string_io_headers
176
+ headers['Content-Length'] = body.size.to_s
177
+ unless headers['Content-MD5']
178
+ headers['Content-MD5'] = Digest::MD5.new.tap do |checksum|
179
+ while chunk = body.read(5242880)
180
+ checksum << chunk
181
+ end
182
+ body.rewind
183
+ end.base64digest
184
+ end
185
+ end
186
+
187
+ def apply_miscellaneous_headers
188
+ headers['Content-Length'] = body.size.to_s
189
+ headers['Content-MD5'] = Base64.strict_encode64(Digest::MD5.digest(body.to_s)) unless headers['Content-MD5']
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,102 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'azure/core/http/http_error'
16
+
17
+ module Azure
18
+ module Core
19
+ module Http
20
+ # A small proxy to clean up the API of Net::HTTPResponse.
21
+ class HttpResponse
22
+ # Public: Initialize a new response.
23
+ #
24
+ # http_response - A Net::HTTPResponse.
25
+ def initialize(http_response, uri='')
26
+ @http_response = http_response
27
+ @uri = uri
28
+ end
29
+
30
+ attr_accessor :uri
31
+
32
+ # Public: Get the response body.
33
+ #
34
+ # Returns a String.
35
+ def body
36
+ @http_response.body
37
+ end
38
+
39
+ # Public: Get the response status code.
40
+ #
41
+ # Returns a Fixnum.
42
+ def status_code
43
+ @http_response.status
44
+ end
45
+
46
+ # Public: Get the response reason phrase.
47
+ #
48
+ # Returns a String.
49
+ def reason_phrase
50
+ @http_response.reason_phrase
51
+ end
52
+
53
+ # Public: Check if this response was successful. A request is considered
54
+ # successful if the response is in the 200 - 399 range.
55
+ #
56
+ # Returns nil|false.
57
+ def success?
58
+ @http_response.success?
59
+ end
60
+
61
+ # Public: Get all the response headers as a Hash.
62
+ #
63
+ # Returns a Hash.
64
+ def headers
65
+ @http_response.headers
66
+ end
67
+
68
+ # Public: Get an error that wraps this HTTP response, as long as this
69
+ # response was unsuccessful. This method will return nil if the
70
+ # response was successful.
71
+ #
72
+ # Returns an Azure::Core::Http::HTTPError.
73
+ def exception
74
+ HTTPError.new(self) unless success?
75
+ end
76
+
77
+ alias_method :error, :exception
78
+
79
+ # TODO: This needs to be deleted and HttpError needs to be refactored to not rely on HttpResponse.
80
+ # The dependency on knowing the internal structure of HttpResponse breaks good design principles.
81
+ # The only reason this class exists is because the HttpError parses the HttpResponse to produce an error msg.
82
+ class MockResponse
83
+ def initialize(code, body, headers)
84
+ @status = code
85
+ @body = body
86
+ @headers = headers
87
+ @headers.each { |k,v|
88
+ @headers[k] = [v] unless v.respond_to? 'first'
89
+ }
90
+ end
91
+ attr_accessor :status
92
+ attr_accessor :body
93
+ attr_accessor :headers
94
+
95
+ def to_hash
96
+ @headers
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end