Details
-
Bug
-
Resolution: Out of scope
-
P2: Important
-
None
-
5.15.2, 6.0.2
-
None
Description
It seems that when using QNetworkAccessManager with custom HTTP verbs, when the server returns a code 301 (Moved Permanently), Qt changes the verb to GET.
I was made aware about this issue by a user of my app (see here for more details: https://gitlab.com/rpdev/opentodolist/-/issues/437). I filed a slightly similar request some time back (QTBUG-84162) and then there is also QTBUG-63142 which seems a bit similar.
What I did to trigger the error is the following:
- Start a `centos:7` docker container, forwarding port `8080` from the host to port `80` in the container.
- Inside the container, install `httpd`.
- Add a file `/etc/httpd/conf.d/dav.conf` with the following content:
<VirtualHost _default_:80> DocumentRoot /var/www <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/> Options Indexes FollowSymLinks MultiViews AllowOverride AuthConfig Order allow,deny allow from all </Directory> Alias /webdav /var/www/ToDoList <Directory /var/www/ToDoList/> DAV On DavDepthInfinity on AuthType Basic AuthName "webdav" AuthUserFile /etc/apache2/auth/ToGoList_passwd Require valid-user </Directory> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory> </VirtualHost>
4. Run the following, to prepare the environment:
mkdir /var/www/ToDoList chown apache:apache /var/www/ToDoList mkdir -p /etc/apache2/auth/ htpasswd -bc /etc/apache2/auth/ToGoList_passwd admin admin # start apache: httpd -k start
5. On the host, compiled the following minimal example program:
#include <QCoreApplication> #include <QNetworkAccessManager> #include <QNetworkReply> #include <QNetworkRequest> #include <QUrl> static const QByteArray PropFindRequestData = "<?xml version=\"1.0\"?>" "<a:propfind xmlns:a=\"DAV:\">" "<a:prop>" "<a:getetag/>" "<a:resourcetype/>" "</a:prop>" "</a:propfind>"; static const char *DefaultEncoding = "text/xml; charset=utf-8"; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QNetworkAccessManager nam; nam.setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); QNetworkRequest req; req.setUrl(QUrl("http://admin:admin@localhost:8080/webdav")); req.setRawHeader("Depth", "0"); req.setHeader(QNetworkRequest::ContentLengthHeader, PropFindRequestData.size()); req.setHeader(QNetworkRequest::ContentTypeHeader, DefaultEncoding); auto reply = nam.sendCustomRequest(req, "PROPFIND", PropFindRequestData); QObject::connect(reply, &QNetworkReply::finished, [=]() { qDebug().noquote().nospace() << reply->readAll(); reply->deleteLater(); qApp->quit(); }); return a.exec(); }
When being run, the following happens:
- The request seemingly succeeds - in fact, if you check, the request finishes with a status code of 200.
- However, as we started with a `PROPFIND`, we would - rightfully! - have expected a code 207 (WebDAV Multi-Status).
When you check the Apache server logs, you can see the following sequence:
10.0.2.100 - - [16/Apr/2021:19:55:01 +0000] "PROPFIND /webdav HTTP/1.1" 401 381 "-" "Mozilla/5.0" 10.0.2.100 - admin [16/Apr/2021:19:55:01 +0000] "PROPFIND /webdav HTTP/1.1" 301 237 "-" "Mozilla/5.0" 10.0.2.100 - admin [16/Apr/2021:19:55:01 +0000] "GET /webdav/ HTTP/1.1" 200 883 "-" "Mozilla/5.0"
So we see, we first do an anonymous `PROPFIND`, followed by a `PROPFIND` with the username and password. This yields a redirect (from `/webdav` to `/webdav/`).
However, the last request is done via the `GET` verb. This will cause Apache to deliver the HTML folder listing - not the expected Multi-Status response.
According to https://tools.ietf.org/html/rfc7231#section-6.4.2:
Note: For historical reasons, a user agent MAY change the request method from POST to GET for the subsequent request. If this behavior is undesired, the 307 (Temporary Redirect) status code can be used instead.
So clients rightfully may use a `GET` if previously a `POST` was used - but this isn't the case.
This behaviour is the same for Qt 5.15 as well as 6.0.