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,323 +1,351 @@
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[:access_tier] = (xml > "AccessTier").text if (xml > "AccessTier").any?
203
+ props[:access_tier_change_time] = (xml > "AccessTierChangeTime").text if (xml > "AccessTierChangeTime").any?
204
+ props[:creation_Time] = (xml > "Creation-Time").text if (xml > "Creation-Time").any?
205
+ props[:last_modified] = (xml > "Last-Modified").text if (xml > "Last-Modified").any?
206
+ props[:etag] = xml.Etag.text if (xml > "Etag").any?
207
+ props[:lease_status] = xml.LeaseStatus.text if (xml > "LeaseStatus").any?
208
+ props[:lease_state] = xml.LeaseState.text if (xml > "LeaseState").any?
209
+ props[:lease_duration] = xml.LeaseDuration.text if (xml > "LeaseDuration").any?
210
+ props[:content_length] = (xml > "Content-Length").text.to_i if (xml > "Content-Length").any?
211
+ props[:content_type] = (xml > "Content-Type").text if (xml > "Content-Type").any?
212
+ props[:content_encoding] = (xml > "Content-Encoding").text if (xml > "Content-Encoding").any?
213
+ props[:content_language] = (xml > "Content-Language").text if (xml > "Content-Language").any?
214
+ props[:content_md5] = (xml > "Content-MD5").text if (xml > "Content-MD5").any?
215
+
216
+ props[:cache_control] = (xml > "Cache-Control").text if (xml > "Cache-Control").any?
217
+ props[:sequence_number] = (xml > "x-ms-blob-sequence-number").text.to_i if (xml > "x-ms-blob-sequence-number").any?
218
+ props[:blob_type] = xml.BlobType.text if (xml > "BlobType").any?
219
+ props[:copy_id] = xml.CopyId.text if (xml > "CopyId").any?
220
+ props[:copy_status] = xml.CopyStatus.text if (xml > "CopyStatus").any?
221
+ props[:copy_source] = xml.CopySource.text if (xml > "CopySource").any?
222
+ props[:copy_progress] = xml.CopyProgress.text if (xml > "CopyProgress").any?
223
+ props[:copy_completion_time] = xml.CopyCompletionTime.text if (xml > "CopyCompletionTime").any?
224
+ props[:copy_status_description] = xml.CopyStatusDescription.text if (xml > "CopyStatusDescription").any?
225
+ props[:incremental_copy] = xml.IncrementalCopy.text == "true" if (xml > "IncrementalCopy").any?
226
+
227
+ props
228
+ end
229
+
230
+ def self.blob_properties_from_headers(headers)
231
+ props = {}
232
+
233
+ props[:last_modified] = headers["Last-Modified"]
234
+ props[:etag] = headers["Etag"]
235
+ props[:lease_status] = headers["x-ms-lease-status"]
236
+ props[:lease_state] = headers["x-ms-lease-state"]
237
+ props[:lease_duration] = headers["x-ms-lease-duration"]
238
+
239
+ props[:content_length] = headers["x-ms-blob-content-length"] || headers["Content-Length"]
240
+ props[:content_length] = props[:content_length].to_i if props[:content_length]
241
+
242
+ props[:content_type] = headers["x-ms-blob-content-type"] || headers["Content-Type"]
243
+ props[:content_encoding] = headers["x-ms-blob-content-encoding"] || headers["Content-Encoding"]
244
+ props[:content_language] = headers["x-ms-blob-content-language"] || headers["Content-Language"]
245
+ props[:content_disposition] = headers["x-ms-blob-content-disposition"] || headers["Content-Disposition"]
246
+ props[:content_md5] = headers["x-ms-blob-content-md5"] || headers["Content-MD5"]
247
+ props[:range_md5] = headers["Content-MD5"] if headers["x-ms-blob-content-md5"] && headers["Content-MD5"]
248
+
249
+ props[:cache_control] = headers["x-ms-blob-cache-control"] || headers["Cache-Control"]
250
+ props[:sequence_number] = headers["x-ms-blob-sequence-number"].to_i if headers["x-ms-blob-sequence-number"]
251
+ props[:blob_type] = headers["x-ms-blob-type"]
252
+
253
+ props[:copy_id] = headers["x-ms-copy-id"]
254
+ props[:copy_status] = headers["x-ms-copy-status"]
255
+ props[:copy_source] = headers["x-ms-copy-source"]
256
+ props[:copy_progress] = headers["x-ms-copy-progress"]
257
+ props[:copy_completion_time] = headers["x-ms-copy-completion-time"]
258
+ props[:copy_status_description] = headers["x-ms-copy-status-description"]
259
+
260
+ props[:accept_ranges] = headers["Accept-Ranges"].to_i if headers["Accept-Ranges"]
261
+
262
+ props[:append_offset] = headers["x-ms-blob-append-offset"].to_i if headers["x-ms-blob-append-offset"]
263
+ props[:committed_count] = headers["x-ms-blob-committed-block-count"].to_i if headers["x-ms-blob-committed-block-count"]
264
+ props[:incremental_copy] = headers["x-ms-incremental-copy"].to_s == "true" if headers["x-ms-incremental-copy"]
265
+
266
+ props
267
+ end
268
+
269
+ def self.block_list_to_xml(block_list)
270
+ builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
271
+ xml.BlockList {
272
+ block_list.each { |block|
273
+ encoded_id = Base64.strict_encode64(block[0])
274
+ case block[1]
275
+ when :uncommitted
276
+ xml.Uncommitted encoded_id
277
+ when :committed
278
+ xml.Committed encoded_id
279
+ else
280
+ xml.Latest encoded_id
281
+ end
282
+ }
283
+ }
284
+ end
285
+ builder.to_xml
286
+ end
287
+
288
+ def self.block_list_from_xml(xml)
289
+ xml = slopify(xml)
290
+ expect_node("BlockList", xml)
291
+
292
+ block_list = {
293
+ committed: [],
294
+ uncommitted: []
295
+ }
296
+
297
+ if ((xml > "CommittedBlocks") > "Block").any?
298
+ if xml.CommittedBlocks.Block.count == 0
299
+ add_block(:committed, xml.CommittedBlocks.Block, block_list)
300
+ else
301
+ xml.CommittedBlocks.Block.each { |block_node|
302
+ add_block(:committed, block_node, block_list)
303
+ }
304
+ end
305
+ end
306
+
307
+ return block_list unless (xml > "UncommittedBlocks")
308
+
309
+ if ((xml > "UncommittedBlocks") > "Block").any?
310
+ if xml.UncommittedBlocks.Block.count == 0
311
+ add_block(:uncommitted, xml.UncommittedBlocks.Block, block_list)
312
+ else
313
+ xml.UncommittedBlocks.Block.each { |block_node|
314
+ add_block(:uncommitted, block_node, block_list)
315
+ }
316
+ end
317
+ end
318
+
319
+ block_list
320
+ end
321
+
322
+ def self.add_block(type, block_node, block_list)
323
+ block = Block.new do |b|
324
+ b.name = Base64.strict_decode64(block_node.Name.text) if (block_node > "Name").any?
325
+ b.size = block_node.Size.text.to_i if (block_node > "Size").any?
326
+ b.type = type
327
+ end
328
+ block_list[type].push block
329
+ end
330
+
331
+ def self.page_list_from_xml(xml)
332
+ xml = slopify(xml)
333
+ expect_node("PageList", xml)
334
+
335
+ page_list = []
336
+
337
+ return page_list unless (xml > "PageRange").any?
338
+
339
+ if xml.PageRange.count == 0
340
+ page_list.push [xml.PageRange.Start.text.to_i, xml.PageRange.End.text.to_i]
341
+ else
342
+ xml.PageRange.each { |page_range|
343
+ page_list.push [page_range.Start.text.to_i, page_range.End.text.to_i]
344
+ }
345
+ end
346
+
347
+ page_list
348
+ end
349
+ end
350
+ end
351
+ end