azure-storage-blob2 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,720 @@
1
+ # frozen_string_literal: true
2
+
3
+ #-------------------------------------------------------------------------
4
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
5
+ #
6
+ # The MIT License(MIT)
7
+
8
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ # of this software and associated documentation files(the "Software"), to deal
10
+ # in the Software without restriction, including without limitation the rights
11
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
12
+ # copies of the Software, and to permit persons to whom the Software is
13
+ # furnished to do so, subject to the following conditions :
14
+
15
+ # The above copyright notice and this permission notice shall be included in
16
+ # all copies or substantial portions of the Software.
17
+
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
21
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ # THE SOFTWARE.
25
+ #--------------------------------------------------------------------------
26
+ require "azure/storage/blob/page"
27
+ require "azure/storage/blob/block"
28
+ require "azure/storage/blob/append"
29
+ require "azure/storage/blob/blob"
30
+
31
+ module Azure::Storage
32
+ include Azure::Storage::Common::Service
33
+ StorageService = Azure::Storage::Common::Service::StorageService
34
+
35
+ module Blob
36
+ class BlobService < StorageService
37
+ include Azure::Storage::Common::Core::Utility
38
+ include Azure::Storage::Blob
39
+ include Azure::Storage::Blob::Container
40
+
41
+ class << self
42
+ # Public: Creates an instance of [Azure::Storage::Blob::BlobService]
43
+ #
44
+ # ==== Attributes
45
+ #
46
+ # * +options+ - Hash. Optional parameters.
47
+ #
48
+ # ==== Options
49
+ #
50
+ # Accepted key/value pairs in options parameter are:
51
+ #
52
+ # * +:use_development_storage+ - TrueClass|FalseClass. Whether to use storage emulator.
53
+ # * +:development_storage_proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost.
54
+ # * +:storage_account_name+ - String. The name of the storage account.
55
+ # * +:storage_access_key+ - Base64 String. The access key of the storage account.
56
+ # * +:storage_sas_token+ - String. The signed access signature for the storage account or one of its service.
57
+ # * +:storage_blob_host+ - String. Specified Blob service endpoint or hostname
58
+ # * +:storage_dns_suffix+ - String. The suffix of a regional Storage Service, to
59
+ # * +:default_endpoints_protocol+ - String. http or https
60
+ # * +:use_path_style_uri+ - String. Whether use path style URI for specified endpoints
61
+ # * +:ca_file+ - String. File path of the CA file if having issue with SSL
62
+ # * +:user_agent_prefix+ - String. The user agent prefix that can identify the application calls the library
63
+ #
64
+ # The valid set of options include:
65
+ # * Storage Emulator: +:use_development_storage+ required, +:development_storage_proxy_uri+ optionally
66
+ # * Storage account name and key: +:storage_account_name+ and +:storage_access_key+ required, set +:storage_dns_suffix+ necessarily
67
+ # * Storage account name and SAS token: +:storage_account_name+ and +:storage_sas_token+ required, set +:storage_dns_suffix+ necessarily
68
+ # * 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
69
+ # * Anonymous Blob: only +:storage_blob_host+, if it is to only access blobs within a container
70
+ #
71
+ # Additional notes:
72
+ # * Specified hosts can be set when use account name with access key or sas token
73
+ # * +:default_endpoints_protocol+ can be set if the scheme is not specified in hosts
74
+ # * Storage emulator always use path style URI
75
+ # * +:ca_file+ is independent.
76
+ #
77
+ # When empty options are given, it will try to read settings from Environment Variables. Refer to [Azure::Storage::Common::ClientOptions.env_vars_mapping] for the mapping relationship
78
+ #
79
+ # @return [Azure::Storage::Blob::BlobService]
80
+ def create(options = {}, &block)
81
+ service_options = { client: Azure::Storage::Common::Client::create(options, &block), api_version: Azure::Storage::Blob::Default::STG_VERSION }
82
+ service_options[:user_agent_prefix] = options[:user_agent_prefix] if options[:user_agent_prefix]
83
+ Azure::Storage::Blob::BlobService.new(service_options, &block)
84
+ end
85
+
86
+ # Public: Creates an instance of [Azure::Storage::Blob::BlobService] with Storage Emulator
87
+ #
88
+ # ==== Attributes
89
+ #
90
+ # * +proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost.
91
+ #
92
+ # @return [Azure::Storage::Blob::BlobService]
93
+ def create_development(proxy_uri = nil, &block)
94
+ service_options = { client: Azure::Storage::Common::Client::create_development(proxy_uri, &block), api_version: Azure::Storage::Blob::Default::STG_VERSION }
95
+ Azure::Storage::Blob::BlobService.new(service_options, &block)
96
+ end
97
+
98
+ # Public: Creates an instance of [Azure::Storage::Blob::BlobService] from Environment Variables
99
+ #
100
+ # @return [Azure::Storage::Blob::BlobService]
101
+ def create_from_env(&block)
102
+ service_options = { client: Azure::Storage::Common::Client::create_from_env(&block), api_version: Azure::Storage::Blob::Default::STG_VERSION }
103
+ Azure::Storage::Blob::BlobService.new(service_options, &block)
104
+ end
105
+
106
+ # Public: Creates an instance of [Azure::Storage::Blob::BlobService] from Environment Variables
107
+ #
108
+ # ==== Attributes
109
+ #
110
+ # * +connection_string+ - String. Please refer to https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/.
111
+ #
112
+ # @return [Azure::Storage::Blob::BlobService]
113
+ def create_from_connection_string(connection_string, &block)
114
+ service_options = { client: Azure::Storage::Common::Client::create_from_connection_string(connection_string, &block), api_version: Azure::Storage::Blob::Default::STG_VERSION }
115
+ Azure::Storage::Blob::BlobService.new(service_options, &block)
116
+ end
117
+ end
118
+
119
+ # Public: Initializes an instance of [Azure::Storage::Blob::BlobService]
120
+ #
121
+ # ==== Attributes
122
+ #
123
+ # * +options+ - Hash. Optional parameters.
124
+ #
125
+ # ==== Options
126
+ #
127
+ # Accepted key/value pairs in options parameter are:
128
+ #
129
+ # * +:use_development_storage+ - TrueClass|FalseClass. Whether to use storage emulator.
130
+ # * +:development_storage_proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost.
131
+ # * +:storage_connection_string+ - String. The storage connection string.
132
+ # * +:storage_account_name+ - String. The name of the storage account.
133
+ # * +:storage_access_key+ - Base64 String. The access key of the storage account.
134
+ # * +:storage_sas_token+ - String. The signed access signature for the storage account or one of its service.
135
+ # * +:storage_blob_host+ - String. Specified Blob serivce endpoint or hostname
136
+ # * +:storage_dns_suffix+ - String. The suffix of a regional Storage Serivce, to
137
+ # * +:default_endpoints_protocol+ - String. http or https
138
+ # * +:use_path_style_uri+ - String. Whether use path style URI for specified endpoints
139
+ # * +:ca_file+ - String. File path of the CA file if having issue with SSL
140
+ # * +:ssl_version+ - Symbol. The ssl version to be used, sample: :TLSv1_1, :TLSv1_2, for the details, see https://github.com/ruby/openssl/blob/master/lib/openssl/ssl.rb
141
+ # * +:ssl_min_version+ - Symbol. The min ssl version supported, only supported in Ruby 2.5+
142
+ # * +:ssl_max_version+ - Symbol. The max ssl version supported, only supported in Ruby 2.5+
143
+ # * +:user_agent_prefix+ - String. The user agent prefix that can identify the application calls the library
144
+ # * +:client+ - Azure::Storage::Common::Client. The common client used to initalize the service.
145
+ #
146
+ # The valid set of options include:
147
+ # * Storage Emulator: +:use_development_storage+ required, +:development_storage_proxy_uri+ optionally
148
+ # * Storage account name and key: +:storage_account_name+ and +:storage_access_key+ required, set +:storage_dns_suffix+ necessarily
149
+ # * Storage account name and SAS token: +:storage_account_name+ and +:storage_sas_token+ required, set +:storage_dns_suffix+ necessarily
150
+ # * 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
151
+ # * Azure::Storage::Common::Client: The common client used to initalize the service. This client can be initalized and used repeatedly.
152
+ # * Anonymous Blob: only +:storage_blob_host+, if it is to only access blobs within a container
153
+ #
154
+ # Additional notes:
155
+ # * Specified hosts can be set when use account name with access key or sas token
156
+ # * +:default_endpoints_protocol+ can be set if the scheme is not specified in hosts
157
+ # * Storage emulator always use path style URI
158
+ # * +:ca_file+ is independent.
159
+ #
160
+ # When empty options are given, it will try to read settings from Environment Variables. Refer to [Azure::Storage::Common::ClientOptions.env_vars_mapping] for the mapping relationship
161
+ def initialize(options = {}, &block)
162
+ service_options = options.clone
163
+ client_config = service_options[:client] ||= Azure::Storage::Common::Client::create(service_options, &block)
164
+ @user_agent_prefix = service_options[:user_agent_prefix] if service_options[:user_agent_prefix]
165
+ @api_version = service_options[:api_version] || Azure::Storage::Blob::Default::STG_VERSION
166
+ signer = service_options[:signer] || client_config.signer || Azure::Storage::Common::Core::Auth::SharedKey.new(client_config.storage_account_name, client_config.storage_access_key)
167
+ signer.api_ver = @api_version if signer.is_a? Azure::Storage::Common::Core::Auth::SharedAccessSignatureSigner
168
+ super(signer, client_config.storage_account_name, service_options, &block)
169
+ @storage_service_host[:primary] = client.storage_blob_host
170
+ @storage_service_host[:secondary] = client.storage_blob_host true
171
+ end
172
+
173
+ def call(method, uri, body = nil, headers = {}, options = {})
174
+ content_type = get_or_apply_content_type(body, headers[Azure::Storage::Common::HeaderConstants::BLOB_CONTENT_TYPE])
175
+ headers[Azure::Storage::Common::HeaderConstants::BLOB_CONTENT_TYPE] = content_type if content_type
176
+
177
+ headers["x-ms-version"] = @api_version ? @api_version : Default::STG_VERSION
178
+ headers["User-Agent"] = @user_agent_prefix ? "#{@user_agent_prefix}; #{Default::USER_AGENT}" : Default::USER_AGENT
179
+ response = super
180
+
181
+ # Force the response.body to the content charset of specified in the header.
182
+ # Content-Type is echo'd back for the blob and is used to store the encoding of the octet stream
183
+ if !response.nil? && !response.body.nil? && response.headers["Content-Type"]
184
+ charset = parse_charset_from_content_type(response.headers["Content-Type"])
185
+ response.body.force_encoding(charset) if charset && charset.length > 0
186
+ end
187
+
188
+ response
189
+ end
190
+
191
+ # Public: Get a list of Containers from the server.
192
+ #
193
+ # ==== Attributes
194
+ #
195
+ # * +options+ - Hash. Optional parameters.
196
+ #
197
+ # ==== Options
198
+ #
199
+ # Accepted key/value pairs in options parameter are:
200
+ # * +:prefix+ - String. Filters the results to return only containers
201
+ # whose name begins with the specified prefix. (optional)
202
+ #
203
+ # * +:marker+ - String. An identifier the specifies the portion of the
204
+ # list to be returned. This value comes from the property
205
+ # Azure::Storage::Common::EnumerationResults.continuation_token when there
206
+ # are more containers available than were returned. The
207
+ # marker value may then be used here to request the next set
208
+ # of list items. (optional)
209
+ #
210
+ # * +:max_results+ - Integer. Specifies the maximum number of containers to return.
211
+ # If max_results is not specified, or is a value greater than
212
+ # 5,000, the server will return up to 5,000 items. If it is set
213
+ # to a value less than or equal to zero, the server will return
214
+ # status code 400 (Bad Request). (optional)
215
+ #
216
+ # * +:metadata+ - Boolean. Specifies whether or not to return the container metadata.
217
+ # (optional, Default=false)
218
+ #
219
+ # * +:timeout+ - Integer. A timeout in seconds.
220
+ #
221
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
222
+ # in the analytics logs when storage analytics logging is enabled.
223
+ #
224
+ # * +:location_mode+ - LocationMode. Specifies the location mode used to decide
225
+ # which location the request should be sent to.
226
+ #
227
+ # See: https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
228
+ #
229
+ # NOTE: Metadata requested with the :metadata parameter must have been stored in
230
+ # accordance with the naming restrictions imposed by the 2009-09-19 version of the Blob
231
+ # service. Beginning with that version, all metadata names must adhere to the naming
232
+ # conventions for C# identifiers. See: https://msdn.microsoft.com/en-us/library/aa664670(VS.71).aspx
233
+ #
234
+ # Any metadata with invalid names which were previously stored, will be returned with the
235
+ # key "x-ms-invalid-name" in the metadata hash. This may contain multiple values and be an
236
+ # Array (vs a String if it only contains a single value).
237
+ #
238
+ # Returns an Azure::Storage::Common::EnumerationResults
239
+ #
240
+ def list_containers(options = {})
241
+ query = {}
242
+ if options
243
+ StorageService.with_query query, "prefix", options[:prefix]
244
+ StorageService.with_query query, "marker", options[:marker]
245
+ StorageService.with_query query, "maxresults", options[:max_results].to_s if options[:max_results]
246
+ StorageService.with_query query, "include", "metadata" if options[:metadata] == true
247
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
248
+ end
249
+
250
+ options[:request_location_mode] = Azure::Storage::Common::RequestLocationMode::PRIMARY_OR_SECONDARY
251
+ uri = containers_uri(query, options)
252
+ response = call(:get, uri, nil, {}, options)
253
+
254
+ Serialization.container_enumeration_results_from_xml(response.body)
255
+ end
256
+
257
+ # Public: Obtain a user delegation key for the purpose of signing SAS tokens.
258
+ #
259
+ # ==== Attributes
260
+ #
261
+ # * +start+ - Time. The start time for the user delegation SAS.
262
+ # * +expiry+ - Time. The expiry time of user delegation SAS.
263
+ #
264
+ # See: https://docs.microsoft.com/en-us/rest/api/storageservices/get-user-delegation-key
265
+ #
266
+ # NOTE: A token credential must be present on the service object for this request to succeed.
267
+ # The start and expiry times must be within 7 days of the current time.
268
+ #
269
+ # Returns an Azure::Storage::Common::UserDelegationKey
270
+ #
271
+ def get_user_delegation_key(start, expiry)
272
+ max_delegation_time = Time.now + BlobConstants::MAX_USER_DELEGATION_KEY_SECONDS
273
+ raise ArgumentError, "Start time must be before #{max_delegation_time}" if start > max_delegation_time
274
+ raise ArgumentError, "Expiry time must be before #{max_delegation_time}" if expiry > max_delegation_time
275
+ raise ArgumentError, "Start time must be before expiry time" if start >= expiry
276
+
277
+ body = Serialization.key_info_to_xml(start, expiry)
278
+
279
+ response = call(:post, user_delegation_key_uri, body)
280
+
281
+ Serialization.user_delegation_key_from_xml(response.body)
282
+ end
283
+
284
+ # Protected: Establishes an exclusive write lock on a container or a blob. The lock duration can be 15 to 60 seconds, or can be infinite.
285
+ # To write to a locked container or blob, a client must provide a lease ID.
286
+ #
287
+ # ==== Attributes
288
+ #
289
+ # * +container+ - String. The container name.
290
+ # * +blob+ - String. The blob name.
291
+ # * +options+ - Hash. Optional parameters.
292
+ #
293
+ # ==== Options
294
+ #
295
+ # Accepted key/value pairs in options parameter are:
296
+ # * +:duration+ - Integer. Default -1. Specifies the duration of the lease, in seconds, or negative one (-1)
297
+ # for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. (optional)
298
+ # * +:proposed_lease_id+ - String. Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request)
299
+ # if the proposed lease ID is not in the correct format. (optional)
300
+ # * +:timeout+ - Integer. A timeout in seconds.
301
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
302
+ # in the analytics logs when storage analytics logging is enabled.
303
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
304
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
305
+ # the Blob service returns status code 412 (Precondition Failed).
306
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
307
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
308
+ # the Blob service returns status code 412 (Precondition Failed).
309
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
310
+ # only if the blob's ETag value matches the value specified. If the values do not match,
311
+ # the Blob service returns status code 412 (Precondition Failed).
312
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
313
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
314
+ # the Blob service returns status code 412 (Precondition Failed).
315
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
316
+ # in cross-origin resource sharing headers on the response.
317
+ #
318
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
319
+ #
320
+ # Returns a String of the new unique lease id. While the lease is active, you must include the lease ID with any request
321
+ # to write, or to renew, change, or release the lease.
322
+ #
323
+ protected
324
+ def acquire_lease(container, blob, options = {})
325
+ query = { "comp" => "lease" }
326
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
327
+
328
+ if blob
329
+ uri = blob_uri(container, blob, query)
330
+ else
331
+ uri = container_uri(container, query)
332
+ end
333
+
334
+ duration = -1
335
+ duration = options[:duration] if options[:duration]
336
+
337
+ headers = {}
338
+ StorageService.with_header headers, "x-ms-lease-action", "acquire"
339
+ StorageService.with_header headers, "x-ms-lease-duration", duration.to_s if duration
340
+ StorageService.with_header headers, "x-ms-proposed-lease-id", options[:proposed_lease_id]
341
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
342
+ add_blob_conditional_headers options, headers
343
+
344
+ response = call(:put, uri, nil, headers, options)
345
+ response.headers["x-ms-lease-id"]
346
+ end
347
+
348
+ # Protected: Renews the lease. The lease can be renewed if the lease ID specified on the request matches that
349
+ # associated with the blob. Note that the lease may be renewed even if it has expired as long as the container or blob
350
+ # has not been modified or leased again since the expiration of that lease. When you renew a lease, the
351
+ # lease duration clock resets.
352
+ #
353
+ # ==== Attributes
354
+ #
355
+ # * +container+ - String. The container name.
356
+ # * +blob+ - String. The blob name.
357
+ # * +lease+ - String. The lease id
358
+ # * +options+ - Hash. Optional parameters.
359
+ #
360
+ # ==== Options
361
+ #
362
+ # Accepted key/value pairs in options parameter are:
363
+ # * +:timeout+ - Integer. A timeout in seconds.
364
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
365
+ # in the analytics logs when storage analytics logging is enabled.
366
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to renew the lease
367
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
368
+ # the Blob service returns status code 412 (Precondition Failed).
369
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to renew the lease
370
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
371
+ # the Blob service returns status code 412 (Precondition Failed).
372
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to renew the lease
373
+ # only if the blob's ETag value matches the value specified. If the values do not match,
374
+ # the Blob service returns status code 412 (Precondition Failed).
375
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to renew the lease
376
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
377
+ # the Blob service returns status code 412 (Precondition Failed).
378
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
379
+ # in cross-origin resource sharing headers on the response.
380
+ #
381
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
382
+ #
383
+ # Returns the renewed lease id
384
+ #
385
+ protected
386
+ def renew_lease(container, blob, lease, options = {})
387
+ query = { "comp" => "lease" }
388
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
389
+
390
+ if blob
391
+ uri = blob_uri(container, blob, query)
392
+ else
393
+ uri = container_uri(container, query)
394
+ end
395
+
396
+ headers = {}
397
+ StorageService.with_header headers, "x-ms-lease-action", "renew"
398
+ StorageService.with_header headers, "x-ms-lease-id", lease
399
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
400
+ add_blob_conditional_headers options, headers
401
+
402
+ response = call(:put, uri, nil, headers, options)
403
+ response.headers["x-ms-lease-id"]
404
+ end
405
+
406
+ # Protected: Change the ID of an existing lease.
407
+ #
408
+ # ==== Attributes
409
+ #
410
+ # * +container+ - String. The container name.
411
+ # * +blob+ - String. The blob name.
412
+ # * +lease+ - String. The existing lease id.
413
+ # * +proposed_lease+ - String. Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request)
414
+ # if the proposed lease ID is not in the correct format. (optional).
415
+ # * +options+ - Hash. Optional parameters.
416
+ #
417
+ # ==== Options
418
+ #
419
+ # Accepted key/value pairs in options parameter are:
420
+ # * +:timeout+ - Integer. A timeout in seconds.
421
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
422
+ # in the analytics logs when storage analytics logging is enabled.
423
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to change the lease
424
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
425
+ # the Blob service returns status code 412 (Precondition Failed).
426
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to change the lease
427
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
428
+ # the Blob service returns status code 412 (Precondition Failed).
429
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to change the lease
430
+ # only if the blob's ETag value matches the value specified. If the values do not match,
431
+ # the Blob service returns status code 412 (Precondition Failed).
432
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to change the lease
433
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
434
+ # the Blob service returns status code 412 (Precondition Failed).
435
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
436
+ # in cross-origin resource sharing headers on the response.
437
+ #
438
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
439
+ #
440
+ # Returns a String of the new unique lease id. While the lease is active, you must include the lease ID with any request
441
+ # to write, or to renew, change, or release the lease.
442
+ #
443
+ protected
444
+ def change_lease(container, blob, lease, proposed_lease, options = {})
445
+ query = { "comp" => "lease" }
446
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
447
+
448
+ if blob
449
+ uri = blob_uri(container, blob, query)
450
+ else
451
+ uri = container_uri(container, query)
452
+ end
453
+
454
+ headers = {}
455
+ StorageService.with_header headers, "x-ms-lease-action", "change"
456
+ StorageService.with_header headers, "x-ms-lease-id", lease
457
+ StorageService.with_header headers, "x-ms-proposed-lease-id", proposed_lease
458
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
459
+ add_blob_conditional_headers options, headers
460
+
461
+ response = call(:put, uri, nil, headers, options)
462
+ response.headers["x-ms-lease-id"]
463
+ end
464
+
465
+ # Protected: Releases the lease. The lease may be released if the lease ID specified on the request matches that
466
+ # associated with the container or blob. Releasing the lease allows another client to immediately acquire the lease for
467
+ # the container or blob as soon as the release is complete.
468
+ #
469
+ # ==== Attributes
470
+ #
471
+ # * +container+ - String. The container name.
472
+ # * +blob+ - String. The blob name.
473
+ # * +lease+ - String. The lease id.
474
+ # * +options+ - Hash. Optional parameters.
475
+ #
476
+ # ==== Options
477
+ #
478
+ # Accepted key/value pairs in options parameter are:
479
+ # * +:timeout+ - Integer. A timeout in seconds.
480
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
481
+ # in the analytics logs when storage analytics logging is enabled.
482
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to release the lease
483
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
484
+ # the Blob service returns status code 412 (Precondition Failed).
485
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to release the lease
486
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
487
+ # the Blob service returns status code 412 (Precondition Failed).
488
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to release the lease
489
+ # only if the blob's ETag value matches the value specified. If the values do not match,
490
+ # the Blob service returns status code 412 (Precondition Failed).
491
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to release the lease
492
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
493
+ # the Blob service returns status code 412 (Precondition Failed).
494
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
495
+ # in cross-origin resource sharing headers on the response.
496
+ #
497
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
498
+ #
499
+ # Returns nil on success
500
+ #
501
+ protected
502
+ def release_lease(container, blob, lease, options = {})
503
+ query = { "comp" => "lease" }
504
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
505
+
506
+ if blob
507
+ uri = blob_uri(container, blob, query)
508
+ else
509
+ uri = container_uri(container, query)
510
+ end
511
+
512
+ headers = {}
513
+ StorageService.with_header headers, "x-ms-lease-action", "release"
514
+ StorageService.with_header headers, "x-ms-lease-id", lease
515
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
516
+ add_blob_conditional_headers options, headers
517
+
518
+ call(:put, uri, nil, headers, options)
519
+ nil
520
+ end
521
+
522
+ # Protected: Breaks the lease, if the container or blob has an active lease. Once a lease is broken, it cannot be renewed. Any
523
+ # authorized request can break the lease; the request is not required to specify a matching lease ID. When a
524
+ # lease is broken, the lease break period is allowed to elapse, during which time no lease operation except
525
+ # break and release can be performed on the container or blob. When a lease is successfully broken, the response indicates
526
+ # the interval in seconds until a new lease can be acquired.
527
+ #
528
+ # A lease that has been broken can also be released, in which case another client may immediately acquire the
529
+ # lease on the container or blob.
530
+ #
531
+ # ==== Attributes
532
+ #
533
+ # * +container+ - String. The container name.
534
+ # * +blob+ - String. The blob name.
535
+ # * +options+ - Hash. Optional parameters.
536
+ #
537
+ # ==== Options
538
+ #
539
+ # Accepted key/value pairs in options parameter are:
540
+ # * +:break_period+ - Integer. The proposed duration of seconds that the lease should continue before it is
541
+ # broken, between 0 and 60 seconds. This break period is only used if it is shorter than
542
+ # the time remaining on the lease. If longer, the time remaining on the lease is used. A
543
+ # new lease will not be available before the break period has expired, but the lease may
544
+ # be held for longer than the break period.
545
+ #
546
+ # If this option is not used, a fixed-duration lease breaks after the remaining lease
547
+ # period elapses, and an infinite lease breaks immediately.
548
+ # * +:timeout+ - Integer. A timeout in seconds.
549
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
550
+ # in the analytics logs when storage analytics logging is enabled.
551
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
552
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
553
+ # the Blob service returns status code 412 (Precondition Failed).
554
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
555
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
556
+ # the Blob service returns status code 412 (Precondition Failed).
557
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
558
+ # only if the blob's ETag value matches the value specified. If the values do not match,
559
+ # the Blob service returns status code 412 (Precondition Failed).
560
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
561
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
562
+ # the Blob service returns status code 412 (Precondition Failed).
563
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
564
+ # in cross-origin resource sharing headers on the response.
565
+ #
566
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
567
+ #
568
+ # Returns an Integer of the remaining lease time. This value is the approximate time remaining in the lease
569
+ # period, in seconds. This header is returned only for a successful request to break the lease. If the break
570
+ # is immediate, 0 is returned.
571
+ #
572
+ protected
573
+ def break_lease(container, blob, options = {})
574
+ query = { "comp" => "lease" }
575
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
576
+
577
+ if blob
578
+ uri = blob_uri(container, blob, query)
579
+ else
580
+ uri = container_uri(container, query)
581
+ end
582
+
583
+ headers = {}
584
+ StorageService.with_header headers, "x-ms-lease-action", "break"
585
+ StorageService.with_header headers, "x-ms-lease-break-period", options[:break_period].to_s if options[:break_period]
586
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
587
+ add_blob_conditional_headers options, headers
588
+
589
+ response = call(:put, uri, nil, headers, options)
590
+ response.headers["x-ms-lease-time"].to_i
591
+ end
592
+
593
+ # Protected: Generate the URI for the collection of containers.
594
+ #
595
+ # ==== Attributes
596
+ #
597
+ # * +query+ - A Hash of key => value query parameters.
598
+ #
599
+ # Returns a URI.
600
+ #
601
+ protected
602
+ def containers_uri(query = {}, options = {})
603
+ query = { "comp" => "list" }.merge(query)
604
+ generate_uri("", query, options)
605
+ end
606
+
607
+ # Protected: Generate the URI for the user delegation key.
608
+ #
609
+ # ==== Attributes
610
+ #
611
+ # * +query+ - A Hash of key => value query parameters.
612
+ #
613
+ # Returns a URI.
614
+ #
615
+ protected
616
+ def user_delegation_key_uri(query = {}, options = {})
617
+ query = { :restype => "service", :comp => "userdelegationkey" }.merge(query)
618
+ generate_uri("", query, options)
619
+ end
620
+
621
+ # Protected: Generate the URI for a specific container.
622
+ #
623
+ # ==== Attributes
624
+ #
625
+ # * +name+ - The container name. If this is a URI, we just return this.
626
+ # * +query+ - A Hash of key => value query parameters.
627
+ #
628
+ # Returns a URI.
629
+ #
630
+ protected
631
+ def container_uri(name, query = {}, options = {})
632
+ return name if name.kind_of? ::URI
633
+ query = { "restype" => "container" }.merge(query)
634
+ generate_uri(name, query, options)
635
+ end
636
+
637
+ # Protected: Generate the URI for a specific Blob.
638
+ #
639
+ # ==== Attributes
640
+ #
641
+ # * +container_name+ - String representing the name of the container.
642
+ # * +blob_name+ - String representing the name of the blob.
643
+ # * +query+ - A Hash of key => value query parameters.
644
+ #
645
+ # Returns a URI.
646
+ #
647
+ protected
648
+ def blob_uri(container_name, blob_name, query = {}, options = {})
649
+ if container_name.nil? || container_name.empty?
650
+ path = blob_name
651
+ else
652
+ path = ::File.join(container_name, blob_name)
653
+ end
654
+ options = { encode: true }.merge(options)
655
+ generate_uri(path, query, options)
656
+ end
657
+
658
+ # Adds conditional header with required condition
659
+ #
660
+ # headers - A Hash of HTTP headers
661
+ # options - A Hash of condition name/value pairs
662
+ #
663
+ protected
664
+ def add_blob_conditional_headers(options, headers)
665
+ return unless options
666
+
667
+ # Common conditional headers for blobs: https://msdn.microsoft.com/en-us/library/azure/dd179371.aspx
668
+ StorageService.with_header headers, "If-Modified-Since", options[:if_modified_since]
669
+ StorageService.with_header headers, "If-Unmodified-Since", options[:if_unmodified_since]
670
+ StorageService.with_header headers, "If-Match", options[:if_match]
671
+ StorageService.with_header headers, "If-None-Match", options[:if_none_match]
672
+
673
+ # Conditional headers for copying blob
674
+ StorageService.with_header headers, "If-Modified-Since", options[:dest_if_modified_since]
675
+ StorageService.with_header headers, "If-Unmodified-Since", options[:dest_if_unmodified_since]
676
+ StorageService.with_header headers, "If-Match", options[:dest_if_match]
677
+ StorageService.with_header headers, "If-None-Match", options[:dest_if_none_match]
678
+ StorageService.with_header headers, "x-ms-source-if-modified-since", options[:source_if_modified_since]
679
+ StorageService.with_header headers, "x-ms-source-if-unmodified-since", options[:source_if_unmodified_since]
680
+ StorageService.with_header headers, "x-ms-source-if-match", options[:source_if_match]
681
+ StorageService.with_header headers, "x-ms-source-if-none-match", options[:source_if_none_match]
682
+
683
+ # Conditional headers for page blob
684
+ StorageService.with_header headers, "x-ms-if-sequence-number-le", options[:if_sequence_number_le] if options[:if_sequence_number_le]
685
+ StorageService.with_header headers, "x-ms-if-sequence-number-lt", options[:if_sequence_number_lt] if options[:if_sequence_number_lt]
686
+ StorageService.with_header headers, "x-ms-if-sequence-number-eq", options[:if_sequence_number_eq] if options[:if_sequence_number_eq]
687
+
688
+ # Conditional headers for append blob
689
+ StorageService.with_header headers, "x-ms-blob-condition-maxsize", options[:max_size]
690
+ StorageService.with_header headers, "x-ms-blob-condition-appendpos", options[:append_position]
691
+ end
692
+
693
+ # Get the content type according to the blob content type header and request body.
694
+ #
695
+ # headers - The request body
696
+ # content_type - The request content type
697
+ protected
698
+ def get_or_apply_content_type(body, content_type = nil)
699
+ unless body.nil?
700
+ if (body.is_a? String) && body.encoding.to_s != "ASCII_8BIT" && !body.empty?
701
+ if content_type.nil?
702
+ content_type = "text/plain; charset=#{body.encoding}"
703
+ else
704
+ # Force the request.body to the content encoding of specified in the header
705
+ charset = parse_charset_from_content_type(content_type)
706
+ body.force_encoding(charset) if charset
707
+ end
708
+ else
709
+ # It is either that the body is not a string, or that the body's encoding is ASCII_8BIT, which is a binary
710
+ # In this case, set the content type to be default content-type
711
+ content_type = Default::CONTENT_TYPE_VALUE unless content_type
712
+ end
713
+ end
714
+ content_type
715
+ end
716
+ end
717
+ end
718
+ end
719
+
720
+ Azure::Storage::BlobService = Azure::Storage::Blob::BlobService