azure-storage-blob 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,676 @@
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
+ # * +:user_agent_prefix+ - String. The user agent prefix that can identify the application calls the library
141
+ # * +:client+ - Azure::Storage::Common::Client. The common client used to initalize the service.
142
+ #
143
+ # The valid set of options include:
144
+ # * Storage Emulator: +:use_development_storage+ required, +:development_storage_proxy_uri+ optionally
145
+ # * Storage account name and key: +:storage_account_name+ and +:storage_access_key+ required, set +:storage_dns_suffix+ necessarily
146
+ # * Storage account name and SAS token: +:storage_account_name+ and +:storage_sas_token+ required, set +:storage_dns_suffix+ necessarily
147
+ # * 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
148
+ # * Azure::Storage::Common::Client: The common client used to initalize the service. This client can be initalized and used repeatedly.
149
+ # * Anonymous Blob: only +:storage_blob_host+, if it is to only access blobs within a container
150
+ #
151
+ # Additional notes:
152
+ # * Specified hosts can be set when use account name with access key or sas token
153
+ # * +:default_endpoints_protocol+ can be set if the scheme is not specified in hosts
154
+ # * Storage emulator always use path style URI
155
+ # * +:ca_file+ is independent.
156
+ #
157
+ # 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
158
+ def initialize(options = {}, &block)
159
+ service_options = options.clone
160
+ client_config = service_options[:client] ||= Azure::Storage::Common::Client::create(service_options, &block)
161
+ @user_agent_prefix = service_options[:user_agent_prefix] if service_options[:user_agent_prefix]
162
+ @api_version = service_options[:api_version] || Azure::Storage::Blob::Default::STG_VERSION
163
+ signer = service_options[:signer] || client_config.signer || Azure::Storage::Common::Core::Auth::SharedKey.new(client_config.storage_account_name, client_config.storage_access_key)
164
+ signer.api_ver = @api_version if signer.is_a? Azure::Storage::Common::Core::Auth::SharedAccessSignatureSigner
165
+ super(signer, client_config.storage_account_name, service_options, &block)
166
+ @storage_service_host[:primary] = client.storage_blob_host
167
+ @storage_service_host[:secondary] = client.storage_blob_host true
168
+ end
169
+
170
+ def call(method, uri, body = nil, headers = {}, options = {})
171
+ content_type = get_or_apply_content_type(body, headers[Azure::Storage::Common::HeaderConstants::BLOB_CONTENT_TYPE])
172
+ headers[Azure::Storage::Common::HeaderConstants::BLOB_CONTENT_TYPE] = content_type if content_type
173
+
174
+ headers["x-ms-version"] = @api_version ? @api_version : Default::STG_VERSION
175
+ headers["User-Agent"] = @user_agent_prefix ? "#{@user_agent_prefix}; #{Default::USER_AGENT}" : Default::USER_AGENT
176
+ response = super
177
+
178
+ # Force the response.body to the content charset of specified in the header.
179
+ # Content-Type is echo'd back for the blob and is used to store the encoding of the octet stream
180
+ if !response.nil? && !response.body.nil? && response.headers["Content-Type"]
181
+ charset = parse_charset_from_content_type(response.headers["Content-Type"])
182
+ response.body.force_encoding(charset) if charset && charset.length > 0
183
+ end
184
+
185
+ response
186
+ end
187
+
188
+ # Public: Get a list of Containers from the server.
189
+ #
190
+ # ==== Attributes
191
+ #
192
+ # * +options+ - Hash. Optional parameters.
193
+ #
194
+ # ==== Options
195
+ #
196
+ # Accepted key/value pairs in options parameter are:
197
+ # * +:prefix+ - String. Filters the results to return only containers
198
+ # whose name begins with the specified prefix. (optional)
199
+ #
200
+ # * +:marker+ - String. An identifier the specifies the portion of the
201
+ # list to be returned. This value comes from the property
202
+ # Azure::Storage::Common::EnumerationResults.continuation_token when there
203
+ # are more containers available than were returned. The
204
+ # marker value may then be used here to request the next set
205
+ # of list items. (optional)
206
+ #
207
+ # * +:max_results+ - Integer. Specifies the maximum number of containers to return.
208
+ # If max_results is not specified, or is a value greater than
209
+ # 5,000, the server will return up to 5,000 items. If it is set
210
+ # to a value less than or equal to zero, the server will return
211
+ # status code 400 (Bad Request). (optional)
212
+ #
213
+ # * +:metadata+ - Boolean. Specifies whether or not to return the container metadata.
214
+ # (optional, Default=false)
215
+ #
216
+ # * +:timeout+ - Integer. A timeout in seconds.
217
+ #
218
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
219
+ # in the analytics logs when storage analytics logging is enabled.
220
+ #
221
+ # * +:location_mode+ - LocationMode. Specifies the location mode used to decide
222
+ # which location the request should be sent to.
223
+ #
224
+ # See: https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
225
+ #
226
+ # NOTE: Metadata requested with the :metadata parameter must have been stored in
227
+ # accordance with the naming restrictions imposed by the 2009-09-19 version of the Blob
228
+ # service. Beginning with that version, all metadata names must adhere to the naming
229
+ # conventions for C# identifiers. See: https://msdn.microsoft.com/en-us/library/aa664670(VS.71).aspx
230
+ #
231
+ # Any metadata with invalid names which were previously stored, will be returned with the
232
+ # key "x-ms-invalid-name" in the metadata hash. This may contain multiple values and be an
233
+ # Array (vs a String if it only contains a single value).
234
+ #
235
+ # Returns an Azure::Storage::Common::EnumerationResults
236
+ #
237
+ def list_containers(options = {})
238
+ query = {}
239
+ if options
240
+ StorageService.with_query query, "prefix", options[:prefix]
241
+ StorageService.with_query query, "marker", options[:marker]
242
+ StorageService.with_query query, "maxresults", options[:max_results].to_s if options[:max_results]
243
+ StorageService.with_query query, "include", "metadata" if options[:metadata] == true
244
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
245
+ end
246
+
247
+ options[:request_location_mode] = Azure::Storage::Common::RequestLocationMode::PRIMARY_OR_SECONDARY
248
+ uri = containers_uri(query, options)
249
+ response = call(:get, uri, nil, {}, options)
250
+
251
+ Serialization.container_enumeration_results_from_xml(response.body)
252
+ end
253
+
254
+ # 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.
255
+ # To write to a locked container or blob, a client must provide a lease ID.
256
+ #
257
+ # ==== Attributes
258
+ #
259
+ # * +container+ - String. The container name.
260
+ # * +blob+ - String. The blob name.
261
+ # * +options+ - Hash. Optional parameters.
262
+ #
263
+ # ==== Options
264
+ #
265
+ # Accepted key/value pairs in options parameter are:
266
+ # * +:duration+ - Integer. Default -1. Specifies the duration of the lease, in seconds, or negative one (-1)
267
+ # for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. (optional)
268
+ # * +:proposed_lease_id+ - String. Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request)
269
+ # if the proposed lease ID is not in the correct format. (optional)
270
+ # * +:timeout+ - Integer. A timeout in seconds.
271
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
272
+ # in the analytics logs when storage analytics logging is enabled.
273
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
274
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
275
+ # the Blob service returns status code 412 (Precondition Failed).
276
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
277
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
278
+ # the Blob service returns status code 412 (Precondition Failed).
279
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
280
+ # only if the blob's ETag value matches the value specified. If the values do not match,
281
+ # the Blob service returns status code 412 (Precondition Failed).
282
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
283
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
284
+ # the Blob service returns status code 412 (Precondition Failed).
285
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
286
+ # in cross-origin resource sharing headers on the response.
287
+ #
288
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
289
+ #
290
+ # Returns a String of the new unique lease id. While the lease is active, you must include the lease ID with any request
291
+ # to write, or to renew, change, or release the lease.
292
+ #
293
+ protected
294
+ def acquire_lease(container, blob, options = {})
295
+ query = { "comp" => "lease" }
296
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
297
+
298
+ if blob
299
+ uri = blob_uri(container, blob, query)
300
+ else
301
+ uri = container_uri(container, query)
302
+ end
303
+
304
+ duration = -1
305
+ duration = options[:duration] if options[:duration]
306
+
307
+ headers = {}
308
+ StorageService.with_header headers, "x-ms-lease-action", "acquire"
309
+ StorageService.with_header headers, "x-ms-lease-duration", duration.to_s if duration
310
+ StorageService.with_header headers, "x-ms-proposed-lease-id", options[:proposed_lease_id]
311
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
312
+ add_blob_conditional_headers options, headers
313
+
314
+ response = call(:put, uri, nil, headers, options)
315
+ response.headers["x-ms-lease-id"]
316
+ end
317
+
318
+ # Protected: Renews the lease. The lease can be renewed if the lease ID specified on the request matches that
319
+ # associated with the blob. Note that the lease may be renewed even if it has expired as long as the container or blob
320
+ # has not been modified or leased again since the expiration of that lease. When you renew a lease, the
321
+ # lease duration clock resets.
322
+ #
323
+ # ==== Attributes
324
+ #
325
+ # * +container+ - String. The container name.
326
+ # * +blob+ - String. The blob name.
327
+ # * +lease+ - String. The lease id
328
+ # * +options+ - Hash. Optional parameters.
329
+ #
330
+ # ==== Options
331
+ #
332
+ # Accepted key/value pairs in options parameter are:
333
+ # * +:timeout+ - Integer. A timeout in seconds.
334
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
335
+ # in the analytics logs when storage analytics logging is enabled.
336
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to renew the lease
337
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
338
+ # the Blob service returns status code 412 (Precondition Failed).
339
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to renew the lease
340
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
341
+ # the Blob service returns status code 412 (Precondition Failed).
342
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to renew the lease
343
+ # only if the blob's ETag value matches the value specified. If the values do not match,
344
+ # the Blob service returns status code 412 (Precondition Failed).
345
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to renew the lease
346
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
347
+ # the Blob service returns status code 412 (Precondition Failed).
348
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
349
+ # in cross-origin resource sharing headers on the response.
350
+ #
351
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
352
+ #
353
+ # Returns the renewed lease id
354
+ #
355
+ protected
356
+ def renew_lease(container, blob, lease, options = {})
357
+ query = { "comp" => "lease" }
358
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
359
+
360
+ if blob
361
+ uri = blob_uri(container, blob, query)
362
+ else
363
+ uri = container_uri(container, query)
364
+ end
365
+
366
+ headers = {}
367
+ StorageService.with_header headers, "x-ms-lease-action", "renew"
368
+ StorageService.with_header headers, "x-ms-lease-id", lease
369
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
370
+ add_blob_conditional_headers options, headers
371
+
372
+ response = call(:put, uri, nil, headers, options)
373
+ response.headers["x-ms-lease-id"]
374
+ end
375
+
376
+ # Protected: Change the ID of an existing lease.
377
+ #
378
+ # ==== Attributes
379
+ #
380
+ # * +container+ - String. The container name.
381
+ # * +blob+ - String. The blob name.
382
+ # * +lease+ - String. The existing lease id.
383
+ # * +proposed_lease+ - String. Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request)
384
+ # if the proposed lease ID is not in the correct format. (optional).
385
+ # * +options+ - Hash. Optional parameters.
386
+ #
387
+ # ==== Options
388
+ #
389
+ # Accepted key/value pairs in options parameter are:
390
+ # * +:timeout+ - Integer. A timeout in seconds.
391
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
392
+ # in the analytics logs when storage analytics logging is enabled.
393
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to change the lease
394
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
395
+ # the Blob service returns status code 412 (Precondition Failed).
396
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to change the lease
397
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
398
+ # the Blob service returns status code 412 (Precondition Failed).
399
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to change the lease
400
+ # only if the blob's ETag value matches the value specified. If the values do not match,
401
+ # the Blob service returns status code 412 (Precondition Failed).
402
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to change the lease
403
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
404
+ # the Blob service returns status code 412 (Precondition Failed).
405
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
406
+ # in cross-origin resource sharing headers on the response.
407
+ #
408
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
409
+ #
410
+ # Returns a String of the new unique lease id. While the lease is active, you must include the lease ID with any request
411
+ # to write, or to renew, change, or release the lease.
412
+ #
413
+ protected
414
+ def change_lease(container, blob, lease, proposed_lease, options = {})
415
+ query = { "comp" => "lease" }
416
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
417
+
418
+ if blob
419
+ uri = blob_uri(container, blob, query)
420
+ else
421
+ uri = container_uri(container, query)
422
+ end
423
+
424
+ headers = {}
425
+ StorageService.with_header headers, "x-ms-lease-action", "change"
426
+ StorageService.with_header headers, "x-ms-lease-id", lease
427
+ StorageService.with_header headers, "x-ms-proposed-lease-id", proposed_lease
428
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
429
+ add_blob_conditional_headers options, headers
430
+
431
+ response = call(:put, uri, nil, headers, options)
432
+ response.headers["x-ms-lease-id"]
433
+ end
434
+
435
+ # Protected: Releases the lease. The lease may be released if the lease ID specified on the request matches that
436
+ # associated with the container or blob. Releasing the lease allows another client to immediately acquire the lease for
437
+ # the container or blob as soon as the release is complete.
438
+ #
439
+ # ==== Attributes
440
+ #
441
+ # * +container+ - String. The container name.
442
+ # * +blob+ - String. The blob name.
443
+ # * +lease+ - String. The lease id.
444
+ # * +options+ - Hash. Optional parameters.
445
+ #
446
+ # ==== Options
447
+ #
448
+ # Accepted key/value pairs in options parameter are:
449
+ # * +:timeout+ - Integer. A timeout in seconds.
450
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
451
+ # in the analytics logs when storage analytics logging is enabled.
452
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to release the lease
453
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
454
+ # the Blob service returns status code 412 (Precondition Failed).
455
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to release the lease
456
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
457
+ # the Blob service returns status code 412 (Precondition Failed).
458
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to release the lease
459
+ # only if the blob's ETag value matches the value specified. If the values do not match,
460
+ # the Blob service returns status code 412 (Precondition Failed).
461
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to release the lease
462
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
463
+ # the Blob service returns status code 412 (Precondition Failed).
464
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
465
+ # in cross-origin resource sharing headers on the response.
466
+ #
467
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
468
+ #
469
+ # Returns nil on success
470
+ #
471
+ protected
472
+ def release_lease(container, blob, lease, options = {})
473
+ query = { "comp" => "lease" }
474
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
475
+
476
+ if blob
477
+ uri = blob_uri(container, blob, query)
478
+ else
479
+ uri = container_uri(container, query)
480
+ end
481
+
482
+ headers = {}
483
+ StorageService.with_header headers, "x-ms-lease-action", "release"
484
+ StorageService.with_header headers, "x-ms-lease-id", lease
485
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
486
+ add_blob_conditional_headers options, headers
487
+
488
+ call(:put, uri, nil, headers, options)
489
+ nil
490
+ end
491
+
492
+ # Protected: Breaks the lease, if the container or blob has an active lease. Once a lease is broken, it cannot be renewed. Any
493
+ # authorized request can break the lease; the request is not required to specify a matching lease ID. When a
494
+ # lease is broken, the lease break period is allowed to elapse, during which time no lease operation except
495
+ # break and release can be performed on the container or blob. When a lease is successfully broken, the response indicates
496
+ # the interval in seconds until a new lease can be acquired.
497
+ #
498
+ # A lease that has been broken can also be released, in which case another client may immediately acquire the
499
+ # lease on the container or blob.
500
+ #
501
+ # ==== Attributes
502
+ #
503
+ # * +container+ - String. The container name.
504
+ # * +blob+ - String. The blob name.
505
+ # * +options+ - Hash. Optional parameters.
506
+ #
507
+ # ==== Options
508
+ #
509
+ # Accepted key/value pairs in options parameter are:
510
+ # * +:break_period+ - Integer. The proposed duration of seconds that the lease should continue before it is
511
+ # broken, between 0 and 60 seconds. This break period is only used if it is shorter than
512
+ # the time remaining on the lease. If longer, the time remaining on the lease is used. A
513
+ # new lease will not be available before the break period has expired, but the lease may
514
+ # be held for longer than the break period.
515
+ #
516
+ # If this option is not used, a fixed-duration lease breaks after the remaining lease
517
+ # period elapses, and an infinite lease breaks immediately.
518
+ # * +:timeout+ - Integer. A timeout in seconds.
519
+ # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
520
+ # in the analytics logs when storage analytics logging is enabled.
521
+ # * +:if_modified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
522
+ # only if the blob has been modified since the specified date/time. If the blob has not been modified,
523
+ # the Blob service returns status code 412 (Precondition Failed).
524
+ # * +:if_unmodified_since+ - String. A DateTime value. Specify this conditional header to acquire the lease
525
+ # only if the blob has not been modified since the specified date/time. If the blob has been modified,
526
+ # the Blob service returns status code 412 (Precondition Failed).
527
+ # * +:if_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
528
+ # only if the blob's ETag value matches the value specified. If the values do not match,
529
+ # the Blob service returns status code 412 (Precondition Failed).
530
+ # * +:if_none_match+ - String. An ETag value. Specify an ETag value for this conditional header to acquire the lease
531
+ # only if the blob's ETag value does not match the value specified. If the values are identical,
532
+ # the Blob service returns status code 412 (Precondition Failed).
533
+ # * +:origin+ - String. Optional. Specifies the origin from which the request is issued. The presence of this header results
534
+ # in cross-origin resource sharing headers on the response.
535
+ #
536
+ # See http://msdn.microsoft.com/en-us/library/azure/ee691972.aspx
537
+ #
538
+ # Returns an Integer of the remaining lease time. This value is the approximate time remaining in the lease
539
+ # period, in seconds. This header is returned only for a successful request to break the lease. If the break
540
+ # is immediate, 0 is returned.
541
+ #
542
+ protected
543
+ def break_lease(container, blob, options = {})
544
+ query = { "comp" => "lease" }
545
+ StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout]
546
+
547
+ if blob
548
+ uri = blob_uri(container, blob, query)
549
+ else
550
+ uri = container_uri(container, query)
551
+ end
552
+
553
+ headers = {}
554
+ StorageService.with_header headers, "x-ms-lease-action", "break"
555
+ StorageService.with_header headers, "x-ms-lease-break-period", options[:break_period].to_s if options[:break_period]
556
+ StorageService.with_header headers, "Origin", options[:origin].to_s if options[:origin]
557
+ add_blob_conditional_headers options, headers
558
+
559
+ response = call(:put, uri, nil, headers, options)
560
+ response.headers["x-ms-lease-time"].to_i
561
+ end
562
+
563
+ # Protected: Generate the URI for the collection of containers.
564
+ #
565
+ # ==== Attributes
566
+ #
567
+ # * +query+ - A Hash of key => value query parameters.
568
+ #
569
+ # Returns a URI.
570
+ #
571
+ protected
572
+ def containers_uri(query = {}, options = {})
573
+ query = { "comp" => "list" }.merge(query)
574
+ generate_uri("", query, options)
575
+ end
576
+
577
+ # Protected: Generate the URI for a specific container.
578
+ #
579
+ # ==== Attributes
580
+ #
581
+ # * +name+ - The container name. If this is a URI, we just return this.
582
+ # * +query+ - A Hash of key => value query parameters.
583
+ #
584
+ # Returns a URI.
585
+ #
586
+ protected
587
+ def container_uri(name, query = {}, options = {})
588
+ return name if name.kind_of? ::URI
589
+ query = { "restype" => "container" }.merge(query)
590
+ generate_uri(name, query, options)
591
+ end
592
+
593
+ # Protected: Generate the URI for a specific Blob.
594
+ #
595
+ # ==== Attributes
596
+ #
597
+ # * +container_name+ - String representing the name of the container.
598
+ # * +blob_name+ - String representing the name of the blob.
599
+ # * +query+ - A Hash of key => value query parameters.
600
+ #
601
+ # Returns a URI.
602
+ #
603
+ protected
604
+ def blob_uri(container_name, blob_name, query = {}, options = {})
605
+ if container_name.nil? || container_name.empty?
606
+ path = blob_name
607
+ else
608
+ path = ::File.join(container_name, blob_name)
609
+ end
610
+ options = { encode: true }.merge(options)
611
+ generate_uri(path, query, options)
612
+ end
613
+
614
+ # Adds conditional header with required condition
615
+ #
616
+ # headers - A Hash of HTTP headers
617
+ # options - A Hash of condition name/value pairs
618
+ #
619
+ protected
620
+ def add_blob_conditional_headers(options, headers)
621
+ return unless options
622
+
623
+ # Common conditional headers for blobs: https://msdn.microsoft.com/en-us/library/azure/dd179371.aspx
624
+ StorageService.with_header headers, "If-Modified-Since", options[:if_modified_since]
625
+ StorageService.with_header headers, "If-Unmodified-Since", options[:if_unmodified_since]
626
+ StorageService.with_header headers, "If-Match", options[:if_match]
627
+ StorageService.with_header headers, "If-None-Match", options[:if_none_match]
628
+
629
+ # Conditional headers for copying blob
630
+ StorageService.with_header headers, "If-Modified-Since", options[:dest_if_modified_since]
631
+ StorageService.with_header headers, "If-Unmodified-Since", options[:dest_if_unmodified_since]
632
+ StorageService.with_header headers, "If-Match", options[:dest_if_match]
633
+ StorageService.with_header headers, "If-None-Match", options[:dest_if_none_match]
634
+ StorageService.with_header headers, "x-ms-source-if-modified-since", options[:source_if_modified_since]
635
+ StorageService.with_header headers, "x-ms-source-if-unmodified-since", options[:source_if_unmodified_since]
636
+ StorageService.with_header headers, "x-ms-source-if-match", options[:source_if_match]
637
+ StorageService.with_header headers, "x-ms-source-if-none-match", options[:source_if_none_match]
638
+
639
+ # Conditional headers for page blob
640
+ StorageService.with_header headers, "x-ms-if-sequence-number-le", options[:if_sequence_number_le] if options[:if_sequence_number_le]
641
+ StorageService.with_header headers, "x-ms-if-sequence-number-lt", options[:if_sequence_number_lt] if options[:if_sequence_number_lt]
642
+ StorageService.with_header headers, "x-ms-if-sequence-number-eq", options[:if_sequence_number_eq] if options[:if_sequence_number_eq]
643
+
644
+ # Conditional headers for append blob
645
+ StorageService.with_header headers, "x-ms-blob-condition-maxsize", options[:max_size]
646
+ StorageService.with_header headers, "x-ms-blob-condition-appendpos", options[:append_position]
647
+ end
648
+
649
+ # Get the content type according to the blob content type header and request body.
650
+ #
651
+ # headers - The request body
652
+ # content_type - The request content type
653
+ protected
654
+ def get_or_apply_content_type(body, content_type = nil)
655
+ unless body.nil?
656
+ if (body.is_a? String) && body.encoding.to_s != "ASCII_8BIT" && !body.empty?
657
+ if content_type.nil?
658
+ content_type = "text/plain; charset=#{body.encoding}"
659
+ else
660
+ # Force the request.body to the content encoding of specified in the header
661
+ charset = parse_charset_from_content_type(content_type)
662
+ body.force_encoding(charset) if charset
663
+ end
664
+ else
665
+ # It is either that the body is not a string, or that the body's encoding is ASCII_8BIT, which is a binary
666
+ # In this case, set the content type to be default content-type
667
+ content_type = Default::CONTENT_TYPE_VALUE unless content_type
668
+ end
669
+ end
670
+ content_type
671
+ end
672
+ end
673
+ end
674
+ end
675
+
676
+ Azure::Storage::BlobService = Azure::Storage::Blob::BlobService