azure-storage-blob 1.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,676 +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
- # * +: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
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