'Transfer data for an erasure coded object.
This method was added in the PUT method extraction change'

def _transfer_data(self, req, policy, data_source, putters, nodes, min_conns, etag_hasher):

    bytes_transferred = 0
    chunk_transform = chunk_transformer(policy)
    chunk_transform.send(None)
    frag_hashers = collections.defaultdict(md5)
    def send_chunk(chunk):
        if etag_hasher:
            etag_hasher.update(chunk)
        backend_chunks = chunk_transform.send(chunk)
        if (backend_chunks is None):
            return
        updated_frag_indexes = set()
        for putter in list(putters):
            frag_index = putter_to_frag_index[putter]
            backend_chunk = backend_chunks[frag_index]
            if (not putter.failed):
                if (frag_index not in updated_frag_indexes):
                    frag_hashers[frag_index].update(backend_chunk)
                    updated_frag_indexes.add(frag_index)
                putter.send_chunk(backend_chunk)
            else:
                putter.close()
                putters.remove(putter)
        self._check_min_conn(req, putters, min_conns, msg=_('Object    PUT    exceptions    during    send,    %(conns)s/%(nodes)s    required    connections'))
    try:
        with ContextPool(len(putters)) as pool:
            putter_to_frag_index = self._determine_chunk_destinations(putters, policy)
            for putter in putters:
                putter.spawn_sender_greenthread(pool, self.app.put_queue_depth, self.app.node_timeout, self.app.exception_occurred)
            while True:
                with ChunkReadTimeout(self.app.client_timeout):
                    try:
                        chunk = next(data_source)
                    except StopIteration:
                        break
                bytes_transferred += len(chunk)
                if (bytes_transferred > constraints.MAX_FILE_SIZE):
                    raise HTTPRequestEntityTooLarge(request=req)
                send_chunk(chunk)
            if (req.content_length and (bytes_transferred < req.content_length)):
                req.client_disconnect = True
                self.app.logger.warning(_('Client    disconnected    without    sending    enough    data'))
                self.app.logger.increment('client_disconnects')
                raise HTTPClientDisconnect(request=req)
            computed_etag = (etag_hasher.hexdigest() if etag_hasher else None)
            received_etag = req.headers.get('etag', '').strip('"')
            if (computed_etag and received_etag and (computed_etag != received_etag)):
                raise HTTPUnprocessableEntity(request=req)
            send_chunk('')
            footers = self._get_footers(req)
            received_etag = footers.get('etag', '').strip('"')
            if (computed_etag and received_etag and (computed_etag != received_etag)):
                raise HTTPUnprocessableEntity(request=req)
            footers = {(k, v) for (k, v) in footers.items() if (not k.lower().startswith('x-object-sysmeta-ec-'))}
            for putter in putters:
                frag_index = putter_to_frag_index[putter]
                trail_md = trailing_metadata(policy, etag_hasher, bytes_transferred, frag_index)
                trail_md.update(footers)
                trail_md['Etag'] = frag_hashers[frag_index].hexdigest()
                putter.end_of_object_data(footer_metadata=trail_md)
            for putter in putters:
                putter.wait()
            final_phase = False
            (statuses, reasons, bodies, _junk) = self._get_put_responses(req, putters, len(nodes), final_phase=final_phase, min_responses=min_conns)
            if (not self.have_quorum(statuses, len(nodes), quorum=min_conns)):
                self.app.logger.error(_("Not    enough    object    servers    ack'ed    (got    %d)"), statuses.count(HTTP_CONTINUE))
                raise HTTPServiceUnavailable(request=req)
            elif (not self._have_adequate_informational(statuses, min_conns)):
                resp = self.best_response(req, statuses, reasons, bodies, _('Object    PUT'), quorum_size=min_conns)
                if is_client_error(resp.status_int):
                    raise HTTPServiceUnavailable(request=req)
                else:
                    raise resp
            for putter in putters:
                putter.send_commit_confirmation()
            for putter in putters:
                putter.wait()
    except ChunkReadTimeout as err:
        self.app.logger.warning(_('ERROR    Client    read    timeout    (%ss)'), err.seconds)
        self.app.logger.increment('client_timeouts')
        raise HTTPRequestTimeout(request=req)
    except ChunkReadError:
        req.client_disconnect = True
        self.app.logger.warning(_('Client    disconnected    without    sending    last    chunk'))
        self.app.logger.increment('client_disconnects')
        raise HTTPClientDisconnect(request=req)
    except HTTPException:
        raise
    except Timeout:
        self.app.logger.exception(_('ERROR    Exception    causing    client    disconnect'))
        raise HTTPClientDisconnect(request=req)
    except Exception:
        self.app.logger.exception(_('ERROR    Exception    transferring    data    to    object    servers    %s'), {'path': req.path})
        raise HTTPInternalServerError(request=req)
