File indexing completed on 2024-04-21 04:42:37
0001 /* 0002 SPDX-FileCopyrightText: 2009 Dawit Alemayehu <adawit@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "networkaccessmanager.h" 0008 #include "settings/webkitsettings.h" 0009 0010 #include "kwebkitpart_debug.h" 0011 #include <KLocalizedString> 0012 #include <KProtocolInfo> 0013 #include <KRun> 0014 0015 #include <QTimer> 0016 #include <QWidget> 0017 #include <QNetworkReply> 0018 #include <QWebFrame> 0019 #include <QWebElementCollection> 0020 #include <QMimeType> 0021 #include <QMimeDatabase> 0022 0023 0024 #define QL1S(x) QLatin1String(x) 0025 #define HIDABLE_ELEMENTS QL1S("audio,img,embed,object,iframe,frame,video") 0026 0027 /* Null network reply */ 0028 class NullNetworkReply : public QNetworkReply 0029 { 0030 public: 0031 explicit NullNetworkReply(const QNetworkRequest &req, QObject* parent = nullptr) 0032 :QNetworkReply(parent) 0033 { 0034 setRequest(req); 0035 setUrl(req.url()); 0036 setHeader(QNetworkRequest::ContentLengthHeader, 0); 0037 setHeader(QNetworkRequest::ContentTypeHeader, "text/plain"); 0038 setError(QNetworkReply::ContentAccessDenied, i18n("Blocked by ad filter")); 0039 setAttribute(QNetworkRequest::User, QNetworkReply::ContentAccessDenied); 0040 QTimer::singleShot(0, this, SIGNAL(finished())); 0041 } 0042 0043 void abort() override {} 0044 qint64 bytesAvailable() const override { return 0; } 0045 0046 protected: 0047 qint64 readData(char*, qint64) override {return -1;} 0048 }; 0049 0050 namespace KDEPrivate { 0051 0052 MyNetworkAccessManager::MyNetworkAccessManager(QObject *parent) 0053 : KIO::AccessManager(parent) 0054 { 0055 } 0056 0057 static bool isMixedContent(const QUrl& baseUrl, const QUrl& reqUrl) 0058 { 0059 const QString baseProtocol (baseUrl.scheme()); 0060 const bool hasSecureScheme = (baseProtocol.compare(QL1S("https")) == 0 || 0061 baseProtocol.compare(QL1S("webdavs")) == 0); 0062 return (hasSecureScheme && baseProtocol != reqUrl.scheme()); 0063 } 0064 0065 static bool blockRequest(QNetworkAccessManager::Operation op, const QUrl& requestUrl) 0066 { 0067 if (op != QNetworkAccessManager::GetOperation) 0068 return false; 0069 0070 if (!WebKitSettings::self()->isAdFilterEnabled()) 0071 return false; 0072 0073 if (!WebKitSettings::self()->isAdFiltered(requestUrl.toString())) 0074 return false; 0075 0076 qCDebug(KWEBKITPART_LOG) << "*** REQUEST BLOCKED: URL" << requestUrl << "RULE" << WebKitSettings::self()->adFilteredBy(requestUrl.toString()); 0077 return true; 0078 } 0079 0080 0081 QNetworkReply *MyNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData) 0082 { 0083 QWebFrame* frame = qobject_cast<QWebFrame*>(req.originatingObject()); 0084 0085 if (!blockRequest(op, req.url())) { 0086 if (KProtocolInfo::isHelperProtocol(req.url())) { 0087 (void) new KRun(req.url(), qobject_cast<QWidget*>(req.originatingObject())); 0088 return new NullNetworkReply(req, this); 0089 } 0090 QNetworkReply* reply = KIO::AccessManager::createRequest(op, req, outgoingData); 0091 if (frame && isMixedContent(frame->baseUrl(), req.url())) { 0092 connect(reply, SIGNAL(metaDataChanged()), this, SLOT(slotMetaDataChanged())); 0093 } 0094 return reply; 0095 } 0096 0097 if (frame) { 0098 if (!m_blockedRequests.contains(frame)) 0099 connect(frame, SIGNAL(loadFinished(bool)), this, SLOT(slotFinished(bool))); 0100 m_blockedRequests.insert(frame, req.url()); 0101 } 0102 0103 return new NullNetworkReply(req, this); 0104 } 0105 0106 static void hideBlockedElements(const QUrl& url, QWebElementCollection& collection) 0107 { 0108 for (QWebElementCollection::iterator it = collection.begin(); it != collection.end(); ++it) { 0109 const QUrl baseUrl ((*it).webFrame()->baseUrl()); 0110 QString src = (*it).attribute(QL1S("src")); 0111 if (src.isEmpty()) 0112 src = (*it).evaluateJavaScript(QL1S("this.src")).toString(); 0113 if (src.isEmpty()) 0114 continue; 0115 const QUrl resolvedUrl(baseUrl.resolved(QUrl(src))); 0116 if (url == resolvedUrl) { 0117 //qCDebug(KWEBKITPART_LOG) << "*** HIDING ELEMENT: " << (*it).tagName() << resolvedUrl; 0118 (*it).removeFromDocument(); 0119 } 0120 } 0121 } 0122 0123 void MyNetworkAccessManager::slotFinished(bool ok) 0124 { 0125 if (!ok) 0126 return; 0127 0128 if(!WebKitSettings::self()->isAdFilterEnabled()) 0129 return; 0130 0131 if(!WebKitSettings::self()->isHideAdsEnabled()) 0132 return; 0133 0134 QWebFrame* frame = qobject_cast<QWebFrame*>(sender()); 0135 if (!frame) 0136 return; 0137 0138 QList<QUrl> urls = m_blockedRequests.values(frame); 0139 if (urls.isEmpty()) 0140 return; 0141 0142 QWebElementCollection collection = frame->findAllElements(HIDABLE_ELEMENTS); 0143 if (frame->parentFrame()) 0144 collection += frame->parentFrame()->findAllElements(HIDABLE_ELEMENTS); 0145 0146 Q_FOREACH(const QUrl& url, urls) 0147 hideBlockedElements(url, collection); 0148 } 0149 0150 static bool isActiveContent(const QString& contentType) 0151 { 0152 QMimeDatabase db; 0153 const QMimeType mime = db.mimeTypeForName(contentType); 0154 return (mime.isValid() && mime.inherits(QLatin1String("application/javascript"))); 0155 } 0156 0157 void MyNetworkAccessManager::slotMetaDataChanged() 0158 { 0159 QNetworkReply* reply = qobject_cast<QNetworkReply*> (sender()); 0160 if (reply) { 0161 const bool activeContent = isActiveContent(reply->header(QNetworkRequest::ContentTypeHeader).toString()); 0162 if ((activeContent && !WebKitSettings::self()->alowActiveMixedContent()) || 0163 (!activeContent && !WebKitSettings::self()->allowMixedContentDisplay())) { 0164 reply->abort(); 0165 emit QMetaObject::invokeMethod(reply, "finished", Qt::AutoConnection); 0166 } 0167 } 0168 } 0169 }