aliyun-sdk 0.5.0 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +25 -0
  3. data/README.md +174 -172
  4. data/examples/aliyun/oss/bucket.rb +0 -0
  5. data/examples/aliyun/oss/callback.rb +0 -0
  6. data/examples/aliyun/oss/object.rb +0 -0
  7. data/examples/aliyun/oss/resumable_download.rb +0 -0
  8. data/examples/aliyun/oss/resumable_upload.rb +0 -0
  9. data/examples/aliyun/oss/streaming.rb +0 -0
  10. data/examples/aliyun/oss/using_sts.rb +0 -0
  11. data/examples/aliyun/sts/assume_role.rb +0 -0
  12. data/ext/crcx/crc64_ecma.c +0 -0
  13. data/ext/crcx/crcx.c +0 -0
  14. data/ext/crcx/crcx.h +0 -0
  15. data/ext/crcx/extconf.rb +0 -0
  16. data/lib/aliyun/common.rb +0 -0
  17. data/lib/aliyun/common/exception.rb +0 -0
  18. data/lib/aliyun/common/logging.rb +3 -2
  19. data/lib/aliyun/common/struct.rb +0 -0
  20. data/lib/aliyun/oss.rb +0 -0
  21. data/lib/aliyun/oss/bucket.rb +29 -32
  22. data/lib/aliyun/oss/client.rb +6 -2
  23. data/lib/aliyun/oss/config.rb +0 -0
  24. data/lib/aliyun/oss/download.rb +0 -0
  25. data/lib/aliyun/oss/exception.rb +0 -0
  26. data/lib/aliyun/oss/http.rb +25 -46
  27. data/lib/aliyun/oss/iterator.rb +0 -0
  28. data/lib/aliyun/oss/multipart.rb +0 -0
  29. data/lib/aliyun/oss/object.rb +0 -0
  30. data/lib/aliyun/oss/protocol.rb +27 -12
  31. data/lib/aliyun/oss/struct.rb +2 -2
  32. data/lib/aliyun/oss/upload.rb +0 -0
  33. data/lib/aliyun/oss/util.rb +6 -0
  34. data/lib/aliyun/sts.rb +0 -0
  35. data/lib/aliyun/sts/client.rb +1 -1
  36. data/lib/aliyun/sts/config.rb +0 -0
  37. data/lib/aliyun/sts/exception.rb +0 -0
  38. data/lib/aliyun/sts/protocol.rb +3 -3
  39. data/lib/aliyun/sts/struct.rb +0 -0
  40. data/lib/aliyun/sts/util.rb +0 -0
  41. data/lib/aliyun/version.rb +1 -1
  42. data/spec/aliyun/oss/bucket_spec.rb +140 -18
  43. data/spec/aliyun/oss/client/bucket_spec.rb +276 -30
  44. data/spec/aliyun/oss/client/client_spec.rb +26 -1
  45. data/spec/aliyun/oss/client/resumable_download_spec.rb +0 -0
  46. data/spec/aliyun/oss/client/resumable_upload_spec.rb +0 -0
  47. data/spec/aliyun/oss/http_spec.rb +0 -0
  48. data/spec/aliyun/oss/multipart_spec.rb +10 -10
  49. data/spec/aliyun/oss/object_spec.rb +109 -16
  50. data/spec/aliyun/oss/service_spec.rb +0 -0
  51. data/spec/aliyun/oss/util_spec.rb +51 -0
  52. data/spec/aliyun/sts/client_spec.rb +0 -0
  53. data/spec/aliyun/sts/util_spec.rb +0 -0
  54. data/tests/config.rb +0 -0
  55. data/tests/helper.rb +0 -0
  56. data/tests/test_content_encoding.rb +0 -0
  57. data/tests/test_content_type.rb +0 -0
  58. data/tests/test_crc_check.rb +0 -0
  59. data/tests/test_custom_headers.rb +0 -0
  60. data/tests/test_encoding.rb +0 -0
  61. data/tests/test_large_file.rb +0 -0
  62. data/tests/test_multipart.rb +0 -0
  63. data/tests/test_object_acl.rb +0 -0
  64. data/tests/test_object_key.rb +18 -0
  65. data/tests/test_object_url.rb +20 -0
  66. data/tests/test_resumable.rb +0 -0
  67. metadata +8 -10
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -11,7 +11,6 @@ module Aliyun
11
11
  # logger.info(xxx)
12
12
  module Logging
13
13
 
14
- DEFAULT_LOG_FILE = "./aliyun_sdk.log"
15
14
  MAX_NUM_LOG = 100
