azure-storage-blob 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,323 +1,348 @@
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 "base64"
27
-
28
- module Azure::Storage
29
- module Blob
30
- module Serialization
31
- include Azure::Storage::Common::Service::Serialization
32
-
33
- def self.container_enumeration_results_from_xml(xml)
34
- xml = slopify(xml)
35
- expect_node("EnumerationResults", xml)
36
-
37
- results = enumeration_results_from_xml(xml, Azure::Storage::Common::Service::EnumerationResults.new)
38
-
39
- return results unless (xml > "Containers").any? && ((xml > "Containers") > "Container").any?
40
-
41
- if xml.Containers.Container.count == 0
42
- results.push(container_from_xml(xml.Containers.Container))
43
- else
44
- xml.Containers.Container.each { |container_node|
45
- results.push(container_from_xml(container_node))
46
- }
47
- end
48
-
49
- results
50
- end
51
-
52
- def self.container_from_xml(xml)
53
- xml = slopify(xml)
54
- expect_node("Container", xml)
55
-
56
- Container::Container.new do |container|
57
- container.name = xml.Name.text if (xml > "Name").any?
58
- container.properties = container_properties_from_xml(xml.Properties) if (xml > "Properties").any?
59
- container.metadata = metadata_from_xml(xml.Metadata) if (xml > "Metadata").any?
60
- container.public_access_level = public_access_level_from_properties_xml(xml.Properties) if (xml > "Properties").any?
61
- end
62
- end
63
-
64
- def self.container_from_headers(headers)
65
- Container::Container.new do |container|
66
- container.properties = container_properties_from_headers(headers)
67
- container.public_access_level = public_access_level_from_headers(headers)
68
- container.metadata = metadata_from_headers(headers)
69
- end
70
- end
71
-
72
- def self.container_properties_from_xml(xml)
73
- xml = slopify(xml)
74
- expect_node("Properties", xml)
75
-
76
- props = {}
77
-
78
- props[:last_modified] = (xml > "Last-Modified").text if (xml > "Last-Modified").any?
79
- props[:etag] = xml.Etag.text if (xml > "Etag").any?
80
- props[:lease_status] = xml.LeaseStatus.text if (xml > "LeaseStatus").any?
81
- props[:lease_state] = xml.LeaseState.text if (xml > "LeaseState").any?
82
- props[:lease_duration] = xml.LeaseDuration.text if (xml > "LeaseDuration").any?
83
-
84
- props
85
- end
86
-
87
- def self.container_properties_from_headers(headers)
88
- props = {}
89
-
90
- props[:last_modified] = headers["Last-Modified"]
91
- props[:etag] = headers["Etag"]
92
- props[:lease_status] = headers["x-ms-lease-status"]
93
- props[:lease_state] = headers["x-ms-lease-state"]
94
- props[:lease_duration] = headers["x-ms-lease-duration"]
95
-
96
- props
97
- end
98
-
99
- def self.public_access_level_from_headers(headers)
100
- headers["x-ms-blob-public-access"]
101
- end
102
-
103
- def self.public_access_level_from_properties_xml(xml)
104
- (xml > "PublicAccess").any? ? xml.PublicAccess.text : nil
105
- end
106
-
107
- def self.blob_enumeration_results_from_xml(xml)
108
- xml = slopify(xml)
109
- expect_node("EnumerationResults", xml)
110
-
111
- results = enumeration_results_from_xml(xml, Azure::Storage::Common::Service::EnumerationResults.new)
112
-
113
- return results unless (xml > "Blobs").any?
114
-
115
- if ((xml > "Blobs") > "Blob").any?
116
- if xml.Blobs.Blob.count == 0
117
- results.push(blob_from_xml(xml.Blobs.Blob))
118
- else
119
- xml.Blobs.Blob.each { |blob_node|
120
- results.push(blob_from_xml(blob_node))
121
- }
122
- end
123
- end
124
-
125
- if ((xml > "Blobs") > "BlobPrefix").any?
126
- if xml.Blobs.BlobPrefix.count == 0
127
- results.push(blob_prefix_from_xml(xml.Blobs.BlobPrefix))
128
- else
129
- xml.Blobs.BlobPrefix.each { |blob_prefix|
130
- results.push(blob_prefix_from_xml(blob_prefix))
131
- }
132
- end
133
- end
134
-
135
- results
136
- end
137
-
138
- def self.blob_prefix_from_xml(xml)
139
- xml = slopify(xml)
140
- expect_node("BlobPrefix", xml)
141
-
142
- name = xml.Name.text if (xml > "Name").any?
143
- name
144
- end
145
-
146
- def self.blob_from_xml(xml)
147
- xml = slopify(xml)
148
- expect_node("Blob", xml)
149
-
150
- Blob.new do |blob|
151
- blob.name = xml.Name.text if (xml > "Name").any?
152
- blob.snapshot = xml.Snapshot.text if (xml > "Snapshot").any?
153
-
154
- blob.metadata = metadata_from_xml(xml.Metadata) if (xml > "Metadata").any?
155
- if (xml > "Properties").any?
156
- blob.properties = blob_properties_from_xml(xml.Properties)
157
- blob.encrypted = xml.Properties.ServerEncrypted.text == "true" if (xml.Properties > "ServerEncrypted").any?
158
- end
159
- end
160
- end
161
-
162
- def self.blob_from_headers(headers)
163
- Blob.new do |blob|
164
- blob.properties = blob_properties_from_headers(headers)
165
- blob.metadata = metadata_from_headers(headers)
166
- blob.encrypted = headers[Azure::Storage::Common::HeaderConstants::REQUEST_SERVER_ENCRYPTED] || headers[Azure::Storage::Common::HeaderConstants::SERVER_ENCRYPTED]
167
- blob.encrypted = blob.encrypted.to_s == "true" unless blob.encrypted.nil?
168
- end
169
- end
170
-
171
- def self.blob_properties_from_xml(xml)
172
- xml = slopify(xml)
173
- expect_node("Properties", xml)
174
-
175
- props = {}
176
-
177
- props[:last_modified] = (xml > "Last-Modified").text if (xml > "Last-Modified").any?
178
- props[:etag] = xml.Etag.text if (xml > "Etag").any?
179
- props[:lease_status] = xml.LeaseStatus.text if (xml > "LeaseStatus").any?
180
- props[:lease_state] = xml.LeaseState.text if (xml > "LeaseState").any?
181
- props[:lease_duration] = xml.LeaseDuration.text if (xml > "LeaseDuration").any?
182
- props[:content_length] = (xml > "Content-Length").text.to_i if (xml > "Content-Length").any?
183
- props[:content_type] = (xml > "Content-Type").text if (xml > "Content-Type").any?
184
- props[:content_encoding] = (xml > "Content-Encoding").text if (xml > "Content-Encoding").any?
185
- props[:content_language] = (xml > "Content-Language").text if (xml > "Content-Language").any?
186
- props[:content_md5] = (xml > "Content-MD5").text if (xml > "Content-MD5").any?
187
-
188
- props[:cache_control] = (xml > "Cache-Control").text if (xml > "Cache-Control").any?
189
- props[:sequence_number] = (xml > "x-ms-blob-sequence-number").text.to_i if (xml > "x-ms-blob-sequence-number").any?
190
- props[:blob_type] = xml.BlobType.text if (xml > "BlobType").any?
191
- props[:copy_id] = xml.CopyId.text if (xml > "CopyId").any?
192
- props[:copy_status] = xml.CopyStatus.text if (xml > "CopyStatus").any?
193
- props[:copy_source] = xml.CopySource.text if (xml > "CopySource").any?
194
- props[:copy_progress] = xml.CopyProgress.text if (xml > "CopyProgress").any?
195
- props[:copy_completion_time] = xml.CopyCompletionTime.text if (xml > "CopyCompletionTime").any?
196
- props[:copy_status_description] = xml.CopyStatusDescription.text if (xml > "CopyStatusDescription").any?
197
- props[:incremental_copy] = xml.IncrementalCopy.text == "true" if (xml > "IncrementalCopy").any?
198
-
199
- props
200
- end
201
-
202
- def self.blob_properties_from_headers(headers)
203
- props = {}
204
-
205
- props[:last_modified] = headers["Last-Modified"]
206
- props[:etag] = headers["Etag"]
207
- props[:lease_status] = headers["x-ms-lease-status"]
208
- props[:lease_state] = headers["x-ms-lease-state"]
209
- props[:lease_duration] = headers["x-ms-lease-duration"]
210
-
211
- props[:content_length] = headers["x-ms-blob-content-length"] || headers["Content-Length"]
212
- props[:content_length] = props[:content_length].to_i if props[:content_length]
213
-
214
- props[:content_type] = headers["x-ms-blob-content-type"] || headers["Content-Type"]
215
- props[:content_encoding] = headers["x-ms-blob-content-encoding"] || headers["Content-Encoding"]
216
- props[:content_language] = headers["x-ms-blob-content-language"] || headers["Content-Language"]
217
- props[:content_disposition] = headers["x-ms-blob-content-disposition"] || headers["Content-Disposition"]
218
- props[:content_md5] = headers["x-ms-blob-content-md5"] || headers["Content-MD5"]
219
- props[:range_md5] = headers["Content-MD5"] if headers["x-ms-blob-content-md5"] && headers["Content-MD5"]
220
-
221
- props[:cache_control] = headers["x-ms-blob-cache-control"] || headers["Cache-Control"]
222
- props[:sequence_number] = headers["x-ms-blob-sequence-number"].to_i if headers["x-ms-blob-sequence-number"]
223
- props[:blob_type] = headers["x-ms-blob-type"]
224
-
225
- props[:copy_id] = headers["x-ms-copy-id"]
226
- props[:copy_status] = headers["x-ms-copy-status"]
227
- props[:copy_source] = headers["x-ms-copy-source"]
228
- props[:copy_progress] = headers["x-ms-copy-progress"]
229
- props[:copy_completion_time] = headers["x-ms-copy-completion-time"]
230
- props[:copy_status_description] = headers["x-ms-copy-status-description"]
231
-
232
- props[:accept_ranges] = headers["Accept-Ranges"].to_i if headers["Accept-Ranges"]
233
-
234
- props[:append_offset] = headers["x-ms-blob-append-offset"].to_i if headers["x-ms-blob-append-offset"]
235
- props[:committed_count] = headers["x-ms-blob-committed-block-count"].to_i if headers["x-ms-blob-committed-block-count"]
236
- props[:incremental_copy] = headers["x-ms-incremental-copy"].to_s == "true" if headers["x-ms-incremental-copy"]
237
-
238
- props
239
- end
240
-
241
- def self.block_list_to_xml(block_list)
242
- builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
243
- xml.BlockList {
244
- block_list.each { |block|
245
- encoded_id = Base64.strict_encode64(block[0])
246
- case block[1]
247
- when :uncommitted
248
- xml.Uncommitted encoded_id
249
- when :committed
250
- xml.Committed encoded_id
251
- else
252
- xml.Latest encoded_id
253
- end
254
- }
255
- }
256
- end
257
- builder.to_xml
258
- end
259
-
260
- def self.block_list_from_xml(xml)
261
- xml = slopify(xml)
262
- expect_node("BlockList", xml)
263
-
264
- block_list = {
265
- committed: [],
266
- uncommitted: []
267
- }
268
-
269
- if ((xml > "CommittedBlocks") > "Block").any?
270
- if xml.CommittedBlocks.Block.count == 0
271
- add_block(:committed, xml.CommittedBlocks.Block, block_list)
272
- else
273
- xml.CommittedBlocks.Block.each { |block_node|
274
- add_block(:committed, block_node, block_list)
275
- }
276
- end
277
- end
278
-
279
- return block_list unless (xml > "UncommittedBlocks")
280
-
281
- if ((xml > "UncommittedBlocks") > "Block").any?
282
- if xml.UncommittedBlocks.Block.count == 0
283
- add_block(:uncommitted, xml.UncommittedBlocks.Block, block_list)
284
- else
285
- xml.UncommittedBlocks.Block.each { |block_node|
286
- add_block(:uncommitted, block_node, block_list)
287
- }
288
- end
289
- end
290
-
291
- block_list
292
- end
293
-
294
- def self.add_block(type, block_node, block_list)
295
- block = Block.new do |b|
296
- b.name = Base64.strict_decode64(block_node.Name.text) if (block_node > "Name").any?
297
- b.size = block_node.Size.text.to_i if (block_node > "Size").any?
298
- b.type = type
299
- end
300
- block_list[type].push block
301
- end
302
-
303
- def self.page_list_from_xml(xml)
304
- xml = slopify(xml)
305
- expect_node("PageList", xml)
306
-
307
- page_list = []
308
-
309
- return page_list unless (xml > "PageRange").any?
310
-
311
- if xml.PageRange.count == 0
312
- page_list.push [xml.PageRange.Start.text.to_i, xml.PageRange.End.text.to_i]
313
- else
314
- xml.PageRange.each { |page_range|
315
- page_list.push [page_range.Start.text.to_i, page_range.End.text.to_i]
316
- }
317
- end
318
-
319
- page_list
320
- end
321
- end
322
- end
323
- end
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 "base64"
27
+
28
+ module Azure::Storage
29
+ module Blob
30
+ module Serialization
31
+ include Azure::Storage::Common::Service::Serialization
32
+
33
+ def self.container_enumeration_results_from_xml(xml)
34
+ xml = slopify(xml)
35
+ expect_node("EnumerationResults", xml)
36
+
37
+ results = enumeration_results_from_xml(xml, Azure::Storage::Common::Service::EnumerationResults.new)
38
+
39
+ return results unless (xml > "Containers").any? && ((xml > "Containers") > "Container").any?
40
+
41
+ if xml.Containers.Container.count == 0
42
+ results.push(container_from_xml(xml.Containers.Container))
43
+ else
44
+ xml.Containers.Container.each { |container_node|
45
+ results.push(container_from_xml(container_node))
46
+ }
47
+ end
48
+
49
+ results
50
+ end
51
+
52
+ def self.key_info_to_xml(start, expiry)
53
+ builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
54
+ xml.KeyInfo {
55
+ xml.Start start.utc.iso8601
56
+ xml.Expiry expiry.utc.iso8601
57
+ }
58
+ end
59
+ builder.to_xml
60
+ end
61
+
62
+ def self.user_delegation_key_from_xml(xml)
63
+ xml = slopify(xml)
64
+ expect_node("UserDelegationKey", xml)
65
+
66
+ Azure::Storage::Common::Service::UserDelegationKey.new do |user_delegation_key|
67
+ user_delegation_key.signed_oid = xml.SignedOid.text if (xml > "SignedOid").any?
68
+ user_delegation_key.signed_tid = xml.SignedTid.text if (xml > "SignedTid").any?
69
+ user_delegation_key.signed_start = xml.SignedStart.text if (xml > "SignedStart").any?
70
+ user_delegation_key.signed_expiry = xml.SignedExpiry.text if (xml > "SignedExpiry").any?
71
+ user_delegation_key.signed_service = xml.SignedService.text if (xml > "SignedService").any?
72
+ user_delegation_key.signed_version = xml.SignedVersion.text if (xml > "SignedVersion").any?
73
+ user_delegation_key.value = xml.Value.text if (xml > "Value").any?
74
+ end
75
+ end
76
+
77
+ def self.container_from_xml(xml)
78
+ xml = slopify(xml)
79
+ expect_node("Container", xml)
80
+
81
+ Container::Container.new do |container|
82
+ container.name = xml.Name.text if (xml > "Name").any?
83
+ container.properties = container_properties_from_xml(xml.Properties) if (xml > "Properties").any?
84
+ container.metadata = metadata_from_xml(xml.Metadata) if (xml > "Metadata").any?
85
+ container.public_access_level = public_access_level_from_properties_xml(xml.Properties) if (xml > "Properties").any?
86
+ end
87
+ end
88
+
89
+ def self.container_from_headers(headers)
90
+ Container::Container.new do |container|
91
+ container.properties = container_properties_from_headers(headers)
92
+ container.public_access_level = public_access_level_from_headers(headers)
93
+ container.metadata = metadata_from_headers(headers)
94
+ end
95
+ end
96
+
97
+ def self.container_properties_from_xml(xml)
98
+ xml = slopify(xml)
99
+ expect_node("Properties", xml)
100
+
101
+ props = {}
102
+
103
+ props[:last_modified] = (xml > "Last-Modified").text if (xml > "Last-Modified").any?
104
+ props[:etag] = xml.Etag.text if (xml > "Etag").any?
105
+ props[:lease_status] = xml.LeaseStatus.text if (xml > "LeaseStatus").any?
106
+ props[:lease_state] = xml.LeaseState.text if (xml > "LeaseState").any?
107
+ props[:lease_duration] = xml.LeaseDuration.text if (xml > "LeaseDuration").any?
108
+
109
+ props
110
+ end
111
+
112
+ def self.container_properties_from_headers(headers)
113
+ props = {}
114
+
115
+ props[:last_modified] = headers["Last-Modified"]
116
+ props[:etag] = headers["Etag"]
117
+ props[:lease_status] = headers["x-ms-lease-status"]
118
+ props[:lease_state] = headers["x-ms-lease-state"]
119
+ props[:lease_duration] = headers["x-ms-lease-duration"]
120
+
121
+ props
122
+ end
123
+
124
+ def self.public_access_level_from_headers(headers)
125
+ headers["x-ms-blob-public-access"]
126
+ end
127
+
128
+ def self.public_access_level_from_properties_xml(xml)
129
+ (xml > "PublicAccess").any? ? xml.PublicAccess.text : nil
130
+ end
131
+
132
+ def self.blob_enumeration_results_from_xml(xml)
133
+ xml = slopify(xml)
134
+ expect_node("EnumerationResults", xml)
135
+
136
+ results = enumeration_results_from_xml(xml, Azure::Storage::Common::Service::EnumerationResults.new)
137
+
138
+ return results unless (xml > "Blobs").any?
139
+
140
+ if ((xml > "Blobs") > "Blob").any?
141
+ if xml.Blobs.Blob.count == 0
142
+ results.push(blob_from_xml(xml.Blobs.Blob))
143
+ else
144
+ xml.Blobs.Blob.each { |blob_node|
145
+ results.push(blob_from_xml(blob_node))
146
+ }
147
+ end
148
+ end
149
+
150
+ if ((xml > "Blobs") > "BlobPrefix").any?
151
+ if xml.Blobs.BlobPrefix.count == 0
152
+ results.push(blob_prefix_from_xml(xml.Blobs.BlobPrefix))
153
+ else
154
+ xml.Blobs.BlobPrefix.each { |blob_prefix|
155
+ results.push(blob_prefix_from_xml(blob_prefix))
156
+ }
157
+ end
158
+ end
159
+
160
+ results
161
+ end
162
+
163
+ def self.blob_prefix_from_xml(xml)
164
+ xml = slopify(xml)
165
+ expect_node("BlobPrefix", xml)
166
+
167
+ name = xml.Name.text if (xml > "Name").any?
168
+ name
169
+ end
170
+
171
+ def self.blob_from_xml(xml)
172
+ xml = slopify(xml)
173
+ expect_node("Blob", xml)
174
+
175
+ Blob.new do |blob|
176
+ blob.name = xml.Name.text if (xml > "Name").any?
177
+ blob.snapshot = xml.Snapshot.text if (xml > "Snapshot").any?
178
+
179
+ blob.metadata = metadata_from_xml(xml.Metadata) if (xml > "Metadata").any?
180
+ if (xml > "Properties").any?
181
+ blob.properties = blob_properties_from_xml(xml.Properties)
182
+ blob.encrypted = xml.Properties.ServerEncrypted.text == "true" if (xml.Properties > "ServerEncrypted").any?
183
+ end
184
+ end
185
+ end
186
+
187
+ def self.blob_from_headers(headers)
188
+ Blob.new do |blob|
189
+ blob.properties = blob_properties_from_headers(headers)
190
+ blob.metadata = metadata_from_headers(headers)
191
+ blob.encrypted = headers[Azure::Storage::Common::HeaderConstants::REQUEST_SERVER_ENCRYPTED] || headers[Azure::Storage::Common::HeaderConstants::SERVER_ENCRYPTED]
192
+ blob.encrypted = blob.encrypted.to_s == "true" unless blob.encrypted.nil?
193
+ end
194
+ end
195
+
196
+ def self.blob_properties_from_xml(xml)
197
+ xml = slopify(xml)
198
+ expect_node("Properties", xml)
199
+
200
+ props = {}
201
+
202
+ props[:last_modified] = (xml > "Last-Modified").text if (xml > "Last-Modified").any?
203
+ props[:etag] = xml.Etag.text if (xml > "Etag").any?
204
+ props[:lease_status] = xml.LeaseStatus.text if (xml > "LeaseStatus").any?
205
+ props[:lease_state] = xml.LeaseState.text if (xml > "LeaseState").any?
206
+ props[:lease_duration] = xml.LeaseDuration.text if (xml > "LeaseDuration").any?
207
+ props[:content_length] = (xml > "Content-Length").text.to_i if (xml > "Content-Length").any?
208
+ props[:content_type] = (xml > "Content-Type").text if (xml > "Content-Type").any?
209
+ props[:content_encoding] = (xml > "Content-Encoding").text if (xml > "Content-Encoding").any?
210
+ props[:content_language] = (xml > "Content-Language").text if (xml > "Content-Language").any?
211
+ props[:content_md5] = (xml > "Content-MD5").text if (xml > "Content-MD5").any?
212
+
213
+ props[:cache_control] = (xml > "Cache-Control").text if (xml > "Cache-Control").any?
214
+ props[:sequence_number] = (xml > "x-ms-blob-sequence-number").text.to_i if (xml > "x-ms-blob-sequence-number").any?
215
+ props[:blob_type] = xml.BlobType.text if (xml > "BlobType").any?
216
+ props[:copy_id] = xml.CopyId.text if (xml > "CopyId").any?
217
+ props[:copy_status] = xml.CopyStatus.text if (xml > "CopyStatus").any?
218
+ props[:copy_source] = xml.CopySource.text if (xml > "CopySource").any?
219
+ props[:copy_progress] = xml.CopyProgress.text if (xml > "CopyProgress").any?
220
+ props[:copy_completion_time] = xml.CopyCompletionTime.text if (xml > "CopyCompletionTime").any?
221
+ props[:copy_status_description] = xml.CopyStatusDescription.text if (xml > "CopyStatusDescription").any?
222
+ props[:incremental_copy] = xml.IncrementalCopy.text == "true" if (xml > "IncrementalCopy").any?
223
+
224
+ props
225
+ end
226
+
227
+ def self.blob_properties_from_headers(headers)
228
+ props = {}
229
+
230
+ props[:last_modified] = headers["Last-Modified"]
231
+ props[:etag] = headers["Etag"]
232
+ props[:lease_status] = headers["x-ms-lease-status"]
233
+ props[:lease_state] = headers["x-ms-lease-state"]
234
+ props[:lease_duration] = headers["x-ms-lease-duration"]
235
+
236
+ props[:content_length] = headers["x-ms-blob-content-length"] || headers["Content-Length"]
237
+ props[:content_length] = props[:content_length].to_i if props[:content_length]
238
+
239
+ props[:content_type] = headers["x-ms-blob-content-type"] || headers["Content-Type"]
240
+ props[:content_encoding] = headers["x-ms-blob-content-encoding"] || headers["Content-Encoding"]
241
+ props[:content_language] = headers["x-ms-blob-content-language"] || headers["Content-Language"]
242
+ props[:content_disposition] = headers["x-ms-blob-content-disposition"] || headers["Content-Disposition"]
243
+ props[:content_md5] = headers["x-ms-blob-content-md5"] || headers["Content-MD5"]
244
+ props[:range_md5] = headers["Content-MD5"] if headers["x-ms-blob-content-md5"] && headers["Content-MD5"]
245
+
246
+ props[:cache_control] = headers["x-ms-blob-cache-control"] || headers["Cache-Control"]
247
+ props[:sequence_number] = headers["x-ms-blob-sequence-number"].to_i if headers["x-ms-blob-sequence-number"]
248
+ props[:blob_type] = headers["x-ms-blob-type"]
249
+
250
+ props[:copy_id] = headers["x-ms-copy-id"]
251
+ props[:copy_status] = headers["x-ms-copy-status"]
252
+ props[:copy_source] = headers["x-ms-copy-source"]
253
+ props[:copy_progress] = headers["x-ms-copy-progress"]
254
+ props[:copy_completion_time] = headers["x-ms-copy-completion-time"]
255
+ props[:copy_status_description] = headers["x-ms-copy-status-description"]
256
+
257
+ props[:accept_ranges] = headers["Accept-Ranges"].to_i if headers["Accept-Ranges"]
258
+
259
+ props[:append_offset] = headers["x-ms-blob-append-offset"].to_i if headers["x-ms-blob-append-offset"]
260
+ props[:committed_count] = headers["x-ms-blob-committed-block-count"].to_i if headers["x-ms-blob-committed-block-count"]
261
+ props[:incremental_copy] = headers["x-ms-incremental-copy"].to_s == "true" if headers["x-ms-incremental-copy"]
262
+
263
+ props
264
+ end
265
+
266
+ def self.block_list_to_xml(block_list)
267
+ builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
268
+ xml.BlockList {
269
+ block_list.each { |block|
270
+ encoded_id = Base64.strict_encode64(block[0])
271
+ case block[1]
272
+ when :uncommitted
273
+ xml.Uncommitted encoded_id
274
+ when :committed
275
+ xml.Committed encoded_id
276
+ else
277
+ xml.Latest encoded_id
278
+ end
279
+ }
280
+ }
281
+ end
282
+ builder.to_xml
283
+ end
284
+
285
+ def self.block_list_from_xml(xml)
286
+ xml = slopify(xml)
287
+ expect_node("BlockList", xml)
288
+
289
+ block_list = {
290
+ committed: [],
291
+ uncommitted: []
292
+ }
293
+
294
+ if ((xml > "CommittedBlocks") > "Block").any?
295
+ if xml.CommittedBlocks.Block.count == 0
296
+ add_block(:committed, xml.CommittedBlocks.Block, block_list)
297
+ else
298
+ xml.CommittedBlocks.Block.each { |block_node|
299
+ add_block(:committed, block_node, block_list)
300
+ }
301
+ end
302
+ end
303
+
304
+ return block_list unless (xml > "UncommittedBlocks")
305
+
306
+ if ((xml > "UncommittedBlocks") > "Block").any?
307
+ if xml.UncommittedBlocks.Block.count == 0
308
+ add_block(:uncommitted, xml.UncommittedBlocks.Block, block_list)
309
+ else
310
+ xml.UncommittedBlocks.Block.each { |block_node|
311
+ add_block(:uncommitted, block_node, block_list)
312
+ }
313
+ end
314
+ end
315
+
316
+ block_list
317
+ end
318
+
319
+ def self.add_block(type, block_node, block_list)
320
+ block = Block.new do |b|
321
+ b.name = Base64.strict_decode64(block_node.Name.text) if (block_node > "Name").any?
322
+ b.size = block_node.Size.text.to_i if (block_node > "Size").any?
323
+ b.type = type
324
+ end
325
+ block_list[type].push block
326
+ end
327
+
328
+ def self.page_list_from_xml(xml)
329
+ xml = slopify(xml)
330
+ expect_node("PageList", xml)
331
+
332
+ page_list = []
333
+
334
+ return page_list unless (xml > "PageRange").any?
335
+
336
+ if xml.PageRange.count == 0
337
+ page_list.push [xml.PageRange.Start.text.to_i, xml.PageRange.End.text.to_i]
338
+ else
339
+ xml.PageRange.each { |page_range|
340
+ page_list.push [page_range.Start.text.to_i, page_range.End.text.to_i]
341
+ }
342
+ end
343
+
344
+ page_list
345
+ end
346
+ end
347
+ end
348
+ end