'Read bytes from the request body and return or write them to a file.
A number of bytes less than or equal to the \'size\' argument are read
off the socket. The actual number of bytes read are tracked in
self.bytes_read. The number may be smaller than \'size\' when 1) the
client sends fewer bytes, 2) the \'Content-Length\' request header
specifies fewer bytes than requested, or 3) the number of bytes read
exceeds self.maxbytes (in which case, 413 is raised).
If the \'fp_out\' argument is None (the default), all bytes read are
returned in a single byte string.
If the \'fp_out\' argument is not None, it must be a file-like object that
supports the \'write\' method; all bytes read will be written to the fp,
and None is returned.'

def read(self, size=None, fp_out=None):

    if (self.length is None):
        if (size is None):
            remaining = inf
        else:
            remaining = size
    else:
        remaining = (self.length - self.bytes_read)
        if (size and (size < remaining)):
            remaining = size
    if (remaining == 0):
        self.finish()
        if (fp_out is None):
            return ntob('')
        else:
            return None
    chunks = []
    if self.buffer:
        if (remaining is inf):
            data = self.buffer
            self.buffer = ntob('')
        else:
            data = self.buffer[:remaining]
            self.buffer = self.buffer[remaining:]
        datalen = len(data)
        remaining -= datalen
        self.bytes_read += datalen
        if (self.maxbytes and (self.bytes_read > self.maxbytes)):
            raise cherrypy.HTTPError(413)
        if (fp_out is None):
            chunks.append(data)
        else:
            fp_out.write(data)
    while (remaining > 0):
        chunksize = min(remaining, self.bufsize)
        try:
            data = self.fp.read(chunksize)
        except Exception:
            e = sys.exc_info()[1]
            if (e.__class__.__name__ == 'MaxSizeExceeded'):
                raise cherrypy.HTTPError(413, ('Maximum    request    length:    %r' % e.args[1]))
            else:
                raise
        if (not data):
            self.finish()
            break
        datalen = len(data)
        remaining -= datalen
        self.bytes_read += datalen
        if (self.maxbytes and (self.bytes_read > self.maxbytes)):
            raise cherrypy.HTTPError(413)
        if (fp_out is None):
            chunks.append(data)
        else:
            fp_out.write(data)
    if (fp_out is None):
        return ntob('').join(chunks)