16
15
  ROTATE_SIZE = 10 * 1024 * 1024
17
16
 
@@ -34,8 +33,10 @@ module Aliyun
34
33
 
35
34
  def self.logger
36
35
  unless @logger
36
+ # Environment parameter ALIYUN_OSS_SDK_LOG_PATH used to set output log to a file,do not output log if not set
37
+ @log_file ||= ENV["ALIYUN_OSS_SDK_LOG_PATH"]
37
38
  @logger = Logger.new(
38
- @log_file ||= DEFAULT_LOG_FILE, MAX_NUM_LOG, ROTATE_SIZE)
39
+ @log_file, MAX_NUM_LOG, ROTATE_SIZE)
39
40
  @logger.level = Logger::INFO
40
41
  end
41
42
  @logger
File without changes
File without changes
@@ -588,42 +588,39 @@ module Aliyun
588
588
  # 获取Object的URL
589
589
  # @param [String] key Object的key
590
590
  # @param [Boolean] sign 是否对URL进行签名,默认为是
591
- # @param [Fixnum] expiry URL的有效时间,单位为秒,默认为60s
591
+ # @param [Integer] expiry URL的有效时间,单位为秒,默认为60s
592
+ # @param [Hash] parameters 附加的query参数,默认为空
592
593
  # @return [String] 用于直接访问Object的URL
593
- def object_url(key, sign = true, expiry = 60)
594
- url = @protocol.get_request_url(name, key)
595
- return url unless sign
596
-
597
- expires = Time.now.to_i + expiry
598
- query = {
599
- 'Expires' => expires.to_s,
600
- 'OSSAccessKeyId' => CGI.escape(access_key_id)
601
- }
602
-
603
- sub_res = []
604
- if @protocol.get_sts_token
605
- sub_res << "security-token=#{@protocol.get_sts_token}"
606
- query['security-token'] = CGI.escape(@protocol.get_sts_token)
607
- end
608
-
609
- resource = "/#{name}/#{key}"
610
- unless sub_res.empty?
611
- resource << "?#{sub_res.join('&')}"
612
- end
594
+ def object_url(key, sign = true, expiry = 60, parameters = {})
595
+ url = @protocol.get_request_url(name, key).gsub('%2F', '/')
596
+ query = parameters.dup
597
+
598
+ if sign
599
+ #header
600
+ expires = Time.now.to_i + expiry
601
+ headers = {
602
+ 'date' => expires.to_s,
603
+ }
604
+
605
+ #query
606
+ if @protocol.get_sts_token
607
+ query['security-token'] = @protocol.get_sts_token
608
+ end
613
609
 
614
- string_to_sign = "" <<
615
- "GET\n" << # method
616
- "\n" << # Content-MD5
617
- "\n" << # Content-Type
618
- "#{expires}\n" <<
619
- "#{resource}"
610
+ res = {
611
+ :path => @protocol.get_resource_path(name, key),
612
+ :sub_res => query,
613
+ }
614
+ signature = Util.get_signature(@protocol.get_access_key_secret, 'GET', headers, res)
620
615
 
621
- signature = sign(string_to_sign)
622
- query_string =
623
- query.merge('Signature' => CGI.escape(signature))
624
- .map { |k, v| "#{k}=#{v}" }.join('&')
616
+ query['Expires'] = expires.to_s
617
+ query['OSSAccessKeyId'] = @protocol.get_access_key_id
618
+ query['Signature'] = signature
619
+ end
625
620
 
626
- [url, query_string].join('?')
621
+ query_string = query.map { |k, v| v ? [k, CGI.escape(v)].join("=") : k }.join("&")
622
+ link_char = query_string.empty? ? '' : '?'
623
+ [url, query_string].join(link_char)
627
624
  end
628
625
 
629
626
  # 获取用户所设置的ACCESS_KEY_ID
@@ -34,9 +34,9 @@ module Aliyun
34
34
  # 是否开启CRC校验,默认为不开启(false)
35
35
  # @option opts [String] :sts_token [可选] 指定STS的
36
36
  # SecurityToken,如果指定,则使用STS授权访问
37
- # @option opts [Fixnum] :open_timeout [可选] 指定建立连接的超时
37
+ # @option opts [Integer] :open_timeout [可选] 指定建立连接的超时
38
38
  # 时间,默认为10秒
39
- # @option opts [Fixnum] :read_timeout [可选] 指定等待响应的超时
39
+ # @option opts [Integer] :read_timeout [可选] 指定等待响应的超时
40
40
  # 时间,默认为120秒
41
41
  # @example 标准endpoint
