• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 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,2010 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 
00032 #include <kdebug.h>
00033 #include <kconfiggroup.h>
00034 #include <ksharedconfig.h>
00035 #include <kprotocolinfo.h>
00036 #include <klocalizedstring.h>
00037 
00038 #include <QtCore/QUrl>
00039 #include <QtGui/QWidget>
00040 #include <QtCore/QWeakPointer>
00041 #include <QtDBus/QDBusInterface>
00042 #include <QtDBus/QDBusConnection>
00043 #include <QtDBus/QDBusReply>
00044 #include <QtNetwork/QNetworkReply>
00045 #include <QtNetwork/QNetworkRequest>
00046 #include <QtNetwork/QSslCipher>
00047 #include <QtNetwork/QSslCertificate>
00048 #include <QtNetwork/QSslConfiguration>
00049 
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 static qint64 sizeFromRequest(const QNetworkRequest& req)
00061 {
00062     const QVariant size = req.header(QNetworkRequest::ContentLengthHeader);
00063     if (!size.isValid())
00064         return -1;
00065     bool ok = false;
00066     const qlonglong value = size.toLongLong(&ok);
00067     return (ok ? value : -1);
00068 }
00069 
00070 namespace KIO {
00071 
00072 class AccessManager::AccessManagerPrivate
00073 {
00074 public:
00075     AccessManagerPrivate()
00076       : externalContentAllowed(true),
00077         emitReadyReadOnMetaDataChange(false),
00078         window(0)
00079     {}
00080 
00081     void setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData);
00082 
00083     bool externalContentAllowed;
00084     bool emitReadyReadOnMetaDataChange;
00085     KIO::MetaData requestMetaData;
00086     KIO::MetaData sessionMetaData;
00087     QWidget* window;
00088 };
00089 
00090 namespace Integration {
00091 
00092 class CookieJar::CookieJarPrivate
00093 {
00094 public:
00095   CookieJarPrivate()
00096     : windowId((WId)-1), 
00097       isEnabled(true),
00098       isStorageDisabled(false)
00099   {}
00100 
00101   WId windowId;
00102   bool isEnabled;
00103   bool isStorageDisabled;
00104 };
00105 
00106 }
00107 
00108 }
00109 
00110 using namespace KIO;
00111 
00112 AccessManager::AccessManager(QObject *parent)
00113               :QNetworkAccessManager(parent), d(new AccessManager::AccessManagerPrivate())
00114 {
00115     // KDE Cookiejar (KCookieJar) integration...
00116     setCookieJar(new KIO::Integration::CookieJar);
00117 }
00118 
00119 AccessManager::~AccessManager()
00120 {
00121     delete d;
00122 }
00123 
00124 void AccessManager::setExternalContentAllowed(bool allowed)
00125 {
00126     d->externalContentAllowed = allowed;
00127 }
00128 
00129 bool AccessManager::isExternalContentAllowed() const
00130 {
00131     return d->externalContentAllowed;
00132 }
00133 
00134 #ifndef KDE_NO_DEPRECATED
00135 void AccessManager::setCookieJarWindowId(WId id)
00136 {
00137     QWidget* window = QWidget::find(id);
00138     if (!window) {
00139         return;
00140     }
00141 
00142     KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
00143     if (jar) {
00144         jar->setWindowId(id);
00145     }
00146 
00147     d->window = window->isWindow() ? window : window->window();
00148 }
00149 #endif
00150 
00151 void AccessManager::setWindow(QWidget* widget)
00152 {
00153     if (!widget) {
00154         return;
00155     }
00156 
00157     d->window = widget->isWindow() ? widget : widget->window();
00158 
00159     if (!d->window) {
00160         return;
00161     }
00162 
00163     KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
00164     if (jar) {
00165         jar->setWindowId(d->window->winId());
00166     }
00167 }
00168 
00169 #ifndef KDE_NO_DEPRECATED
00170 WId AccessManager::cookieJarWindowid() const
00171 {
00172     KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
00173     if (jar)
00174         return jar->windowId();
00175 
00176     return 0;
00177 }
00178 #endif
00179 
00180 QWidget* AccessManager::window() const
00181 {
00182     return d->window;
00183 }
00184 
00185 KIO::MetaData& AccessManager::requestMetaData()
00186 {
00187     return d->requestMetaData;
00188 }
00189 
00190 KIO::MetaData& AccessManager::sessionMetaData()
00191 {
00192     return d->sessionMetaData;
00193 }
00194 
00195 void AccessManager::putReplyOnHold(QNetworkReply* reply)
00196 {
00197     KDEPrivate::AccessManagerReply* r = qobject_cast<KDEPrivate::AccessManagerReply*>(reply);
00198     if (!r) {
00199       return;
00200     }
00201 
00202     r->putOnHold();
00203 }
00204 
00205 void AccessManager::setEmitReadyReadOnMetaDataChange(bool enable)
00206 {
00207     d->emitReadyReadOnMetaDataChange = enable;
00208 }
00209 
00210 QNetworkReply *AccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData)
00211 {
00212     /*
00213      * WORKAROUND: Since there is no way to do a synchronous KIO request
00214      * without creating a nested event loop and creating such a loop here is
00215      * the surest way to encounter the inherent flaws of creating such loops,
00216      * i.e. crashes (bug# 287778), we let Qt's networking layer handle such
00217      * requests because it can block without the need for nested event loops.
00218      *
00219      * The only consequence of doing this is the HTTP response will never be
00220      * cached since it won't be handled by kio_http.
00221      */
00222     if (req.attribute(gSynchronousNetworkRequestAttribute).toBool()) {
00223         return QNetworkAccessManager::createRequest(op, req, outgoingData);
00224     }
00225 
00226     KIO::SimpleJob *kioJob = 0;
00227     const KUrl reqUrl (req.url());
00228 
00229     if (!d->externalContentAllowed &&
00230         !KDEPrivate::AccessManagerReply::isLocalRequest(reqUrl) &&
00231         reqUrl.scheme() != QL1S("data")) {
00232         kDebug( 7044 ) << "Blocked: " << reqUrl;
00233         KDEPrivate::AccessManagerReply* reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, d->emitReadyReadOnMetaDataChange, this);
00234         reply->setStatus(i18n("Blocked request."),QNetworkReply::ContentAccessDenied);
00235         return reply;
00236     }
00237 
00238     // Check if the internal ignore content disposition header is set.
00239     const bool ignoreContentDisposition = req.hasRawHeader("x-kdewebkit-ignore-disposition");
00240 
00241     // Retrieve the KIO meta data...
00242     KIO::MetaData metaData;
00243     d->setMetaDataForRequest(req, metaData);
00244 
00245     switch (op) {
00246         case HeadOperation: {
00247             //kDebug( 7044 ) << "HeadOperation:" << reqUrl;
00248             kioJob = KIO::mimetype(reqUrl, KIO::HideProgressInfo);
00249             break;
00250         }
00251         case GetOperation: {
00252             //kDebug( 7044 ) << "GetOperation:" << reqUrl;
00253             if (!reqUrl.path().isEmpty() || reqUrl.host().isEmpty())
00254                 kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo);
00255             else
00256                 kioJob = KIO::stat(reqUrl, KIO::HideProgressInfo);
00257 
00258             // WORKAROUND: Avoid the brain damaged stuff QtWebKit does when a POST
00259             // operation is redirected! See BR# 268694.
00260             metaData.remove(QL1S("content-type")); // Remove the content-type from a GET/HEAD request!
00261             break;
00262         }
00263         case PutOperation: {
00264             //kDebug( 7044 ) << "PutOperation:" << reqUrl;
00265             if (outgoingData)
00266                 kioJob = KIO::storedPut(outgoingData->readAll(), reqUrl, -1, KIO::HideProgressInfo);
00267             else
00268                 kioJob = KIO::put(reqUrl, -1, KIO::HideProgressInfo);
00269             break;
00270         }
00271         case PostOperation: {
00272             kioJob = KIO::http_post(reqUrl, outgoingData, sizeFromRequest(req), KIO::HideProgressInfo);
00273             if (!metaData.contains(QL1S("content-type")))  {
00274                 const QVariant header = req.header(QNetworkRequest::ContentTypeHeader);
00275                 if (header.isValid()) {
00276                     metaData.insert(QL1S("content-type"),
00277                                     (QL1S("Content-Type: ") + header.toString()));
00278                 } else {
00279                     metaData.insert(QL1S("content-type"),
00280                                     QL1S("Content-Type: application/x-www-form-urlencoded"));
00281                 }
00282             }
00283             break;
00284         }
00285         case DeleteOperation: {
00286             //kDebug(7044) << "DeleteOperation:" << reqUrl;
00287             kioJob = KIO::http_delete(reqUrl, KIO::HideProgressInfo);
00288             break;
00289         }
00290         case CustomOperation: {
00291             const QByteArray& method = req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray();
00292             //kDebug(7044) << "CustomOperation:" << reqUrl << "method:" << method << "outgoing data:" << outgoingData;
00293 
00294             if (method.isEmpty()) {
00295                 KDEPrivate::AccessManagerReply* reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, d->emitReadyReadOnMetaDataChange, this);
00296                 reply->setStatus(i18n("Unknown HTTP verb."), QNetworkReply::ProtocolUnknownError);
00297                 return reply;
00298             }
00299 
00300             if (outgoingData)
00301                 kioJob = KIO::http_post(reqUrl, outgoingData, sizeFromRequest(req), KIO::HideProgressInfo);
00302             else
00303                 kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo);
00304 
00305             metaData.insert(QL1S("CustomHTTPMethod"), method);
00306             break;
00307         }
00308         default: {
00309             kWarning(7044) << "Unsupported KIO operation requested! Defering to QNetworkAccessManager...";
00310             return QNetworkAccessManager::createRequest(op, req, outgoingData);
00311         }
00312     }
00313 
00314     // Set the window on the the KIO ui delegate
00315     if (d->window) {
00316         kioJob->ui()->setWindow(d->window);
00317     }
00318 
00319     // Disable internal automatic redirection handling
00320     kioJob->setRedirectionHandlingEnabled(false);
00321 
00322     // Set the job priority
00323     switch (req.priority()) {
00324     case QNetworkRequest::HighPriority:
00325         KIO::Scheduler::setJobPriority(kioJob, -5);
00326         break;
00327     case QNetworkRequest::LowPriority:
00328         KIO::Scheduler::setJobPriority(kioJob, 5);
00329         break;
00330     default:
00331         break;
00332     }
00333 
00334     // Set the meta data for this job...
00335     kioJob->setMetaData(metaData);
00336 
00337     // Create the reply...
00338     KDEPrivate::AccessManagerReply *reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, d->emitReadyReadOnMetaDataChange, this);
00339 
00340     if (ignoreContentDisposition) {
00341         kDebug(7044) << "Content-Disposition WILL BE IGNORED!";
00342         reply->setIgnoreContentDisposition(ignoreContentDisposition);
00343     }
00344 
00345     return reply;
00346 }
00347 
00348 void AccessManager::AccessManagerPrivate::setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData)
00349 {
00350     // Add any meta data specified within request...
00351     QVariant userMetaData = request.attribute (static_cast<QNetworkRequest::Attribute>(MetaData));
00352     if (userMetaData.isValid() && userMetaData.type() == QVariant::Map)
00353         metaData += userMetaData.toMap();
00354 
00355     metaData.insert(QL1S("PropagateHttpHeader"), QL1S("true"));
00356 
00357     if (request.hasRawHeader("User-Agent")) {
00358         metaData.insert(QL1S("UserAgent"), request.rawHeader("User-Agent"));
00359         request.setRawHeader("User-Agent", QByteArray());
00360     }
00361 
00362     if (request.hasRawHeader("Accept")) {
00363         metaData.insert(QL1S("accept"), request.rawHeader("Accept"));
00364         request.setRawHeader("Accept", QByteArray());
00365     }
00366 
00367     if (request.hasRawHeader("Accept-Charset")) {
00368         metaData.insert(QL1S("Charsets"), request.rawHeader("Accept-Charset"));
00369         request.setRawHeader("Accept-Charset", QByteArray());
00370     }
00371 
00372     if (request.hasRawHeader("Accept-Language")) {
00373         metaData.insert(QL1S("Languages"), request.rawHeader("Accept-Language"));
00374         request.setRawHeader("Accept-Language", QByteArray());
00375     }
00376 
00377     if (request.hasRawHeader("Referer")) {
00378         metaData.insert(QL1S("referrer"), request.rawHeader("Referer"));
00379         request.setRawHeader("Referer", QByteArray());
00380     }
00381 
00382     if (request.hasRawHeader("Content-Type")) {
00383         metaData.insert(QL1S("content-type"), request.rawHeader("Content-Type"));
00384         request.setRawHeader("Content-Type", QByteArray());
00385     }
00386 
00387     if (request.attribute(QNetworkRequest::AuthenticationReuseAttribute) == QNetworkRequest::Manual) {
00388         metaData.insert(QL1S("no-preemptive-auth-reuse"), QL1S("true"));
00389     }
00390 
00391     request.setRawHeader("Content-Length", QByteArray());
00392     request.setRawHeader("Connection", QByteArray());
00393     request.setRawHeader("If-None-Match", QByteArray());
00394     request.setRawHeader("If-Modified-Since", QByteArray());
00395     request.setRawHeader("x-kdewebkit-ignore-disposition", QByteArray());
00396 
00397     QStringList customHeaders;
00398     Q_FOREACH(const QByteArray &key, request.rawHeaderList()) {
00399         const QByteArray value = request.rawHeader(key);
00400         if (value.length())
00401             customHeaders << (key + QL1S(": ") + value);
00402     }
00403 
00404     if (!customHeaders.isEmpty()) {
00405         metaData.insert(QL1S("customHTTPHeader"), customHeaders.join("\r\n"));
00406     }
00407 
00408     // Append per request meta data, if any...
00409     if (!requestMetaData.isEmpty()) {
00410         metaData += requestMetaData;
00411         // Clear per request meta data...
00412         requestMetaData.clear();
00413     }
00414 
00415     // Append per session meta data, if any...
00416     if (!sessionMetaData.isEmpty()) {
00417         metaData += sessionMetaData;
00418     }
00419 }
00420 
00421 
00422 using namespace KIO::Integration;
00423 
00424 static QSsl::SslProtocol qSslProtocolFromString(const QString& str)
00425 {
00426     if (str.compare(QLatin1String("SSLv3"), Qt::CaseInsensitive) == 0) {
00427         return QSsl::SslV3;
00428     }
00429 
00430     if (str.compare(QLatin1String("SSLv2"), Qt::CaseInsensitive) == 0) {
00431         return QSsl::SslV2;
00432     }
00433 
00434     if (str.compare(QLatin1String("TLSv1"), Qt::CaseInsensitive) == 0) {
00435         return QSsl::TlsV1;
00436     }
00437 
00438     return QSsl::AnyProtocol;
00439 }
00440 
00441 bool KIO::Integration::sslConfigFromMetaData(const KIO::MetaData& metadata, QSslConfiguration& sslconfig)
00442 {
00443     bool success = false;
00444 
00445     if (metadata.contains(QL1S("ssl_in_use"))) {
00446         const QSsl::SslProtocol sslProto = qSslProtocolFromString(metadata.value(QL1S("ssl_protocol_version")));
00447         QList<QSslCipher> cipherList;
00448         cipherList << QSslCipher(metadata.value(QL1S("ssl_cipher_name")), sslProto);
00449         sslconfig.setCaCertificates(QSslCertificate::fromData(metadata.value(QL1S("ssl_peer_chain")).toUtf8()));
00450         sslconfig.setCiphers(cipherList);
00451         sslconfig.setProtocol(sslProto);
00452         success = sslconfig.isNull();
00453     }
00454 
00455     return success;
00456 }
00457 
00458 CookieJar::CookieJar(QObject* parent)
00459           :QNetworkCookieJar(parent), d(new CookieJar::CookieJarPrivate)
00460 {
00461     reparseConfiguration();
00462 }
00463 
00464 CookieJar::~CookieJar()
00465 {
00466     delete d;
00467 }
00468 
00469 WId CookieJar::windowId() const
00470 {
00471     return d->windowId;
00472 }
00473 
00474 bool CookieJar::isCookieStorageDisabled() const
00475 {
00476    return d->isStorageDisabled;
00477 }
00478 
00479 QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
00480 {
00481     QList<QNetworkCookie> cookieList;
00482 
00483     if (!d->isEnabled) {
00484         return cookieList;
00485     }
00486     QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer");
00487     QDBusReply<QString> reply = kcookiejar.call("findDOMCookies", url.toString(QUrl::RemoveUserInfo), (qlonglong)d->windowId);
00488 
00489     if (!reply.isValid()) {
00490         kWarning(7044) << "Unable to communicate with the cookiejar!";
00491         return cookieList;
00492     }
00493 
00494     const QString cookieStr = reply.value();
00495     const QStringList cookies = cookieStr.split(QL1S("; "), QString::SkipEmptyParts);
00496     Q_FOREACH(const QString& cookie, cookies) {
00497         const int index = cookie.indexOf(QL1C('='));
00498         const QString name = cookie.left(index);
00499         const QString value = cookie.right((cookie.length() - index - 1));
00500         cookieList << QNetworkCookie(name.toUtf8(), value.toUtf8());
00501         //kDebug(7044) << "cookie: name=" << name << ", value=" << value;
00502     }
00503 
00504     return cookieList;
00505 }
00506 
00507 bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
00508 {
00509     if (!d->isEnabled) {
00510         return false;
00511     }
00512 
00513     QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer");
00514     Q_FOREACH(const QNetworkCookie &cookie, cookieList) {
00515         QByteArray cookieHeader ("Set-Cookie: ");
00516         if (d->isStorageDisabled && !cookie.isSessionCookie()) {
00517             QNetworkCookie sessionCookie(cookie);
00518             sessionCookie.setExpirationDate(QDateTime());
00519             cookieHeader += sessionCookie.toRawForm();
00520         } else {
00521             cookieHeader += cookie.toRawForm();
00522         }
00523         kcookiejar.call("addCookies", url.toString(QUrl::RemoveUserInfo), cookieHeader, (qlonglong)d->windowId);
00524         //kDebug(7044) << "[" << d->windowId << "]" << cookieHeader << " from " << url;
00525     }
00526 
00527     return !kcookiejar.lastError().isValid();
00528 }
00529 
00530 void CookieJar::setDisableCookieStorage(bool disable)
00531 {
00532     d->isStorageDisabled = disable;
00533 }
00534 
00535 void CookieJar::setWindowId(WId id)
00536 {
00537     d->windowId = id;
00538 }
00539 
00540 void CookieJar::reparseConfiguration()
00541 {
00542     KConfigGroup cfg = KSharedConfig::openConfig("kcookiejarrc", KConfig::NoGlobals)->group("Cookie Policy");
00543     d->isEnabled = cfg.readEntry("Cookies", true);
00544 }
00545 
00546 #include "accessmanager.moc"
00547 
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 18:20:52 by doxygen 1.8.0 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.8.3 API Reference

Skip menu "kdelibs-4.8.3 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