aliyun-sdk 0.3.1 → 0.3.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/examples/aliyun/oss/resumable_download.rb +3 -1
- data/examples/aliyun/oss/resumable_upload.rb +4 -1
- data/lib/aliyun/oss/bucket.rb +6 -0
- data/lib/aliyun/oss/http.rb +7 -7
- data/lib/aliyun/oss/object.rb +1 -1
- data/lib/aliyun/oss/protocol.rb +51 -20
- data/lib/aliyun/oss/util.rb +3 -3
- data/lib/aliyun/version.rb +1 -1
- data/spec/aliyun/oss/client/bucket_spec.rb +55 -0
- data/spec/aliyun/oss/client/resumable_upload_spec.rb +27 -31
- data/spec/aliyun/oss/util_spec.rb +4 -4
- data/tests/test_content_type.rb +10 -10
- data/tests/test_custom_headers.rb +75 -0
- data/tests/test_object_acl.rb +54 -0
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92abcf259fe7eaea3a58e48e8e9fa46b6e7a842e
|
4
|
+
data.tar.gz: c1c3c72bd651bc19bf42b1a325bf55003852487d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4221cfa8663737bed084077793f6acaed03fcd5912a3fd1741f5b71435c9ccc1b25071123c59801fc5613c64e38bd168206885d4b5221f2269cbb549e26c6dc
|
7
|
+
data.tar.gz: 86123f41ba9d877d6443df644e16053235fe473fb6d7ede26f9a64d9f50e44b27d4db2ba253c3959a42931c5dc54b0181f8075e91765f127074afe036a509dbd
|
data/CHANGELOG.md
CHANGED
@@ -25,10 +25,12 @@ end
|
|
25
25
|
|
26
26
|
demo "Resumable download" do
|
27
27
|
# 下载一个100M的文件
|
28
|
+
cpt_file = '/tmp/y.cpt'
|
29
|
+
File.delete(cpt_file) if File.exist?(cpt_file)
|
28
30
|
start = Time.now
|
29
31
|
puts "Start download: resumable => /tmp/y"
|
30
32
|
bucket.resumable_download(
|
31
|
-
'resumable', '/tmp/y', :cpt_file =>
|
33
|
+
'resumable', '/tmp/y', :cpt_file => cpt_file) do |progress|
|
32
34
|
puts "Progress: #{(progress * 100).round(2)} %"
|
33
35
|
end
|
34
36
|
puts "Download complete. Cost: #{Time.now - start} seconds."
|
@@ -30,11 +30,14 @@ demo "Resumable upload" do
|
|
30
30
|
(1..1024*1024).each{ |i| f.puts i.to_s.rjust(99, '0') }
|
31
31
|
end
|
32
32
|
|
33
|
+
cpt_file = '/tmp/x.cpt'
|
34
|
+
File.delete(cpt_file) if File.exist?(cpt_file)
|
35
|
+
|
33
36
|
# 上传一个100M的文件
|
34
37
|
start = Time.now
|
35
38
|
puts "Start upload: /tmp/x => resumable"
|
36
39
|
bucket.resumable_upload(
|
37
|
-
'resumable', '/tmp/x', :cpt_file =>
|
40
|
+
'resumable', '/tmp/x', :cpt_file => cpt_file) do |progress|
|
38
41
|
puts "Progress: #{(progress * 100).round(2)} %"
|
39
42
|
end
|
40
43
|
puts "Upload complete. Cost: #{Time.now - start} seconds."
|
data/lib/aliyun/oss/bucket.rb
CHANGED
@@ -181,6 +181,8 @@ module Aliyun
|
|
181
181
|
# @option opts [Callback] :callback 指定操作成功后OSS的
|
182
182
|
# 上传回调,上传成功后OSS会向用户的应用服务器发一个HTTP POST请
|
183
183
|
# 求,`:callback`参数指定这个请求的相关参数
|
184
|
+
# @option opts [Hash] :headers 指定请求的HTTP Header,不区分大小
|
185
|
+
# 写。这里指定的值会覆盖通过`:content_type`和`:metas`设置的值。
|
184
186
|
# @yield [HTTP::StreamWriter] 如果调用的时候传递了block,则写入
|
185
187
|
# 到object的数据由block指定
|
186
188
|
# @example 流式上传数据
|
@@ -315,6 +317,8 @@ module Aliyun
|
|
315
317
|
# @option opts [Hash] :metas 设置object的meta,这是一些用户自定
|
316
318
|
# 义的属性,它们会和object一起存储,在{#get_object}的时候会
|
317
319
|
# 返回这些meta。属性的key不区分大小写。例如:{ 'year' => '2015' }
|
320
|
+
# @option opts [Hash] :headers 指定请求的HTTP Header,不区分大小
|
321
|
+
# 写。这里指定的值会覆盖通过`:content_type`和`:metas`设置的值。
|
318
322
|
# @example 流式上传数据
|
319
323
|
# pos = append_object('x', 0){ |stream| 100.times { |i| stream << i.to_s } }
|
320
324
|
# append_object('x', pos){ |stream| stream << get_data }
|
@@ -439,6 +443,8 @@ module Aliyun
|
|
439
443
|
# @option opts [Callback] :callback 指定文件上传成功后OSS的
|
440
444
|
# 上传回调,上传成功后OSS会向用户的应用服务器发一个HTTP POST请
|
441
445
|
# 求,`:callback`参数指定这个请求的相关参数
|
446
|
+
# @option opts [Hash] :headers 指定请求的HTTP Header,不区分大小
|
447
|
+
# 写。这里指定的值会覆盖通过`:content_type`和`:metas`设置的值。
|
442
448
|
# @yield [Float] 如果调用的时候传递了block,则会将上传进度交由
|
443
449
|
# block处理,进度值是一个0-1之间的小数
|
444
450
|
# @raise [CheckpointBrokenError] 如果cpt文件被损坏,则抛出此错误
|
data/lib/aliyun/oss/http.rb
CHANGED
@@ -207,16 +207,16 @@ module Aliyun
|
|
207
207
|
sub_res = resources[:sub_res]
|
208
208
|
|
209
209
|
headers = http_options[:headers] || {}
|
210
|
-
headers['
|
211
|
-
headers['
|
212
|
-
headers['
|
210
|
+
headers['user-agent'] = get_user_agent
|
211
|
+
headers['date'] = Time.now.httpdate
|
212
|
+
headers['content-type'] ||= DEFAULT_CONTENT_TYPE
|
213
213
|
headers[STS_HEADER] = @config.sts_token if @config.sts_token
|
214
214
|
|
215
215
|
if body = http_options[:body]
|
216
216
|
if body.respond_to?(:read)
|
217
|
-
headers['
|
217
|
+
headers['transfer-encoding'] = 'chunked'
|
218
218
|
else
|
219
|
-
headers['
|
219
|
+
headers['content-md5'] = Util.get_content_md5(body)
|
220
220
|
end
|
221
221
|
end
|
222
222
|
|
@@ -227,7 +227,7 @@ module Aliyun
|
|
227
227
|
|
228
228
|
if @config.access_key_id and @config.access_key_secret
|
229
229
|
sig = Util.get_signature(@config.access_key_secret, verb, headers, res)
|
230
|
-
headers['
|
230
|
+
headers['authorization'] = "OSS #{@config.access_key_id}:#{sig}"
|
231
231
|
end
|
232
232
|
|
233
233
|
logger.debug("Send HTTP request, verb: #{verb}, resources: " \
|
@@ -295,7 +295,7 @@ module RestClient
|
|
295
295
|
module Payload
|
296
296
|
class Base
|
297
297
|
def headers
|
298
|
-
({'
|
298
|
+
({'content-length' => size.to_s} if size) || {}
|
299
299
|
end
|
300
300
|
end
|
301
301
|
end
|
data/lib/aliyun/oss/object.rb
CHANGED
data/lib/aliyun/oss/protocol.rb
CHANGED
@@ -499,6 +499,8 @@ module Aliyun
|
|
499
499
|
# @param bucket_name [String] the bucket name
|
500
500
|
# @param object_name [String] the object name
|
501
501
|
# @param opts [Hash] Options
|
502
|
+
# @option opts [String] :acl specify the object's ACL. See
|
503
|
+
# {OSS::ACL}
|
502
504
|
# @option opts [String] :content_type the HTTP Content-Type
|
503
505
|
# for the file, if not specified client will try to determine
|
504
506
|
# the type itself and fall back to HTTP::DEFAULT_CONTENT_TYPE
|
@@ -508,6 +510,9 @@ module Aliyun
|
|
508
510
|
# with the object
|
509
511
|
# @option opts [Callback] :callback the HTTP callback performed
|
510
512
|
# by OSS after `put_object` succeeds
|
513
|
+
# @option opts [Hash] :headers custom HTTP headers, case
|
514
|
+
# insensitive. Headers specified here will overwrite `:metas`
|
515
|
+
# and `:content_type`
|
511
516
|
# @yield [HTTP::StreamWriter] a stream writer is
|
512
517
|
# yielded to the caller to which it can write chunks of data
|
513
518
|
# streamingly
|
@@ -518,14 +523,17 @@ module Aliyun
|
|
518
523
|
logger.debug("Begin put object, bucket: #{bucket_name}, object: "\
|
519
524
|
"#{object_name}, options: #{opts}")
|
520
525
|
|
521
|
-
headers = {'
|
526
|
+
headers = {'content-type' => opts[:content_type]}
|
527
|
+
headers['x-oss-object-acl'] = opts[:acl] if opts.key?(:acl)
|
528
|
+
to_lower_case(opts[:metas] || {})
|
529
|
+
.each { |k, v| headers["x-oss-meta-#{k.to_s}"] = v.to_s }
|
530
|
+
|
531
|
+
headers.merge!(to_lower_case(opts[:headers])) if opts.key?(:headers)
|
532
|
+
|
522
533
|
if opts.key?(:callback)
|
523
534
|
headers[CALLBACK_HEADER] = opts[:callback].serialize
|
524
535
|
end
|
525
536
|
|
526
|
-
(opts[:metas] || {})
|
527
|
-
.each { |k, v| headers["x-oss-meta-#{k.to_s}"] = v.to_s }
|
528
|
-
|
529
537
|
r = @http.put(
|
530
538
|
{:bucket => bucket_name, :object => object_name},
|
531
539
|
{:headers => headers, :body => HTTP::StreamPayload.new(&block)})
|
@@ -546,6 +554,8 @@ module Aliyun
|
|
546
554
|
# @param object_name [String] the object name
|
547
555
|
# @param position [Integer] the position to append
|
548
556
|
# @param opts [Hash] Options
|
557
|
+
# @option opts [String] :acl specify the object's ACL. See
|
558
|
+
# {OSS::ACL}
|
549
559
|
# @option opts [String] :content_type the HTTP Content-Type
|
550
560
|
# for the file, if not specified client will try to determine
|
551
561
|
# the type itself and fall back to HTTP::DEFAULT_CONTENT_TYPE
|
@@ -553,6 +563,9 @@ module Aliyun
|
|
553
563
|
# @option opts [Hash<Symbol, String>] :metas key-value pairs
|
554
564
|
# that serve as the object meta which will be stored together
|
555
565
|
# with the object
|
566
|
+
# @option opts [Hash] :headers custom HTTP headers, case
|
567
|
+
# insensitive. Headers specified here will overwrite `:metas`
|
568
|
+
# and `:content_type`
|
556
569
|
# @return [Integer] next position to append
|
557
570
|
# @yield [HTTP::StreamWriter] a stream writer is
|
558
571
|
# yielded to the caller to which it can write chunks of data
|
@@ -566,10 +579,13 @@ module Aliyun
|
|
566
579
|
"#{object_name}, position: #{position}, options: #{opts}")
|
567
580
|
|
568
581
|
sub_res = {'append' => nil, 'position' => position}
|
569
|
-
headers = {'
|
570
|
-
|
582
|
+
headers = {'content-type' => opts[:content_type]}
|
583
|
+
headers['x-oss-object-acl'] = opts[:acl] if opts.key?(:acl)
|
584
|
+
to_lower_case(opts[:metas] || {})
|
571
585
|
.each { |k, v| headers["x-oss-meta-#{k.to_s}"] = v.to_s }
|
572
586
|
|
587
|
+
headers.merge!(to_lower_case(opts[:headers])) if opts.key?(:headers)
|
588
|
+
|
573
589
|
r = @http.post(
|
574
590
|
{:bucket => bucket_name, :object => object_name, :sub_res => sub_res},
|
575
591
|
{:headers => headers, :body => HTTP::StreamPayload.new(&block)})
|
@@ -721,7 +737,7 @@ module Aliyun
|
|
721
737
|
rewrites = opts[:rewrite]
|
722
738
|
|
723
739
|
headers = {}
|
724
|
-
headers['
|
740
|
+
headers['range'] = get_bytes_range(range) if range
|
725
741
|
headers.merge!(get_conditions(conditions)) if conditions
|
726
742
|
|
727
743
|
sub_res = {}
|
@@ -758,7 +774,7 @@ module Aliyun
|
|
758
774
|
:etag => h[:etag],
|
759
775
|
:metas => metas,
|
760
776
|
:last_modified => wrap(h[:last_modified]) { |x| Time.parse(x) },
|
761
|
-
:
|
777
|
+
:headers => h)
|
762
778
|
|
763
779
|
logger.debug("Done get object")
|
764
780
|
|
@@ -801,7 +817,7 @@ module Aliyun
|
|
801
817
|
:etag => h[:etag],
|
802
818
|
:metas => metas,
|
803
819
|
:last_modified => wrap(h[:last_modified]) { |x| Time.parse(x) },
|
804
|
-
:
|
820
|
+
:headers => h)
|
805
821
|
|
806
822
|
logger.debug("Done get object meta")
|
807
823
|
|
@@ -840,7 +856,7 @@ module Aliyun
|
|
840
856
|
headers = {
|
841
857
|
'x-oss-copy-source' =>
|
842
858
|
@http.get_resource_path(bucket_name, src_object_name),
|
843
|
-
'
|
859
|
+
'content-type' => opts[:content_type]
|
844
860
|
}
|
845
861
|
(opts[:metas] || {})
|
846
862
|
.each { |k, v| headers["x-oss-meta-#{k.to_s}"] = v.to_s }
|
@@ -982,9 +998,9 @@ module Aliyun
|
|
982
998
|
"headers: #{headers.join(',')}")
|
983
999
|
|
984
1000
|
h = {
|
985
|
-
'
|
986
|
-
'
|
987
|
-
'
|
1001
|
+
'origin' => origin,
|
1002
|
+
'access-control-request-method' => method,
|
1003
|
+
'access-control-request-headers' => headers.join(',')
|
988
1004
|
}
|
989
1005
|
|
990
1006
|
r = @http.options(
|
@@ -1017,16 +1033,21 @@ module Aliyun
|
|
1017
1033
|
# @option opts [Hash<Symbol, String>] :metas key-value pairs
|
1018
1034
|
# that serve as the object meta which will be stored together
|
1019
1035
|
# with the object
|
1036
|
+
# @option opts [Hash] :headers custom HTTP headers, case
|
1037
|
+
# insensitive. Headers specified here will overwrite `:metas`
|
1038
|
+
# and `:content_type`
|
1020
1039
|
# @return [String] the upload id
|
1021
1040
|
def initiate_multipart_upload(bucket_name, object_name, opts = {})
|
1022
1041
|
logger.info("Begin initiate multipart upload, bucket: "\
|
1023
1042
|
"#{bucket_name}, object: #{object_name}, options: #{opts}")
|
1024
1043
|
|
1025
1044
|
sub_res = {'uploads' => nil}
|
1026
|
-
headers = {'
|
1027
|
-
(opts[:metas] || {})
|
1045
|
+
headers = {'content-type' => opts[:content_type]}
|
1046
|
+
to_lower_case(opts[:metas] || {})
|
1028
1047
|
.each { |k, v| headers["x-oss-meta-#{k.to_s}"] = v.to_s }
|
1029
1048
|
|
1049
|
+
headers.merge!(to_lower_case(opts[:headers])) if opts.key?(:headers)
|
1050
|
+
|
1030
1051
|
r = @http.post(
|
1031
1052
|
{:bucket => bucket_name, :object => object_name,
|
1032
1053
|
:sub_res => sub_res},
|
@@ -1092,7 +1113,7 @@ module Aliyun
|
|
1092
1113
|
'x-oss-copy-source' =>
|
1093
1114
|
@http.get_resource_path(bucket_name, source_object)
|
1094
1115
|
}
|
1095
|
-
headers['
|
1116
|
+
headers['range'] = get_bytes_range(range) if range
|
1096
1117
|
headers.merge!(get_copy_conditions(conditions)) if conditions
|
1097
1118
|
|
1098
1119
|
sub_res = {'partNumber' => part_no, 'uploadId' => txn_id}
|
@@ -1392,14 +1413,14 @@ module Aliyun
|
|
1392
1413
|
# @return [Hash] conditions for HTTP headers
|
1393
1414
|
def get_conditions(conditions)
|
1394
1415
|
{
|
1395
|
-
:if_modified_since => '
|
1396
|
-
:if_unmodified_since => '
|
1416
|
+
:if_modified_since => 'if-modified-since',
|
1417
|
+
:if_unmodified_since => 'if-unmodified-since',
|
1397
1418
|
}.reduce({}) { |h, (k, v)|
|
1398
1419
|
conditions.key?(k)? h.merge(v => conditions[k].httpdate) : h
|
1399
1420
|
}.merge(
|
1400
1421
|
{
|
1401
|
-
:if_match_etag => '
|
1402
|
-
:if_unmatch_etag => '
|
1422
|
+
:if_match_etag => 'if-match',
|
1423
|
+
:if_unmatch_etag => 'if-none-match'
|
1403
1424
|
}.reduce({}) { |h, (k, v)|
|
1404
1425
|
conditions.key?(k)? h.merge(v => conditions[k]) : h
|
1405
1426
|
}
|
@@ -1445,6 +1466,16 @@ module Aliyun
|
|
1445
1466
|
kv.each { |k, v| hash[k] = v.call(hash[k]) if hash.key?(k) }
|
1446
1467
|
end
|
1447
1468
|
|
1469
|
+
# Convert hash keys to lower case Non-Recursively
|
1470
|
+
# @param hash [Hash] the hash to be converted
|
1471
|
+
# @return [Hash] hash with lower case keys
|
1472
|
+
def to_lower_case(hash)
|
1473
|
+
hash.reduce({}) do |result, (k, v)|
|
1474
|
+
result[k.to_s.downcase] = v
|
1475
|
+
result
|
1476
|
+
end
|
1477
|
+
end
|
1478
|
+
|
1448
1479
|
end # Protocol
|
1449
1480
|
end # OSS
|
1450
1481
|
end # Aliyun
|
data/lib/aliyun/oss/util.rb
CHANGED
@@ -24,9 +24,9 @@ module Aliyun
|
|
24
24
|
def get_signature(key, verb, headers, resources)
|
25
25
|
logger.debug("Sign, headers: #{headers}, resources: #{resources}")
|
26
26
|
|
27
|
-
content_md5 = headers['
|
28
|
-
content_type = headers['
|
29
|
-
date = headers['
|
27
|
+
content_md5 = headers['content-md5'] || ""
|
28
|
+
content_type = headers['content-type'] || ""
|
29
|
+
date = headers['date']
|
30
30
|
|
31
31
|
cano_headers = headers.select { |k, v| k.start_with?(HEADER_PREFIX) }
|
32
32
|
.map { |k, v| [k.downcase.strip, v.strip] }
|
data/lib/aliyun/version.rb
CHANGED
@@ -239,6 +239,17 @@ module Aliyun
|
|
239
239
|
.with(:body => content, :query => {})
|
240
240
|
end
|
241
241
|
|
242
|
+
it "should put object with acl" do
|
243
|
+
key = 'ruby'
|
244
|
+
stub_request(:put, object_url(key))
|
245
|
+
|
246
|
+
@bucket.put_object(key, :acl => ACL::PUBLIC_READ)
|
247
|
+
|
248
|
+
expect(WebMock)
|
249
|
+
.to have_requested(:put, object_url(key))
|
250
|
+
.with(:headers => {'X-Oss-Object-Acl' => ACL::PUBLIC_READ})
|
251
|
+
end
|
252
|
+
|
242
253
|
it "should put object with callback" do
|
243
254
|
key = 'ruby'
|
244
255
|
stub_request(:put, object_url(key))
|
@@ -276,6 +287,37 @@ module Aliyun
|
|
276
287
|
.with { |req| req.headers.key?('X-Oss-Callback') }
|
277
288
|
end
|
278
289
|
|
290
|
+
it "should set custom headers when put object" do
|
291
|
+
key = 'ruby'
|
292
|
+
stub_request(:put, object_url(key))
|
293
|
+
|
294
|
+
@bucket.put_object(
|
295
|
+
key, headers: {'cache-control' => 'xxx', 'expires' => 'yyy'})
|
296
|
+
|
297
|
+
headers = {}
|
298
|
+
expect(WebMock).to have_requested(:put, object_url(key))
|
299
|
+
.with { |req| headers = req.headers }
|
300
|
+
expect(headers['Cache-Control']).to eq('xxx')
|
301
|
+
expect(headers['Expires']).to eq('yyy')
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should set custom headers when append object" do
|
305
|
+
key = 'ruby'
|
306
|
+
query = {'append' => '', 'position' => 11}
|
307
|
+
stub_request(:post, object_url(key)).with(:query => query)
|
308
|
+
|
309
|
+
@bucket.append_object(
|
310
|
+
key, 11,
|
311
|
+
headers: {'CACHE-CONTROL' => 'nocache', 'EXPIRES' => 'seripxe'})
|
312
|
+
|
313
|
+
headers = {}
|
314
|
+
expect(WebMock).to have_requested(:post, object_url(key))
|
315
|
+
.with(:query => query)
|
316
|
+
.with { |req| headers = req.headers }
|
317
|
+
expect(headers['Cache-Control']).to eq('nocache')
|
318
|
+
expect(headers['Expires']).to eq('seripxe')
|
319
|
+
end
|
320
|
+
|
279
321
|
it "should get object to file" do
|
280
322
|
key = 'ruby'
|
281
323
|
# 100 KB
|
@@ -334,6 +376,19 @@ module Aliyun
|
|
334
376
|
:headers => {'Content-Type' => 'text/html'})
|
335
377
|
end
|
336
378
|
|
379
|
+
it "should append object with acl" do
|
380
|
+
key = 'ruby'
|
381
|
+
query = {'append' => '', 'position' => 11}
|
382
|
+
stub_request(:post, object_url(key)).with(:query => query)
|
383
|
+
|
384
|
+
@bucket.append_object(key, 11, :acl => ACL::PUBLIC_READ_WRITE)
|
385
|
+
|
386
|
+
expect(WebMock)
|
387
|
+
.to have_requested(:post, object_url(key))
|
388
|
+
.with(:query => query,
|
389
|
+
:headers => {'X-Oss-Object-Acl' => ACL::PUBLIC_READ_WRITE})
|
390
|
+
end
|
391
|
+
|
337
392
|
it "should answer object exists?" do
|
338
393
|
key = 'ruby'
|
339
394
|
|
@@ -115,27 +115,15 @@ module Aliyun
|
|
115
115
|
body: 'hello world',
|
116
116
|
host: 'server.com'
|
117
117
|
)
|
118
|
-
prg = []
|
119
118
|
@bucket.resumable_upload(
|
120
|
-
@object_key, @file,
|
121
|
-
:part_size => 10, :callback => callback) { |p| prg << p }
|
119
|
+
@object_key, @file, part_size: 10, callback: callback)
|
122
120
|
|
123
121
|
expect(WebMock).to have_requested(
|
124
122
|
:post, /#{object_url}\?uploads.*/).times(1)
|
125
123
|
|
126
|
-
part_numbers = Set.new([])
|
127
|
-
upload_ids = Set.new([])
|
128
|
-
|
129
124
|
expect(WebMock).to have_requested(
|
130
|
-
|
131
|
-
|
132
|
-
part_numbers << query['partNumber']
|
133
|
-
upload_ids << query['uploadId']
|
134
|
-
}.times(10)
|
135
|
-
|
136
|
-
expect(part_numbers.to_a).to match_array((1..10).map{ |x| x.to_s })
|
137
|
-
expect(upload_ids.to_a).to match_array(['upload_id'])
|
138
|
-
|
125
|
+
:put, /#{object_url}\?partNumber.*/)
|
126
|
+
.times(10)
|
139
127
|
expect(WebMock)
|
140
128
|
.to have_requested(
|
141
129
|
:post, /#{object_url}\?uploadId.*/)
|
@@ -143,7 +131,6 @@ module Aliyun
|
|
143
131
|
.times(1)
|
144
132
|
|
145
133
|
expect(File.exist?("#{@file}.cpt")).to be false
|
146
|
-
expect(prg.size).to eq(10)
|
147
134
|
end
|
148
135
|
|
149
136
|
it "should raise CallbackError when callback failed" do
|
@@ -162,28 +149,17 @@ module Aliyun
|
|
162
149
|
body: 'hello world',
|
163
150
|
host: 'server.com'
|
164
151
|
)
|
165
|
-
prg = []
|
166
152
|
expect {
|
167
153
|
@bucket.resumable_upload(
|
168
|
-
@object_key, @file,
|
169
|
-
:part_size => 10, :callback => callback) { |p| prg << p }
|
154
|
+
@object_key, @file, part_size: 10, callback: callback)
|
170
155
|
}.to raise_error(CallbackError, err(message))
|
171
156
|
|
172
157
|
expect(WebMock).to have_requested(
|
173
158
|
:post, /#{object_url}\?uploads.*/).times(1)
|
174
159
|
|
175
|
-
part_numbers = Set.new([])
|
176
|
-
upload_ids = Set.new([])
|
177
|
-
|
178
160
|
expect(WebMock).to have_requested(
|
179
|
-
|
180
|
-
|
181
|
-
part_numbers << query['partNumber']
|
182
|
-
upload_ids << query['uploadId']
|
183
|
-
}.times(10)
|
184
|
-
|
185
|
-
expect(part_numbers.to_a).to match_array((1..10).map{ |x| x.to_s })
|
186
|
-
expect(upload_ids.to_a).to match_array(['upload_id'])
|
161
|
+
:put, /#{object_url}\?partNumber.*/)
|
162
|
+
.times(10)
|
187
163
|
|
188
164
|
expect(WebMock)
|
189
165
|
.to have_requested(
|
@@ -192,7 +168,27 @@ module Aliyun
|
|
192
168
|
.times(1)
|
193
169
|
|
194
170
|
expect(File.exist?("#{@file}.cpt")).to be true
|
195
|
-
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should upload file with custom headers" do
|
174
|
+
stub_request(:post, /#{object_url}\?uploads.*/)
|
175
|
+
.to_return(:body => mock_txn_id('upload_id'))
|
176
|
+
stub_request(:put, /#{object_url}\?partNumber.*/)
|
177
|
+
stub_request(:post, /#{object_url}\?uploadId.*/)
|
178
|
+
|
179
|
+
@bucket.resumable_upload(
|
180
|
+
@object_key, @file,
|
181
|
+
part_size: 10,
|
182
|
+
headers: {'cache-CONTROL' => 'cacheit', 'CONTENT-disposition' => 'oh;yeah'})
|
183
|
+
|
184
|
+
headers = {}
|
185
|
+
expect(WebMock).to have_requested(
|
186
|
+
:post, /#{object_url}\?uploads.*/)
|
187
|
+
.with { |req| headers = req.headers }.times(1)
|
188
|
+
|
189
|
+
expect(headers['Cache-Control']).to eq('cacheit')
|
190
|
+
expect(headers['Content-Disposition']).to eq('oh;yeah')
|
191
|
+
expect(File.exist?("#{@file}.cpt")).to be false
|
196
192
|
end
|
197
193
|
|
198
194
|
it "should restart when begin txn fails" do
|
@@ -23,22 +23,22 @@ module Aliyun
|
|
23
23
|
key = 'helloworld'
|
24
24
|
date = 'Fri, 30 Oct 2015 07:21:00 GMT'
|
25
25
|
|
26
|
-
signature = Util.get_signature(key, 'GET', {'
|
26
|
+
signature = Util.get_signature(key, 'GET', {'date' => date}, {})
|
27
27
|
expect(signature).to eq("u8QKAAj/axKX4JhHXa5DYfYSPxE=")
|
28
28
|
|
29
29
|
signature = Util.get_signature(
|
30
|
-
key, 'PUT', {'
|
30
|
+
key, 'PUT', {'date' => date}, {:path => '/bucket'})
|
31
31
|
expect(signature).to eq("lMKrMCJIuGygd8UsdMA+S0QOAsQ=")
|
32
32
|
|
33
33
|
signature = Util.get_signature(
|
34
34
|
key, 'PUT',
|
35
|
-
{'
|
35
|
+
{'date' => date, 'x-oss-copy-source' => '/bucket/object-old'},
|
36
36
|
{:path => '/bucket/object-new'})
|
37
37
|
expect(signature).to eq("McYUmBaErN//yvE9voWRhCgvsIc=")
|
38
38
|
|
39
39
|
signature = Util.get_signature(
|
40
40
|
key, 'PUT',
|
41
|
-
{'
|
41
|
+
{'date' => date},
|
42
42
|
{:path => '/bucket/object-new',
|
43
43
|
:sub_res => {'append' => nil, 'position' => 0}})
|
44
44
|
expect(signature).to eq("7Oh2wobzeg6dw/cWYbF/2m6s6qc=")
|
data/tests/test_content_type.rb
CHANGED
@@ -43,15 +43,15 @@ class TestContentType < Minitest::Test
|
|
43
43
|
@types.each do |k, v|
|
44
44
|
key = get_key('from_key', k)
|
45
45
|
@bucket.put_object(key)
|
46
|
-
assert_equal v, @bucket.get_object(key).content_type
|
46
|
+
assert_equal v, @bucket.get_object(key).headers[:content_type]
|
47
47
|
|
48
48
|
copy_key = get_key('copy.from_key', k)
|
49
49
|
@bucket.copy_object(key, copy_key)
|
50
|
-
assert_equal v, @bucket.get_object(copy_key).content_type
|
50
|
+
assert_equal v, @bucket.get_object(copy_key).headers[:content_type]
|
51
51
|
|
52
52
|
append_key = get_key('append.from_key', k)
|
53
53
|
@bucket.append_object(append_key, 0)
|
54
|
-
assert_equal v, @bucket.get_object(append_key).content_type
|
54
|
+
assert_equal v, @bucket.get_object(append_key).headers[:content_type]
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -63,15 +63,15 @@ class TestContentType < Minitest::Test
|
|
63
63
|
|
64
64
|
key = get_key('from_file', k)
|
65
65
|
@bucket.put_object(key, :file => upload_file)
|
66
|
-
assert_equal v, @bucket.get_object(key).content_type
|
66
|
+
assert_equal v, @bucket.get_object(key).headers[:content_type]
|
67
67
|
|
68
68
|
append_key = get_key('append.from_file', k)
|
69
69
|
@bucket.append_object(append_key, 0, :file => upload_file)
|
70
|
-
assert_equal v, @bucket.get_object(append_key).content_type
|
70
|
+
assert_equal v, @bucket.get_object(append_key).headers[:content_type]
|
71
71
|
|
72
72
|
multipart_key = get_key('multipart.from_file', k)
|
73
73
|
@bucket.resumable_upload(multipart_key, upload_file)
|
74
|
-
assert_equal v, @bucket.get_object(multipart_key).content_type
|
74
|
+
assert_equal v, @bucket.get_object(multipart_key).headers[:content_type]
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
@@ -82,19 +82,19 @@ class TestContentType < Minitest::Test
|
|
82
82
|
|
83
83
|
key = get_key('from_user', k)
|
84
84
|
@bucket.put_object(key, :file => upload_file, :content_type => v)
|
85
|
-
assert_equal v, @bucket.get_object(key).content_type
|
85
|
+
assert_equal v, @bucket.get_object(key).headers[:content_type]
|
86
86
|
|
87
87
|
copy_key = get_key('copy.from_user', k)
|
88
88
|
@bucket.copy_object(key, copy_key, :content_type => v)
|
89
|
-
assert_equal v, @bucket.get_object(copy_key).content_type
|
89
|
+
assert_equal v, @bucket.get_object(copy_key).headers[:content_type]
|
90
90
|
|
91
91
|
append_key = get_key('append.from_user', k)
|
92
92
|
@bucket.append_object(append_key, 0, :file => upload_file, :content_type => v)
|
93
|
-
assert_equal v, @bucket.get_object(append_key).content_type
|
93
|
+
assert_equal v, @bucket.get_object(append_key).headers[:content_type]
|
94
94
|
|
95
95
|
multipart_key = get_key('multipart.from_file', k)
|
96
96
|
@bucket.resumable_upload(multipart_key, upload_file, :content_type => v)
|
97
|
-
assert_equal v, @bucket.get_object(multipart_key).content_type
|
97
|
+
assert_equal v, @bucket.get_object(multipart_key).headers[:content_type]
|
98
98
|
end
|
99
99
|
end
|
100
100
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'yaml'
|
3
|
+
$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
require 'aliyun/oss'
|
5
|
+
require 'zlib'
|
6
|
+
|
7
|
+
class TestCustomHeaders < Minitest::Test
|
8
|
+
def setup
|
9
|
+
Aliyun::Common::Logging.set_log_level(Logger::DEBUG)
|
10
|
+
conf_file = '~/.oss.yml'
|
11
|
+
conf = YAML.load(File.read(File.expand_path(conf_file)))
|
12
|
+
client = Aliyun::OSS::Client.new(
|
13
|
+
:endpoint => conf['endpoint'],
|
14
|
+
:cname => conf['cname'],
|
15
|
+
:access_key_id => conf['access_key_id'],
|
16
|
+
:access_key_secret => conf['access_key_secret'])
|
17
|
+
@bucket = client.get_bucket(conf['bucket'])
|
18
|
+
|
19
|
+
@prefix = "tests/custom_headers/"
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_key(k)
|
23
|
+
"#{@prefix}#{k}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_custom_headers
|
27
|
+
key = get_key('ruby')
|
28
|
+
cache_control = 'max-age: 3600'
|
29
|
+
@bucket.put_object(key, headers: {'cache-control' => cache_control})
|
30
|
+
obj = @bucket.get_object(key)
|
31
|
+
assert_equal cache_control, obj.headers[:cache_control]
|
32
|
+
|
33
|
+
content_disposition = 'attachment; filename="fname.ext"'
|
34
|
+
@bucket.put_object(
|
35
|
+
key,
|
36
|
+
headers: {'cache-control' => cache_control,
|
37
|
+
'CONTENT-DISPOSITION' => content_disposition})
|
38
|
+
obj = @bucket.get_object(key)
|
39
|
+
assert_equal cache_control, obj.headers[:cache_control]
|
40
|
+
assert_equal content_disposition, obj.headers[:content_disposition]
|
41
|
+
|
42
|
+
content_encoding = 'deflate'
|
43
|
+
expires = (Time.now + 3600).httpdate
|
44
|
+
@bucket.put_object(
|
45
|
+
key,
|
46
|
+
headers: {'cache-control' => cache_control,
|
47
|
+
'CONTENT-DISPOSITION' => content_disposition,
|
48
|
+
'content-ENCODING' => content_encoding,
|
49
|
+
'EXPIRES' => expires }) do |s|
|
50
|
+
s << Zlib::Deflate.deflate('hello world')
|
51
|
+
end
|
52
|
+
|
53
|
+
content = ''
|
54
|
+
obj = @bucket.get_object(key) { |c| content << c }
|
55
|
+
assert_equal 'hello world', content
|
56
|
+
assert_equal cache_control, obj.headers[:cache_control]
|
57
|
+
assert_equal content_disposition, obj.headers[:content_disposition]
|
58
|
+
assert_equal content_encoding, obj.headers[:content_encoding]
|
59
|
+
assert_equal expires, obj.headers[:expires]
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_headers_overwrite
|
63
|
+
key = get_key('rails')
|
64
|
+
@bucket.put_object(
|
65
|
+
key,
|
66
|
+
content_type: 'text/html',
|
67
|
+
metas: {'hello' => 'world'},
|
68
|
+
headers: {'content-type' => 'application/json',
|
69
|
+
'x-oss-meta-hello' => 'bar'}) { |s| s << 'hello world' }
|
70
|
+
obj = @bucket.get_object(key)
|
71
|
+
|
72
|
+
assert_equal 'application/json', obj.headers[:content_type]
|
73
|
+
assert_equal ({'hello' => 'bar'}), obj.metas
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'yaml'
|
3
|
+
$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
require 'aliyun/oss'
|
5
|
+
|
6
|
+
class TestObjectACL < Minitest::Test
|
7
|
+
def setup
|
8
|
+
Aliyun::Common::Logging.set_log_level(Logger::DEBUG)
|
9
|
+
conf_file = '~/.oss.yml'
|
10
|
+
conf = YAML.load(File.read(File.expand_path(conf_file)))
|
11
|
+
client = Aliyun::OSS::Client.new(
|
12
|
+
:endpoint => conf['endpoint'],
|
13
|
+
:cname => conf['cname'],
|
14
|
+
:access_key_id => conf['access_key_id'],
|
15
|
+
:access_key_secret => conf['access_key_secret'])
|
16
|
+
@bucket = client.get_bucket(conf['bucket'])
|
17
|
+
|
18
|
+
@prefix = "tests/object_acl/"
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_key(k)
|
22
|
+
"#{@prefix}#{k}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_put_object
|
26
|
+
key = get_key('put')
|
27
|
+
|
28
|
+
@bucket.put_object(key, acl: Aliyun::OSS::ACL::PRIVATE)
|
29
|
+
acl = @bucket.get_object_acl(key)
|
30
|
+
|
31
|
+
assert_equal Aliyun::OSS::ACL::PRIVATE, acl
|
32
|
+
|
33
|
+
@bucket.put_object(key, acl: Aliyun::OSS::ACL::PUBLIC_READ)
|
34
|
+
acl = @bucket.get_object_acl(key)
|
35
|
+
|
36
|
+
assert_equal Aliyun::OSS::ACL::PUBLIC_READ, acl
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_append_object
|
40
|
+
key = get_key('append-1')
|
41
|
+
|
42
|
+
@bucket.append_object(key, 0, acl: Aliyun::OSS::ACL::PRIVATE)
|
43
|
+
acl = @bucket.get_object_acl(key)
|
44
|
+
|
45
|
+
assert_equal Aliyun::OSS::ACL::PRIVATE, acl
|
46
|
+
|
47
|
+
key = get_key('append-2')
|
48
|
+
|
49
|
+
@bucket.put_object(key, acl: Aliyun::OSS::ACL::PUBLIC_READ)
|
50
|
+
acl = @bucket.get_object_acl(key)
|
51
|
+
|
52
|
+
assert_equal Aliyun::OSS::ACL::PUBLIC_READ, acl
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aliyun-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tianlong Wu
|
@@ -180,9 +180,11 @@ files:
|
|
180
180
|
- spec/aliyun/sts/client_spec.rb
|
181
181
|
- spec/aliyun/sts/util_spec.rb
|
182
182
|
- tests/test_content_type.rb
|
183
|
+
- tests/test_custom_headers.rb
|
183
184
|
- tests/test_encoding.rb
|
184
185
|
- tests/test_large_file.rb
|
185
186
|
- tests/test_multipart.rb
|
187
|
+
- tests/test_object_acl.rb
|
186
188
|
- tests/test_object_key.rb
|
187
189
|
- tests/test_resumable.rb
|
188
190
|
homepage: https://github.com/aliyun/aliyun-oss-ruby-sdk
|
@@ -223,8 +225,10 @@ test_files:
|
|
223
225
|
- spec/aliyun/sts/client_spec.rb
|
224
226
|
- spec/aliyun/sts/util_spec.rb
|
225
227
|
- tests/test_content_type.rb
|
228
|
+
- tests/test_custom_headers.rb
|
226
229
|
- tests/test_encoding.rb
|
227
230
|
- tests/test_large_file.rb
|
228
231
|
- tests/test_multipart.rb
|
232
|
+
- tests/test_object_acl.rb
|
229
233
|
- tests/test_object_key.rb
|
230
234
|
- tests/test_resumable.rb
|