azure-storage 0.10.0.preview

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/lib/azure/storage.rb +58 -0
  3. data/lib/azure/storage/autoload.rb +71 -0
  4. data/lib/azure/storage/blob/append.rb +154 -0
  5. data/lib/azure/storage/blob/blob.rb +821 -0
  6. data/lib/azure/storage/blob/blob_service.rb +510 -0
  7. data/lib/azure/storage/blob/block.rb +264 -0
  8. data/lib/azure/storage/blob/container.rb +552 -0
  9. data/lib/azure/storage/blob/page.rb +380 -0
  10. data/lib/azure/storage/blob/serialization.rb +297 -0
  11. data/lib/azure/storage/client.rb +185 -0
  12. data/lib/azure/storage/configurable.rb +137 -0
  13. data/lib/azure/storage/core.rb +33 -0
  14. data/lib/azure/storage/core/auth/shared_access_signature.rb +27 -0
  15. data/lib/azure/storage/core/auth/shared_access_signature_generator.rb +194 -0
  16. data/lib/azure/storage/core/auth/shared_access_signature_signer.rb +49 -0
  17. data/lib/azure/storage/core/auth/shared_key.rb +125 -0
  18. data/lib/azure/storage/core/auth/shared_key_lite.rb +55 -0
  19. data/lib/azure/storage/core/auth/signer.rb +60 -0
  20. data/lib/azure/storage/core/autoload.rb +35 -0
  21. data/lib/azure/storage/core/client_options.rb +334 -0
  22. data/lib/azure/storage/core/client_options_error.rb +39 -0
  23. data/lib/azure/storage/core/constants.rb +1077 -0
  24. data/lib/azure/storage/core/error.rb +47 -0
  25. data/lib/azure/storage/core/filtered_service.rb +54 -0
  26. data/lib/azure/storage/core/http/debug_filter.rb +45 -0
  27. data/lib/azure/storage/core/http/http_error.rb +95 -0
  28. data/lib/azure/storage/core/http/http_filter.rb +62 -0
  29. data/lib/azure/storage/core/http/http_request.rb +182 -0
  30. data/lib/azure/storage/core/http/http_response.rb +105 -0
  31. data/lib/azure/storage/core/http/retry_policy.rb +83 -0
  32. data/lib/azure/storage/core/http/signer_filter.rb +42 -0
  33. data/lib/azure/storage/core/http_client.rb +63 -0
  34. data/lib/azure/storage/core/service.rb +55 -0
  35. data/lib/azure/storage/core/signed_service.rb +54 -0
  36. data/lib/azure/storage/core/sr.rb +83 -0
  37. data/lib/azure/storage/core/utility.rb +254 -0
  38. data/lib/azure/storage/queue/message.rb +39 -0
  39. data/lib/azure/storage/queue/queue.rb +37 -0
  40. data/lib/azure/storage/queue/queue_service.rb +580 -0
  41. data/lib/azure/storage/queue/serialization.rb +113 -0
  42. data/lib/azure/storage/service/access_policy.rb +35 -0
  43. data/lib/azure/storage/service/cors.rb +36 -0
  44. data/lib/azure/storage/service/cors_rule.rb +46 -0
  45. data/lib/azure/storage/service/enumeration_results.rb +30 -0
  46. data/lib/azure/storage/service/logging.rb +45 -0
  47. data/lib/azure/storage/service/metrics.rb +43 -0
  48. data/lib/azure/storage/service/retention_policy.rb +35 -0
  49. data/lib/azure/storage/service/serialization.rb +308 -0
  50. data/lib/azure/storage/service/signed_identifier.rb +39 -0
  51. data/lib/azure/storage/service/storage_service.rb +131 -0
  52. data/lib/azure/storage/service/storage_service_properties.rb +46 -0
  53. data/lib/azure/storage/table/auth/shared_key.rb +68 -0
  54. data/lib/azure/storage/table/auth/shared_key_lite.rb +53 -0
  55. data/lib/azure/storage/table/batch.rb +339 -0
  56. data/lib/azure/storage/table/batch_response.rb +127 -0
  57. data/lib/azure/storage/table/edmtype.rb +136 -0
  58. data/lib/azure/storage/table/entity.rb +40 -0
  59. data/lib/azure/storage/table/guid.rb +33 -0
  60. data/lib/azure/storage/table/query.rb +121 -0
  61. data/lib/azure/storage/table/serialization.rb +117 -0
  62. data/lib/azure/storage/table/table_service.rb +571 -0
  63. data/lib/azure/storage/version.rb +46 -0
  64. metadata +329 -0
