Skip to content

Commit 9c95c2e

Browse files
authored
Merge pull request #58 from yaxia/dev
Changes for v0.11.2-preview
2 parents 61c7227 + 2231cfa commit 9c95c2e

6 files changed

Lines changed: 65 additions & 46 deletions

File tree

ChangeLog.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
2016.10 - version 0.11.2-preview
2+
3+
ALL
4+
* Fixed the issue where it retries on HTTP 4xx errors.
5+
6+
BLOB
7+
* Fixed the issue of wrong "Content-Encoding". [#49](https://github.com/Azure/azure-storage-ruby/issues/49)
8+
19
2016.09 - version 0.11.1-preview
210

311
ALL
@@ -6,7 +14,7 @@ ALL
614
* Added the retry for the connection reset error.
715

816
BLOB
9-
* Fixed the issue where "list_blobs" doesn't work when delimiter is specified. (https://github.com/Azure/azure-storage-ruby/issues/41)
17+
* Fixed the issue where "list_blobs" doesn't work when delimiter is specified. [#41](https://github.com/Azure/azure-storage-ruby/issues/41)
1018

1119
2016.08 - version 0.11.0-preview
1220

lib/azure/storage/blob/blob_service.rb

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ module Azure::Storage
3434

3535
module Blob
3636
class BlobService < StorageService
37+
include Azure::Storage::Core::Utility
3738
include Azure::Storage::Blob
3839
include Azure::Storage::Blob::Container
3940

@@ -43,24 +44,25 @@ def initialize(options = {})
4344
super(signer, client_config.storage_account_name, options)
4445
@host = client.storage_blob_host
4546
end
46-
47+
4748
def call(method, uri, body=nil, headers={}, options={})
4849
# Force the request.body to the content encoding of specified in the header
49-
# (content encoding probably shouldn't be used this way)
50-
if headers && !body.nil?
51-
if headers['Content-Encoding'].nil?
52-
Service::StorageService.with_header headers, 'Content-Encoding', body.encoding.to_s
50+
if headers && !body.nil? && !(body.encoding.to_s <=> 'ASCII_8BIT')
51+
if headers['x-ms-blob-content-type'].nil?
52+
Service::StorageService.with_header headers, 'x-ms-blob-content-type', "text/plain; charset=#{body.encoding.to_s}"
5353
else
54-
body.force_encoding(headers['Content-Encoding'])
54+
charset = parse_charset_from_content_type(headers['x-ms-blob-content-type'])
55+
body.force_encoding(charset)
5556
end
5657
end
5758

5859
response = super
5960

60-
# Force the response.body to the content encoding of specified in the header.
61-
# content-encoding is echo'd back for the blob and is used to store the encoding of the octet stream
62-
if !response.nil? && !response.body.nil? && response.headers['content-encoding']
63-
response.body.force_encoding(response.headers['content-encoding'])
61+
# Force the response.body to the content charset of specified in the header.
62+
# Content-Type is echo'd back for the blob and is used to store the encoding of the octet stream
63+
if !response.nil? && !response.body.nil? && response.headers['Content-Type']
64+
charset = parse_charset_from_content_type(response.headers['Content-Type'])
65+
response.body.force_encoding(charset) if charset && charset.length > 0
6466
end
6567

6668
response
@@ -99,12 +101,12 @@ def call(method, uri, body=nil, headers={}, options={})
99101
# * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded
100102
# in the analytics logs when storage analytics logging is enabled.
101103
#
104+
# See: https://msdn.microsoft.com/en-us/library/azure/dd179352.aspx
105+
#
102106
# NOTE: Metadata requested with the :metadata parameter must have been stored in
103107
# accordance with the naming restrictions imposed by the 2009-09-19 version of the Blob
104108
# service. Beginning with that version, all metadata names must adhere to the naming
105-
# conventions for C# identifiers.
106-
#
107-
# See: http://msdn.microsoft.com/en-us/library/aa664670(VS.71).aspx
109+
# conventions for C# identifiers. See: https://msdn.microsoft.com/en-us/library/aa664670(VS.71).aspx
108110
#
109111
# Any metadata with invalid names which were previously stored, will be returned with the
110112
# key "x-ms-invalid-name" in the metadata hash. This may contain multiple values and be an

lib/azure/storage/core/filter/retry_filter.rb

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,12 @@ def should_retry_on_local_error?(retry_data)
115115
# incrementing counter, timestamp, etc). The retry_data object
116116
# will be the same instance throughout the lifetime of the request.
117117
def should_retry_on_error?(response, retry_data)
118+
response = response || retry_data[:error].http_response if retry_data[:error] && retry_data[:error].respond_to?('http_response')
118119
unless response
119120
retry_data[:retryable] = false unless retry_data[:error]
120121
return retry_data[:retryable]
121122
end
122-
123+
123124
# If a request sent to the secondary location fails with 404 (Not Found), it is possible
124125
# that the resource replication is not finished yet. So, in case of 404 only in the secondary
125126
# location, the failure should still be retryable.
@@ -133,7 +134,7 @@ def should_retry_on_error?(response, retry_data)
133134
else
134135
retry_data[:status_code] = nil
135136
end
136-
end
137+
end
137138

138139
# Non-timeout Cases
139140
if (retry_data[:status_code] >= 300 && retry_data[:status_code] != 408)
@@ -142,26 +143,26 @@ def should_retry_on_error?(response, retry_data)
142143
retry_data[:retryable] = false;
143144
return false;
144145
end
145-
end
146-
147-
# When absorb_conditional_errors_on_retry is set (for append blob)
148-
if (retry_data[:request_options] && retry_data[:request_options][:absorb_conditional_errors_on_retry])
149-
if (retry_data[:status_code] == 412)
150-
# When appending block with precondition failure and their was a server error before, we ignore the error.
151-
if (retry_data[:last_server_error])
152-
retry_data[:error] = nil;
146+
147+
# When absorb_conditional_errors_on_retry is set (for append blob)
148+
if (retry_data[:request_options] && retry_data[:request_options][:absorb_conditional_errors_on_retry])
149+
if (retry_data[:status_code] == 412)
150+
# When appending block with precondition failure and their was a server error before, we ignore the error.
151+
if (retry_data[:last_server_error])
152+
retry_data[:error] = nil;
153+
retry_data[:retryable] = true;
154+
else
155+
retry_data[:retryable] = false;
156+
end
157+
elsif (retry_data[:retryable] && retry_data[:status_code] >= 500 && retry_data[:status_code] < 600)
158+
# Retry on the server error
153159
retry_data[:retryable] = true;
154-
else
155-
retry_data[:retryable] = false;
160+
retry_data[:last_server_error] = true;
156161
end
157-
elsif (retry_data[:retryable] && retry_data[:status_code] >= 500 && retry_data[:status_code] < 600)
158-
# Retry on the server error
159-
retry_data[:retryable] = true;
160-
retry_data[:last_server_error] = true;
162+
elsif (retry_data[:status_code] < 500)
163+
# No retry on the client error
164+
retry_data[:retryable] = false;
161165
end
162-
elsif (retry_data[:status_code] < 500)
163-
# No retry on the client error
164-
retry_data[:retryable] = false;
165166
end
166167
end
167168

lib/azure/storage/core/utility.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ def get_certificate(private_key_file)
107107
def initialize_external_logger(logger)
108108
Loggerx.initialize_external_logger(logger)
109109
end
110+
111+
def parse_charset_from_content_type(content_type)
112+
if (content_type && content_type.length > 0)
113+
charset = content_type.split(';').delete_if { |attribute| !attribute.lstrip.start_with?('charset=') }.map { |x| x.lstrip }[0]
114+
charset['charset='.length...charset.length] if charset
115+
end
116+
end
110117
end
111118

112119
# Logger

lib/azure/storage/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class Version
2828
# Fields represent the parts defined in http://semver.org/
2929
MAJOR = 0 unless defined? MAJOR
3030
MINOR = 11 unless defined? MINOR
31-
UPDATE = 1 unless defined? UPDATE
31+
UPDATE = 2 unless defined? UPDATE
3232
PRE = 'preview' unless defined? PRE
3333

3434
class << self

test/integration/blob/blob_gb18030_test.rb

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,58 +150,59 @@
150150
}
151151
end
152152

