class Aliyun::Log::Request

Public Class Methods

new(config) click to toggle source
# File lib/aliyun/log/request.rb, line 17
def initialize(config)
  @config = config
end

Public Instance Methods

canonicalized_headers(headers) click to toggle source
# File lib/aliyun/log/request.rb, line 125
def canonicalized_headers(headers)
  h = {}
  headers.each do |k, v|
    h[k.downcase] = v if k =~ /x-log-.*/
  end
  h.keys.sort.map do |e|
    h[e]
    "#{e}:#{h[e].gsub(/^\s+/, '')}"
  end.join("\n")
end
canonicalized_resource(resource = '', query = {}) click to toggle source
# File lib/aliyun/log/request.rb, line 136
def canonicalized_resource(resource = '', query = {})
  return resource if query.empty?

  url = URI.parse(resource)
  sort_str = query.keys.sort.map do |e|
    "#{e}=#{query[e]}"
  end.join('&')
  "#{url}?#{sort_str}"
end
compact_headers(body = nil, is_pb = false) click to toggle source
# File lib/aliyun/log/request.rb, line 77
def compact_headers(body = nil, is_pb = false)
  headers = {
    'x-log-apiversion' => '0.6.0',
    'x-log-signaturemethod' => 'hmac-sha1',
    'x-log-bodyrawsize' => '0',
    'Date' => DateTime.now.httpdate,
    'User-Agent' => "aliyun-log ruby-#{RUBY_VERSION}/#{RUBY_PLATFORM}"
  }
  return headers if body.nil?

  if is_pb
    compressed = Zlib::Deflate.deflate(body.encode)
    headers['Content-Length'] = compressed.bytesize.to_s
    raise 'content length is larger than 3MB' if headers['Content-Length'].to_i > 3_145_728

    headers['Content-MD5'] = Digest::MD5.hexdigest(compressed).upcase
    headers['Content-Type'] = 'application/x-protobuf'
    headers['x-log-compresstype'] = 'deflate'
    headers['x-log-bodyrawsize'] = body.encode.bytesize.to_s
  else
    headers['Content-Type'] = 'application/json'
    headers['Content-MD5'] = Digest::MD5.hexdigest(body.encode).upcase
    headers['x-log-bodyrawsize'] = body.bytesize.to_s
  end
  headers
end
delete(resources, payload) click to toggle source
# File lib/aliyun/log/request.rb, line 33
def delete(resources, payload)
  do_request('DELETE', resources, payload)
end
do_request(verb, resources, payload) click to toggle source
# File lib/aliyun/log/request.rb, line 37
def do_request(verb, resources, payload)
  resource_path = Utils.get_resource_path(resources)
  url = Utils.get_request_url(@config.endpoint, resources)
  request_options = {
    method: verb,
    url: url,
    open_timeout: @config.open_timeout,
    read_timeout: @config.read_timeout
  }
  if verb == 'GET'
    headers = compact_headers
    headers['Authorization'] = signature(verb, resource_path, headers, payload)
    request_options[:headers] = headers
    request_options[:url] = URI.escape(canonicalized_resource(request_options[:url], payload))
  else
    headers = compact_headers(payload, resources[:is_pb])
    headers['Authorization'] = signature(verb, resource_path, headers)
    request_options[:headers] = headers
    payload = Zlib::Deflate.deflate(payload.encode) if resources[:is_pb]
    request_options[:payload] = payload
  end
  request = RestClient::Request.new(request_options)
  response = request.execute do |resp|
    if resp.code >= 300
      e = ServerError.new(resp)
      logger.error("#{e.to_s} #{resp.code} #{resp}")
      raise e
    else
      resp.return!
    end
  end

  logger.debug("Received HTTP response, code: #{response.code}, " \
                "url: #{request_options[:url]}, " \
                "method: #{verb}, headers: #{response.headers}, " \
                "body: #{response.body.force_encoding('UTF-8')}")

  response
end
get(resources, payload = {}) click to toggle source
# File lib/aliyun/log/request.rb, line 21
def get(resources, payload = {})
  do_request('GET', resources, payload)
end
post(resources, payload) click to toggle source
# File lib/aliyun/log/request.rb, line 25
def post(resources, payload)
  do_request('POST', resources, payload)
end
put(resources, payload) click to toggle source
# File lib/aliyun/log/request.rb, line 29
def put(resources, payload)
  do_request('PUT', resources, payload)
end
signature(verb, resource, headers, query = {}) click to toggle source
# File lib/aliyun/log/request.rb, line 104
def signature(verb, resource, headers, query = {})
  sha1_digest = OpenSSL::HMAC.digest(
    OpenSSL::Digest.new('sha1'),
    @config.access_key_secret,
    string_to_sign(verb, resource, headers, query).chomp
  )
  base64_sign = Base64.strict_encode64(sha1_digest)
  "LOG #{@config.access_key_id}:#{base64_sign}"
end
string_to_sign(verb, resource, headers, query = {}) click to toggle source
# File lib/aliyun/log/request.rb, line 114
      def string_to_sign(verb, resource, headers, query = {})
        <<~DOC
          #{verb}
          #{headers['Content-MD5']}
          #{headers['Content-Type']}
          #{headers['Date']}
          #{canonicalized_headers(headers)}
          #{canonicalized_resource(resource, query)}
        DOC
      end