only upload media if there is one
[arvados.git] / lib / google / api_client / request.rb
index ce2f85438b645d4aa019d634bb4d0ec05e36c393..78ec87793368db05b3e81bed2588f9f44d6292eb 100644 (file)
 # limitations under the License.
 
 require 'faraday'
-require 'faraday/utils'
+require 'faraday/request/multipart'
 require 'multi_json'
 require 'compat/multi_json'
 require 'addressable/uri'
 require 'stringio'
 require 'google/api_client/discovery'
+require 'google/api_client/logging'
 
 module Google
   class APIClient
@@ -26,6 +27,8 @@ module Google
     ##
     # Represents an API request.
     class Request
+      include Google::APIClient::Logging
+      
       MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze
 
       # @return [Hash] Request parameters
@@ -68,8 +71,10 @@ module Google
       # @option options [String, Symbol] :http_method
       #   HTTP method when requesting a URI
       def initialize(options={})
-        @parameters = Hash[options[:parameters] || {}]
+        @parameters = Faraday::Utils::ParamsHash.new
         @headers = Faraday::Utils::Headers.new
+
+        self.parameters.merge!(options[:parameters]) unless options[:parameters].nil?
         self.headers.merge!(options[:headers]) unless options[:headers].nil?
         self.api_method = options[:api_method]
         self.authenticated = options[:authenticated]
@@ -147,18 +152,26 @@ module Google
       #
       # @param [Faraday::Connection] connection
       #   the connection to transmit with
+      # @param [TrueValue,FalseValue] is_retry
+      #   True if request has been previous sent
       #
       # @return [Google::APIClient::Result]
       #   result of API request
-      def send(connection)
-        http_response = connection.app.call(self.to_env(connection))
+      def send(connection, is_retry = false)
+        self.body.rewind if is_retry && self.body.respond_to?(:rewind)          
+        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
+        if result.status == 200 && self.upload_type == 'resumable' && self.media
+          upload = result.resumable_upload
           unless upload.complete?
+            logger.debug { "#{self.class} Sending upload body" }
             result = upload.send(connection)
           end
         end
@@ -173,14 +186,15 @@ module Google
       # @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>]
       def to_http_request
         request = (
-          if self.uri
+          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
 
       ##
@@ -219,7 +233,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
@@ -273,6 +287,7 @@ module Google
             raise ArgumentError, "Can not specify body & body object for simple uploads"
           end
           self.headers['Content-Type'] ||= self.media.content_type
+          self.headers['Content-Length'] ||= self.media.length.to_s
           self.body = self.media
         when "multipart"
           unless options[:body_object]
@@ -305,10 +320,10 @@ module Google
       # @param [String] boundary
       #   Boundary for separating each part of the message
       def build_multipart(parts, mime_type = 'multipart/related', boundary = MULTIPART_BOUNDARY)
-        env = {
-          :request_headers => {'Content-Type' => "#{mime_type};boundary=#{boundary}"},
-          :request => { :boundary => boundary }
-        }
+        env = Faraday::Env.new
+        env.request = Faraday::RequestOptions.new
+        env.request.boundary = boundary
+        env.request_headers = {'Content-Type' => "#{mime_type};boundary=#{boundary}"}
         multipart = Faraday::Request::Multipart.new
         self.body = multipart.create_multipart(env, parts.map {|part| [nil, part]})
         self.headers.update(env[:request_headers])