def _serve_fileobj(fileobj, content_type, content_length, debug=False):
    """Set ``response.body`` to the given file object, perhaps ranged.

    Internal helper.
    """
    response = cherrypy.serving.response

    # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
    request = cherrypy.serving.request
    if request.protocol >= (1, 1):
        response.headers['Accept-Ranges'] = 'bytes'
        r = httputil.get_ranges(request.headers.get('Range'), content_length)
        if r == []:
            response.headers['Content-Range'] = 'bytes */%s' % content_length
            message = (
                'Invalid Range (first-byte-pos greater than Content-Length)'
            )
            if debug:
                cherrypy.log(message, 'TOOLS.STATIC')
            raise cherrypy.HTTPError(416, message)

        if r:
            if len(r) == 1:
                # Return a single-part response.
                start, stop = r[0]
                if stop > content_length:
                    stop = content_length
                r_len = stop - start
                if debug:
                    cherrypy.log(
                        'Single part; start: %r, stop: %r' % (start, stop),
                        'TOOLS.STATIC',
                    )
                response.status = '206 Partial Content'
                response.headers['Content-Range'] = 'bytes %s-%s/%s' % (
                    start,
                    stop - 1,
                    content_length,
                )
                response.headers['Content-Length'] = r_len
                fileobj.seek(start)
                response.body = file_generator_limited(fileobj, r_len)
            else:
                # Return a multipart/byteranges response.
                response.status = '206 Partial Content'
                boundary = make_boundary()
                ct = 'multipart/byteranges; boundary=%s' % boundary
                response.headers['Content-Type'] = ct
                if 'Content-Length' in response.headers:
                    # Delete Content-Length header so finalize() recalcs it.
                    del response.headers['Content-Length']

                def file_ranges():
                    # Apache compatibility:
                    yield b'\r\n'

                    for start, stop in r:
                        if debug:
                            cherrypy.log(
                                'Multipart; start: %r, stop: %r'
                                % (start, stop),
                                'TOOLS.STATIC',
                            )
                        yield ntob('--' + boundary, 'ascii')
                        yield ntob(
                            '\r\nContent-type: %s' % content_type,
                            'ascii',
                        )
                        yield ntob(
                            '\r\nContent-range: bytes %s-%s/%s\r\n\r\n'
                            % (start, stop - 1, content_length),
                            'ascii',
                        )
                        fileobj.seek(start)
                        gen = file_generator_limited(fileobj, stop - start)
                        for chunk in gen:
                            yield chunk
                        yield b'\r\n'
                    # Final boundary
                    yield ntob('--' + boundary + '--', 'ascii')

                    # Apache compatibility:
                    yield b'\r\n'

                response.body = file_ranges()
            return response.body
        else:
            if debug:
                cherrypy.log('No byteranges requested', 'TOOLS.STATIC')

    # Set Content-Length and use an iterable (file object)
    #   this way CP won't load the whole file in memory
    response.headers['Content-Length'] = content_length
    response.body = fileobj
    return response.body
Set ``response.body`` to the given file object, perhaps ranged.

    Internal helper.
    
cherrypy/lib/static.py