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

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal