class AliyunSDK::OSS::HTTP
HTTP
wraps the HTTP
functionalities for accessing OSS
RESTful API. It handles the OSS-specific protocol elements, and rest-client details for the user, which includes:
-
automatically generate signature for every request
-
parse response headers/body
-
raise exceptions and capture the request id
-
encapsulates streaming upload/download
@example simple get
headers, body = http.get({:bucket => 'bucket'})
@example streaming download
http.get({:bucket => 'bucket', :object => 'object'}) do |chunk| # handle chunk end
@example streaming upload
def streaming_upload(&block) http.put({:bucket => 'bucket', :object => 'object'}, {:body => HTTP::StreamPlayload.new(block)}) end streaming_upload do |stream| stream << "hello world" end
Constants
- DEFAULT_ACCEPT_ENCODING
- DEFAULT_CONTENT_TYPE
- OPEN_TIMEOUT
- READ_TIMEOUT
- STS_HEADER
Public Class Methods
# File lib/aliyun_sdk/oss/http.rb, line 136 def initialize(config) @config = config end
Public Instance Methods
# File lib/aliyun_sdk/oss/http.rb, line 214 def delete(resources = {}, http_options = {}, &block) do_request('DELETE', resources, http_options, &block) end
helper methods
# File lib/aliyun_sdk/oss/http.rb, line 202 def get(resources = {}, http_options = {}, &block) do_request('GET', resources, http_options, &block) end
# File lib/aliyun_sdk/oss/http.rb, line 140 def get_request_url(bucket, object) url = @config.endpoint.dup isIP = !!(url.host =~ Resolv::IPv4::Regex) url.host = "#{bucket}." + url.host if bucket && !@config.cname && !isIP url.path = '/' url.path << "#{bucket}/" if bucket && isIP url.path << "#{CGI.escape(object)}" if object url.to_s end
# File lib/aliyun_sdk/oss/http.rb, line 151 def get_resource_path(bucket, object) res = '/' res << "#{bucket}/" if bucket res << "#{object}" if object res end
Handle Net::HTTPRespoonse
# File lib/aliyun_sdk/oss/http.rb, line 160 def handle_response(r, &block) # read all body on error if r.code.to_i >= 300 r.read_body else # streaming read body on success encoding = r['content-encoding'] if encoding == 'gzip' stream = StreamWriter.new { |s| r.read_body { |chunk| s << chunk } } reader = Zlib::GzipReader.new(stream) yield reader.read(16 * 1024) until reader.eof? elsif encoding == 'deflate' begin stream = Zlib::Inflate.new # 1.9.x doesn't support streaming inflate if RUBY_VERSION < '2.0.0' yield stream.inflate(r.read_body) else r.read_body { |chunk| stream << chunk } stream.finish { |chunk| yield chunk } end rescue Zlib::DataError # No luck with Zlib decompression. Let's try with raw deflate, # like some broken web servers do. stream = Zlib::Inflate.new(-Zlib::MAX_WBITS) # 1.9.x doesn't support streaming inflate if RUBY_VERSION < '2.0.0' yield stream.inflate(r.read_body) else r.read_body { |chunk| stream << chunk } stream.finish { |chunk| yield chunk } end end else r.read_body { |chunk| yield chunk } end end end
# File lib/aliyun_sdk/oss/http.rb, line 218 def head(resources = {}, http_options = {}, &block) do_request('HEAD', resources, http_options, &block) end
# File lib/aliyun_sdk/oss/http.rb, line 222 def options(resources = {}, http_options = {}, &block) do_request('OPTIONS', resources, http_options, &block) end
# File lib/aliyun_sdk/oss/http.rb, line 210 def post(resources = {}, http_options = {}, &block) do_request('POST', resources, http_options, &block) end
# File lib/aliyun_sdk/oss/http.rb, line 206 def put(resources = {}, http_options = {}, &block) do_request('PUT', resources, http_options, &block) end
Private Instance Methods
Do HTTP
reqeust @param verb [String] HTTP
Verb: GET/PUT/POST/DELETE/HEAD/OPTIONS @param resources [Hash] OSS
related resources @option resources [String] :bucket the bucket name @option resources [String] :object the object name @option resources [Hash] :sub_res sub-resources @param http_options [Hash] HTTP
options @option http_options [Hash] :headers HTTP
headers @option http_options [Hash] :query HTTP
queries @option http_options [Object] :body HTTP
body, may be String
or Stream
# File lib/aliyun_sdk/oss/http.rb, line 238 def do_request(verb, resources = {}, http_options = {}, &block) bucket = resources[:bucket] object = resources[:object] sub_res = resources[:sub_res] headers = http_options[:headers] || {} headers['user-agent'] = get_user_agent headers['date'] = Time.now.httpdate headers['content-type'] ||= DEFAULT_CONTENT_TYPE headers['accept-encoding'] ||= DEFAULT_ACCEPT_ENCODING headers[STS_HEADER] = @config.sts_token if @config.sts_token if body = http_options[:body] if body.respond_to?(:read) headers['transfer-encoding'] = 'chunked' else headers['content-md5'] = Util.get_content_md5(body) end end res = { :path => get_resource_path(bucket, object), :sub_res => sub_res, } if @config.access_key_id and @config.access_key_secret sig = Util.get_signature(@config.access_key_secret, verb, headers, res) headers['authorization'] = "OSS #{@config.access_key_id}:#{sig}" end logger.debug("Send HTTP request, verb: #{verb}, resources: " \ "#{resources}, http options: #{http_options}") # From rest-client: # "Due to unfortunate choices in the original API, the params # used to populate the query string are actually taken out of # the headers hash." headers[:params] = (sub_res || {}).merge(http_options[:query] || {}) block_response = ->(r) { handle_response(r, &block) } if block r = RestClient::Request.execute( :method => verb, :url => get_request_url(bucket, object), :headers => headers, :payload => http_options[:body], :block_response => block_response, :open_timeout => @config.open_timeout || OPEN_TIMEOUT, :timeout => @config.read_timeout || READ_TIMEOUT ) do |response, request, result, &blk| if response.code >= 300 e = ServerError.new(response) logger.error(e.to_s) raise e else response.return!(request, result, &blk) end end # If streaming read_body is used, we need to create the # RestClient::Response ourselves unless r.is_a?(RestClient::Response) if r.code.to_i >= 300 r = RestClient::Response.create( RestClient::Request.decode(r['content-encoding'], r.body), r, nil, nil) e = ServerError.new(r) logger.error(e.to_s) raise e end r = RestClient::Response.create(nil, r, nil, nil) r.return! end logger.debug("Received HTTP response, code: #{r.code}, headers: " \ "#{r.headers}, body: #{r.body}") r end
# File lib/aliyun_sdk/oss/http.rb, line 318 def get_user_agent "aliyun-sdk-ruby/#{VERSION} ruby-#{RUBY_VERSION}/#{RUBY_PLATFORM}" end