diff --git a/lib/qiniu.rb b/lib/qiniu.rb index 337b78a..e7a36e5 100755 --- a/lib/qiniu.rb +++ b/lib/qiniu.rb @@ -64,7 +64,7 @@ module Qiniu opts[:enable_resumable_upload] = true unless opts.has_key?(:enable_resumable_upload) if opts[:enable_resumable_upload] && File::size(source_file) > Config.settings[:block_size] - code, data = Storage.upload_with_token(opts[:uptoken], + code, data, raw_headers = Storage.upload_with_token(opts[:uptoken], opts[:file], opts[:bucket], opts[:key], @@ -74,7 +74,7 @@ module Qiniu opts[:callback_params], opts[:rotate]) else - code, data = Storage.upload_with_token(opts[:uptoken], + code, data, raw_headers = Storage.upload_with_token(opts[:uptoken], opts[:file], opts[:bucket], opts[:key], diff --git a/lib/qiniu/auth.rb b/lib/qiniu/auth.rb index 5b2e531..7df31b6 100755 --- a/lib/qiniu/auth.rb +++ b/lib/qiniu/auth.rb @@ -132,22 +132,6 @@ module Qiniu end # class PutPolicy class << self - - include Utils - - def call_with_signature(url, data, retry_times = 0, options = {}) - return Utils.http_request( - url, - data, - options.merge({:qbox_signature_token => generate_acctoken(url, data)}) - ) - end # call_with_signature - - def request(url, data = nil, options = {}) - code, data, raw_headers = Auth.call_with_signature(url, data, 0, options) - [code, data, raw_headers] - end # request - EMPTY_ARGS = {} ### 生成下载授权URL diff --git a/lib/qiniu/http.rb b/lib/qiniu/http.rb new file mode 100755 index 0000000..a03ff82 --- /dev/null +++ b/lib/qiniu/http.rb @@ -0,0 +1,129 @@ +# -*- encoding: utf-8 -*- +# vim: sw=2 ts=2 + +module Qiniu + module HTTP + + class << self + public + def is_response_ok?(http_code) + return 200 <= http_code && http_code <= 299 + end # is_response_ok? + + def generate_query_string(params) + if params.is_a?(Hash) + total_param = params.map { |key, value| %Q(#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s).gsub('+', '%20')}) } + return total_param.join("&") + end + + return params + end # generate_query_string + + def get (url, opts = {}) + ### 配置请求Header + req_headers = { + :accept => '*/*', + :user_agent => Config.settings[:user_agent] + } + + # 优先使用外部Header,覆盖任何特定Header + if opts[:headers].is_a?(Hash) then + req_headers.merge!(opts[:headers]) + end + + ### 发送请求 + response = RestClient.get(url, req_headers) + return response.code.to_i, response.body, response.raw_headers + rescue => e + Log.logger.warn "#{e.message} => Qiniu::HTTP.get('#{url}')" + return nil, nil, nil + end # get + + API_RESULT_MIMETYPE = 'application/json' + + def api_get (url, opts = {}) + ### 配置请求Header + headers = { + :accept => API_RESULT_MIMETYPE + } + + # 将特定Header混入外部Header中 + if opts[:headers].is_a?(Hash) then + opts[:headers] = opts[:headers].dup.merge!(headers) + else + opts[:headers] = headers + end + + ### 发送请求,然后转换返回值 + resp_code, resp_body, resp_headers = get(url, opts) + if resp_code.nil? then + return 0, {}, {} + end + + content_type = resp_headers["content-type"][0] + if !content_type.nil? && content_type == API_RESULT_MIMETYPE then + # 如果是JSON格式,则反序列化 + resp_body = Utils.safe_json_parse(resp_body) + end + + return resp_code, resp_body, resp_headers + end # api_get + + def post (url, req_body = nil, opts = {}) + ### 配置请求Header + req_headers = { + :accept => '*/*', + :user_agent => Config.settings[:user_agent] + } + + # 优先使用外部Header,覆盖任何特定Header + if opts[:headers].is_a?(Hash) then + req_headers.merge!(opts[:headers]) + end + + ### 发送请求 + response = RestClient.post(url, req_body, req_headers) + return response.code.to_i, response.body, response.raw_headers + rescue => e + Log.logger.warn "#{e.message} => Qiniu::HTTP.post('#{url}')" + return nil, nil, nil + end # post + + def api_post (url, req_body = nil, opts = {}) + ### 配置请求Header + headers = { + :accept => API_RESULT_MIMETYPE + } + + # 将特定Header混入外部Header中 + if opts[:headers].is_a?(Hash) then + opts[:headers] = opts[:headers].dup.merge!(headers) + else + opts[:headers] = headers + end + + ### 发送请求,然后转换返回值 + resp_code, resp_body, resp_headers = post(url, req_body, opts) + if resp_code.nil? then + return 0, {}, {} + end + + content_type = resp_headers["content-type"][0] + if !content_type.nil? && content_type == API_RESULT_MIMETYPE then + # 如果是JSON格式,则反序列化 + resp_body = Utils.safe_json_parse(resp_body) + end + + return resp_code, resp_body, resp_headers + end # api_post + + def management_post (url, body = '') + ### 授权并执行管理操作 + return HTTP.api_post(url, body, { + :headers => { 'Authorization' => 'QBox ' + Auth.generate_acctoken(url, body) } + }) + end # management_post + end # class << self + + end # module HTTP +end # module Qiniu diff --git a/lib/qiniu/image.rb b/lib/qiniu/image.rb index 146dcc4..cdd997c 100755 --- a/lib/qiniu/image.rb +++ b/lib/qiniu/image.rb @@ -7,11 +7,11 @@ module Qiniu include Utils def info(url) - Utils.http_request url + '?imageInfo', nil, {:method => :get} + return HTTP.api_get(url + '?imageInfo') end # info def exif(url) - Utils.http_request url + '?exif', nil, {:method => :get} + return HTTP.api_get(url + '?exif') end # exif def mogrify_preview_url(source_image_url, options) diff --git a/lib/qiniu/management.rb b/lib/qiniu/management.rb index 6797da2..911d2e1 100755 --- a/lib/qiniu/management.rb +++ b/lib/qiniu/management.rb @@ -1,31 +1,38 @@ # -*- encoding: utf-8 -*- +# vim: sw=2 ts=2 + +require 'qiniu/http' module Qiniu module Storage class << self include Utils + public def buckets - Auth.request Config.settings[:rs_host] + '/buckets' + url = Config.settings[:rs_host] + '/buckets' + return HTTP.management_post(url) end # buckets PRIVATE_BUCKET = 0 PUBLIC_BUCKET = 1 def mkbucket(bucket_name, is_public = PUBLIC_BUCKET) - Auth.request Config.settings[:rs_host] + '/mkbucket2/' + bucket_name + '/public/' + is_public.to_s + url = Config.settings[:rs_host] + '/mkbucket2/' + bucket_name + '/public/' + is_public.to_s + return HTTP.management_post(url) end # mkbucket def make_a_private_bucket(bucket_name) - return mkbucket(bucket_name, PRIVATE_BUCKET) + return mkbucket(bucket_name, PRIVATE_BUCKET) end # make_a_private_bucket def make_a_public_bucket(bucket_name) - return mkbucket(bucket_name, PUBLIC_BUCKET) + return mkbucket(bucket_name, PUBLIC_BUCKET) end # make_a_public_bucket def stat(bucket, key) - Auth.request Config.settings[:rs_host] + '/stat/' + encode_entry_uri(bucket, key) + url = Config.settings[:rs_host] + '/stat/' + encode_entry_uri(bucket, key) + return HTTP.management_post(url) end # stat def get(bucket, key, save_as = nil, expires_in = nil, version = nil) @@ -33,35 +40,41 @@ module Qiniu url += '/base/' + version unless version.nil? url += '/attName/' + Utils.urlsafe_base64_encode(save_as) unless save_as.nil? url += '/expires/' + expires_in.to_s if !expires_in.nil? && expires_in > 0 - Auth.request url + return HTTP.management_post(url) end # get def copy(source_bucket, source_key, target_bucket, target_key) uri = _generate_cp_or_mv_opstr('copy', source_bucket, source_key, target_bucket, target_key) - Auth.request Config.settings[:rs_host] + uri + url = Config.settings[:rs_host] + uri + return HTTP.management_post(url) end # copy def move(source_bucket, source_key, target_bucket, target_key) uri = _generate_cp_or_mv_opstr('move', source_bucket, source_key, target_bucket, target_key) - Auth.request Config.settings[:rs_host] + uri + url = Config.settings[:rs_host] + uri + return HTTP.management_post(url) end # move def delete(bucket, key) - Auth.request Config.settings[:rs_host] + '/delete/' + encode_entry_uri(bucket, key) + url = Config.settings[:rs_host] + '/delete/' + encode_entry_uri(bucket, key) + return HTTP.management_post(url) end # delete def publish(domain, bucket) encoded_domain = Utils.urlsafe_base64_encode(domain) - Auth.request Config.settings[:rs_host] + "/publish/#{encoded_domain}/from/#{bucket}" + url = Config.settings[:rs_host] + "/publish/#{encoded_domain}/from/#{bucket}" + return HTTP.management_post(url) end # publish def unpublish(domain) encoded_domain = Utils.urlsafe_base64_encode(domain) - Auth.request Config.settings[:rs_host] + "/unpublish/#{encoded_domain}" + url = Config.settings[:rs_host] + "/unpublish/#{encoded_domain}" + return HTTP.management_post(url) end # unpublish def drop(bucket) - Auth.request Config.settings[:rs_host] + "/drop/#{bucket}" + url = Config.settings[:rs_host] + "/drop/#{bucket}" + return HTTP.management_post(url) end # drop def batch(command, bucket, keys) @@ -70,7 +83,8 @@ module Qiniu encoded_uri = encode_entry_uri(bucket, key) execs << "op=/#{command}/#{encoded_uri}" end - Auth.request Config.settings[:rs_host] + "/batch", execs.join("&"), {:mime => "application/x-www-form-urlencoded" } + url = Config.settings[:rs_host] + "/batch" + return HTTP.management_post(url, execs.join("&")) end # batch def batch_get(bucket, keys) @@ -97,7 +111,7 @@ module Qiniu encoded_uri = encode_entry_uri(bucket, key) save_as_string = '/save-as/' + encoded_uri new_url = source_url + '?' + op_params_string + save_as_string - Auth.request new_url + return HTTP.management_post(new_url) end # save_as def image_mogrify_save_as(bucket, key, source_image_url, options) @@ -118,7 +132,8 @@ module Qiniu op_args.each do |e| execs << 'op=' + _generate_cp_or_mv_opstr(command, e[0], e[1], e[2], e[3]) if e.size == 4 end - Auth.request Config.settings[:rs_host] + "/batch", execs.join("&"), {:mime => "application/x-www-form-urlencoded" } + url = Config.settings[:rs_host] + "/batch" + return HTTP.management_post(url, execs.join("&")) end # _batch_cp_or_mv end end # module Storage diff --git a/lib/qiniu/misc.rb b/lib/qiniu/misc.rb index d9d61b9..6359bfa 100755 --- a/lib/qiniu/misc.rb +++ b/lib/qiniu/misc.rb @@ -3,33 +3,31 @@ module Qiniu module Misc class << self - include Utils - def set_protected(bucket, protected_mode) - host = Config.settings[:pub_host] - Auth.request %Q(#{host}/accessMode/#{bucket}/mode/#{protected_mode}) - end + url = Config.settings[:pub_host] + %Q(/accessMode/#{bucket}/mode/#{protected_mode}) + return HTTP.management_post(url) + end # set_protected def set_separator(bucket, separator) - host = Config.settings[:pub_host] encoded_separator = Utils.urlsafe_base64_encode(separator) - Auth.request %Q(#{host}/separator/#{bucket}/sep/#{encoded_separator}) - end + url = Config.settings[:pub_host] + %Q(/separator/#{bucket}/sep/#{encoded_separator}) + return HTTP.management_post(url) + end # set_separator def set_style(bucket, name, style) - host = Config.settings[:pub_host] encoded_name = Utils.urlsafe_base64_encode(name) encoded_style = Utils.urlsafe_base64_encode(style) - Auth.request %Q(#{host}/style/#{bucket}/name/#{encoded_name}/style/#{encoded_style}) - end + url = Config.settings[:pub_host] + %Q(/style/#{bucket}/name/#{encoded_name}/style/#{encoded_style}) + return HTTP.management_post(url) + end # set_style def unset_style(bucket, name) - host = Config.settings[:pub_host] encoded_name = Utils.urlsafe_base64_encode(name) - Auth.request %Q(#{host}/unstyle/#{bucket}/name/#{encoded_name}) - end + url = Config.settings[:pub_host] + %Q(/unstyle/#{bucket}/name/#{encoded_name}) + return HTTP.management_post(url) + end # unset_style + end # class << self - end end # module Misc end # module Qiniu diff --git a/lib/qiniu/resumable_upload.rb b/lib/qiniu/resumable_upload.rb index 633fff6..1c20946 100755 --- a/lib/qiniu/resumable_upload.rb +++ b/lib/qiniu/resumable_upload.rb @@ -97,13 +97,17 @@ module Qiniu def _call_binary_with_token(uptoken, url, data, content_type = nil, retry_times = 0) options = { - :method => :post, - :content_type => 'application/octet-stream', - :upload_signature_token => uptoken + :headers => { + :content_type => 'application/octet-stream', + 'Authorization' => 'UpToken ' + uptoken + } } - options[:content_type] = content_type if !content_type.nil? && !content_type.empty? - code, data = http_request url, data, options - unless Utils.is_response_ok?(code) + if !content_type.nil? && !content_type.empty? then + options[:headers][:content_type] = content_type + end + + code, data = HTTP.api_post(url, data, options) + unless HTTP.is_response_ok?(code) retry_times += 1 if Config.settings[:auto_reconnect] && retry_times < Config.settings[:max_retry_times] return _call_binary_with_token(uptoken, url, data, options[:content_type], retry_times) @@ -148,7 +152,7 @@ module Qiniu end code, data = _mkblock(uptoken, block_size, body) body_crc32 = Zlib.crc32(body) - if Utils.is_response_ok?(code) && data["crc32"] == body_crc32 + if HTTP.is_response_ok?(code) && data["crc32"] == body_crc32 progress[:ctx] = data["ctx"] progress[:offset] = body_length progress[:restsize] = block_size - body_length @@ -179,7 +183,7 @@ module Qiniu end code, data = _putblock(progress[:host], uptoken, progress[:ctx], progress[:offset], body) body_crc32 = Zlib.crc32(body) - if Utils.is_response_ok?(code) && data["crc32"] == body_crc32 + if HTTP.is_response_ok?(code) && data["crc32"] == body_crc32 progress[:ctx] = data["ctx"] progress[:offset] += body_length progress[:restsize] -= body_length @@ -228,7 +232,7 @@ module Qiniu #code, data = _resumable_put_block(uptoken, fh, block_index, block_size, Config.settings[:chunk_size], progresses[block_index], Config.settings[:max_retry_times], chunk_notifier) # Put the whole block as a chunk code, data = _resumable_put_block(uptoken, fh, block_index, block_size, block_size, progresses[block_index], Config.settings[:max_retry_times], chunk_notifier) - if Utils.is_response_ok?(code) + if HTTP.is_response_ok?(code) #checksums[block_index] = data["checksum"] checksums[block_index] = data["ctx"] if !block_notifier.nil? && block_notifier.respond_to?("notify") @@ -254,7 +258,7 @@ module Qiniu path += '/mimeType/' + Utils.urlsafe_base64_encode(mime_type) if !mime_type.nil? && !mime_type.empty? path += '/meta/' + Utils.urlsafe_base64_encode(custom_meta) if !custom_meta.nil? && !custom_meta.empty? path += '/customer/' + customer if !customer.nil? && !customer.empty? - callback_query_string = Utils.generate_query_string(callback_params) if !callback_params.nil? && !callback_params.empty? + callback_query_string = HTTP.generate_query_string(callback_params) if !callback_params.nil? && !callback_params.empty? path += '/params/' + Utils.urlsafe_base64_encode(callback_query_string) if !callback_query_string.nil? && !callback_query_string.empty? path += '/rotate/' + rotate if !rotate.nil? && rotate.to_i >= 0 url = uphost + path @@ -289,13 +293,13 @@ module Qiniu code, data = _resumable_put(uptoken, fh, checksums, progresses, block_notifier, chunk_notifier) - if Utils.is_response_ok?(code) + if HTTP.is_response_ok?(code) uphost = data["host"] entry_uri = bucket + ':' + key code, data = _mkfile(uphost, uptoken, entry_uri, fsize, checksums, mime_type, custom_meta, customer, callback_params, rotate) end - if Utils.is_response_ok?(code) + if HTTP.is_response_ok?(code) Utils.debug "File #{fh.path} {size: #{fsize}} successfully uploaded." end diff --git a/lib/qiniu/tokens/qbox_token.rb b/lib/qiniu/tokens/qbox_token.rb index bca67c2..186aaa9 100755 --- a/lib/qiniu/tokens/qbox_token.rb +++ b/lib/qiniu/tokens/qbox_token.rb @@ -23,7 +23,7 @@ module Qiniu signature += '?' + query_string if !query_string.nil? && !query_string.empty? signature += "\n" if @params.is_a?(Hash) - params_string = Utils.generate_query_string(@params) + params_string = HTTP.generate_query_string(@params) signature += params_string end signature diff --git a/lib/qiniu/upload.rb b/lib/qiniu/upload.rb index ecb3743..4e76eec 100755 --- a/lib/qiniu/upload.rb +++ b/lib/qiniu/upload.rb @@ -28,10 +28,20 @@ module Qiniu if callback_params.nil? callback_params = {:bucket => bucket, :key => key, :mime_type => mime_type} end - callback_query_string = Utils.generate_query_string(callback_params) - url = Config.settings[:up_host] + '/upload' + callback_query_string = HTTP.generate_query_string(callback_params) - Utils.upload_multipart_data(url, local_file, action_params, callback_query_string, uptoken) + url = Config.settings[:up_host] + '/upload' + post_data = { + :params => callback_query_string, + :action => action_params, + :file => File.new(local_file, 'rb'), + :multipart => true + } + if !uptoken.nil? then + post_data[:auth] = uptoken unless uptoken.nil? + end + + return HTTP.api_post(url, post_data) end # upload_with_token def upload_with_token_2(uptoken, @@ -59,7 +69,7 @@ module Qiniu end ### 发送请求 - Utils.http_request url, post_data + HTTP.api_post(url, post_data) end # upload_with_token_2 ### 授权举例 diff --git a/lib/qiniu/utils.rb b/lib/qiniu/utils.rb index 4b1f024..ad92f1b 100755 --- a/lib/qiniu/utils.rb +++ b/lib/qiniu/utils.rb @@ -31,20 +31,13 @@ module Qiniu {} end - def is_response_ok?(status_code) - status_code/100 == 2 - end - - def response_error(status_code, errmsg) - [status_code, {"error" => errmsg}] - end - def debug(msg) if Config.settings[:enable_debug] Log.logger.debug(msg) end end + ### 已过时,仅作为兼容接口保留 def send_request_with url, data = nil, options = {} options[:method] = Config.settings[:method] unless options[:method] options[:content_type] = Config.settings[:content_type] unless options[:content_type] @@ -69,7 +62,7 @@ module Qiniu response = RestClient.post(url, data, header_options) end code = response.respond_to?(:code) ? response.code.to_i : 0 - unless is_response_ok?(code) + unless HTTP.is_response_ok?(code) raise RequestFailed.new("Request Failed", response) else data = {} @@ -80,6 +73,7 @@ module Qiniu [code, data, raw_headers] end # send_request_with + ### 已过时,仅作为兼容接口保留 def http_request url, data = nil, options = {} retry_times = 0 begin @@ -107,23 +101,6 @@ module Qiniu end end - def upload_multipart_data(url, filepath, action_string, callback_query_string = '', uptoken = nil) - post_data = { - :params => callback_query_string, - :action => action_string, - :file => File.new(filepath, 'rb'), - :multipart => true - } - post_data[:auth] = uptoken unless uptoken.nil? - http_request url, post_data - end - - def generate_query_string(params) - return params if params.is_a?(String) - total_param = params.map { |key, value| %Q(#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s).gsub('+', '%20')}) } - total_param.join("&") - end - def crc32checksum(filepath) File.open(filepath, "rb") { |f| Zlib.crc32 f.read } end