public function sendfile($path, $cb, $pri = EIO_PRI_DEFAULT)
    {
        if ($this->state === self::STATE_FINISHED) {
            return false;
        }
        try {
            $this->header('Content-Type: ' . MIME::get($path));
        } catch (RequestHeadersAlreadySent $e) {
        }
        if ($this->upstream->checkSendfileCap()) {
            FileSystem::sendfile($this->upstream, $path, $cb, function ($file, $length, $handler) {
                try {
                    $this->header('Content-Length: ' . $length);
                } catch (RequestHeadersAlreadySent $e) {
                }
                $this->ensureSentHeaders();
                $this->upstream->onWriteOnce(function ($conn) use ($handler, $file) {
                    $handler($file);
                });
                return true;
            }, 0, null, $pri);
            return true;
        }
        $first = true;

        FileSystem::readfileChunked(
            $path,
            $cb,
            function ($file, $chunk) use (&$first) {
                // readed chunk
                if ($this->upstream->isFreed()) {
                    return false;
                }

                if ($first) {
                    try {
                        $this->header('Content-Length: ' . $file->stat['size']);
                    } catch (RequestHeadersAlreadySent $e) {
                    }
                    $first = false;
                }
                $this->out($chunk);
                return true;
            }
        );

        return true;
    }