• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

KIO

accessmanager.cpp
Go to the documentation of this file.
00001 /*
00002  * This file is part of the KDE project.
00003  *
00004  * Copyright (C) 2009 - 2012 Dawit Alemayehu <adawit @ kde.org>
00005  * Copyright (C) 2008 - 2009 Urs Wolfer <uwolfer @ kde.org>
00006  * Copyright (C) 2007 Trolltech ASA
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Library General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Library General Public License
00019  * along with this library; see the file COPYING.LIB.  If not, write to
00020  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021  * Boston, MA 02110-1301, USA.
00022  *
00023  */
00024 
00025 #include "accessmanager.h"
00026 
00027 #include "accessmanagerreply_p.h"
00028 #include "job.h"
00029 #include "scheduler.h"
00030 #include "jobuidelegate.h"
00031 #include "netaccess.h"
00032 
00033 #include <kdebug.h>
00034 #include <kconfiggroup.h>
00035 #include <ksharedconfig.h>
00036 #include <kprotocolinfo.h>
00037 #include <klocalizedstring.h>
00038 
00039 #include <QtCore/QUrl>
00040 #include <QtCore/QPointer>
00041 #include <QtGui/QWidget>
00042 #include <QtDBus/QDBusInterface>
00043 #include <QtDBus/QDBusConnection>
00044 #include <QtDBus/QDBusReply>
00045 #include <QtNetwork/QNetworkReply>
00046 #include <QtNetwork/QNetworkRequest>
00047 #include <QtNetwork/QSslCipher>
00048 #include <QtNetwork/QSslCertificate>
00049 #include <QtNetwork/QSslConfiguration>
00050 
00051 #define QL1S(x)   QLatin1String(x)
00052 #define QL1C(x)   QLatin1Char(x)
00053 
00054 #if QT_VERSION >= 0x040800
00055 static QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = QNetworkRequest::SynchronousRequestAttribute;
00056 #else // QtWebkit hack to use the internal attribute
00057 static QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = static_cast<QNetworkRequest::Attribute>(QNetworkRequest::HttpPipeliningWasUsedAttribute + 7);
00058 #endif
00059 
00060 
00061 
00062 
00063 static qint64 sizeFromRequest(const QNetworkRequest& req)
00064 {
00065     const QVariant size = req.header(QNetworkRequest::ContentLengthHeader);
00066     if (!size.isValid())
00067         return -1;
00068     bool ok = false;
00069     const qlonglong value = size.toLongLong(&ok);
00070     return (ok ? value : -1);
00071 }
00072 
00073 namespace KIO {
00074 
00075 class AccessManager::AccessManagerPrivate
00076 {
00077 public:
00078     AccessManagerPrivate()
00079       : externalContentAllowed(true),
00080         emitReadyReadOnMetaDataChange(false),
00081         window(0)
00082     {}
00083 
00084     void setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData);
00085 
00086     bool externalContentAllowed;
00087     bool emitReadyReadOnMetaDataChange;
00088     KIO::MetaData requestMetaData;
00089     KIO::MetaData sessionMetaData;
00090     QPointer<QWidget> window;
00091 };
00092 
00093 namespace Integration {
00094 
00095 class CookieJar::CookieJarPrivate
00096 {
00097 public:
00098   CookieJarPrivate()
00099     : windowId((WId)-1), 
00100       isEnabled(true),
00101       isStorageDisabled(false)
00102   {}
00103 
00104   WId windowId;
00105   bool isEnabled;
00106   bool isStorageDisabled;
00107 };
00108 
00109 }
00110 
00111 }
00112 
00113 using namespace KIO;
00114 
00115 AccessManager::AccessManager(QObject *parent)
00116               :QNetworkAccessManager(parent), d(new AccessManager::AccessManagerPrivate())
00117 {
00118     // KDE Cookiejar (KCookieJar) integration...
00119     setCookieJar(new KIO::Integration::CookieJar);
00120 }
00121 
00122 AccessManager::~AccessManager()
00123 {
00124     delete d;
00125 }
00126 
00127 void AccessManager::setExternalContentAllowed(bool allowed)
00128 {
00129     d->externalContentAllowed = allowed;
00130 }
00131 
00132 bool AccessManager::isExternalContentAllowed() const
00133 {
00134     return d->externalContentAllowed;
00135 }
00136 
00137 #ifndef KDE_NO_DEPRECATED
00138 void AccessManager::setCookieJarWindowId(WId id)
00139 {
00140     QWidget* window = QWidget::find(id);
00141     if (!window) {
00142         return;
00143     }
00144 
00145     KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
00146     if (jar) {
00147         jar->setWindowId(id);
00148     }
00149 
00150     d->window = window->isWindow() ? window : window->window();
00151 }
00152 #endif
00153 
00154 void AccessManager::setWindow(QWidget* widget)
00155 {
00156     if (!widget) {
00157         return;
00158     }
00159 
00160     d->window = widget->isWindow() ? widget : widget->window();
00161 
00162     if (!d->window) {
00163         return;
00164     }
00165 
00166     KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
00167     if (jar) {
00168         jar->setWindowId(d->window->winId());
00169     }
00170 }
00171 
00172 #ifndef KDE_NO_DEPRECATED
00173 WId AccessManager::cookieJarWindowid() const
00174 {
00175     KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
00176     if (jar)
00177         return jar->windowId();
00178 
00179     return 0;
00180 }
00181 #endif
00182 
00183 QWidget* AccessManager::window() const
00184 {
00185     return d->window;
00186 }
00187 
00188 KIO::MetaData& AccessManager::requestMetaData()
00189 {
00190     return d->requestMetaData;
00191 }
00192 
00193 KIO::MetaData& AccessManager::sessionMetaData()
00194 {
00195     return d->sessionMetaData;
00196 }
00197 
00198 void AccessManager::putReplyOnHold(QNetworkReply* reply)
00199 {
00200     KDEPrivate::AccessManagerReply* r = qobject_cast<KDEPrivate::AccessManagerReply*>(reply);
00201     if (!r) {
00202       return;
00203     }
00204 
00205     r->putOnHold();
00206 }
00207 
00208 void AccessManager::setEmitReadyReadOnMetaDataChange(bool enable)
00209 {
00210     d->emitReadyReadOnMetaDataChange = enable;
00211 }
00212 
00213 QNetworkReply *AccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData)
00214 {
00215     const KUrl reqUrl (req.url());
00216 
00217     if (!d->externalContentAllowed &&
00218         !KDEPrivate::AccessManagerReply::isLocalRequest(reqUrl) &&
00219         reqUrl.scheme() != QL1S("data")) {
00220         kDebug( 7044 ) << "Blocked: " << reqUrl;
00221         return new KDEPrivate::AccessManagerReply(op, req, QNetworkReply::ContentAccessDenied, i18n("Blocked request."), this);
00222     }
00223 
00224     // Check if the internal ignore content disposition header is set.
00225     const bool ignoreContentDisposition = req.hasRawHeader("x-kdewebkit-ignore-disposition");
00226 
00227     // Retrieve the KIO meta data...
00228     KIO::MetaData metaData;
00229     d->setMetaDataForRequest(req, metaData);
00230 
00231     KIO::SimpleJob *kioJob = 0;
00232 
00233     switch (op) {
00234         case HeadOperation: {
00235             //kDebug( 7044 ) << "HeadOperation:" << reqUrl;
00236             kioJob = KIO::mimetype(reqUrl, KIO::HideProgressInfo);
00237             break;
00238         }
00239         case GetOperation: {
00240             //kDebug( 7044 ) << "GetOperation:" << reqUrl;
00241             if (!reqUrl.path().isEmpty() || reqUrl.host().isEmpty())
00242                 kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo);
00243             else
00244                 kioJob = KIO::stat(reqUrl, KIO::HideProgressInfo);
00245 
00246             // WORKAROUND: Avoid the brain damaged stuff QtWebKit does when a POST
00247             // operation is redirected! See BR# 268694.
00248             metaData.remove(QL1S("content-type")); // Remove the content-type from a GET/HEAD request!
00249             break;
00250         }
00251         case PutOperation: {
00252             //kDebug( 7044 ) << "PutOperation:" << reqUrl;
00253             if (outgoingData)
00254                 kioJob = KIO::storedPut(outgoingData->readAll(), reqUrl, -1, KIO::HideProgressInfo);
00255             else
00256                 kioJob = KIO::put(reqUrl, -1, KIO::HideProgressInfo);
00257             break;
00258         }
00259         case PostOperation: {
00260             kioJob = KIO::http_post(reqUrl, outgoingData, sizeFromRequest(req), KIO::HideProgressInfo);
00261             if (!metaData.contains(QL1S("content-type")))  {
00262                 const QVariant header = req.header(QNetworkRequest::ContentTypeHeader);
00263                 if (header.isValid()) {
00264                     metaData.insert(QL1S("content-type"),
00265                                     (QL1S("Content-Type: ") + header.toString()));
00266                 } else {
00267                     metaData.insert(QL1S("content-type"),
00268                                     QL1S("Content-Type: application/x-www-form-urlencoded"));
00269                 }
00270             }
00271             break;
00272         }
00273         case DeleteOperation: {
00274             //kDebug(7044) << "DeleteOperation:" << reqUrl;
00275             kioJob = KIO::http_delete(reqUrl, KIO::HideProgressInfo);
00276             break;
00277         }
00278         case CustomOperation: {
00279             const QByteArray& method = req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray();
00280             //kDebug(7044) << "CustomOperation:" << reqUrl << "method:" << method << "outgoing data:" << outgoingData;
00281 
00282             if (method.isEmpty()) {
00283                 return new KDEPrivate::AccessManagerReply(op, req, QNetworkReply::ProtocolUnknownError, i18n("Unknown HTTP verb."), this);
00284             }
00285 
00286             if (outgoingData)
00287                 kioJob = KIO::http_post(reqUrl, outgoingData, sizeFromRequest(req), KIO::HideProgressInfo);
00288             else
00289                 kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo);
00290 
00291             metaData.insert(QL1S("CustomHTTPMethod"), method);
00292             break;
00293         }
00294         default: {
00295             kWarning(7044) << "Unsupported KIO operation requested! Defering to QNetworkAccessManager...";
00296             return QNetworkAccessManager::createRequest(op, req, outgoingData);
00297         }
00298     }
00299 
00300     // Set the job priority
00301     switch (req.priority()) {
00302     case QNetworkRequest::HighPriority:
00303         KIO::Scheduler::setJobPriority(kioJob, -5);
00304         break;
00305     case QNetworkRequest::LowPriority:
00306         KIO::Scheduler::setJobPriority(kioJob, 5);
00307         break;
00308     default:
00309         break;
00310     }
00311 
00312     KDEPrivate::AccessManagerReply *reply;
00313 
00314     /*
00315       NOTE: Here we attempt to handle synchronous XHR requests. Unfortunately,
00316       due to the fact that QNAM is both synchronous and multi-thread while KIO
00317       is completely the opposite (asynchronous and not thread safe), the code
00318       below might cause crashes like the one reported in bug# 287778 (nested
00319       event loops are inherently dangerous).
00320 
00321       Unfortunately, all attempts to address the crash has so far failed due to
00322       the many regressions they caused, e.g. bug# 231932 and 297954. Hence, until
00323       a solution is found, we have to live with the side effects of creating
00324       nested event loops.
00325     */
00326     if (req.attribute(gSynchronousNetworkRequestAttribute).toBool()) {
00327         KUrl finalURL;
00328         QByteArray data;
00329 
00330         if (KIO::NetAccess::synchronousRun(kioJob, d->window, &data, &finalURL, &metaData)) {
00331             reply = new KDEPrivate::AccessManagerReply(op, req, data, finalURL, metaData, this);
00332             kDebug(7044) << "Synchronous XHR:" << reply << reqUrl;
00333         } else {
00334             kWarning(7044) << "Failed to create a synchronous XHR for" << reqUrl;
00335             reply = new KDEPrivate::AccessManagerReply(op, req, QNetworkReply::UnknownNetworkError, kioJob->errorText(), this);
00336         }
00337     } else {
00338         // Set the window on the the KIO ui delegate
00339         if (d->window) {
00340             kioJob->ui()->setWindow(d->window);
00341         }
00342 
00343         // Disable internal automatic redirection handling
00344         kioJob->setRedirectionHandlingEnabled(false);
00345 
00346         // Set the job priority
00347         switch (req.priority()) {
00348         case QNetworkRequest::HighPriority:
00349             KIO::Scheduler::setJobPriority(kioJob, -5);
00350             break;
00351         case QNetworkRequest::LowPriority:
00352             KIO::Scheduler::setJobPriority(kioJob, 5);
00353             break;
00354         default:
00355             break;
00356         }
00357 
00358         // Set the meta data for this job...
00359         kioJob->setMetaData(metaData);
00360 
00361         // Create the reply...
00362         reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, d->emitReadyReadOnMetaDataChange, this);
00363         //kDebug(7044) << reply << reqUrl;
00364     }
00365 
00366     if (ignoreContentDisposition && reply) {
00367         //kDebug(7044) << "Content-Disposition WILL BE IGNORED!";
00368         reply->setIgnoreContentDisposition(ignoreContentDisposition);
00369     }
00370 
00371     return reply;
00372 }
00373 
00374 void AccessManager::AccessManagerPrivate::setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData)
00375 {
00376     // Add any meta data specified within request...
00377     QVariant userMetaData = request.attribute (static_cast<QNetworkRequest::Attribute>(MetaData));
00378     if (userMetaData.isValid() && userMetaData.type() == QVariant::Map)
00379         metaData += userMetaData.toMap();
00380 
00381     metaData.insert(QL1S("PropagateHttpHeader"), QL1S("true"));
00382 
00383     if (request.hasRawHeader("User-Agent")) {
00384         metaData.insert(QL1S("UserAgent"), request.rawHeader("User-Agent"));
00385         request.setRawHeader("User-Agent", QByteArray());
00386     }
00387 
00388     if (request.hasRawHeader("Accept")) {
00389         metaData.insert(QL1S("accept"), request.rawHeader("Accept"));
00390         request.setRawHeader("Accept", QByteArray());
00391     }
00392 
00393     if (request.hasRawHeader("Accept-Charset")) {
00394         metaData.insert(QL1S("Charsets"), request.rawHeader("Accept-Charset"));
00395         request.setRawHeader("Accept-Charset", QByteArray());
00396     }
00397 
00398     if (request.hasRawHeader("Accept-Language")) {
00399         metaData.insert(QL1S("Languages"), request.rawHeader("Accept-Language"));
00400         request.setRawHeader("Accept-Language", QByteArray());
00401     }
00402 
00403     if (request.hasRawHeader("Referer")) {
00404         metaData.insert(QL1S("referrer"), request.rawHeader("Referer"));
00405         request.setRawHeader("Referer", QByteArray());
00406     }
00407 
00408     if (request.hasRawHeader("Content-Type")) {
00409         metaData.insert(QL1S("content-type"), request.rawHeader("Content-Type"));
00410         request.setRawHeader("Content-Type", QByteArray());
00411     }
00412 
00413     if (request.attribute(QNetworkRequest::AuthenticationReuseAttribute) == QNetworkRequest::Manual) {
00414         metaData.insert(QL1S("no-preemptive-auth-reuse"), QL1S("true"));
00415     }
00416 
00417     request.setRawHeader("Content-Length", QByteArray());
00418     request.setRawHeader("Connection", QByteArray());
00419     request.setRawHeader("If-None-Match", QByteArray());
00420     request.setRawHeader("If-Modified-Since", QByteArray());
00421     request.setRawHeader("x-kdewebkit-ignore-disposition", QByteArray());
00422 
00423     QStringList customHeaders;
00424     Q_FOREACH(const QByteArray &key, request.rawHeaderList()) {
00425         const QByteArray value = request.rawHeader(key);
00426         if (value.length())
00427             customHeaders << (key + QL1S(": ") + value);
00428     }
00429 
00430     if (!customHeaders.isEmpty()) {
00431         metaData.insert(QL1S("customHTTPHeader"), customHeaders.join("\r\n"));
00432     }
00433 
00434     // Append per request meta data, if any...
00435     if (!requestMetaData.isEmpty()) {
00436         metaData += requestMetaData;
00437         // Clear per request meta data...
00438         requestMetaData.clear();
00439     }
00440 
00441     // Append per session meta data, if any...
00442     if (!sessionMetaData.isEmpty()) {
00443         metaData += sessionMetaData;
00444     }
00445 }
00446 
00447 
00448 using namespace KIO::Integration;
00449 
00450 static QSsl::SslProtocol qSslProtocolFromString(const QString& str)
00451 {
00452     if (str.compare(QLatin1String("SSLv3"), Qt::CaseInsensitive) == 0) {
00453         return QSsl::SslV3;
00454     }
00455 
00456     if (str.compare(QLatin1String("SSLv2"), Qt::CaseInsensitive) == 0) {
00457         return QSsl::SslV2;
00458     }
00459 
00460     if (str.compare(QLatin1String("TLSv1"), Qt::CaseInsensitive) == 0) {
00461         return QSsl::TlsV1;
00462     }
00463 
00464     return QSsl::AnyProtocol;
00465 }
00466 
00467 bool KIO::Integration::sslConfigFromMetaData(const KIO::MetaData& metadata, QSslConfiguration& sslconfig)
00468 {
00469     bool success = false;
00470 
00471     if (metadata.contains(QL1S("ssl_in_use"))) {
00472         const QSsl::SslProtocol sslProto = qSslProtocolFromString(metadata.value(QL1S("ssl_protocol_version")));
00473         QList<QSslCipher> cipherList;
00474         cipherList << QSslCipher(metadata.value(QL1S("ssl_cipher_name")), sslProto);
00475         sslconfig.setCaCertificates(QSslCertificate::fromData(metadata.value(QL1S("ssl_peer_chain")).toUtf8()));
00476         sslconfig.setCiphers(cipherList);
00477         sslconfig.setProtocol(sslProto);
00478         success = sslconfig.isNull();
00479     }
00480 
00481     return success;
00482 }
00483 
00484 CookieJar::CookieJar(QObject* parent)
00485           :QNetworkCookieJar(parent), d(new CookieJar::CookieJarPrivate)
00486 {
00487     reparseConfiguration();
00488 }
00489 
00490 CookieJar::~CookieJar()
00491 {
00492     delete d;
00493 }
00494 
00495 WId CookieJar::windowId() const
00496 {
00497     return d->windowId;
00498 }
00499 
00500 bool CookieJar::isCookieStorageDisabled() const
00501 {
00502    return d->isStorageDisabled;
00503 }
00504 
00505 QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
00506 {
00507     QList<QNetworkCookie> cookieList;
00508 
00509     if (!d->isEnabled) {
00510         return cookieList;
00511     }
00512     QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer");
00513     QDBusReply<QString> reply = kcookiejar.call("findDOMCookies", url.toString(QUrl::RemoveUserInfo), (qlonglong)d->windowId);
00514 
00515     if (!reply.isValid()) {
00516         kWarning(7044) << "Unable to communicate with the cookiejar!";
00517         return cookieList;
00518     }
00519 
00520     const QString cookieStr = reply.value();
00521     const QStringList cookies = cookieStr.split(QL1S("; "), QString::SkipEmptyParts);
00522     Q_FOREACH(const QString& cookie, cookies) {
00523         const int index = cookie.indexOf(QL1C('='));
00524         const QString name = cookie.left(index);
00525         const QString value = cookie.right((cookie.length() - index - 1));
00526         cookieList << QNetworkCookie(name.toUtf8(), value.toUtf8());
00527         //kDebug(7044) << "cookie: name=" << name << ", value=" << value;
00528     }
00529 
00530     return cookieList;
00531 }
00532 
00533 bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
00534 {
00535     if (!d->isEnabled) {
00536         return false;
00537     }
00538 
00539     QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer");
00540     Q_FOREACH(const QNetworkCookie &cookie, cookieList) {
00541         QByteArray cookieHeader ("Set-Cookie: ");
00542         if (d->isStorageDisabled && !cookie.isSessionCookie()) {
00543             QNetworkCookie sessionCookie(cookie);
00544             sessionCookie.setExpirationDate(QDateTime());
00545             cookieHeader += sessionCookie.toRawForm();
00546         } else {
00547             cookieHeader += cookie.toRawForm();
00548         }
00549         kcookiejar.call("addCookies", url.toString(QUrl::RemoveUserInfo), cookieHeader, (qlonglong)d->windowId);
00550         //kDebug(7044) << "[" << d->windowId << "]" << cookieHeader << " from " << url;
00551     }
00552 
00553     return !kcookiejar.lastError().isValid();
00554 }
00555 
00556 void CookieJar::setDisableCookieStorage(bool disable)
00557 {
00558     d->isStorageDisabled = disable;
00559 }
00560 
00561 void CookieJar::setWindowId(WId id)
00562 {
00563     d->windowId = id;
00564 }
00565 
00566 void CookieJar::reparseConfiguration()
00567 {
00568     KConfigGroup cfg = KSharedConfig::openConfig("kcookiejarrc", KConfig::NoGlobals)->group("Cookie Policy");
00569     d->isEnabled = cfg.readEntry("Cookies", true);
00570 }
00571 
00572 #include "accessmanager.moc"
00573 
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:34:57 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal