From efe6b50c5084fc8607bb2040381e5878d7b0a7b7 Mon Sep 17 00:00:00 2001 From: Liang Tao Date: Wed, 2 Apr 2014 23:35:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86HTTP=E4=BA=8B=E5=8A=A1=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=9A=84=E4=BB=A3=E7=A0=81=E6=8F=90=E5=8F=96=E5=88=B0?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E7=9A=84=E7=B1=BB=E4=B8=AD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/qiniu.rb | 4 +- lib/qiniu/auth.rb | 16 ---- lib/qiniu/http.rb | 137 ++++++++++++++++++++++++++++++++++ lib/qiniu/image.rb | 4 +- lib/qiniu/management.rb | 45 +++++++---- lib/qiniu/misc.rb | 28 ++++--- lib/qiniu/resumable_upload.rb | 28 ++++--- lib/qiniu/upload.rb | 18 ++++- 8 files changed, 214 insertions(+), 66 deletions(-) create mode 100644 lib/qiniu/http.rb 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 100644 index 0000000..917bb5c --- /dev/null +++ b/lib/qiniu/http.rb @@ -0,0 +1,137 @@ +# -*- encoding: utf-8 -*- +# vim: sw=2 ts=2 + +require 'json' + +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 safe_json_parse(data) + JSON.parse(data) + rescue JSON::ParserError + {} + end # safe_json_parse + + 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 = 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 = 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/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 ### 授权举例