Skip to content

Conversation

@jtjbrady
Copy link
Contributor

Qt internal resources are often stored compressed. The two compression formats being zlib and zstd.
When Qt NAM connects it by default sends:

Accept-Encoding: gzip, deflate

deflate maps to zlib compression.

The PR adds a helper function that if the Accept-Encoding header matches the compression format used for the Qt resource then rather than uncompressing the data internally in the server the data is sent unmodified to the client. If the data is not in the requested format the data is uncompressed (if it was compressed in the first place) and sent as usual.

This also checks all the edge cases for Accept-Encoding such as only supporting compressed data and not plain text.

I've tested this for zlib compression, every Qt version I have currently have access to has zstd disabled so I have not tested that.
I did have an issue with the unit tests with conditionally enabling resources based on zstd being configured in Qt.

This was honestly just an experiment in whether Qt resources exactly matched the HTTP data formats and it turns out for zlib at least they do.

@jtjbrady jtjbrady force-pushed the send-compressed branch 3 times, most recently from 28c746d to ce45fe3 Compare July 21, 2025 13:11
@jtjbrady
Copy link
Contributor Author

jtjbrady commented Jul 22, 2025

I'm not happy with the user API for this. In particular the error reporting path, e.g. from the unit test:

  QIODevice *processFileRequest(const QString &path, QByteArray &contentType) override
   {
       const auto [device, encodingOrError] = fileForEncoding("searchpath:" + path);

// I really don't like this if statement.
       if (!device) {
           if (!encodingOrError.isEmpty()) {
               writeHTTP(encodingOrError);
               // We set a fault so KDSoapServerSocket doesn't add a not found error
               // The first parameters are ignored but if the first one is null setFault
               // will assert.
               setFault(QStringLiteral("HTTP"), QString());
           }
           return nullptr;
       }

       m_contentEncoding = encodingOrError;
       contentType = "text/plain";
       return device;
   }

However, I can't see a way of implementing this without changing the API of KDSoapServerObjectInterface.
My though was to add a replacement method, something like this:

    std::tuple<QIODevice *, QByteArray, QByteArray> processFileRequest(const QString &path)
    {
        QByteArray contentType;
        return {processFileRequest(path, contentType), contentType, QByteArray()};
    }

Which defaults to calling the old API, but it needs further discussion.

@dfaure-kdab
Copy link
Member

In a tuple, the members are unnamed, so it becomes very unclear what each QByteArray is. Better return a struct, which allows to name the member variables.

@dfaure-kdab
Copy link
Member

I have to wonder if this will be useful to anyone else. Maybe it would make more sense to add the minimum required to KDSoapServer for the custom server implementation to be able to do this. I.e. no use of QResource in the server code, just a way to provide zlib-compressed data. It would make this more extensible to other cases of zlib-compressed data, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants