Attempts a resumable upload.

        Returns etag from server upon success.

        Raises ResumableUploadException if any problems occur.

def _attempt_resumable_upload(self, key, fp, file_length, headers, cb,
                                  num_cb):
        """
        Attempts a resumable upload.

        Returns etag from server upon success.

        Raises ResumableUploadException if any problems occur.
        """
        (server_start, server_end) = self.SERVER_HAS_NOTHING
        conn = key.bucket.connection
        if self.tracker_uri:
            # Try to resume existing resumable upload.
            try:
                (server_start, server_end) = (
                    self._query_server_pos(conn, file_length))
                self.server_has_bytes = server_start
                key=key
                if conn.debug >= 1:
                    print 'Resuming transfer.'
            except ResumableUploadException, e:
                if conn.debug >= 1:
                    print 'Unable to resume transfer (%s).' % e.message
                self._start_new_resumable_upload(key, headers)
        else:
            self._start_new_resumable_upload(key, headers)

        # upload_start_point allows the code that instantiated the
        # ResumableUploadHandler to find out the point from which it started
        # uploading (e.g., so it can correctly compute throughput).
        if self.upload_start_point is None:
            self.upload_start_point = server_end

        if server_end == file_length:
            # Boundary condition: complete file was already uploaded (e.g.,
            # user interrupted a previous upload attempt after the upload
            # completed but before the gsutil tracker file was deleted). Set
            # total_bytes_uploaded to server_end so we'll attempt to upload
            # no more bytes but will still make final HTTP request and get
            # back the response (which contains the etag we need to compare
            # at the end).
            total_bytes_uploaded = server_end
        else:
            total_bytes_uploaded = server_end + 1
        fp.seek(total_bytes_uploaded)
        conn = key.bucket.connection

        # Get a new HTTP connection (vs conn.get_http_connection(), which reuses
        # pool connections) because httplib requires a new HTTP connection per
        # transaction. (Without this, calling http_conn.getresponse() would get
        # "ResponseNotReady".)
        http_conn = conn.new_http_connection(self.tracker_uri_host,
                                             conn.is_secure)
        http_conn.set_debuglevel(conn.debug)

        # Make sure to close http_conn at end so if a local file read
        # failure occurs partway through server will terminate current upload
        # and can report that progress on next attempt.
        try:
            return self._upload_file_bytes(conn, http_conn, fp, file_length,
                                           total_bytes_uploaded, cb, num_cb)
        except (ResumableUploadException, socket.error):
            resp = self._query_server_state(conn, file_length)
            if resp.status == 400:
                raise ResumableUploadException('Got 400 response from server '
                    'state query after failed resumable upload attempt. This '
                    'can happen for various reasons, including specifying an '
                    'invalid request (e.g., an invalid canned ACL) or if the '
                    'file size changed between upload attempts',
                    ResumableTransferDisposition.ABORT)
            else:
                raise
        finally:
            http_conn.close()