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

KIO

  • kio
  • kio
accessmanager.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the KDE project.
3  *
4  * Copyright (C) 2009 - 2012 Dawit Alemayehu <adawit @ kde.org>
5  * Copyright (C) 2008 - 2009 Urs Wolfer <uwolfer @ kde.org>
6  * Copyright (C) 2007 Trolltech ASA
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB. If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #include "accessmanager.h"
26 
27 #include "accessmanagerreply_p.h"
28 #include "job.h"
29 #include "scheduler.h"
30 #include "jobuidelegate.h"
31 #include "netaccess.h"
32 
33 #include <kdebug.h>
34 #include <kconfiggroup.h>
35 #include <ksharedconfig.h>
36 #include <kprotocolinfo.h>
37 #include <klocalizedstring.h>
38 
39 #include <QtCore/QUrl>
40 #include <QtCore/QPointer>
41 #include <QtGui/QWidget>
42 #include <QtDBus/QDBusInterface>
43 #include <QtDBus/QDBusConnection>
44 #include <QtDBus/QDBusReply>
45 #include <QtNetwork/QNetworkReply>
46 #include <QtNetwork/QNetworkRequest>
47 #include <QtNetwork/QSslCipher>
48 #include <QtNetwork/QSslCertificate>
49 #include <QtNetwork/QSslConfiguration>
50 
51 #define QL1S(x) QLatin1String(x)
52 #define QL1C(x) QLatin1Char(x)
53 
54 #if QT_VERSION >= 0x040800
55 static QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = QNetworkRequest::SynchronousRequestAttribute;
56 #else // QtWebkit hack to use the internal attribute
57 static QNetworkRequest::Attribute gSynchronousNetworkRequestAttribute = static_cast<QNetworkRequest::Attribute>(QNetworkRequest::HttpPipeliningWasUsedAttribute + 7);
58 #endif
59 
60 
61 
62 
63 static qint64 sizeFromRequest(const QNetworkRequest& req)
64 {
65  const QVariant size = req.header(QNetworkRequest::ContentLengthHeader);
66  if (!size.isValid())
67  return -1;
68  bool ok = false;
69  const qlonglong value = size.toLongLong(&ok);
70  return (ok ? value : -1);
71 }
72 
73 namespace KIO {
74 
75 class AccessManager::AccessManagerPrivate
76 {
77 public:
78  AccessManagerPrivate()
79  : externalContentAllowed(true),
80  emitReadyReadOnMetaDataChange(false),
81  window(0)
82  {}
83 
84  void setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData);
85 
86  bool externalContentAllowed;
87  bool emitReadyReadOnMetaDataChange;
88  KIO::MetaData requestMetaData;
89  KIO::MetaData sessionMetaData;
90  QPointer<QWidget> window;
91 };
92 
93 namespace Integration {
94 
95 class CookieJar::CookieJarPrivate
96 {
97 public:
98  CookieJarPrivate()
99  : windowId((WId)-1),
100  isEnabled(true),
101  isStorageDisabled(false)
102  {}
103 
104  WId windowId;
105  bool isEnabled;
106  bool isStorageDisabled;
107 };
108 
109 }
110 
111 }
112 
113 using namespace KIO;
114 
115 AccessManager::AccessManager(QObject *parent)
116  :QNetworkAccessManager(parent), d(new AccessManager::AccessManagerPrivate())
117 {
118  // KDE Cookiejar (KCookieJar) integration...
119  setCookieJar(new KIO::Integration::CookieJar);
120 }
121 
122 AccessManager::~AccessManager()
123 {
124  delete d;
125 }
126 
127 void AccessManager::setExternalContentAllowed(bool allowed)
128 {
129  d->externalContentAllowed = allowed;
130 }
131 
132 bool AccessManager::isExternalContentAllowed() const
133 {
134  return d->externalContentAllowed;
135 }
136 
137 #ifndef KDE_NO_DEPRECATED
138 void AccessManager::setCookieJarWindowId(WId id)
139 {
140  QWidget* window = QWidget::find(id);
141  if (!window) {
142  return;
143  }
144 
145  KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
146  if (jar) {
147  jar->setWindowId(id);
148  }
149 
150  d->window = window->isWindow() ? window : window->window();
151 }
152 #endif
153 
154 void AccessManager::setWindow(QWidget* widget)
155 {
156  if (!widget) {
157  return;
158  }
159 
160  d->window = widget->isWindow() ? widget : widget->window();
161 
162  if (!d->window) {
163  return;
164  }
165 
166  KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
167  if (jar) {
168  jar->setWindowId(d->window->winId());
169  }
170 }
171 
172 #ifndef KDE_NO_DEPRECATED
173 WId AccessManager::cookieJarWindowid() const
174 {
175  KIO::Integration::CookieJar *jar = qobject_cast<KIO::Integration::CookieJar *> (cookieJar());
176  if (jar)
177  return jar->windowId();
178 
179  return 0;
180 }
181 #endif
182 
183 QWidget* AccessManager::window() const
184 {
185  return d->window;
186 }
187 
188 KIO::MetaData& AccessManager::requestMetaData()
189 {
190  return d->requestMetaData;
191 }
192 
193 KIO::MetaData& AccessManager::sessionMetaData()
194 {
195  return d->sessionMetaData;
196 }
197 
198 void AccessManager::putReplyOnHold(QNetworkReply* reply)
199 {
200  KDEPrivate::AccessManagerReply* r = qobject_cast<KDEPrivate::AccessManagerReply*>(reply);
201  if (!r) {
202  return;
203  }
204 
205  r->putOnHold();
206 }
207 
208 void AccessManager::setEmitReadyReadOnMetaDataChange(bool enable)
209 {
210  d->emitReadyReadOnMetaDataChange = enable;
211 }
212 
213 QNetworkReply *AccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData)
214 {
215  const KUrl reqUrl (req.url());
216 
217  if (!d->externalContentAllowed &&
218  !KDEPrivate::AccessManagerReply::isLocalRequest(reqUrl) &&
219  reqUrl.scheme() != QL1S("data")) {
220  kDebug( 7044 ) << "Blocked: " << reqUrl;
221  return new KDEPrivate::AccessManagerReply(op, req, QNetworkReply::ContentAccessDenied, i18n("Blocked request."), this);
222  }
223 
224  // Check if the internal ignore content disposition header is set.
225  const bool ignoreContentDisposition = req.hasRawHeader("x-kdewebkit-ignore-disposition");
226 
227  // Retrieve the KIO meta data...
228  KIO::MetaData metaData;
229  d->setMetaDataForRequest(req, metaData);
230 
231  KIO::SimpleJob *kioJob = 0;
232 
233  switch (op) {
234  case HeadOperation: {
235  //kDebug( 7044 ) << "HeadOperation:" << reqUrl;
236  kioJob = KIO::mimetype(reqUrl, KIO::HideProgressInfo);
237  break;
238  }
239  case GetOperation: {
240  //kDebug( 7044 ) << "GetOperation:" << reqUrl;
241  if (!reqUrl.path().isEmpty() || reqUrl.host().isEmpty())
242  kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo);
243  else
244  kioJob = KIO::stat(reqUrl, KIO::HideProgressInfo);
245 
246  // WORKAROUND: Avoid the brain damaged stuff QtWebKit does when a POST
247  // operation is redirected! See BR# 268694.
248  metaData.remove(QL1S("content-type")); // Remove the content-type from a GET/HEAD request!
249  break;
250  }
251  case PutOperation: {
252  //kDebug( 7044 ) << "PutOperation:" << reqUrl;
253  if (outgoingData)
254  kioJob = KIO::storedPut(outgoingData->readAll(), reqUrl, -1, KIO::HideProgressInfo);
255  else
256  kioJob = KIO::put(reqUrl, -1, KIO::HideProgressInfo);
257  break;
258  }
259  case PostOperation: {
260  kioJob = KIO::http_post(reqUrl, outgoingData, sizeFromRequest(req), KIO::HideProgressInfo);
261  if (!metaData.contains(QL1S("content-type"))) {
262  const QVariant header = req.header(QNetworkRequest::ContentTypeHeader);
263  if (header.isValid()) {
264  metaData.insert(QL1S("content-type"),
265  (QL1S("Content-Type: ") + header.toString()));
266  } else {
267  metaData.insert(QL1S("content-type"),
268  QL1S("Content-Type: application/x-www-form-urlencoded"));
269  }
270  }
271  break;
272  }
273  case DeleteOperation: {
274  //kDebug(7044) << "DeleteOperation:" << reqUrl;
275  kioJob = KIO::http_delete(reqUrl, KIO::HideProgressInfo);
276  break;
277  }
278  case CustomOperation: {
279  const QByteArray& method = req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray();
280  //kDebug(7044) << "CustomOperation:" << reqUrl << "method:" << method << "outgoing data:" << outgoingData;
281 
282  if (method.isEmpty()) {
283  return new KDEPrivate::AccessManagerReply(op, req, QNetworkReply::ProtocolUnknownError, i18n("Unknown HTTP verb."), this);
284  }
285 
286  if (outgoingData)
287  kioJob = KIO::http_post(reqUrl, outgoingData, sizeFromRequest(req), KIO::HideProgressInfo);
288  else
289  kioJob = KIO::get(reqUrl, KIO::NoReload, KIO::HideProgressInfo);
290 
291  metaData.insert(QL1S("CustomHTTPMethod"), method);
292  break;
293  }
294  default: {
295  kWarning(7044) << "Unsupported KIO operation requested! Defering to QNetworkAccessManager...";
296  return QNetworkAccessManager::createRequest(op, req, outgoingData);
297  }
298  }
299 
300  // Set the job priority
301  switch (req.priority()) {
302  case QNetworkRequest::HighPriority:
303  KIO::Scheduler::setJobPriority(kioJob, -5);
304  break;
305  case QNetworkRequest::LowPriority:
306  KIO::Scheduler::setJobPriority(kioJob, 5);
307  break;
308  default:
309  break;
310  }
311 
312  KDEPrivate::AccessManagerReply *reply;
313 
314  /*
315  NOTE: Here we attempt to handle synchronous XHR requests. Unfortunately,
316  due to the fact that QNAM is both synchronous and multi-thread while KIO
317  is completely the opposite (asynchronous and not thread safe), the code
318  below might cause crashes like the one reported in bug# 287778 (nested
319  event loops are inherently dangerous).
320 
321  Unfortunately, all attempts to address the crash has so far failed due to
322  the many regressions they caused, e.g. bug# 231932 and 297954. Hence, until
323  a solution is found, we have to live with the side effects of creating
324  nested event loops.
325  */
326  if (req.attribute(gSynchronousNetworkRequestAttribute).toBool()) {
327  KUrl finalURL;
328  QByteArray data;
329 
330  if (KIO::NetAccess::synchronousRun(kioJob, d->window, &data, &finalURL, &metaData)) {
331  reply = new KDEPrivate::AccessManagerReply(op, req, data, finalURL, metaData, this);
332  kDebug(7044) << "Synchronous XHR:" << reply << reqUrl;
333  } else {
334  kWarning(7044) << "Failed to create a synchronous XHR for" << reqUrl;
335  reply = new KDEPrivate::AccessManagerReply(op, req, QNetworkReply::UnknownNetworkError, kioJob->errorText(), this);
336  }
337  } else {
338  // Set the window on the the KIO ui delegate
339  if (d->window) {
340  kioJob->ui()->setWindow(d->window);
341  }
342 
343  // Disable internal automatic redirection handling
344  kioJob->setRedirectionHandlingEnabled(false);
345 
346  // Set the job priority
347  switch (req.priority()) {
348  case QNetworkRequest::HighPriority:
349  KIO::Scheduler::setJobPriority(kioJob, -5);
350  break;
351  case QNetworkRequest::LowPriority:
352  KIO::Scheduler::setJobPriority(kioJob, 5);
353  break;
354  default:
355  break;
356  }
357 
358  // Set the meta data for this job...
359  kioJob->setMetaData(metaData);
360 
361  // Create the reply...
362  reply = new KDEPrivate::AccessManagerReply(op, req, kioJob, d->emitReadyReadOnMetaDataChange, this);
363  //kDebug(7044) << reply << reqUrl;
364  }
365 
366  if (ignoreContentDisposition && reply) {
367  //kDebug(7044) << "Content-Disposition WILL BE IGNORED!";
368  reply->setIgnoreContentDisposition(ignoreContentDisposition);
369  }
370 
371  return reply;
372 }
373 
374 void AccessManager::AccessManagerPrivate::setMetaDataForRequest(QNetworkRequest request, KIO::MetaData& metaData)
375 {
376  // Add any meta data specified within request...
377  QVariant userMetaData = request.attribute (static_cast<QNetworkRequest::Attribute>(MetaData));
378  if (userMetaData.isValid() && userMetaData.type() == QVariant::Map)
379  metaData += userMetaData.toMap();
380 
381  metaData.insert(QL1S("PropagateHttpHeader"), QL1S("true"));
382 
383  if (request.hasRawHeader("User-Agent")) {
384  metaData.insert(QL1S("UserAgent"), request.rawHeader("User-Agent"));
385  request.setRawHeader("User-Agent", QByteArray());
386  }
387 
388  if (request.hasRawHeader("Accept")) {
389  metaData.insert(QL1S("accept"), request.rawHeader("Accept"));
390  request.setRawHeader("Accept", QByteArray());
391  }
392 
393  if (request.hasRawHeader("Accept-Charset")) {
394  metaData.insert(QL1S("Charsets"), request.rawHeader("Accept-Charset"));
395  request.setRawHeader("Accept-Charset", QByteArray());
396  }
397 
398  if (request.hasRawHeader("Accept-Language")) {
399  metaData.insert(QL1S("Languages"), request.rawHeader("Accept-Language"));
400  request.setRawHeader("Accept-Language", QByteArray());
401  }
402 
403  if (request.hasRawHeader("Referer")) {
404  metaData.insert(QL1S("referrer"), request.rawHeader("Referer"));
405  request.setRawHeader("Referer", QByteArray());
406  }
407 
408  if (request.hasRawHeader("Content-Type")) {
409  metaData.insert(QL1S("content-type"), request.rawHeader("Content-Type"));
410  request.setRawHeader("Content-Type", QByteArray());
411  }
412 
413  if (request.attribute(QNetworkRequest::AuthenticationReuseAttribute) == QNetworkRequest::Manual) {
414  metaData.insert(QL1S("no-preemptive-auth-reuse"), QL1S("true"));
415  }
416 
417  request.setRawHeader("Content-Length", QByteArray());
418  request.setRawHeader("Connection", QByteArray());
419  request.setRawHeader("If-None-Match", QByteArray());
420  request.setRawHeader("If-Modified-Since", QByteArray());
421  request.setRawHeader("x-kdewebkit-ignore-disposition", QByteArray());
422 
423  QStringList customHeaders;
424  Q_FOREACH(const QByteArray &key, request.rawHeaderList()) {
425  const QByteArray value = request.rawHeader(key);
426  if (value.length())
427  customHeaders << (key + QL1S(": ") + value);
428  }
429 
430  if (!customHeaders.isEmpty()) {
431  metaData.insert(QL1S("customHTTPHeader"), customHeaders.join("\r\n"));
432  }
433 
434  // Append per request meta data, if any...
435  if (!requestMetaData.isEmpty()) {
436  metaData += requestMetaData;
437  // Clear per request meta data...
438  requestMetaData.clear();
439  }
440 
441  // Append per session meta data, if any...
442  if (!sessionMetaData.isEmpty()) {
443  metaData += sessionMetaData;
444  }
445 }
446 
447 
448 using namespace KIO::Integration;
449 
450 static QSsl::SslProtocol qSslProtocolFromString(const QString& str)
451 {
452  if (str.compare(QLatin1String("SSLv3"), Qt::CaseInsensitive) == 0) {
453  return QSsl::SslV3;
454  }
455 
456  if (str.compare(QLatin1String("SSLv2"), Qt::CaseInsensitive) == 0) {
457  return QSsl::SslV2;
458  }
459 
460  if (str.compare(QLatin1String("TLSv1"), Qt::CaseInsensitive) == 0) {
461  return QSsl::TlsV1;
462  }
463 
464  return QSsl::AnyProtocol;
465 }
466 
467 bool KIO::Integration::sslConfigFromMetaData(const KIO::MetaData& metadata, QSslConfiguration& sslconfig)
468 {
469  bool success = false;
470 
471  if (metadata.contains(QL1S("ssl_in_use"))) {
472  const QSsl::SslProtocol sslProto = qSslProtocolFromString(metadata.value(QL1S("ssl_protocol_version")));
473  QList<QSslCipher> cipherList;
474  cipherList << QSslCipher(metadata.value(QL1S("ssl_cipher_name")), sslProto);
475  sslconfig.setCaCertificates(QSslCertificate::fromData(metadata.value(QL1S("ssl_peer_chain")).toUtf8()));
476  sslconfig.setCiphers(cipherList);
477  sslconfig.setProtocol(sslProto);
478  success = sslconfig.isNull();
479  }
480 
481  return success;
482 }
483 
484 CookieJar::CookieJar(QObject* parent)
485  :QNetworkCookieJar(parent), d(new CookieJar::CookieJarPrivate)
486 {
487  reparseConfiguration();
488 }
489 
490 CookieJar::~CookieJar()
491 {
492  delete d;
493 }
494 
495 WId CookieJar::windowId() const
496 {
497  return d->windowId;
498 }
499 
500 bool CookieJar::isCookieStorageDisabled() const
501 {
502  return d->isStorageDisabled;
503 }
504 
505 QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
506 {
507  QList<QNetworkCookie> cookieList;
508 
509  if (!d->isEnabled) {
510  return cookieList;
511  }
512  QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer");
513  QDBusReply<QString> reply = kcookiejar.call("findDOMCookies", url.toString(QUrl::RemoveUserInfo), (qlonglong)d->windowId);
514 
515  if (!reply.isValid()) {
516  kWarning(7044) << "Unable to communicate with the cookiejar!";
517  return cookieList;
518  }
519 
520  const QString cookieStr = reply.value();
521  const QStringList cookies = cookieStr.split(QL1S("; "), QString::SkipEmptyParts);
522  Q_FOREACH(const QString& cookie, cookies) {
523  const int index = cookie.indexOf(QL1C('='));
524  const QString name = cookie.left(index);
525  const QString value = cookie.right((cookie.length() - index - 1));
526  cookieList << QNetworkCookie(name.toUtf8(), value.toUtf8());
527  //kDebug(7044) << "cookie: name=" << name << ", value=" << value;
528  }
529 
530  return cookieList;
531 }
532 
533 bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
534 {
535  if (!d->isEnabled) {
536  return false;
537  }
538 
539  QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer");
540  Q_FOREACH(const QNetworkCookie &cookie, cookieList) {
541  QByteArray cookieHeader ("Set-Cookie: ");
542  if (d->isStorageDisabled && !cookie.isSessionCookie()) {
543  QNetworkCookie sessionCookie(cookie);
544  sessionCookie.setExpirationDate(QDateTime());
545  cookieHeader += sessionCookie.toRawForm();
546  } else {
547  cookieHeader += cookie.toRawForm();
548  }
549  kcookiejar.call("addCookies", url.toString(QUrl::RemoveUserInfo), cookieHeader, (qlonglong)d->windowId);
550  //kDebug(7044) << "[" << d->windowId << "]" << cookieHeader << " from " << url;
551  }
552 
553  return !kcookiejar.lastError().isValid();
554 }
555 
556 void CookieJar::setDisableCookieStorage(bool disable)
557 {
558  d->isStorageDisabled = disable;
559 }
560 
561 void CookieJar::setWindowId(WId id)
562 {
563  d->windowId = id;
564 }
565 
566 void CookieJar::reparseConfiguration()
567 {
568  KConfigGroup cfg = KSharedConfig::openConfig("kcookiejarrc", KConfig::NoGlobals)->group("Cookie Policy");
569  d->isEnabled = cfg.readEntry("Cookies", true);
570 }
571 
572 #include "accessmanager.moc"
573 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Jul 23 2013 22:00:53 by doxygen 1.8.1.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.10.5 API Reference

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