File 0001-webdav-Handle-redirections-which-add-trailing-slashe.patch of Package kf6-kio

From f7e12ffa4b1aa3935e47480ae2d57d3f6d55802f Mon Sep 17 00:00:00 2001
From: Fabian Vogt <fabian@ritter-vogt.de>
Date: Sat, 12 Oct 2024 16:58:26 +0200
Subject: [PATCH] [webdav] Handle redirections which add trailing slashes

KIO doesn't always send trailing slashes when referencing collections.
The RFC (quoted in the comment) requires that such clients handle
redirections, which KIO can't do correctly in this case.

Add explicit handling for such redirections in the http worker, such that
KIO and applications don't need to be aware of this.

CCBUG: 484580
---
 src/kioworkers/http/http.cpp | 57 +++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 27 deletions(-)

diff --git a/src/kioworkers/http/http.cpp b/src/kioworkers/http/http.cpp
index b6510c996..ae3c94ea0 100644
--- a/src/kioworkers/http/http.cpp
+++ b/src/kioworkers/http/http.cpp
@@ -433,6 +433,8 @@ HTTPProtocol::Response HTTPProtocol::makeRequest(const QUrl &url,
         }
     }
 
+    inputData->startTransaction(); // To be able to restart after redirects.
+
     QNetworkReply *reply = nam.sendCustomRequest(request, methodToString(method), inputData);
 
     bool mimeTypeEmitted = false;
@@ -454,11 +456,28 @@ HTTPProtocol::Response HTTPProtocol::makeRequest(const QUrl &url,
         processedSize(received);
     });
 
-    QObject::connect(reply, &QNetworkReply::metaDataChanged, [this, &mimeTypeEmitted, reply, dataMode, url, method]() {
-        handleRedirection(method, url, reply);
+    // From RFC 4918 5.2 Collection Resources:
+    // > In general, clients SHOULD use the trailing slash form of collection names.
+    // > If clients do not use the trailing slash form the client needs to be prepared to see a redirect response.
+    // KIO doesn't handle trailing slashes well (especially in KDirLister), so handle it transparently.
+    bool redirectToTrailingSlash = false;
 
+    QObject::connect(reply, &QNetworkReply::metaDataChanged, [this, &mimeTypeEmitted, &redirectToTrailingSlash, reply, dataMode, url, method]() {
         int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
 
+        // Handled after returning from the event loop.
+        // 301 is necessary for Apache (see bugs 209508 and 187970).
+        if (statusCode == 301 || statusCode == 307 || statusCode == 308) {
+            const QString redir = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();
+            const QUrl newUrl = url.resolved(QUrl(redir));
+            if (url != newUrl && url == newUrl.adjusted(QUrl::StripTrailingSlash)) {
+                redirectToTrailingSlash = true;
+                return;
+            }
+        }
+
+        handleRedirection(method, url, reply);
+
         if (statusCode == 206) {
             canResume();
         }
@@ -497,6 +516,15 @@ HTTPProtocol::Response HTTPProtocol::makeRequest(const QUrl &url,
     });
     loop.exec();
 
+    // If there was a foo -> foo/ redirect, follow it.
+    if (redirectToTrailingSlash) {
+        inputData->rollbackTransaction();
+        QUrl newUrl = url;
+        newUrl.setPath(newUrl.path() + QLatin1Char('/'));
+        return makeRequest(newUrl, method, inputData, dataMode, extraHeaders);
+    }
+    inputData->commitTransaction();
+
     // make sure data is emitted at least once
     // NOTE: emitting an empty data set means "end of data" and must not happen
     // before we have set up our metadata properties etc. Only emit this at the
@@ -733,11 +761,6 @@ KIO::WorkerResult HTTPProtocol::davStatList(const QUrl &url, bool stat)
 
     Response response = makeDavRequest(url, method, inputData, DataMode::Return, extraHeaders);
 
-    // TODO
-    // if (!stat) {
-    // Utils::appendSlashToPath(m_request.url);
-    // }
-
     // Has a redirection already been called? If so, we're done.
     // if (m_isRedirection || m_kioError) {
     // if (m_isRedirection) {
@@ -1106,26 +1129,6 @@ KIO::WorkerResult HTTPProtocol::rename(const QUrl &src, const QUrl &dest, KIO::J
     QByteArray inputData;
     Response response = makeDavRequest(src, KIO::DAV_MOVE, inputData, DataMode::Discard, extraHeaders);
 
-    // Work around strict Apache-2 WebDAV implementation which refuses to cooperate
-    // with webdav://host/directory, instead requiring webdav://host/directory/
-    // (strangely enough it accepts Destination: without a trailing slash)
-    // See BR# 209508 and BR#187970
-    // TODO
-    // if (m_request.responseCode == 301) {
-    //     QUrl redir = m_request.redirectUrl;
-    //
-    //     resetSessionSettings();
-    //
-    //     m_request.url = redir;
-    //     m_request.method = DAV_MOVE;
-    //     m_request.davData.desturl = newDest.toString();
-    //     m_request.davData.overwrite = (flags & KIO::Overwrite);
-    //     m_request.url.setQuery(QString());
-    //     m_request.cacheTag.policy = CC_Reload;
-    //
-    //     (void)/* handling result via dav codes */ proceedUntilResponseHeader();
-    // }
-
     // The server returns a HTTP/1.1 201 Created or 204 No Content on successful completion
     if (response.httpCode == 201 || response.httpCode == 204) {
         return KIO::WorkerResult::pass();
-- 
2.46.1

openSUSE Build Service is sponsored by