File indexing completed on 2024-05-26 05:17:00

0001 /*
0002     Copyright (c) 2014 Gregory Oestreicher <greg@kamago.net>
0003 
0004     This program is free software; you can redistribute it and/or modify
0005     it under the terms of the GNU General Public License as published by
0006     the Free Software Foundation; either version 2 of the License, or
0007     (at your option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program; if not, write to the Free Software
0016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0017 */
0018 
0019 #include "davjob.h"
0020 
0021 #include "davmanager.h"
0022 #include "libkdav2_debug.h"
0023 
0024 #include <QTextStream>
0025 
0026 using namespace KDAV2;
0027 
0028 class DavJobPrivate {
0029 public:
0030     QByteArray data;
0031     QDomDocument doc;
0032     QUrl url;
0033 
0034     QString location;
0035     QString etag;
0036     QString contentType;
0037     QNetworkReply::NetworkError responseCode = QNetworkReply::NoError;
0038     int httpStatusCode = 0;
0039 };
0040 
0041 DavJob::DavJob(QNetworkReply *reply, QUrl url, QObject *parent)
0042     : KJob(parent),
0043     d(new DavJobPrivate)
0044 {
0045     d->url = url;
0046     connectToReply(reply);
0047 }
0048 
0049 DavJob::~DavJob()
0050 {
0051 }
0052 
0053 void DavJob::connectToReply(QNetworkReply *reply)
0054 {
0055     QObject::connect(reply, &QNetworkReply::readyRead, this, [=] () {
0056         d->data.append(reply->readAll());
0057     });
0058     QObject::connect(reply, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, [=] (QNetworkReply::NetworkError error) {
0059         qCWarning(KDAV2_LOG) << "Network error:" << error << "Message:" << reply->errorString() << "HTTP Status code:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() << "\nAvailable data:" << reply->readAll();
0060     });
0061     QObject::connect(reply, &QNetworkReply::metaDataChanged, this, [=] () {
0062         qCDebug(KDAV2_LOG) << "Metadata changed: " << reply->rawHeaderPairs();
0063         d->location = reply->rawHeader("Location");
0064         d->etag = reply->rawHeader("ETag");
0065         //"text/x-vcard; charset=utf-8" -> "text/x-vcard"
0066         d->contentType = reply->rawHeader("Content-Type").split(';').first();
0067     });
0068     QObject::connect(reply, &QNetworkReply::finished, this, [=] () {
0069         //This is a workaround for QNetworkAccessManager::setRedirectPolicy(QNetworkRequest::UserVerifiedRedirectPolicy),
0070         //which does not seem to work with multiple redirects.
0071         const auto possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
0072         if(!possibleRedirectUrl.isEmpty()) {
0073             qCDebug(KDAV2_LOG) << "Redirecting to " << possibleRedirectUrl;
0074             auto request = reply->request();
0075             request.setUrl(possibleRedirectUrl);
0076             reply->disconnect(this);
0077 
0078             //Set in QWebdav
0079             const auto requestData = reply->property("requestData").toByteArray();
0080             d->data.clear();
0081 
0082             auto redirectReply = [&] {
0083                 if (reply->property("isPut").toBool()) {
0084                     return DavManager::networkAccessManager()->put(request, requestData);
0085                 }
0086                 return DavManager::networkAccessManager()->sendCustomRequest(request, request.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray(), requestData);
0087             }();
0088             redirectReply->setProperty("requestData", requestData);
0089             connectToReply(redirectReply);
0090             return;
0091         }
0092 
0093         //Could have changed due to redirects
0094         d->url = reply->url();
0095 
0096         d->doc.setContent(d->data, true);
0097 
0098         if (KDAV2_LOG().isDebugEnabled()) {
0099             QTextStream stream(stdout, QIODevice::WriteOnly);
0100             d->doc.save(stream, 2);
0101         }
0102 
0103         d->responseCode = reply->error();
0104         d->httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
0105         if (d->responseCode) {
0106             setError(KJob::UserDefinedError);
0107             setErrorText(reply->errorString());
0108         } else if (d->httpStatusCode >= 400) {
0109             qWarning() << "No error set even though we clearly have an http error?" << d->responseCode << d->httpStatusCode;
0110             Q_ASSERT(false);
0111             setError(KJob::UserDefinedError);
0112             setErrorText(reply->errorString());
0113         }
0114         emitResult();
0115     });
0116 
0117 }
0118 
0119 void DavJob::start()
0120 {
0121 }
0122 
0123 QDomDocument DavJob::response() const
0124 {
0125     return d->doc;
0126 }
0127 
0128 QByteArray DavJob::data() const
0129 {
0130     return d->data;
0131 }
0132 
0133 QUrl DavJob::url() const
0134 {
0135     return d->url;
0136 }
0137 
0138 QString DavJob::getLocationHeader() const
0139 {
0140     return d->location;
0141 }
0142 
0143 QString DavJob::getETagHeader() const
0144 {
0145     return d->etag;
0146 }
0147 
0148 QString DavJob::getContentTypeHeader() const
0149 {
0150     return d->contentType;
0151 }
0152 
0153 QNetworkReply::NetworkError DavJob::responseCode() const
0154 {
0155     return d->responseCode;
0156 }
0157 
0158 int DavJob::httpStatusCode() const
0159 {
0160     return d->httpStatusCode;
0161 }