153-
it 'Read/Write Blob Block Content UTF-8' do
153+
it 'Read/Write Blob Block Content UTF-8 with auto charset' do
154154
GB18030TestStrings.get.each { |k,v|
155155
blob_name = 'Read/Write Block Blob Content UTF-8 for ' + k
156156
content = v.encode('UTF-8')
157-
158157
subject.create_block_blob container_name, blob_name, content
159158
blob, returned_content = subject.get_blob container_name, blob_name
160-
161159
returned_content.must_equal content
162160
}
163161
end
164162

165-
it 'Read/Write Blob Block Content GB18030' do
163+
it 'Read/Write Blob Block Content GB18030 with explicit charset' do
166164
GB18030TestStrings.get.each { |k,v|
167165
blob_name = 'Read/Write Block Blob Content GB18030 for ' + k
168166
content = v.encode('GB18030')
169-
options = { :content_encoding=> 'GB18030'}
167+
options = { :content_type => 'text/html; charset=GB18030' }
170168
subject.create_block_blob container_name, blob_name, content, options
171169
blob, returned_content = subject.get_blob container_name, blob_name
172-
returned_content.force_encoding(blob.properties[:content_encoding])
170+
charset = blob.properties[:content_type][blob.properties[:content_type].index('charset=') + 'charset='.length...blob.properties[:content_type].length]
171+
returned_content.force_encoding(charset)
173172
returned_content.must_equal content
174173
}
175174
end
176175

