Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-92909

When following redirects, a PROPFIND request (and probably others) are converted to a GET

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P2: Important
    • Resolution: Out of scope
    • Affects Version/s: 5.15.2, 6.0.2
    • Fix Version/s: None
    • Component/s: Network: HTTP
    • Labels:
      None
    • Platform/s:
      Linux/X11

      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:

      1. Start a `centos:7` docker container, forwarding port `8080` from the host to port `80` in the container.
      2. Inside the container, install `httpd`.
      3. 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.

       

        Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

            Assignee:
            manordheim Mårten Nordheim
            Reporter:
            mhoeher Martin Höher
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:

                Gerrit Reviews

                There are no open Gerrit changes