'Upload an object using an iterator.
If a provider supports it, chunked transfer encoding is used and you
don\'t need to know in advance the amount of data to be uploaded.
Otherwise if a provider doesn\'t support it, iterator will be exhausted
so a total size for data to be uploaded can be determined.
Note: Exhausting the iterator means that the whole data must be
buffered in memory which might result in memory exhausting when
uploading a very large object.
If a file is located on a disk you are advised to use upload_object
function which uses fs.stat function to determine the file size and it
doesn\'t need to buffer whole object in the memory.
:type iterator: ``object``
:param iterator: An object which implements the iterator
interface and yields binary chunks of data.
:type container: :class:`Container`
:param container: Destination container.
:type object_name: ``str``
:param object_name: Object name.
:type extra: ``dict``
:param extra: (optional) Extra attributes (driver specific). Note:
This dictionary must contain a \'content_type\' key which represents
a content type of the stored object.
:rtype: ``object``'

def upload_object_via_stream(self, iterator, container, object_name, extra=None):

    path = self.get_container_cdn_url(container, check=True)
    obj_path = os.path.join(path, object_name)
    base_path = os.path.dirname(obj_path)
    self._make_path(base_path)
    with LockLocalStorage(obj_path):
        with open(obj_path, 'wb') as obj_file:
            for data in iterator:
                obj_file.write(data)
    os.chmod(obj_path, int('664', 8))
    return self._make_object(container, object_name)
