'Uploads an object using the S3 multipart algorithm.
:param container: The destination container
:type container: :class:`Container`
:param object_name: The name of the object which we are uploading
:type object_name: ``str``
:param stream: The generator for fetching the upload data
:type stream: ``generator``
:keyword verify_hash: Indicates if we must calculate the data hash
:type verify_hash: ``bool``
:keyword extra: Additional options
:type extra: ``dict``
:keyword storage_class: The name of the S3 object\'s storage class
:type extra: ``str``
:return: The uploaded object
:rtype: :class:`Object`'

def _put_object_multipart(self, container, object_name, stream, extra=None, verify_hash=False, storage_class=None):

    headers = {}
    extra = (extra or {})
    headers.update(self._to_storage_class_headers(storage_class))
    content_type = extra.get('content_type', None)
    meta_data = extra.get('meta_data', None)
    acl = extra.get('acl', None)
    if content_type:
        headers['Content-Type'] = content_type
    if meta_data:
        for (key, value) in list(meta_data.items()):
            key = (self.http_vendor_prefix + ('-meta-%s' % key))
            headers[key] = value
    if acl:
        headers[(self.http_vendor_prefix + '-acl')] = acl
    upload_id = self._initiate_multipart(container, object_name, headers=headers)
    try:
        result = self._upload_multipart_chunks(container, object_name, upload_id, stream, calculate_hash=verify_hash)
        (chunks, data_hash, bytes_transferred) = result
        etag = self._commit_multipart(container, object_name, upload_id, chunks)
    except Exception:
        self._abort_multipart(container, object_name, upload_id)
        raise
    return Object(name=object_name, size=bytes_transferred, hash=etag, extra={'acl': acl}, meta_data=meta_data, container=container, driver=self)