177-
it 'Read/Write Blob Page Content UTF-8' do
176+
it 'Read/Write Blob Page Content UTF-8 with explicit charset' do
178177
GB18030TestStrings.get.each { |k,v|
179178
blob_name = 'Read/Write Page Blob Content UTF-8 for ' + k
180-
options = { :content_encoding=> 'UTF-8'}
179+
options = { :content_type => 'text/html; charset=UTF-8' }
181180
content = v.encode('UTF-8')
182181
while content.bytesize < 512 do
183182
content << 'X'
184183
end
185184
subject.create_page_blob container_name, blob_name, 512, options
186185
subject.put_blob_pages container_name, blob_name, 0, 511, content
187186
blob, returned_content = subject.get_blob container_name, blob_name
188-
returned_content.force_encoding(blob.properties[:content_encoding])
187+
charset = blob.properties[:content_type][blob.properties[:content_type].index('charset=') + 'charset='.length...blob.properties[:content_type].length]
188+
returned_content.force_encoding(charset)
189189
returned_content.must_equal content
190190
}
191191
end
192192

193-
it 'Read/Write Blob Page Content GB18030' do
193+
it 'Read/Write Blob Page Content GB18030 with explicit charset' do
194194
GB18030TestStrings.get.each { |k,v|
195195
blob_name = 'Read/Write Page Blob Content GB18030 for ' + k
196-
options = { :content_encoding=> 'GB18030'}
196+
options = { :content_type => 'text/html; charset=GB18030' }
197197
content = v.encode('GB18030')
198198
while content.bytesize < 512 do
199199
content << 'X'
200200
end
201201
subject.create_page_blob container_name, blob_name, 512, options
202202
subject.put_blob_pages container_name, blob_name, 0, 511, content
203203
blob, returned_content = subject.get_blob container_name, blob_name
204-
returned_content.force_encoding(blob.properties[:content_encoding])
204+
charset = blob.properties[:content_type][blob.properties[:content_type].index('charset=') + 'charset='.length...blob.properties[:content_type].length]
205+
returned_content.force_encoding(charset)
205206
returned_content.must_equal content
206207
}
207208
end

0 commit comments

Comments
 (0)