qiniu_jxb 6.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +118 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +37 -0
- data/LICENSE +22 -0
- data/README.md +47 -0
- data/Rakefile +21 -0
- data/docs/README.md +790 -0
- data/lib/qiniu-rs.rb +2 -0
- data/lib/qiniu.rb +209 -0
- data/lib/qiniu/abstract.rb +22 -0
- data/lib/qiniu/adt.rb +46 -0
- data/lib/qiniu/auth.rb +234 -0
- data/lib/qiniu/config.rb +58 -0
- data/lib/qiniu/exceptions.rb +120 -0
- data/lib/qiniu/fop.rb +4 -0
- data/lib/qiniu/http.rb +137 -0
- data/lib/qiniu/image.rb +38 -0
- data/lib/qiniu/log.rb +15 -0
- data/lib/qiniu/management.rb +128 -0
- data/lib/qiniu/misc.rb +33 -0
- data/lib/qiniu/pfop.rb +124 -0
- data/lib/qiniu/resumable_upload.rb +319 -0
- data/lib/qiniu/storage.rb +5 -0
- data/lib/qiniu/tokens/access_token.rb +21 -0
- data/lib/qiniu/tokens/download_token.rb +31 -0
- data/lib/qiniu/tokens/qbox_token.rb +38 -0
- data/lib/qiniu/tokens/upload_token.rb +47 -0
- data/lib/qiniu/upload.rb +138 -0
- data/lib/qiniu/utils.rb +109 -0
- data/lib/qiniu/version.rb +17 -0
- data/qiniu.gemspec +29 -0
- data/spec/qiniu/abstract_spec.rb +30 -0
- data/spec/qiniu/auth_spec.rb +81 -0
- data/spec/qiniu/image_logo_for_test.png +0 -0
- data/spec/qiniu/image_spec.rb +89 -0
- data/spec/qiniu/management_spec.rb +156 -0
- data/spec/qiniu/misc_spec.rb +59 -0
- data/spec/qiniu/pfop_spec.rb +89 -0
- data/spec/qiniu/qiniu_spec.rb +329 -0
- data/spec/qiniu/tokens/qbox_token_spec.rb +29 -0
- data/spec/qiniu/upload_spec.rb +308 -0
- data/spec/qiniu/utils_spec.rb +49 -0
- data/spec/qiniu/version_spec.rb +10 -0
- data/spec/spec_helper.rb +19 -0
- metadata +220 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'hmac-sha1'
|
4
|
+
require 'qiniu/config'
|
5
|
+
require 'qiniu/utils'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :access_key, :secret_key
|
13
|
+
|
14
|
+
def generate_encoded_digest(signature)
|
15
|
+
hmac = HMAC::SHA1.new(@secret_key)
|
16
|
+
hmac.update(signature)
|
17
|
+
urlsafe_base64_encode(hmac.digest)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # AccessToken
|
21
|
+
end # module Qiniu
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'qiniu/tokens/access_token'
|
5
|
+
require 'qiniu/utils'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class DownloadToken < AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :pattern, :expires_in
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@pattern = opts[:pattern]
|
16
|
+
@expires_in = opts[:expires_in] || 3600
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_signature
|
20
|
+
params = {"S" => @pattern, "E" => Time.now.to_i + @expires_in}
|
21
|
+
Utils.urlsafe_base64_encode(params.to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate_token
|
25
|
+
signature = generate_signature
|
26
|
+
encoded_digest = generate_encoded_digest(signature)
|
27
|
+
%Q(#{@access_key}:#{encoded_digest}:#{signature})
|
28
|
+
end
|
29
|
+
|
30
|
+
end # moidule DownloadToken
|
31
|
+
end # module Qiniu
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'json'
|
5
|
+
require 'qiniu/tokens/access_token'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class QboxToken < AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :url, :params
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@url = opts[:url]
|
16
|
+
@params = opts[:params]
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_signature
|
20
|
+
uri = URI.parse(@url)
|
21
|
+
signature = uri.path
|
22
|
+
query_string = uri.query
|
23
|
+
signature += '?' + query_string if !query_string.nil? && !query_string.empty?
|
24
|
+
signature += "\n"
|
25
|
+
if @params.is_a?(Hash)
|
26
|
+
params_string = HTTP.generate_query_string(@params)
|
27
|
+
signature += params_string
|
28
|
+
end
|
29
|
+
signature
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_token
|
33
|
+
encoded_digest = generate_encoded_digest(generate_signature)
|
34
|
+
%Q(#{@access_key}:#{encoded_digest})
|
35
|
+
end
|
36
|
+
|
37
|
+
end # module QboxToken
|
38
|
+
end # module Qiniu
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'qiniu/tokens/access_token'
|
5
|
+
require 'qiniu/utils'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class UploadToken < AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :scope, :expires_in, :callback_url, :callback_body, :callback_body_type, :customer, :escape, :async_options, :return_body, :return_url
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@scope = opts[:scope]
|
16
|
+
@expires_in = opts[:expires_in] || 3600
|
17
|
+
@callback_url = opts[:callback_url]
|
18
|
+
@callback_body = opts[:callback_body]
|
19
|
+
@callback_body_type = opts[:callback_body_type]
|
20
|
+
@customer = opts[:customer]
|
21
|
+
@escape = opts[:escape]
|
22
|
+
@async_options = opts[:async_options]
|
23
|
+
@return_body = opts[:return_body]
|
24
|
+
@return_url = opts[:return_url]
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_signature
|
28
|
+
params = {:scope => @scope, :deadline => Time.now.to_i + @expires_in}
|
29
|
+
params[:callbackUrl] = @callback_url if !@callback_url.nil? && !@callback_url.empty?
|
30
|
+
params[:callbackBody] = @callback_body if !@callback_body.nil? && !@callback_body.empty?
|
31
|
+
params[:callbackBodyType] = @callback_body_type if !@callback_body_type.nil? && !@callback_body_type.empty?
|
32
|
+
params[:customer] = @customer if !@customer.nil? && !@customer.empty?
|
33
|
+
params[:escape] = 1 if @escape == 1 || @escape == true
|
34
|
+
params[:asyncOps] = @async_options if !@async_options.nil? && !@async_options.empty?
|
35
|
+
params[:returnBody] = @return_body if !@return_body.nil? && !@return_body.empty?
|
36
|
+
params[:returnUrl] = @return_url if !@return_url.nil? && !@return_url.empty?
|
37
|
+
Utils.urlsafe_base64_encode(params.to_json)
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_token
|
41
|
+
signature = generate_signature
|
42
|
+
encoded_digest = generate_encoded_digest(signature)
|
43
|
+
%Q(#{@access_key}:#{encoded_digest}:#{signature})
|
44
|
+
end
|
45
|
+
|
46
|
+
end # module UploadToken
|
47
|
+
end # module Qiniu
|
data/lib/qiniu/upload.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# vim: sw=2 ts=2
|
3
|
+
|
4
|
+
module Qiniu
|
5
|
+
module Storage
|
6
|
+
class << self
|
7
|
+
include Utils
|
8
|
+
|
9
|
+
def upload_with_token(uptoken,
|
10
|
+
local_file,
|
11
|
+
bucket,
|
12
|
+
key = nil,
|
13
|
+
mime_type = nil,
|
14
|
+
custom_meta = nil,
|
15
|
+
callback_params = nil,
|
16
|
+
enable_crc32_check = false,
|
17
|
+
rotate = nil)
|
18
|
+
action_params = _generate_action_params(
|
19
|
+
local_file,
|
20
|
+
bucket,
|
21
|
+
key,
|
22
|
+
mime_type,
|
23
|
+
custom_meta,
|
24
|
+
enable_crc32_check,
|
25
|
+
rotate
|
26
|
+
)
|
27
|
+
|
28
|
+
if callback_params.nil?
|
29
|
+
callback_params = {:bucket => bucket, :key => key, :mime_type => mime_type}
|
30
|
+
end
|
31
|
+
callback_query_string = HTTP.generate_query_string(callback_params)
|
32
|
+
|
33
|
+
url = Config.settings[:up_host] + '/upload'
|
34
|
+
post_data = {
|
35
|
+
:params => callback_query_string,
|
36
|
+
:action => action_params,
|
37
|
+
:file => File.new(local_file, 'rb'),
|
38
|
+
:multipart => true
|
39
|
+
}
|
40
|
+
if !uptoken.nil? then
|
41
|
+
post_data[:auth] = uptoken unless uptoken.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
return HTTP.api_post(url, post_data)
|
45
|
+
end # upload_with_token
|
46
|
+
|
47
|
+
def upload_with_token_2(uptoken,
|
48
|
+
local_file,
|
49
|
+
key = nil,
|
50
|
+
x_vars = nil, opts={})
|
51
|
+
### 构造URL
|
52
|
+
url = Config.settings[:up_host]
|
53
|
+
url[/\/*$/] = ''
|
54
|
+
url += '/'
|
55
|
+
|
56
|
+
### 构造HTTP Body
|
57
|
+
if local_file.is_a?(String)
|
58
|
+
tmp = Tempfile.new('foo')
|
59
|
+
tmp.write(local_file)
|
60
|
+
tmp.close
|
61
|
+
local_file = tmp
|
62
|
+
end
|
63
|
+
file = File.new(local_file, 'rb')
|
64
|
+
if not opts[:content_type].nil?
|
65
|
+
file.define_singleton_method("content_type") do
|
66
|
+
opts[:content_type]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
post_data = {
|
71
|
+
:file => file,
|
72
|
+
:multipart => true,
|
73
|
+
}
|
74
|
+
if not uptoken.nil?
|
75
|
+
post_data[:token] = uptoken
|
76
|
+
end
|
77
|
+
if not key.nil?
|
78
|
+
post_data[:key] = key
|
79
|
+
end
|
80
|
+
if x_vars.is_a?(Hash)
|
81
|
+
post_data.merge!(x_vars)
|
82
|
+
end
|
83
|
+
|
84
|
+
### 发送请求
|
85
|
+
HTTP.api_post(url, post_data)
|
86
|
+
end # upload_with_token_2
|
87
|
+
|
88
|
+
### 授权举例
|
89
|
+
# put_policy.bucket | put_policy.key | key | 语义 | 授权
|
90
|
+
# :---------------- | :------------- | :------ | :--- | :---
|
91
|
+
# trivial_bucket | <nil> | <nil> | 新增 | 允许,最终key为1)使用put_policy.save_key生成的值或2)资源内容的Hash值
|
92
|
+
# trivial_bucket | <nil> | foo.txt | 新增 | 允许
|
93
|
+
# trivial_bucket | <nil> | bar.jpg | 新增 | 允许
|
94
|
+
# trivial_bucket | foo.txt | <nil> | 覆盖 | 允许,由SDK将put_policy.key赋值给key实现
|
95
|
+
# trivial_bucket | foo.txt | foo.txt | 覆盖 | 允许
|
96
|
+
# trivial_bucket | foo.txt | bar.jpg | 覆盖 | 禁止,put_policy.key与key不一致
|
97
|
+
def upload_with_put_policy(put_policy,
|
98
|
+
local_file,
|
99
|
+
key = nil,
|
100
|
+
x_vars = nil, opts={})
|
101
|
+
uptoken = Auth.generate_uptoken(put_policy)
|
102
|
+
if key.nil? then
|
103
|
+
key = put_policy.key
|
104
|
+
end
|
105
|
+
|
106
|
+
return upload_with_token_2(uptoken, local_file, key, x_vars, opts)
|
107
|
+
end # upload_with_put_policy
|
108
|
+
|
109
|
+
private
|
110
|
+
def _generate_action_params(local_file,
|
111
|
+
bucket,
|
112
|
+
key = nil,
|
113
|
+
mime_type = nil,
|
114
|
+
custom_meta = nil,
|
115
|
+
enable_crc32_check = false,
|
116
|
+
rotate = nil)
|
117
|
+
raise NoSuchFileError, local_file unless File.exist?(local_file)
|
118
|
+
|
119
|
+
if key.nil?
|
120
|
+
key = Digest::SHA1.hexdigest(local_file + Time.now.to_s)
|
121
|
+
end
|
122
|
+
|
123
|
+
entry_uri = bucket + ':' + key
|
124
|
+
if mime_type.nil? || mime_type.empty?
|
125
|
+
mime = MIME::Types.type_for local_file
|
126
|
+
mime_type = mime.empty? ? 'application/octet-stream' : mime[0].content_type
|
127
|
+
end
|
128
|
+
|
129
|
+
action_params = '/rs-put/' + Utils.urlsafe_base64_encode(entry_uri) + '/mimeType/' + Utils.urlsafe_base64_encode(mime_type)
|
130
|
+
action_params += '/meta/' + Utils.urlsafe_base64_encode(custom_meta) unless custom_meta.nil?
|
131
|
+
action_params += '/crc32/' + Utils.crc32checksum(local_file).to_s if enable_crc32_check
|
132
|
+
action_params += '/rotate/' + rotate if !rotate.nil? && rotate.to_i >= 0
|
133
|
+
action_params
|
134
|
+
end # _generate_action_params
|
135
|
+
|
136
|
+
end # class << self
|
137
|
+
end # module Storage
|
138
|
+
end # module Qiniu
|
data/lib/qiniu/utils.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'cgi'
|
5
|
+
require 'json'
|
6
|
+
require 'zlib'
|
7
|
+
require 'base64'
|
8
|
+
require 'rest_client'
|
9
|
+
require 'hmac-sha1'
|
10
|
+
require 'qiniu/exceptions'
|
11
|
+
|
12
|
+
module Qiniu
|
13
|
+
module Utils extend self
|
14
|
+
|
15
|
+
def urlsafe_base64_encode content
|
16
|
+
Base64.encode64(content).strip.gsub('+', '-').gsub('/','_').gsub(/\r?\n/, '')
|
17
|
+
end
|
18
|
+
|
19
|
+
def urlsafe_base64_decode encoded_content
|
20
|
+
Base64.decode64 encoded_content.gsub('_','/').gsub('-', '+')
|
21
|
+
end
|
22
|
+
|
23
|
+
def encode_entry_uri(bucket, key)
|
24
|
+
entry_uri = bucket + ':' + key
|
25
|
+
urlsafe_base64_encode(entry_uri)
|
26
|
+
end
|
27
|
+
|
28
|
+
def safe_json_parse(data)
|
29
|
+
JSON.parse(data)
|
30
|
+
rescue JSON::ParserError
|
31
|
+
{}
|
32
|
+
end
|
33
|
+
|
34
|
+
def debug(msg)
|
35
|
+
if Config.settings[:enable_debug]
|
36
|
+
Log.logger.debug(msg)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
### 已过时,仅作为兼容接口保留
|
41
|
+
def send_request_with url, data = nil, options = {}
|
42
|
+
options[:method] = Config.settings[:method] unless options[:method]
|
43
|
+
options[:content_type] = Config.settings[:content_type] unless options[:content_type]
|
44
|
+
header_options = {
|
45
|
+
:accept => :json,
|
46
|
+
:user_agent => Config.settings[:user_agent]
|
47
|
+
}
|
48
|
+
auth_token = nil
|
49
|
+
if !options[:qbox_signature_token].nil? && !options[:qbox_signature_token].empty?
|
50
|
+
auth_token = 'QBox ' + options[:qbox_signature_token]
|
51
|
+
elsif !options[:upload_signature_token].nil? && !options[:upload_signature_token].empty?
|
52
|
+
auth_token = 'UpToken ' + options[:upload_signature_token]
|
53
|
+
elsif options[:access_token]
|
54
|
+
auth_token = 'Bearer ' + options[:access_token]
|
55
|
+
end
|
56
|
+
header_options.merge!('Authorization' => auth_token) unless auth_token.nil?
|
57
|
+
case options[:method]
|
58
|
+
when :get
|
59
|
+
response = RestClient.get(url, header_options)
|
60
|
+
when :post
|
61
|
+
header_options.merge!(:content_type => options[:content_type])
|
62
|
+
response = RestClient.post(url, data, header_options)
|
63
|
+
end
|
64
|
+
code = response.respond_to?(:code) ? response.code.to_i : 0
|
65
|
+
unless HTTP.is_response_ok?(code)
|
66
|
+
raise RequestFailed.new("Request Failed", response)
|
67
|
+
else
|
68
|
+
data = {}
|
69
|
+
body = response.respond_to?(:body) ? response.body : {}
|
70
|
+
raw_headers = response.respond_to?(:raw_headers) ? response.raw_headers : {}
|
71
|
+
data = safe_json_parse(body) unless body.empty?
|
72
|
+
end
|
73
|
+
[code, data, raw_headers]
|
74
|
+
end # send_request_with
|
75
|
+
|
76
|
+
### 已过时,仅作为兼容接口保留
|
77
|
+
def http_request url, data = nil, options = {}
|
78
|
+
retry_times = 0
|
79
|
+
begin
|
80
|
+
retry_times += 1
|
81
|
+
send_request_with url, data, options
|
82
|
+
rescue Errno::ECONNRESET => err
|
83
|
+
if Config.settings[:auto_reconnect] && retry_times < Config.settings[:max_retry_times]
|
84
|
+
retry
|
85
|
+
else
|
86
|
+
Log.logger.error err
|
87
|
+
end
|
88
|
+
rescue => e
|
89
|
+
Log.logger.warn "#{e.message} => Utils.http_request('#{url}')"
|
90
|
+
code = 0
|
91
|
+
data = {}
|
92
|
+
body = {}
|
93
|
+
if e.respond_to? :response
|
94
|
+
res = e.response
|
95
|
+
code = res.code.to_i if res.respond_to? :code
|
96
|
+
body = res.respond_to?(:body) ? res.body : ""
|
97
|
+
raw_headers = res.respond_to?(:raw_headers) ? res.raw_headers : {}
|
98
|
+
data = safe_json_parse(body) unless body.empty?
|
99
|
+
end
|
100
|
+
[code, data, raw_headers]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def crc32checksum(filepath)
|
105
|
+
File.open(filepath, "rb") { |f| Zlib.crc32 f.read }
|
106
|
+
end
|
107
|
+
|
108
|
+
end # module Utils
|
109
|
+
end # module Qiniu
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Qiniu
|
4
|
+
module Version
|
5
|
+
MAJOR = 6
|
6
|
+
MINOR = 2
|
7
|
+
PATCH = 4
|
8
|
+
# Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
|
9
|
+
#
|
10
|
+
# Example
|
11
|
+
#
|
12
|
+
# Version.to_s # '1.0.2'
|
13
|
+
def self.to_s
|
14
|
+
[MAJOR, MINOR, PATCH].join('.')
|
15
|
+
end
|
16
|
+
end # Version
|
17
|
+
end # module Qiniu
|
data/qiniu.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require File.expand_path('../lib/qiniu/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.authors = ["why404","BluntBlade"]
|
7
|
+
gem.email = ["sdk@qiniu.com"]
|
8
|
+
gem.description = %q{Qiniu Resource (Cloud) Storage SDK for Ruby. See: http://developer.qiniu.com/docs/v6/sdk/ruby-sdk.html}
|
9
|
+
gem.summary = %q{Qiniu Resource (Cloud) Storage SDK for Ruby}
|
10
|
+
gem.homepage = "https://github.com/qiniu/ruby-sdk"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "qiniu_jxb"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = Qiniu::Version.to_s
|
18
|
+
gem.license = "MIT"
|
19
|
+
|
20
|
+
# specify any dependencies here; for example:
|
21
|
+
gem.add_development_dependency "rake", ">= 0.9"
|
22
|
+
gem.add_development_dependency "rspec", ">= 2.11"
|
23
|
+
gem.add_development_dependency "fakeweb", "~> 1.3"
|
24
|
+
gem.add_runtime_dependency "json", "~> 1.7"
|
25
|
+
gem.add_runtime_dependency "rest-client", "~> 1.6"
|
26
|
+
gem.add_runtime_dependency "mime-types", "~> 1.19"
|
27
|
+
gem.add_runtime_dependency "ruby-hmac", "~> 0.4"
|
28
|
+
gem.add_runtime_dependency "jruby-openssl", "~> 0.7" if RUBY_PLATFORM == "java"
|
29
|
+
end
|