@@ -0,0 +1,49 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+
25
+ require 'azure/storage/core/auth/signer'
26
+
27
+ module Azure::Storage
28
+ module Auth
29
+ class SharedAccessSignatureSigner < Azure::Core::Auth::Signer
30
+
31
+ attr :account_name, :sas_token
32
+
33
+ # Public: Initialize the Signer with a SharedAccessSignature
34
+ #
35
+ # @param account_name [String] The account name. Defaults to the one in the global configuration.
36
+ # @param sas_token [String] The sas token to be used for signing
37
+ def initialize(account_name=Azure::Storage.storage_account_name, sas_token=Azure::Storage.storage_sas_token)
38
+ @account_name = account_name
39
+ @sas_token = sas_token
40
+ end
41
+
42
+ def sign_request(req)
43
+ ori_uri = req.uri
44
+ URI.parse(ori_uri.to_s + (ori_uri.query.nil? ? '?' : '&') + sas_token.sub(/^\?/,'') + '&api-version=' + Azure::Storage::Default::STG_VERSION)
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,125 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+ require 'cgi'
25
+ require 'azure/storage/core/auth/signer'
26
+
27
+ module Azure::Storage
28
+ module Auth
29
+ class SharedKey < Azure::Core::Auth::Signer
30
+ # The Azure account's name.
31
+ attr :account_name
32
+
33
+ # Initialize the Signer.
34
+ #
35
+ # @param account_name [String] The account name. Defaults to the one in the
36
+ # global configuration.
37
+ # @param access_key [String] The access_key encoded in Base64. Defaults to the
38
+ # one in the global configuration.
39
+ def initialize(account_name=Azure::Storage.config.storage_account_name, access_key=Azure::Storage.config.storage_access_key)
40
+ @account_name = account_name
41
+ super(access_key)
42
+ end
43
+
44
+ # The name of the strategy.
45
+ #
46
+ # @return [String]
47
+ def name
48
+ 'SharedKey'
49
+ end
50
+
51
+ # Create the signature for the request parameters
52
+ #
53
+ # @param method [Symbol] HTTP request method.
54
+ # @param uri [URI] URI of the request we're signing.
55
+ # @param headers [Hash] HTTP request headers.
56
+ #
57
+ # @return [String] base64 encoded signature
58
+ def sign(method, uri, headers)
59
+ "#{account_name}:#{super(signable_string(method, uri, headers))}"
60
+ end
61
+
62
+ # Sign the request
63
+ #
64
+ # @param req [Azure::Core::Http::HttpRequest] HTTP request to sign
65
+ #
66
+ # @return [Azure::Core::Http::HttpRequest]
67
+ def sign_request(req)
68
+ req.headers['Authorization'] = "#{name} #{sign(req.method, req.uri, req.headers)}"
69
+ req
70
+ end
71
+
72
+ # Generate the string to sign.
73
+ #
74
+ # @param method [Symbol] HTTP request method.
75
+ # @param uri [URI] URI of the request we're signing.
76
+ # @param headers [Hash] HTTP request headers.
77
+ #
78
+ # @return [String]
79
+ def signable_string(method, uri, headers)
80
+ [
81
+ method.to_s.upcase,
82
+ headers.fetch('Content-Encoding', ''),
83
+ headers.fetch('Content-Language', ''),
84
+ headers.fetch('Content-Length', '').sub(/^0+/,''), # from 2015-02-21, if Content-Length == 0, it won't be signed
85
+ headers.fetch('Content-MD5', ''),
86
+ headers.fetch('Content-Type', ''),
87
+ headers.fetch('Date', ''),
88
+ headers.fetch('If-Modified-Since', ''),
89
+ headers.fetch('If-Match', ''),
90
+ headers.fetch('If-None-Match', ''),
91
+ headers.fetch('If-Unmodified-Since', ''),
92
+ headers.fetch('Range', ''),
93
+ canonicalized_headers(headers),
94
+ canonicalized_resource(uri)
95
+ ].join("\n")
96
+ end
97
+
98
+ # Calculate the Canonicalized Headers string for a request.
99
+ #
100
+ # @param headers [Hash] HTTP request headers.
101
+ #
102
+ # @return [String] a string with the canonicalized headers.
103
+ def canonicalized_headers(headers)
104
+ headers = headers.map { |k,v| [k.to_s.downcase, v] }
105
+ headers.select! { |k,v| k =~ /^x-ms-/ }
106
+ headers.sort_by! { |(k,v)| k }
107
+ headers.map! { |k,v| '%s:%s' % [k, v] }
108
+ headers.map! { |h| h.gsub(/\s+/, ' ') }.join("\n")
109
+ end
110
+
111
+ # Calculate the Canonicalized Resource string for a request.
112
+ #
113
+ # @param uri [URI] URI of the request we're signing.
114
+ #
115
+ # @return [String] a string with the canonicalized resource.
116
+ def canonicalized_resource(uri)
117
+ resource = '/' + account_name + (uri.path.empty? ? '/' : uri.path)
118
+ params = CGI.parse(uri.query.to_s).map { |k,v| [k.downcase, v] }
119
+ params.sort_by! { |k,v| k }
120
+ params.map! { |k,v| '%s:%s' % [k, v.map(&:strip).sort.join(',')] }
121
+ [resource, *params].join("\n")
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,55 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+ require "azure/storage/core/auth/shared_key"
25
+
26
+ module Azure::Storage
27
+ module Auth
28
+ class SharedKeyLite < SharedKey
29
+ # The name of the strategy.
30
+ #
31
+ # @return [String]
32
+ def name
33
+ 'SharedKeyLite'
34
+ end
35
+
36
+ # Generate the string to sign.
37
+ #
38
+ # @param method [Symbol] The HTTP request method.
39
+ # @param uri [URI] The URI of the request we're signing.
40
+ # @param headers [Hash] A Hash of HTTP request headers.
41
+ #
42
+ # Returns a plain text string.
43
+ def signable_string(method, uri, headers)
44
+ [
45
+ method.to_s.upcase,
46
+ headers.fetch('Content-MD5', ''),
47
+ headers.fetch('Content-Type', ''),
48
+ headers.fetch('Date') { raise IndexError, 'Headers must include Date' },
49
+ canonicalized_headers(headers),
50
+ canonicalized_resource(uri)
51
+ ].join("\n")
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,60 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+ require 'openssl'
25
+ require 'base64'
26
+
27
+ module Azure
28
+ module Core
29
+ module Auth
30
+ # Utility class to sign strings with HMAC-256 and then encode the
31
+ # signed string using Base64.
32
+ class Signer
33
+ # The access key for the account
34
+ attr :access_key
35
+
36
+ # Initialize the Signer.
37
+ #
38
+ # @param access_key [String] The access_key encoded in Base64.
39
+ def initialize(access_key)
40
+ if access_key.nil?
41
+ raise ArgumentError, 'Signing key must be provided'
42
+ end
43
+
44
+ @access_key = Base64.strict_decode64(access_key)
45
+ end
46
+
47
+ # Generate an HMAC signature.
48
+ #
49
+ # @param body [String] The string to sign.
50
+ #
51
+ # @return [String] a Base64 String signed with HMAC.
52
+ def sign(body)
53
+ signed = OpenSSL::HMAC.digest('sha256', access_key, body)
54
+ Base64.strict_encode64(signed)
55
+ end
56
+
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,35 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+
25
+ module Azure
26
+ module Core
27
+ autoload :HttpClient, 'azure/storage/core/http_client'
28
+ autoload :Utility, 'azure/storage/core/utility'
29
+ autoload :Logger, 'azure/storage/core/utility'
30
+ autoload :Error, 'azure/storage/core/error'
31
+ autoload :Service, 'azure/storage/core/service'
32
+ autoload :FilteredService, 'azure/storage/core/filtered_service'
33
+ autoload :SignedService, 'azure/storage/core/signed_service'
34
+ end
35
+ end
@@ -0,0 +1,334 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+
25
+ require 'uri'
26
+ require 'azure/storage/core'
27
+ require 'azure/storage/core/client_options_error'
28
+
29
+ module Azure::Storage
30
+ module ClientOptions
31
+
32
+ attr_accessor :ca_file
33
+
34
+ # Public: Reset options for [Azure::Storage::Client]
35
+ #
36
+ # ==== Attributes
37
+ #
38
+ # * +options+ - Hash. Optional parameters.
39
+ #
40
+ # ==== Options
41
+ #
42
+ # Accepted key/value pairs in options parameter are:
43
+ #
44
+ # * +:use_development_storage+ - TrueClass. Whether to use storage emulator.
45
+ # * +:development_storage_proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost.
46
+ # * +:storage_account_name+ - String. The name of the storage account.
47
+ # * +:storage_access_key+ - Base64 String. The access key of the storage account.
48
+ # * +:storage_sas_token+ - String. The signed access signiture for the storage account or one of its service.
49
+ # * +:storage_blob_host+ - String. Specified Blob serivce endpoint or hostname
50
+ # * +:storage_table_host+ - String. Specified Table serivce endpoint or hostname
51
+ # * +:storage_queue_host+ - String. Specified Queue serivce endpoint or hostname
52
+ # * +:storage_dns_suffix+ - String. The suffix of a regional Storage Serivce, to
53
+ # * +:default_endpoints_protocol+ - String. http or https
54
+ # * +:use_path_style_uri+ - String. Whether use path style URI for specified endpoints
55
+ # * +:ca_file+ - String. File path of the CA file if having issue with SSL
56
+ #
57
+ # The valid set of options inlcude:
58
+ # * Storage Emulator: +:use_development_storage+ required, +:development_storage_proxy_uri+ optionally
59
+ # * Storage account name and key: +:storage_account_name+ and +:storage_access_key+ required, set +:storage_dns_suffix+ necessarily
60
+ # * Storage account name and SAS token: +:storage_account_name+ and +:storage_sas_token+ required, set +:storage_dns_suffix+ necessarily
61
+ # * Specified hosts and SAS token: At least one of the service host and SAS token. It's up to user to ensure the SAS token is suitable for the serivce
62
+ # * Anonymous Blob: only +:storage_blob_host+, if it is to only access blobs within a container
63
+ #
64
+ # Additional notes:
65
+ # * Specified hosts can be set when use account name with access key or sas token
66
+ # * +:default_endpoints_protocol+ can be set if the scheme is not specified in hosts
67
+ # * Storage emulator always use path style URI
68
+ #
69
+ # When empty options are given, it will try to read settings from Environment Variables. Refer to [Azure::Storage::ClientOptions.env_vars_mapping] for the mapping relationship
70
+ #
71
+ # @return [Azure::Storage::Client]
72
+ def reset!(options = {})
73
+ if options.is_a? String
74
+ options = parse_connection_string(options)
75
+ end
76
+
77
+ options = load_env if options.length == 0
78
+ @ca_file = options.delete(:ca_file)
79
+ @options = filter(options)
80
+ self.send(:reset_config!, @options) if self.respond_to?(:reset_config!)
81
+ self
82
+ end
83
+
84
+ # The options after validated and normalized
85
+ #
86
+ # @return [Hash]
87
+ def options
88
+ @options ||= {}
89
+ end
90
+
91
+ # The valid options for the storage client
92
+ #
93
+ # @return [Array]
94
+ def self.valid_options
95
+ @valid_options ||= [
96
+ :use_development_storage,
97
+ :development_storage_proxy_uri,
98
+ :storage_account_name,
99
+ :storage_access_key,
100
+ :storage_connection_string,
101
+ :storage_sas_token,
102
+ :storage_blob_host,
103
+ :storage_table_host,
104
+ :storage_queue_host,
105
+ :storage_file_host,
106
+ :storage_dns_suffix,
107
+ :default_endpoints_protocol,
108
+ :use_path_style_uri
109
+ ]
110
+ end
111
+
112
+ # The mapping between Storage Environment Variables and the options name
113
+ #
114
+ # @return [Hash]
115
+ def self.env_vars_mapping
116
+ @env_vars_mapping ||= {
117
+ 'EMULATED' => :use_development_storage,
118
+ 'AZURE_STORAGE_ACCOUNT' => :storage_account_name,
119
+ 'AZURE_STORAGE_ACCESS_KEY' => :storage_access_key,
120
+ 'AZURE_STORAGE_CONNECTION_STRING' => :storage_connection_string,
121
+ 'AZURE_STORAGE_BLOB_HOST' => :storage_blob_host,
122
+ 'AZURE_STORAGE_TABLE_HOST' => :storage_table_host,
123
+ 'AZURE_STORAGE_QUEUE_HOST' => :storage_queue_host,
124
+ 'AZURE_STORAGE_FILE_HOST' => :storage_file_host,
125
+ 'AZURE_STORAGE_SAS_TOKEN' => :storage_sas_token,
126
+ 'AZURE_STORAGE_DNS_SUFFIX' => :storage_dns_suffix
127
+ }
128
+ end
129
+
130
+ # The mapping between Storage Connection String items and the options name
131
+ #
132
+ # @return [Hash]
133
+ def self.connection_string_mapping
134
+ @connection_string_mapping ||= {
135
+ 'UseDevelopmentStorage' => :use_development_storage,
136
+ 'DevelopmentStorageProxyUri' => :development_storage_proxy_uri,
137
+ 'DefaultEndpointsProtocol' => :default_endpoints_protocol,
138
+ 'AccountName' => :storage_account_name,
139
+ 'AccountKey' => :storage_access_key,
140
+ 'BlobEndpoint' => :storage_blob_host,
141
+ 'TableEndpoint' => :storage_table_host,
142
+ 'QueueEndpoint' => :storage_queue_host,
143
+ 'FileEndpoint' => :storage_file_host,
144
+ 'SharedAccessSignature' => :storage_sas_token,
145
+ 'EndpointSuffix' => :storage_dns_suffix
146
+ }
147
+ end
148
+
149
+ private
150
+
151
+ # Check if this client is configured with the same options
152
+ def same_options?(opts)
153
+ opts.hash == input.hash
154
+ end
155
+
156
+ def method_missing(method_name)
157
+ return super unless options.key? method_name
158
+ options[method_name]
159
+ end
160
+
161
+ def filter(opts={})
162
+ results = {}
163
+
164
+ # P1 - develpoment storage
165
+ begin
166
+ results = validated_options(opts,
167
+ :required => [:use_development_storage],
168
+ :optional => [:development_storage_proxy_uri])
169
+ results[:use_development_storage] = true
170
+ proxy_uri = results[:development_storage_proxy_uri] ||= StorageServiceClientConstants::DEV_STORE_URI
171
+ results.merge!({:storage_account_name => StorageServiceClientConstants::DEVSTORE_STORAGE_ACCOUNT,
172
+ :storage_access_key => StorageServiceClientConstants::DEVSTORE_STORAGE_ACCESS_KEY,
173
+ :storage_blob_host => "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_BLOB_HOST_PORT}",
174
+ :storage_table_host => "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_TABLE_HOST_PORT}",
175
+ :storage_queue_host => "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_QUEUE_HOST_PORT}",
176
+ :storage_file_host => "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_FILE_HOST_PORT}",
177
+ :use_path_style_uri => true})
178
+ return results
179
+ rescue InvalidOptionsError => e
180
+ end
181
+
182
+ # P2 - explicit hosts with account connection string
183
+ begin
184
+ results = validated_options(opts,
185
+ :required => [:storage_connection_string],
186
+ :optional => [:use_path_style_uri])
187
+ results[:use_path_style_uri] = results.key?(:use_path_style_uri)
188
+ normalize_hosts(results)
189
+ return results
190
+ rescue InvalidOptionsError => e
191
+ end
192
+
193
+ # P3 - account name and key or sas with default hosts or an end suffix
194
+ begin
195
+ results = validated_options(opts,
196
+ :required => [:storage_account_name],
197
+ :only_one => [:storage_access_key, :storage_sas_token],
198
+ :optional => [:default_endpoints_protocol, :storage_dns_suffix])
199
+ protocol = results[:default_endpoints_protocol] ||= StorageServiceClientConstants::DEFAULT_PROTOCOL
200
+ suffix = results[:storage_dns_suffix] ||= StorageServiceClientConstants::DEFAULT_ENDPOINT_SUFFIX
201
+ account = results[:storage_account_name]
202
+ results.merge!({:storage_blob_host => "#{protocol}://#{account}.#{ServiceType::BLOB}.#{suffix}",
203
+ :storage_table_host => "#{protocol}://#{account}.#{ServiceType::TABLE}.#{suffix}",
204
+ :storage_queue_host => "#{protocol}://#{account}.#{ServiceType::QUEUE}.#{suffix}",
205
+ :storage_file_host => "#{protocol}://#{account}.#{ServiceType::FILE}.#{suffix}",
206
+ :use_path_style_uri => false})
207
+ return results
208
+ rescue InvalidOptionsError => e
209
+ end
210
+
211
+ # P4 - explicit hosts with account name and key
212
+ begin
213
+ results = validated_options(opts,
214
+ :required => [:storage_account_name, :storage_access_key],
215
+ :at_least_one => [:storage_blob_host, :storage_table_host, :storage_file_host, :storage_queue_host],
216
+ :optional => [:use_path_style_uri, :default_endpoints_protocol])
217
+ results[:use_path_style_uri] = results.key?(:use_path_style_uri)
218
+ normalize_hosts(results)
219
+ return results
220
+ rescue InvalidOptionsError => e
221
+ end
222
+
223
+ # P5 - anonymous or sas only for one or more particular services, options with account name/key + hosts should be already validated in P4
224
+ begin
225
+ results = validated_options(opts,
226
+ :at_least_one => [:storage_blob_host, :storage_table_host, :storage_file_host, :storage_queue_host],
227
+ :optional => [:use_path_style_uri, :default_endpoints_protocol, :storage_sas_token])
228
+ results[:use_path_style_uri] = results.key?(:use_path_style_uri)
229
+ normalize_hosts(results)
230
+ return results
231
+ rescue InvalidOptionsError => e
232
+ end
233
+
234
+ raise InvalidOptionsError,"options provided are not valid set: #{options}" # wrong opts if move to this line
235
+ end
236
+
237
+ def normalize_hosts(options)
238
+ if options[:default_endpoints_protocol]
239
+ [:storage_blob_host, :storage_table_host, :storage_file_host, :storage_queue_host].each do |k|
240
+ if options[k]
241
+ raise InvalidOptionsError,'Explict host cannot contain scheme if default_endpoints_protocol is set.' if options[k] =~ /^https?/
242
+ options[k] = "#{options[:default_endpoints_protocol]}://#{options[k]}"
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ def is_base64_encoded
249
+ Proc.new do |i|
250
+ i.is_a?(String) && i =~ /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$/
251
+ end
252
+ end
253
+
254
+ def is_url
255
+ Proc.new do |i|
256
+ i = 'http://'+i unless i =~ /\Ahttps?:\/\//
257
+ i =~ URI.regexp(['http', 'https'])
258
+ end
259
+ end
260
+
261
+ def is_true
262
+ Proc.new { |i| i == true || (i.is_a?(String) && i.downcase == 'true') }
263
+ end
264
+
265
+ def is_non_empty_string
266
+ Proc.new { |i| i && i.is_a?(String) && i.strip.length }
267
+ end
268
+
269
+ def validated_options(opts, requirements = {})
270
+ raise InvalidOptionsError,'nil is not allowed for option\'s value' if opts.values.any? { |v| v == nil }
271
+ required = requirements[:required] || []
272
+ at_least_one = requirements[:at_least_one] || []
273
+ only_one = requirements[:only_one] || []
274
+ optional = requirements[:optional] || []
275
+
276
+ raise InvalidOptionsError,"Not all required keys are provided: #{required}" if required.any? { |k| !opts.key? k}
277
+ raise InvalidOptionsError,"Only one of #{only_one} is required" unless only_one.length == 0 || only_one.count { |k| opts.key? k} == 1
278
+ raise InvalidOptionsError,"At least one of #{at_least_one} is required" unless at_least_one.length == 0 || at_least_one.any? { |k| opts.key? k}
279
+
280
+ @@option_validators ||= {
281
+ :use_development_storage => is_true,
282
+ :development_storage_proxy_uri => is_url,
283
+ :storage_account_name => lambda { |i| i.is_a?(String) },
284
+ :storage_access_key => is_base64_encoded,
285
+ :storage_sas_token => lambda { |i| i.is_a?(String) },
286
+ :storage_blob_host => is_url,
287
+ :storage_table_host => is_url,
288
+ :storage_queue_host => is_url,
289
+ :storage_file_host => is_url,
290
+ :storage_dns_suffix => is_url,
291
+ :default_endpoints_protocol => lambda { |i| ['http', 'https'].include? i.downcase },
292
+ :use_path_style_uri => is_true
293
+ }
294
+
295
+ valid_options = required + at_least_one + only_one + optional
296
+ results = {}
297
+ opts.each do |k,v|
298
+ raise InvalidOptionsError,"#{k} is not included in valid options" unless valid_options.length == 0 || valid_options.include?(k)
299
+ unless @@option_validators.key?(k) && @@option_validators[k].call(v)
300
+ raise InvalidOptionsError,"#{k} is invalid"
301
+ end
302
+ results[k] = v
303
+ end
304
+ results
305
+ end
306
+
307
+ def load_env
308
+ cs = ENV['AZURE_STORAGE_CONNECTION_STRING']
309
+ return parse_connection_string(cs) if cs
310
+
311
+ opts = {}
312
+ ClientOptions.env_vars_mapping.each { |k,v| opts[v] = ENV[k] if ENV[k] }
313
+ opts
314
+ end
315
+
316
+ def parse_connection_string(connection_string)
317
+ opts = {}
318
+ cs_items = connection_string.split(';').each do |i|
319
+ e = i.index('=')
320
+ raise InvalidConnectionStringError,SR::INVALID_CONNECTION_STRING if e < 0 || e == i.length - 1
321
+ key,value = i[0..e-1],i[e+1..i.length-1]
322
+ raise InvalidConnectionStringError, SR::INVALID_CONNECTION_STRING_BAD_KEY % key unless ClientOptions.connection_string_mapping.key? key
323
+ raise InvalidConnectionStringError, SR::INVALID_CONNECTION_STRING_EMPTY_KEY % key if value.length == 0
324
+ raise InvalidConnectionStringError, SR::INVALID_CONNECTION_STRING_DUPLICATE_KEY % key if opts.key? key
325
+ opts[ClientOptions.connection_string_mapping[key]] = value
326
+ end
327
+ raise InvalidConnectionStringError,SR::INVALID_CONNECTION_STRING if opts.length == 0
328
+
329
+ opts
330
+ end
331
+
332
+ end
333
+
334
+ end