42
42
  # oss-cn-hangzhou.aliyuncs.com
@@ -70,6 +70,7 @@ module Aliyun
70
70
  # @param opts [Hash] 创建Bucket的属性(可选)
71
71
  # @option opts [:location] [String] 指定bucket所在的区域,默认为oss-cn-hangzhou
72
72
  def create_bucket(name, opts = {})
73
+ Util.ensure_bucket_name_valid(name)
73
74
  @protocol.create_bucket(name, opts)
74
75
  end
75
76
 
@@ -77,6 +78,7 @@ module Aliyun
77
78
  # @param name [String] Bucket名字
78
79
  # @note 如果要删除的Bucket不为空(包含有object),则删除会失败
79
80
  def delete_bucket(name)
81
+ Util.ensure_bucket_name_valid(name)
80
82
  @protocol.delete_bucket(name)
81
83
  end
82
84
 
@@ -84,6 +86,7 @@ module Aliyun
84
86
  # @param name [String] Bucket名字
85
87
  # @return [Boolean] 如果Bucket存在则返回true,否则返回false
86
88
  def bucket_exists?(name)
89
+ Util.ensure_bucket_name_valid(name)
87
90
  exist = false
88
91
 
89
92
  begin
@@ -102,6 +105,7 @@ module Aliyun
102
105
  # @param name [String] Bucket名字
103
106
  # @return [Bucket] Bucket对象
104
107
  def get_bucket(name)
108
+ Util.ensure_bucket_name_valid(name)
105
109
  Bucket.new({:name => name}, @protocol)
106
110
  end
107
111
 
File without changes
File without changes
File without changes
@@ -105,35 +105,11 @@ module Aliyun
105
105
  false
106
106
  end
107
107
 
108
- def inspect
109
- "@buffer: " + @buffer[0, 32].inspect + "...#{@buffer.size} bytes"
110
- end
111
- end
112
-
113
- # RestClient requires the payload to respones to :read(bytes)
114
- # and return a stream.
115
- # We are not doing the real read here, just return a
116
- # readable stream for RestClient playload.rb treats it as:
117
- # def read(bytes=nil)
118
- # @stream.read(bytes)
119
- # end
120
- # alias :to_s :read
121
- # net_http_do_request(http, req, payload ? payload.to_s : nil,
122
- # &@block_response)
123
- class StreamPayload
124
- def initialize(crc_enable = false, init_crc = 0, &block)
125
- @stream = StreamWriter.new(crc_enable, init_crc, &block)
126
- end
127
-
128
- def read(bytes = nil)
129
- @stream
130
- end
131
-
132
108
  def close
133
109
  end
134
110
 
135
- def closed?
136
- false
111
+ def inspect
112
+ "@buffer: " + @buffer[0, 32].inspect + "...#{@buffer.size} bytes"
137
113
  end
138
114
  end
139
115
 
@@ -145,12 +121,13 @@ module Aliyun
145
121
 
146
122
  def get_request_url(bucket, object)
147
123
  url = @config.endpoint.dup
124
+ url.query = nil
125
+ url.fragment = nil
148
126
  isIP = !!(url.host =~ Resolv::IPv4::Regex)
149
127
  url.host = "#{bucket}." + url.host if bucket && !@config.cname && !isIP
150
128
  url.path = '/'
151
129
  url.path << "#{bucket}/" if bucket && isIP
152
- url.path << "#{CGI.escape(object)}" if object
153
-
130
+ url.path << CGI.escape(object) if object
154
131
  url.to_s
155
132
  end
156
133
 
@@ -281,44 +258,46 @@ module Aliyun
281
258
  headers[:params] = (sub_res || {}).merge(http_options[:query] || {})
282
259
 
283
260
  block_response = ->(r) { handle_response(r, &block) } if block
284
- r = RestClient::Request.execute(
261
+ request = RestClient::Request.new(
285
262
  :method => verb,
286
263
  :url => get_request_url(bucket, object),
287
264
  :headers => headers,
288
265
  :payload => http_options[:body],
289
266
  :block_response => block_response,
290
267
  :open_timeout => @config.open_timeout || OPEN_TIMEOUT,
291
- :timeout => @config.read_timeout || READ_TIMEOUT
292
- ) do |response, request, result, &blk|
293
-
294
- if response.code >= 300
295
- e = ServerError.new(response)
268
+ :read_timeout => @config.read_timeout || READ_TIMEOUT
269
+ )
270
+ response = request.execute do |resp, &blk|
271
+ if resp.code >= 300
272
+ e = ServerError.new(resp)
296
273
  logger.error(e.to_s)
