chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.38k stars 467 forks source link

CEF ignore content-type "gzip" when using custom CefResourceHandler #3756

Closed lyhellcat closed 3 months ago

lyhellcat commented 3 months ago

Describe the bug I use CefResourceHandler to intercept url requests. In the response header, I include content-type: gizp and content-length, but it seems that CEF cannot decompress it. img_v3_02d5_b077d195-35fe-4cd2-9faf-5b4383486e5g

img_v3_02d4_c93bbecc-0142-4810-bda8-5104372d501g

I've confirmed that the result of gzip compression is correct: img_v3_02d3_14f9fe2a-6046-4dfd-a733-5b180ade7fag

Example code:

int compress(std::string const &input, std::string &output)
{
    z_stream deflate_s;
    deflate_s.zalloc = Z_NULL;
    deflate_s.zfree = Z_NULL;
    deflate_s.opaque = Z_NULL;
    deflate_s.avail_in = 0;
    deflate_s.next_in = Z_NULL;
    deflateInit2(&deflate_s, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
    deflate_s.next_in = (Bytef*)input.data();
    deflate_s.avail_in = input.size();
    size_t length = 0;
    do {
        size_t increase = input.size() / 2 + 1024;
        output.resize(length + increase);
        deflate_s.avail_out = increase;
        deflate_s.next_out = (Bytef*)(output.data() + length);
        int ret = deflate(&deflate_s, Z_FINISH);
        if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) {
            return -1;
        }
        length += (increase - deflate_s.avail_out);
    } while (deflate_s.avail_out == 0);
    deflateEnd(&deflate_s);
    output.resize(length);

    return 0;
}

CefRefPtr<CefResourceHandler> CreateHttpsResourceHandler(const QUrl& url) {
    CefResponse::HeaderMap header_map = {{"Access-Control-Allow-Origin", "*"},
                                                {"Cache-Control", "public, max-age=3600"},
                                                {"Cross-Origin-Embedder-Policy", "require-corp"},
                                                {"Cross-Origin-Opener-Policy", "same-origin"},
                                                {"content-encoding", "gzip"}};

    auto resource_file_path = xxx;
    if (!resource_file_path.isEmpty()) {
        // compressed and return file stream
        QFileInfo resource_file_info{resource_file_path};
        if (resource_file_info.exists()) {
            QFile resource_file{resource_file_path};

            if (!resource_file.open(QIODevice::ReadOnly)) {
                return CefRefPtr<CefStreamResourceHandler>(nullptr);
            }
            std::string input = resource_file.readAll().toStdString();
            std::string output;
            compress(input, output);
            CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData((void*)output.c_str(), output.size());
            if (stream) {
                QString file_ext = resource_file_info.suffix();
                CefString mime_type = CefGetMimeType(file_ext.toStdString());
                header_map.insert(std::make_pair(CefString{"content-length"}, CefString{std::to_string(output.size())}));
                return CefRefPtr<CefStreamResourceHandler>(new CefStreamResourceHandler(
                    200, "OK", mime_type, header_map,
                    output.size(), stream));
            }
        }
    }
    return CefRefPtr<CefStreamResourceHandler>(nullptr);
}

Expected behavior CEF is expected to correctly decompress gzip information.

Screenshots If applicable, add screenshots to help explain your problem.

Versions (please complete the following information):

Additional context I use gzip compression to solve the problem of slow files returned by cef. I have observed that css files returned using CefResourceHandler are much slower than js files of similar size: img_v3_02d5_29cb844e-a820-48d2-8ed8-c4decfb6391g

magreenblatt commented 3 months ago

There is no benefit to using compression for response contents that are not actually passing over a network. Otherwise, you're adding additional compute time (to compress/decompress) with no benefit.