lib/twitter/rest/request.rb in twitter-6.1.0 vs lib/twitter/rest/request.rb in twitter-6.2.0

- old
+ new

@@ -1,44 +1,133 @@ require 'addressable/uri' -require 'faraday' +require 'http' +require 'http/form_data' require 'json' -require 'timeout' +require 'openssl' require 'twitter/error' require 'twitter/headers' require 'twitter/rate_limit' +require 'twitter/utils' module Twitter module REST class Request - attr_accessor :client, :headers, :options, :rate_limit, :request_method, - :path, :uri + include Twitter::Utils + BASE_URL = 'https://api.twitter.com'.freeze + attr_accessor :client, :headers, :options, :path, :rate_limit, + :request_method, :uri alias verb request_method # @param client [Twitter::Client] # @param request_method [String, Symbol] # @param path [String] # @param options [Hash] # @return [Twitter::REST::Request] def initialize(client, request_method, path, options = {}) @client = client - @request_method = request_method.to_sym - @path = path - @uri = Addressable::URI.parse(client.connection.url_prefix + path) + @uri = Addressable::URI.parse(path.start_with?('http') ? path : BASE_URL + path) + set_multipart_options!(request_method, options) + @path = uri.path @options = options end # @return [Array, Hash] def perform - @headers = Twitter::Headers.new(@client, @request_method, @uri.to_s, @options).request_headers - begin - response = @client.connection.send(@request_method, @path, @options) { |request| request.headers.update(@headers) }.env - rescue Faraday::Error::TimeoutError, Timeout::Error => error - raise(Twitter::Error::RequestTimeout.new(error)) - rescue Faraday::Error::ClientError, JSON::ParserError => error - raise(Twitter::Error.new(error)) + options_key = @request_method == :get ? :params : :form + response = http_client.headers(@headers).public_send(@request_method, @uri.to_s, options_key => @options) + response_body = response.body.empty? ? '' : symbolize_keys!(response.parse) + response_headers = response.headers + fail_or_return_response_body(response.code, response_body, response_headers) + end + + private + + def merge_multipart_file!(options) + key = options.delete(:key) + file = options.delete(:file) + + options[key] = if file.is_a?(StringIO) + HTTP::FormData::File.new(file, mime_type: 'video/mp4') + else + HTTP::FormData::File.new(file, filename: File.basename(file), mime_type: mime_type(File.basename(file))) + end + end + + def set_multipart_options!(request_method, options) + if request_method == :multipart_post + merge_multipart_file!(options) + @request_method = :post + @headers = Twitter::Headers.new(@client, @request_method, @uri).request_headers + else + @request_method = request_method + @headers = Twitter::Headers.new(@client, @request_method, @uri, options).request_headers end - @rate_limit = Twitter::RateLimit.new(response.response_headers) - response.body + end + + def mime_type(basename) + case basename + when /\.gif$/i + 'image/gif' + when /\.jpe?g/i + 'image/jpeg' + when /\.png$/i + 'image/png' + else + 'application/octet-stream' + end + end + + def fail_or_return_response_body(code, body, headers) + error = error(code, body, headers) + raise(error) if error + @rate_limit = Twitter::RateLimit.new(headers) + body + end + + def error(code, body, headers) + klass = Twitter::Error::ERRORS[code] + if klass == Twitter::Error::Forbidden + forbidden_error(body, headers) + elsif !klass.nil? + klass.from_response(body, headers) + end + end + + def forbidden_error(body, headers) + error = Twitter::Error::Forbidden.from_response(body, headers) + klass = Twitter::Error::FORBIDDEN_MESSAGES[error.message] + if klass + klass.from_response(body, headers) + else + error + end + end + + def symbolize_keys!(object) + if object.is_a?(Array) + object.each_with_index do |val, index| + object[index] = symbolize_keys!(val) + end + elsif object.is_a?(Hash) + object.dup.each_key do |key| + object[key.to_sym] = symbolize_keys!(object.delete(key)) + end + end + object + end + + # @return [HTTP::Client, HTTP] + def http_client + client = @client.proxy ? HTTP.via(*proxy) : HTTP + client = client.timeout(:per_operation, connect: @client.timeouts[:connect], read: @client.timeouts[:read], write: @client.timeouts[:write]) if @client.timeouts + client + end + + # Return proxy values as a compacted array + # + # @return [Array] + def proxy + @client.proxy.values_at(:host, :port, :username, :password).compact end end end end