297
274
  raise e
298
275
  else
299
- response.return!(request, result, &blk)
276
+ resp.return!(&blk)
300
277
  end
301
278
  end
302
279
 
303
280
  # If streaming read_body is used, we need to create the
304
281
  # RestClient::Response ourselves
305
- unless r.is_a?(RestClient::Response)
306
- if r.code.to_i >= 300
307
- r = RestClient::Response.create(
308
- RestClient::Request.decode(r['content-encoding'], r.body),
309
- r, nil, nil)
310
- e = ServerError.new(r)
282
+ unless response.is_a?(RestClient::Response)
283
+ if response.code.to_i >= 300
284
+ body = response.body
285
+ if RestClient::version < '2.1.0'
286
+ body = RestClient::Request.decode(response['content-encoding'], response.body)
287
+ end
288
+ response = RestClient::Response.create(body, response, request)
289
+ e = ServerError.new(response)
311
290
  logger.error(e.to_s)
312
291
  raise e
313
292
  end
314
- r = RestClient::Response.create(nil, r, nil, nil)
315
- r.return!
293
+ response = RestClient::Response.create(nil, response, request)
294
+ response.return!
316
295
  end
317
296
 
318
- logger.debug("Received HTTP response, code: #{r.code}, headers: " \
319
- "#{r.headers}, body: #{r.body}")
297
+ logger.debug("Received HTTP response, code: #{response.code}, headers: " \
298
+ "#{response.headers}, body: #{response.body}")
320
299
 
321
- r
300
+ response
322
301
  end
323
302
 
324
303
  def get_user_agent
File without changes
File without changes
File without changes
@@ -346,10 +346,10 @@ module Aliyun
346
346
  xml.Date Time.utc(
347
347
  r.expiry.year, r.expiry.month, r.expiry.day)
348
348
  .iso8601.sub('Z', '.000Z')
349
- elsif r.expiry.is_a?(Fixnum)
349
+ elsif r.expiry.is_a?(Integer)
350
350
  xml.Days r.expiry
351
351
  else
352
- fail ClientError, "Expiry must be a Date or Fixnum."
352
+ fail ClientError, "Expiry must be a Date or Integer."
353
353
  end
354
354
  }
355
355
  }
@@ -535,7 +535,7 @@ module Aliyun
535
535
  headers[CALLBACK_HEADER] = opts[:callback].serialize
536
536
  end
537
537
 
538
- payload = HTTP::StreamPayload.new(@config.upload_crc_enable, opts[:init_crc], &block)
538
+ payload = HTTP::StreamWriter.new(@config.upload_crc_enable, opts[:init_crc], &block)
539
539
  r = @http.put(
540
540
  {:bucket => bucket_name, :object => object_name},
541
541
  {:headers => headers, :body => payload})
@@ -547,7 +547,7 @@ module Aliyun
547
547
  end
548
548
 
549
549
  if @config.upload_crc_enable && !r.headers[:x_oss_hash_crc64ecma].nil?
550
- data_crc = payload.read.data_crc
550
+ data_crc = payload.data_crc
551
551
  Aliyun::OSS::Util.crc_check(data_crc, r.headers[:x_oss_hash_crc64ecma], 'put')
552
552
  end
553
553
 
@@ -593,16 +593,17 @@ module Aliyun
593
593
 
594
594
  headers.merge!(to_lower_case(opts[:headers])) if opts.key?(:headers)
595
595
 
596
- payload = HTTP::StreamPayload.new(@config.upload_crc_enable && !opts[:init_crc].nil?, opts[:init_crc], &block)
596
+ payload = HTTP::StreamWriter.new(
597
+ @config.upload_crc_enable && !opts[:init_crc].nil?, opts[:init_crc], &block)
597
598
 
598
599
  r = @http.post(
599
600
  {:bucket => bucket_name, :object => object_name, :sub_res => sub_res},
600
601
  {:headers => headers, :body => payload})
601
602
 
602
- if @config.upload_crc_enable &&
603
- !r.headers[:x_oss_hash_crc64ecma].nil? &&
603
+ if @config.upload_crc_enable &&
604
+ !r.headers[:x_oss_hash_crc64ecma].nil? &&
604
605
  !opts[:init_crc].nil?
605
- data_crc = payload.read.data_crc
606
+ data_crc = payload.data_crc
606
607
  Aliyun::OSS::Util.crc_check(data_crc, r.headers[:x_oss_hash_crc64ecma], 'append')
607
608
  end
608
609
 
