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 #include "accessmanagerreply_p.h" 00027 00028 #include <kdebug.h> 00029 #include <kio/job.h> 00030 #include <kio/scheduler.h> 00031 #include <kconfiggroup.h> 00032 #include <ksharedconfig.h> 00033 #include <kprotocolinfo.h> 00034 #include <klocalizedstring.h> 00035 00036 #include <QtCore/QUrl> 00037 #include <QtCore/QWeakPointer> 00038 #include <QtDBus/QDBusInterface> 00039 #include <QtDBus/QDBusConnection> 00040 #include <QtDBus/QDBusReply> 00041 #include <QtNetwork/QNetworkReply> 00042 #include <QtNetwork/QNetworkRequest> 00043 #include <QtNetwork/QSslCipher> 00044 #include <QtNetwork/QSslCertificate> 00045 #include <QtNetwork/QSslConfiguration> 00046 00047 #define QL1S(x) QLatin1String(x) 00048 #define QL1C(x) QLatin1Char(x) 00049 00050 static bool isLocalRequest(const KUrl& url) 00051 { 00052 const QString scheme (url.protocol()); 00053 return (KProtocolInfo::isKnownProtocol(scheme) && 00054 KProtocolInfo::protocolClass(scheme).compare(QL1S(":local"), Qt::CaseInsensitive) == 0); 00055 } 00056 00057 namespace KIO { 00058 00059 class AccessManager::AccessManagerPrivate 00060 { 00061 public: 00062 AccessManagerPrivate() 00063 : externalContentAllowed(true) 00064 {} 00065 00066 void setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData); 00067 00068 bool externalContentAllowed; 00069 KIO::MetaData requestMetaData; 00070 KIO::MetaData sessionMetaData; 00071 }; 00072 00073 namespace Integration { 00074 00075 class CookieJar::CookieJarPrivate 00076 { 00077 public: 00078 CookieJarPrivate() 00079 : windowId((WId)-1), 00080 isEnabled(true), 00081 isStorageDisabled(false) 00082 {} 00083 00084 WId windowId; 00085 bool isEnabled; 00086 bool isStorageDisabled; 00087 }; 00088 00089 } 00090 00091 } 00092 00093 using namespace KIO; 00094 00095 AccessManager::AccessManager(QObject *parent) 00096 :QNetworkAccessManager(parent), d(new AccessManager::AccessManagerPrivate()) 00097 { 00098 // KDE Cookiejar (KCookieJar) integration... 00099 setCookieJar(new KIO::Integration::CookieJar); 00100 } 00101 00102 AccessManager::~AccessManager() 00103 { 00104 delete d; 00105 } 00106 00107 void AccessManager::setExternalContentAllowed(bool allowed) 00108 { 00109 d->externalContentAllowed = allowed; 00110 } 00111 00112 bool AccessManager::isExternalContentAllowed() const 00113 { 00114 return d->externalContentAllowed; 00115 } 00116 00117 void AccessManager::setCookieJarWindowId(WId id) 00118 { 00119 KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar()); 00120 if (jar) { 00121 jar->setWindowId(id); 00122 d->sessionMetaData.insert(QL1S("window-id"), QString::number((qlonglong)id)); 00123 } 00124 } 00125 00126 WId AccessManager::cookieJarWindowid() const 00127 { 00128 KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar()); 00129 if (jar) 00130 return jar->windowId(); 00131 00132 return 0; 00133 } 00134 00135 KIO::MetaData& AccessManager::requestMetaData() 00136 { 00137 return d->requestMetaData; 00138 } 00139 00140 KIO::MetaData& AccessManager::sessionMetaData() 00141 { 00142 return d->sessionMetaData; 00143 } 00144 00145 void AccessManager::putReplyOnHold(QNetworkReply* reply) 00146 { 00147 KDEPrivate::AccessManagerReply* r = qobject_cast<KDEPrivate::AccessManagerReply*>(reply); 00148 if (!r) 00149 return; 00150 00151 r->putOnHold(); 00152 } 00153 00154 QNetworkReply *AccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData) 00155 { 00156 KIO::SimpleJob *kioJob = 0; 00157 const KUrl reqUrl (req.url()); 00158 00159 if (!d->externalContentAllowed && !isLocalRequest(reqUrl)) { 00160 kDebug( 7044 ) << "Blocked: " << reqUrl; 00161 KDEPrivate::AccessManagerReply* reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, this); 00162 reply->setStatus(i18n("Blocked request."),QNetworkReply::ContentAccessDenied); 00163 return reply; 00164 } 00165 00166 switch (op) { 00167 case HeadOperation: { 00168 //kDebug( 7044 ) << "HeadOperation:" << reqUrl; 00169 kioJob = KIO::mimetype(reqUrl, KIO::HideProgressInfo); 00170 break; 00171 } 00172 case GetOperation: { 00173 //kDebug( 7044 ) << "GetOperation:" << reqUrl; 00174 if (!reqUrl.path().isEmpty() || reqUrl.host().isEmpty()) 00175 kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo); 00176 else 00177 kioJob = KIO::stat(reqUrl, KIO::HideProgressInfo); 00178 break; 00179 } 00180 case PutOperation: { 00181 //kDebug( 7044 ) << "PutOperation:" << reqUrl; 00182 if (outgoingData) 00183 kioJob = KIO::storedPut(outgoingData->readAll(), reqUrl, -1, KIO::HideProgressInfo); 00184 else 00185 kioJob = KIO::put(reqUrl, -1, KIO::HideProgressInfo); 00186 break; 00187 } 00188 case PostOperation: { 00189 //kDebug( 7044 ) << "PostOperation:" << reqUrl; 00190 kioJob = KIO::http_post(reqUrl, outgoingData->readAll(), KIO::HideProgressInfo); 00191 break; 00192 } 00193 case DeleteOperation: { 00194 //kDebug(7044) << "DeleteOperation:" << reqUrl; 00195 kioJob = KIO::file_delete(reqUrl, KIO::HideProgressInfo); 00196 break; 00197 } 00198 case CustomOperation: { 00199 const QByteArray& method = req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray(); 00200 //kDebug(7044) << "CustomOperation:" << reqUrl << "method:" << method << "outgoing data:" << outgoingData; 00201 if (method.isEmpty()) { 00202 KDEPrivate::AccessManagerReply* reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, this); 00203 reply->setStatus(i18n("Unknown HTTP verb."), QNetworkReply::ProtocolUnknownError); 00204 return reply; 00205 } 00206 if (outgoingData) 00207 kioJob = KIO::http_post(reqUrl, outgoingData->readAll(), KIO::HideProgressInfo); 00208 else 00209 kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo); 00210 kioJob->metaData().insert(QL1S("CustomHTTPMethod"), method); 00211 break; 00212 } 00213 default: { 00214 kWarning(7044) << "Unsupported KIO operation requested! Defering to QNetworkAccessManager..."; 00215 return QNetworkAccessManager::createRequest(op, req, outgoingData); 00216 } 00217 } 00218 00219 kioJob->setRedirectionHandlingEnabled(false); 00220 00221 switch (req.priority()) { 00222 case QNetworkRequest::HighPriority: 00223 KIO::Scheduler::setJobPriority(kioJob, -5); 00224 break; 00225 case QNetworkRequest::LowPriority: 00226 KIO::Scheduler::setJobPriority(kioJob, 5); 00227 break; 00228 default: 00229 break; 00230 } 00231 00232 KDEPrivate::AccessManagerReply *reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, this); 00233 if (req.hasRawHeader("x-kdewebkit-ignore-disposition")) { 00234 kDebug(7044) << "Content-Disposition WILL BE IGNORED!"; 00235 reply->setIgnoreContentDisposition(true); 00236 } 00237 00238 KIO::MetaData metaData; 00239 d->setMetaDataForRequest(req, metaData); 00240 kioJob->addMetaData(metaData); 00241 00242 if ( op == PostOperation && !kioJob->metaData().contains(QL1S("content-type"))) { 00243 const QVariant header = req.header(QNetworkRequest::ContentTypeHeader); 00244 if (header.isValid()) 00245 kioJob->addMetaData(QL1S("content-type"), 00246 (QL1S("Content-Type: ") + header.toString())); 00247 else 00248 kioJob->addMetaData(QL1S("content-type"), 00249 QL1S("Content-Type: application/x-www-form-urlencoded")); 00250 } 00251 00252 return reply; 00253 } 00254 00255 void AccessManager::AccessManagerPrivate::setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData) 00256 { 00257 // Add any meta data specified within request... 00258 QVariant userMetaData = request.attribute (static_cast<QNetworkRequest::Attribute>(MetaData)); 00259 if (userMetaData.isValid() && userMetaData.type() == QVariant::Map) { 00260 metaData += userMetaData.toMap(); 00261 } 00262 00263 metaData.insert("PropagateHttpHeader", "true"); 00264 00265 if (request.hasRawHeader("User-Agent")) { 00266 metaData.insert("UserAgent", request.rawHeader("User-Agent")); 00267 request.setRawHeader("User-Agent", QByteArray()); 00268 } 00269 00270 if (request.hasRawHeader("Accept")) { 00271 metaData.insert("accept", request.rawHeader("Accept")); 00272 request.setRawHeader("Accept", QByteArray()); 00273 } 00274 00275 if (request.hasRawHeader("Referer")) { 00276 metaData.insert(QL1S("referrer"), request.rawHeader("Referer")); 00277 request.setRawHeader("Referer", QByteArray()); 00278 } 00279 00280 if (request.hasRawHeader("Content-Type")) { 00281 metaData.insert(QL1S("content-type"), request.rawHeader("Content-Type")); 00282 request.setRawHeader("Content-Type", QByteArray()); 00283 } 00284 00285 request.setRawHeader("content-length", QByteArray()); 00286 request.setRawHeader("Connection", QByteArray()); 00287 request.setRawHeader("If-None-Match", QByteArray()); 00288 request.setRawHeader("If-Modified-Since", QByteArray()); 00289 request.setRawHeader("x-kdewebkit-ignore-disposition", QByteArray()); 00290 00291 QStringList customHeaders; 00292 Q_FOREACH(const QByteArray &key, request.rawHeaderList()) { 00293 const QByteArray value = request.rawHeader(key); 00294 if (value.length()) 00295 customHeaders << (key + QL1S(": ") + value); 00296 } 00297 00298 if (!customHeaders.isEmpty()) 00299 metaData.insert("customHTTPHeader", customHeaders.join("\r\n")); 00300 00301 // Append per request meta data, if any... 00302 if (!requestMetaData.isEmpty()) { 00303 metaData += requestMetaData; 00304 // Clear per request meta data... 00305 requestMetaData.clear(); 00306 } 00307 00308 // Append per session meta data, if any... 00309 if (!sessionMetaData.isEmpty()) 00310 metaData += sessionMetaData; 00311 } 00312 00313 00314 using namespace KIO::Integration; 00315 00316 static QSsl::SslProtocol qSslProtocolFromString(const QString& str) 00317 { 00318 if (str.compare(QLatin1String("SSLv3"), Qt::CaseInsensitive) == 0) 00319 return QSsl::SslV3; 00320 00321 if (str.compare(QLatin1String("SSLv2"), Qt::CaseInsensitive) == 0) 00322 return QSsl::SslV2; 00323 00324 if (str.compare(QLatin1String("TLSv1"), Qt::CaseInsensitive) == 0) 00325 return QSsl::TlsV1; 00326 00327 return QSsl::AnyProtocol; 00328 } 00329 00330 bool KIO::Integration::sslConfigFromMetaData(const KIO::MetaData& metadata, QSslConfiguration& sslconfig) 00331 { 00332 bool success = false; 00333 00334 if (metadata.contains(QL1S("ssl_in_use"))) { 00335 const QSsl::SslProtocol sslProto = qSslProtocolFromString(metadata.value("ssl_protocol_version")); 00336 QList<QSslCipher> cipherList; 00337 cipherList << QSslCipher(metadata.value("ssl_cipher_name"), sslProto); 00338 sslconfig.setCaCertificates(QSslCertificate::fromData(metadata.value("ssl_peer_chain").toUtf8())); 00339 sslconfig.setCiphers(cipherList); 00340 sslconfig.setProtocol(sslProto); 00341 success = sslconfig.isNull(); 00342 } 00343 00344 return success; 00345 } 00346 00347 CookieJar::CookieJar(QObject* parent) 00348 :QNetworkCookieJar(parent), d(new CookieJar::CookieJarPrivate) { 00349 reparseConfiguration(); 00350 } 00351 00352 CookieJar::~CookieJar() { 00353 delete d; 00354 } 00355 00356 WId CookieJar::windowId() const { 00357 return d->windowId; 00358 } 00359 00360 bool CookieJar::isCookieStorageDisabled() const { 00361 return d->isStorageDisabled; 00362 } 00363 00364 QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const { 00365 QList<QNetworkCookie> cookieList; 00366 00367 if (d->isEnabled) { 00368 QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer"); 00369 QDBusReply<QString> reply = kcookiejar.call("findDOMCookies", url.toString(QUrl::RemoveUserInfo), (qlonglong)d->windowId); 00370 00371 if (reply.isValid()) { 00372 const QString cookieStr = reply.value(); 00373 const QStringList cookies = cookieStr.split(QL1S("; "), QString::SkipEmptyParts); 00374 Q_FOREACH(const QString& cookie, cookies) { 00375 const int index = cookie.indexOf(QL1C('=')); 00376 const QString name = cookie.left(index); 00377 const QString value = cookie.right((cookie.length() - index - 1)); 00378 cookieList << QNetworkCookie(name.toUtf8(), value.toUtf8()); 00379 //kDebug(7044) << "cookie: name=" << name << ", value=" << value; 00380 } 00381 //kDebug(7044) << "cookie for" << url.host() << ":" << cookieStr; 00382 } else { 00383 kWarning(7044) << "Unable to communicate with the cookiejar!"; 00384 } 00385 } 00386 00387 return cookieList; 00388 } 00389 00390 bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) { 00391 if (d->isEnabled) { 00392 QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer"); 00393 Q_FOREACH(const QNetworkCookie &cookie, cookieList) { 00394 QByteArray cookieHeader ("Set-Cookie: "); 00395 if (d->isStorageDisabled && !cookie.isSessionCookie()) { 00396 QNetworkCookie sessionCookie(cookie); 00397 sessionCookie.setExpirationDate(QDateTime()); 00398 cookieHeader += sessionCookie.toRawForm(); 00399 } else 00400 cookieHeader += cookie.toRawForm(); 00401 kcookiejar.call("addCookies", url.toString(QUrl::RemoveUserInfo), cookieHeader, (qlonglong)d->windowId); 00402 //kDebug(7044) << "[" << d->windowId << "]" << cookieHeader << " from " << url; 00403 } 00404 00405 return !kcookiejar.lastError().isValid(); 00406 } 00407 00408 return false; 00409 } 00410 00411 void CookieJar::setDisableCookieStorage(bool disable) { 00412 d->isStorageDisabled = disable; 00413 } 00414 00415 void CookieJar::setWindowId(WId id) { 00416 d->windowId = id; 00417 } 00418 00419 void CookieJar::reparseConfiguration() { 00420 KConfigGroup cfg = KSharedConfig::openConfig("kcookiejarrc", KConfig::NoGlobals)->group("Cookie Policy"); 00421 d->isEnabled = cfg.readEntry("Cookies", true); 00422 } 00423 00424 #include "accessmanager.moc"
KDE 4.6 API Reference