private void doRead(HttpResponseWriter res, T in, long offset, long end,
                        Executor fileReadExecutor, ByteBufAllocator alloc) {
        final int chunkSize = (int) Math.min(MAX_CHUNK_SIZE, end - offset);
        final ByteBuf buf = alloc.buffer(chunkSize);
        final int readBytes;
        boolean success = false;
        try {
            readBytes = read(in, buf);
            if (readBytes < 0) {
                // Should not reach here because we only read up to the end of the stream.
                // If reached, it may mean the stream has been truncated.
                throw new EOFException();
            }
            success = true;
        } catch (Exception e) {
            close(res, in, e);
            return;
        } finally {
            if (!success) {
                buf.release();
            }
        }

        final long nextOffset = offset + readBytes;
        final boolean endOfStream = nextOffset == end;
        if (readBytes > 0) {
            if (!res.tryWrite(HttpData.wrap(buf).withEndOfStream(endOfStream))) {
                close(in);
                return;
            }
        } else {
            buf.release();
        }

        if (endOfStream) {
            close(res, in);
            return;
        }

        res.whenConsumed().thenRun(() -> {
            try {
                fileReadExecutor.execute(() -> doRead(res, in, nextOffset, end, fileReadExecutor, alloc));
            } catch (Exception e) {
                close(res, in, e);
            }
        });
    }
Creates a new instance.

@param contentType the {@link MediaType} of the file which will be used as the {@code "content-type"}
                   header value. {@code null} to disable setting the {@code "content-type"} header.
@param clock the {@link Clock} which provides the current date and time
@param dateEnabled whether to set the {@code "date"} header automatically
@param lastModifiedEnabled whether to add the {@code "last-modified"} header automatically
@param entityTagFunction the {@link BiFunction} that generates an entity tag from the file's attributes.
                         {@code null} to disable setting the {@code "etag"} header.
@param headers the additional headers to set
core/src/main/java/com/linecorp/armeria/server/file/StreamingHttpFile.java