Fix duplication of parameters in qeuery string
[arvados.git] / lib / google / api_client / request.rb
index da3fb6a65a1049c826a975c12ce9559a179423be..9a08c2a5834f36b302e33317de866e713c0eed0e 100644 (file)
@@ -19,6 +19,7 @@ require 'compat/multi_json'
 require 'addressable/uri'
 require 'stringio'
 require 'google/api_client/discovery'
+require 'google/api_client/logging'
 
 module Google
   class APIClient
@@ -26,8 +27,10 @@ module Google
     ##
     # Represents an API request.
     class Request
-      MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze
+      include Google::APIClient::Logging
       
+      MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze
+
       # @return [Hash] Request parameters
       attr_reader :parameters
       # @return [Hash] Additional HTTP headers
@@ -42,7 +45,7 @@ module Google
       attr_accessor :authenticated
       # @return [#read, #to_str] Request body
       attr_accessor :body
-      
+
       ##
       # Build a request
       #
@@ -52,7 +55,7 @@ module Google
       # @option options [Google::APIClient::Method] :api_method
       #   API method to invoke. Either :api_method or :uri must be specified
       # @option options [TrueClass, FalseClass] :authenticated
-      #   True if request should include credentials. Implicitly true if 
+      #   True if request should include credentials. Implicitly true if
       #   unspecified and :authorization present
       # @option options [#generate_signed_request] :authorization
       #   OAuth credentials
@@ -74,12 +77,12 @@ module Google
         self.api_method = options[:api_method]
         self.authenticated = options[:authenticated]
         self.authorization = options[:authorization]
-        
+
         # These parameters are handled differently because they're not
         # parameters to the API method, but rather to the API system.
         self.parameters['key'] ||= options[:key] if options[:key]
         self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip]
-        
+
         if options[:media]
           self.initialize_media_upload(options)
         elsif options[:body]
@@ -90,13 +93,13 @@ module Google
         else
           self.body = ''
         end
-        
+
         unless self.api_method
           self.http_method = options[:http_method] || 'GET'
           self.uri = options[:uri]
         end
       end
-      
+
       # @!attribute [r] upload_type
       # @return [String] protocol used for upload
       def upload_type
@@ -128,7 +131,7 @@ module Google
             "Expected Google::APIClient::Method, got #{new_api_method.class}."
         end
       end
-      
+
       # @!attribute uri
       # @return [Addressable::URI] URI to send request
       def uri
@@ -145,26 +148,31 @@ module Google
       #
       # @api private
       #
-      # @param [Faraday::Connection] connection 
+      # @param [Faraday::Connection] connection
       #   the connection to transmit with
-      # 
-      # @return [Google::APIClient::Result] 
+      #
+      # @return [Google::APIClient::Result]
       #   result of API request
       def send(connection)
-        http_response = connection.app.call(self.to_env(connection))        
+        env = self.to_env(connection)
+        logger.debug  { "#{self.class} Sending API request #{env[:method]} #{env[:url].to_s} #{env[:request_headers]}" }
+        http_response = connection.app.call(env)
         result = self.process_http_response(http_response)
-        
+
+        logger.debug { "#{self.class} Result: #{result.status} #{result.headers}" }
+
         # Resumamble slightly different than other upload protocols in that it requires at least
         # 2 requests.
         if self.upload_type == 'resumable'
           upload =  result.resumable_upload
           unless upload.complete?
+            logger.debug { "#{self.class} Sending upload body" }
             result = upload.send(connection)
           end
         end
         return result
       end
-      
+
       # Convert to an HTTP request. Returns components in order of method, URI,
       # request headers, and body
       #
@@ -172,15 +180,16 @@ module Google
       #
       # @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>]
       def to_http_request
-        request = ( 
-          if self.uri
+        request = (
+          if self.api_method
+            self.api_method.generate_request(self.parameters, self.body, self.headers)
+          elsif self.uri
             unless self.parameters.empty?
               self.uri.query = Addressable::URI.form_encode(self.parameters)
             end
             [self.http_method, self.uri.to_s, self.headers, self.body]
-          else
-            self.api_method.generate_request(self.parameters, self.body, self.headers)
           end)
+        return request
       end
 
       ##
@@ -204,7 +213,7 @@ module Google
         end
         return options
       end
-      
+
       ##
       # Prepares the request for execution, building a hash of parts
       # suitable for sending to Faraday::Connection.
@@ -219,7 +228,7 @@ module Google
       def to_env(connection)
         method, uri, headers, body = self.to_http_request
         http_request = connection.build_request(method) do |req|
-          req.url(uri)
+          req.url(uri.to_s)
           req.headers.update(headers)
           req.body = body
         end
@@ -233,7 +242,7 @@ module Google
 
         request_env = http_request.to_env(connection)
       end
-      
+
       ##
       # Convert HTTP response to an API Result
       #
@@ -247,9 +256,9 @@ module Google
       def process_http_response(response)
         Result.new(self, response)
       end
-      
+
       protected
-      
+
       ##
       # Adjust headers & body for media uploads
       #
@@ -269,14 +278,14 @@ module Google
         self.media = options[:media]
         case self.upload_type
         when "media"
-          if options[:body] || options[:body_object] 
+          if options[:body] || options[:body_object]
             raise ArgumentError, "Can not specify body & body object for simple uploads"
           end
           self.headers['Content-Type'] ||= self.media.content_type
           self.body = self.media
         when "multipart"
-          unless options[:body_object] 
-            raise ArgumentError, "Multipart requested but no body object"              
+          unless options[:body_object]
+            raise ArgumentError, "Multipart requested but no body object"
           end
           metadata = StringIO.new(serialize_body(options[:body_object]))
           build_multipart([Faraday::UploadIO.new(metadata, 'application/json', 'file.json'), self.media])
@@ -286,13 +295,13 @@ module Google
           self.headers['X-Upload-Content-Length'] = file_length.to_s
           if options[:body_object]
             self.headers['Content-Type'] ||= 'application/json'
-            self.body = serialize_body(options[:body_object]) 
+            self.body = serialize_body(options[:body_object])
           else
             self.body = ''
           end
         end
       end
-      
+
       ##
       # Assemble a multipart message from a set of parts
       #
@@ -304,7 +313,7 @@ module Google
       #   MIME type of the message
       # @param [String] boundary
       #   Boundary for separating each part of the message
-      def build_multipart(parts, mime_type = 'multipart/related', boundary = MULTIPART_BOUNDARY) 
+      def build_multipart(parts, mime_type = 'multipart/related', boundary = MULTIPART_BOUNDARY)
         env = {
           :request_headers => {'Content-Type' => "#{mime_type};boundary=#{boundary}"},
           :request => { :boundary => boundary }
@@ -313,10 +322,10 @@ module Google
         self.body = multipart.create_multipart(env, parts.map {|part| [nil, part]})
         self.headers.update(env[:request_headers])
       end
-      
+
       ##
       # Serialize body object to JSON
-      # 
+      #
       # @api private
       #
       # @param [#to_json,#to_hash] body
@@ -326,7 +335,7 @@ module Google
       #   JSON
       def serialize_body(body)
         return body.to_json if body.respond_to?(:to_json)
-        return MultiJson.dump(options[:body_object].to_hash) if body.respond_to?(:to_hash)
+        return MultiJson.dump(body.to_hash) if body.respond_to?(:to_hash)
         raise TypeError, 'Could not convert body object to JSON.' +
                          'Must respond to :to_json or :to_hash.'
       end