@@ -780,7 +781,7 @@ module Aliyun
780
781
  {:bucket => bucket_name, :object => object_name,
781
782
  :sub_res => sub_res},
782
783
  {:headers => headers}
783
- ) do |chunk|
784
+ ) do |chunk|
784
785
  if block_given?
785
786
  # crc enable and no range and oss server support crc
786
787
  data_crc = Aliyun::OSS::Util.crc(chunk, data_crc) if @config.download_crc_enable && range.nil?
@@ -1110,13 +1111,13 @@ module Aliyun
1110
1111
 
1111
1112
  sub_res = {'partNumber' => part_no, 'uploadId' => txn_id}
1112
1113
 
1113
- payload = HTTP::StreamPayload.new(@config.upload_crc_enable, &block)
1114
+ payload = HTTP::StreamWriter.new(@config.upload_crc_enable, &block)
1114
1115
  r = @http.put(
1115
1116
  {:bucket => bucket_name, :object => object_name, :sub_res => sub_res},
1116
1117
  {:body => payload})
1117
1118
 
1118
1119
  if @config.upload_crc_enable && !r.headers[:x_oss_hash_crc64ecma].nil?
1119
- data_crc = payload.read.data_crc
1120
+ data_crc = payload.data_crc
1120
1121
  Aliyun::OSS::Util.crc_check(data_crc, r.headers[:x_oss_hash_crc64ecma], 'put')
1121
1122
  end
1122
1123
 
@@ -1393,12 +1394,26 @@ module Aliyun
1393
1394
  @http.get_request_url(bucket, object)
1394
1395
  end
1395
1396
 
1397
+ # Get bucket/object resource path
1398
+ # @param [String] bucket the bucket name
1399
+ # @param [String] object the bucket name
1400
+ # @return [String] resource path for the bucket/object
1401
+ def get_resource_path(bucket, object = nil)
1402
+ @http.get_resource_path(bucket, object)
1403
+ end
1404
+
1396
1405
  # Get user's access key id
1397
1406
  # @return [String] the access key id
1398
1407
  def get_access_key_id
1399
1408
  @config.access_key_id
1400
1409
  end
1401
1410
 
1411
+ # Get user's access key secret
1412
+ # @return [String] the access key secret
1413
+ def get_access_key_secret
1414
+ @config.access_key_secret
1415
+ end
1416
+
1402
1417
  # Get user's STS token
1403
1418
  # @return [String] the STS token
1404
1419
  def get_sts_token
@@ -1516,7 +1531,7 @@ module Aliyun
1516
1531
  def get_bytes_range(range)
1517
1532
  if range &&
1518
1533
  (!range.is_a?(Array) || range.size != 2 ||
1519
- !range.at(0).is_a?(Fixnum) || !range.at(1).is_a?(Fixnum))
1534
+ !range.at(0).is_a?(Integer) || !range.at(1).is_a?(Integer))
1520
1535
  fail ClientError, "Range must be an array containing 2 Integers."
1521
1536
  end
1522
1537
 
@@ -107,10 +107,10 @@ module Aliyun
107
107
  # * id [String] the unique id of a rule
108
108
  # * enabled [Boolean] whether to enable this rule
109
109
  # * prefix [String] the prefix objects to apply this rule
110
- # * expiry [Date] or [Fixnum] the expire time of objects
110
+ # * expiry [Date] or [Integer] the expire time of objects
111
111
  # * if expiry is a Date, it specifies the absolute date to
112
112
  # expire objects
113
- # * if expiry is a Fixnum, it specifies the relative date to
113
+ # * if expiry is a Integer, it specifies the relative date to
114
114
  # expire objects: how many days after the object's last
115
115
  # modification time to expire the object
116
116
  # @example Specify expiry as Date
File without changes
@@ -93,6 +93,12 @@ module Aliyun
93
93
  end
94
94
  end
95
95
 
96
+ def ensure_bucket_name_valid(name)
97
+ unless (name =~ %r|^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$|)
98
+ fail ClientError, "The bucket name is invalid."
99
+ end
100
+ end
101
+
96
102
  end # self
97
103
  end # Util
98
104
  end # OSS
File without changes
@@ -25,7 +25,7 @@ module Aliyun
25
25
  # @param role [String] the role arn
26
26
  # @param session [String] the session name
27
27
  # @param policy [STS::Policy] the policy
28
- # @param duration [Fixnum] the duration seconds for the
28
+ # @param duration [Integer] the duration seconds for the
29
29
  # requested token
30
30
  # @return [STS::Token] the sts token
31
31
  def assume_role(role, session, policy = nil, duration = 3600)