def read(self, size=None, fp_out=None):
        """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.
        """
        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 b''
            else:
                return None

        chunks = []

        # Read bytes from the buffer.
        if self.buffer:
            if remaining is inf:
                data = self.buffer
                self.buffer = b''
            else:
                data = self.buffer[:remaining]
                self.buffer = self.buffer[remaining:]
            datalen = len(data)
            remaining -= datalen

            # Check lengths.
            self.bytes_read += datalen
            if self.maxbytes and self.bytes_read > self.maxbytes:
                raise cherrypy.HTTPError(413)

            # Store the data.
            if fp_out is None:
                chunks.append(data)
            else:
                fp_out.write(data)

        # Read bytes from the socket.
        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':
                    # Post data is too big
                    raise cherrypy.HTTPError(
                        413,
                        'Maximum request length: %r' % e.args[1],
                    )
                else:
                    raise
            if not data:
                self.finish()
                break
            datalen = len(data)
            remaining -= datalen

            # Check lengths.
            self.bytes_read += datalen
            if self.maxbytes and self.bytes_read > self.maxbytes:
                raise cherrypy.HTTPError(413)

            # Store the data.
            if fp_out is None:
                chunks.append(data)
            else:
                fp_out.write(data)

        if fp_out is None:
            return b''.join(chunks)
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.
        
cherrypy/_cpreqbody.py