diff options
author | Kari Oikarinen <kari.oikarinen@qt.io> | 2019-01-08 08:19:22 +0200 |
---|---|---|
committer | Kari Oikarinen <kari.oikarinen@qt.io> | 2019-01-08 08:19:22 +0200 |
commit | 846320f5877aafb9c7b319da6c972786805d9c30 (patch) | |
tree | b4bda9f9b27ee311fc7f75de3843a828da23c340 | |
parent | 35b97b92968505793b162ccfdada65e25690f711 (diff) | |
parent | 5c85e0748b6c321d9988d126903fed85f311f5e7 (diff) |
Merge 5.12 into 5.12.1
Change-Id: Ia86d2e001e3575bb4995f5f57b88d6c809246941
38 files changed, 593 insertions, 87 deletions
diff --git a/.qmake.conf b/.qmake.conf index c9888ee8b..7ae0b8594 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -5,4 +5,4 @@ QTWEBENGINE_OUT_ROOT = $$shadowed($$PWD) load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.12.0 +MODULE_VERSION = 5.12.1 diff --git a/dist/changes-5.11.3 b/dist/changes-5.11.3 new file mode 100644 index 000000000..562003a49 --- /dev/null +++ b/dist/changes-5.11.3 @@ -0,0 +1,66 @@ +Qt 5.11.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.11.0 through 5.11.2. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.11 series is binary compatible with the 5.10.x series. +Applications compiled for 5.10 will continue to run with 5.11. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.11.3 Changes * +**************************************************************************** + +Chromium +-------- + + - Security fixes from Chromium up to version 70.0.3538.102, including: + * CVE-2018-16066 + * CVE-2018-16067 + * CVE-2018-16068 + * CVE-2018-16070 + * CVE-2018-16071 + * CVE-2018-16072 + * CVE-2018-16073 + * CVE-2018-16074 + * CVE-2018-16076 + * CVE-2018-16077 + * CVE-2018-16083 + * CVE-2018-16085 + * CVE-2018-17462 + * CVE-2018-17466 + * CVE-2018-17468 + * CVE-2018-17468 + * CVE-2018-17469 + * CVE-2018-17470 + * CVE-2018-17471 + * CVE-2018-17473 + * CVE-2018-17474 + * CVE-2018-17476 + * CVE-2018-17478 + +General +------- + + * [QTBUG-69281, QTBUG-71128] Fixed asserts and crashes in proxy (.pac) file handling. + * [QTBUG-70062] Fixed rendering on late 2013 Mac Pros. + * [QTBUG-71393] Fixed issue with some cookies being incorrectly marked as thirdParty. + +Build +----- + + * [QTBUG-70981] macOS: Fixed build on macOS 10.14. + * [QTBUG-71033] Fixed configure check for minimum freetype version. + * [QTBUG-71295] Fixed building without webrtc but with pepper plugins. + * We are now explicitly setting arm_arch when compiling for ARM. + * Windows: Added configure check that we are using a 64 bit compiler. diff --git a/examples/webenginewidgets/minimal/doc/src/minimal.qdoc b/examples/webenginewidgets/minimal/doc/src/minimal.qdoc index 477ff521b..d0b25c4b8 100644 --- a/examples/webenginewidgets/minimal/doc/src/minimal.qdoc +++ b/examples/webenginewidgets/minimal/doc/src/minimal.qdoc @@ -42,6 +42,15 @@ \section1 The Code + We first define a \c commandLineUrlArgument function that returns the URL to open. + This is either the first positional argument given on the command line, or + \c https://www.qt.io as a fallback. + + \quotefromfile webenginewidgets/minimal/main.cpp + \skipto #include + + \printto int main + In the \c main function we first set the \l{QCoreApplication::organizationName} property. This affects the locations where Qt WebEngine stores persistent and cached data (see also @@ -52,14 +61,11 @@ view automatically scale on high-dpi displays. Next, we instantiate a QApplication and a QWebEngineView. The URL - to load is taken from the command-line in \c commandLineUrlArgument and + to load is taken from \c commandLineUrlArgument and loaded by calling \l QWebEngineView::setUrl. The view widget is given a reasonable default size, and shown. Finally, QApplication::exec() launches the main event loop. - \quotefromfile webenginewidgets/minimal/main.cpp - \skipto #include - \printuntil } \section1 Requirements diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp index 2bb870071..ea9081fc1 100644 --- a/src/core/api/qwebengineurlrequestinfo.cpp +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -120,6 +120,9 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q \a info contains the information about the URL request and will track internally whether its members have been altered. + + \warning All method calls to the profile on the main thread will block until + execution of this function is finished. */ diff --git a/src/core/api/qwebengineurlscheme.cpp b/src/core/api/qwebengineurlscheme.cpp index f36f3335b..d63599163 100644 --- a/src/core/api/qwebengineurlscheme.cpp +++ b/src/core/api/qwebengineurlscheme.cpp @@ -84,8 +84,10 @@ public: URLs. Custom URL schemes must be configured early at application startup, before - creating any Qt WebEngine classes. The configuration applies globally to all - profiles. + creating any Qt WebEngine classes. In general this means the schemes need to be configured before + a QGuiApplication or QApplication instance is created. + + Every registered scheme configuration applies globally to all profiles. \code int main(int argc, char **argv) diff --git a/src/core/api/qwebengineurlschemehandler.cpp b/src/core/api/qwebengineurlschemehandler.cpp index 94b85c42b..6f06b2c6e 100644 --- a/src/core/api/qwebengineurlschemehandler.cpp +++ b/src/core/api/qwebengineurlschemehandler.cpp @@ -48,12 +48,51 @@ QT_BEGIN_NAMESPACE \brief The QWebEngineUrlSchemeHandler is a base class for handling custom URL schemes. \since 5.6 - To implement a custom URL scheme for QtWebEngine, you must write a class derived from this class, - and reimplement requestStarted(). Then install it via QWebEngineProfile::installUrlSchemeHandler() + To implement a custom URL scheme for QtWebEngine, you first have to create an instance of + QWebEngineUrlScheme and register it using QWebEngineUrlScheme::registerScheme(). + + \note Make sure that you create and register the scheme object \e before the QGuiApplication + or QApplication object is instantiated. + + Then you must create a class derived from QWebEngineUrlSchemeHandler, + and reimplement the requestStarted() method. + + Finally, install the scheme handler object via QWebEngineProfile::installUrlSchemeHandler() or QQuickWebEngineProfile::installUrlSchemeHandler(). + \code + + class MySchemeHandler : public QWebEngineUrlSchemeHandler + { + public: + MySchemeHandler(QObject *parent = nullptr); + void requestStarted(QWebEngineUrlRequestJob *request) + { + // .... + } + }; + + int main(int argc, char **argv) + { + QWebEngineUrlScheme scheme("myscheme"); + scheme.setSyntax(QWebEngineUrlScheme::Syntax::HostAndPort); + scheme.setDefaultPort(2345); + scheme.setFlags(QWebEngineUrlScheme::SecureScheme); + QWebEngineUrlScheme::registerScheme(scheme); + + // ... + QApplication app(argc, argv); + // ... + + // installUrlSchemeHandler does not take ownership of the handler. + MySchemeHandler *handler = new MySchemeHandler(parent); + QWebEngineProfile::defaultProfile()->installUrlSchemeHandler("myscheme", handler); + } + \endcode + \inmodule QtWebEngineCore + \sa {QWebEngineUrlScheme}, {WebEngine Widgets WebUI Example} */ /*! diff --git a/src/core/browser_main_parts_qt.cpp b/src/core/browser_main_parts_qt.cpp index dbd123586..8f39386d4 100644 --- a/src/core/browser_main_parts_qt.cpp +++ b/src/core/browser_main_parts_qt.cpp @@ -204,9 +204,9 @@ void BrowserMainPartsQt::PreMainMessageLoopStart() void BrowserMainPartsQt::PostMainMessageLoopRun() { - // The BrowserContext's destructor uses the MessageLoop so it should be deleted + // The ProfileQt's destructor uses the MessageLoop so it should be deleted // right before the RenderProcessHostImpl's destructor destroys it. - WebEngineContext::current()->destroyBrowserContext(); + WebEngineContext::current()->destroyProfileAdapter(); } int BrowserMainPartsQt::PreCreateThreads() diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index 9fe233577..abf4a2a95 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -39,6 +39,8 @@ #include "download_manager_delegate_qt.h" +#include "base/files/file_util.h" +#include "base/time/time_to_iso8601.h" #include "content/public/browser/download_item_utils.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/save_page_type.h" @@ -156,15 +158,13 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem* QFileInfo suggestedFile(defaultDownloadDirectory.absoluteFilePath(suggestedFilename)); QString suggestedFilePath = suggestedFile.absoluteFilePath(); - QString tmpFileBase = QString("%1%2%3").arg(suggestedFile.absolutePath()).arg(QDir::separator()).arg(suggestedFile.baseName()); + base::FilePath tmpFilePath(toFilePathString(suggestedFilePath)); - for (int i = 1; QFileInfo::exists(suggestedFilePath); ++i) { - suggestedFilePath = QString("%1(%2).%3").arg(tmpFileBase).arg(i).arg(suggestedFile.completeSuffix()); - if (i >= 99) { - suggestedFilePath = suggestedFile.absoluteFilePath(); - break; - } - } + int uniquifier = base::GetUniquePathNumber(tmpFilePath, base::FilePath::StringType()); + if (uniquifier > 0) + suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)).AsUTF8Unsafe()); + else if (uniquifier == -1) + suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(base::StringPrintf(" - %s", base::TimeToISO8601(item->GetStartTime()).c_str())).AsUTF8Unsafe()); item->AddObserver(this); QList<ProfileAdapterClient*> clients = m_profileAdapter->clients(); diff --git a/src/core/net/network_delegate_qt.cpp b/src/core/net/network_delegate_qt.cpp index 551302291..37309931e 100644 --- a/src/core/net/network_delegate_qt.cpp +++ b/src/core/net/network_delegate_qt.cpp @@ -225,15 +225,22 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet const QUrl qUrl = toQt(request->url()); - QWebEngineUrlRequestInterceptor* interceptor = m_profileIOData->requestInterceptor(); + QUrl firstPartyUrl = QUrl(); + if (resourceType == content::ResourceType::RESOURCE_TYPE_SUB_FRAME) + firstPartyUrl = toQt(request->first_party_url()); + else + firstPartyUrl = toQt(request->site_for_cookies()); + + QWebEngineUrlRequestInterceptor* interceptor = m_profileIOData->acquireInterceptor(); if (interceptor) { QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), toQt(navigationType), qUrl, - toQt(request->site_for_cookies()), + firstPartyUrl, QByteArray::fromStdString(request->method())); QWebEngineUrlRequestInfo requestInfo(infoPrivate); interceptor->interceptRequest(requestInfo); + m_profileIOData->releaseInterceptor(); if (requestInfo.changed()) { int result = infoPrivate->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; @@ -249,7 +256,8 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet if (result != net::OK) return result; } - } + } else + m_profileIOData->releaseInterceptor(); if (!resourceInfo) return net::OK; diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index 86b16fd2c..800fcb401 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -82,7 +82,7 @@ ProfileAdapter::ProfileAdapter(const QString &storageName): , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) , m_httpCacheMaxSize(0) { - WebEngineContext::current()->addBrowserContext(this); + WebEngineContext::current()->addProfileAdapter(this); // creation of profile requires webengine context m_profile.reset(new ProfileQt(this)); content::BrowserContext::Initialize(m_profile.data(), toFilePath(dataPath())); @@ -92,7 +92,7 @@ ProfileAdapter::ProfileAdapter(const QString &storageName): ProfileAdapter::~ProfileAdapter() { - WebEngineContext::current()->removeBrowserContext(this); + WebEngineContext::current()->removeProfileAdapter(this); if (m_downloadManagerDelegate) { m_profile->GetDownloadManager(m_profile.data())->Shutdown(); m_downloadManagerDelegate.reset(); diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp index 0a0d242a3..7783f1ae7 100644 --- a/src/core/profile_io_data_qt.cpp +++ b/src/core/profile_io_data_qt.cpp @@ -690,14 +690,17 @@ void ProfileIODataQt::updateRequestInterceptor() // We in this case do not need to regenerate any Chromium classes. } -QWebEngineUrlRequestInterceptor *ProfileIODataQt::requestInterceptor() +QWebEngineUrlRequestInterceptor *ProfileIODataQt::acquireInterceptor() { - // used in NetworkDelegateQt::OnBeforeURLRequest - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - QMutexLocker lock(&m_mutex); + m_mutex.lock(); return m_requestInterceptor; } +void ProfileIODataQt::releaseInterceptor() +{ + m_mutex.unlock(); +} + bool ProfileIODataQt::canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url) const { return m_cookieDelegate->canSetCookie(firstPartyUrl,cookieLine, url); diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h index 6961e2ad2..5b416861c 100644 --- a/src/core/profile_io_data_qt.h +++ b/src/core/profile_io_data_qt.h @@ -89,10 +89,13 @@ public: void generateUserAgent(); void generateJobFactory(); void regenerateJobFactory(); - QWebEngineUrlRequestInterceptor *requestInterceptor(); bool canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url) const; bool canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) const; + // Used in NetworkDelegateQt::OnBeforeURLRequest. + QWebEngineUrlRequestInterceptor *acquireInterceptor(); + void releaseInterceptor(); + void setRequestContextData(content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors); void setFullConfiguration(); // runs on ui thread diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 1361ebbed..aee5be42f 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -183,13 +183,13 @@ bool usingSoftwareDynamicGL() scoped_refptr<QtWebEngineCore::WebEngineContext> WebEngineContext::m_handle; bool WebEngineContext::m_destroyed = false; -void WebEngineContext::destroyBrowserContext() +void WebEngineContext::destroyProfileAdapter() { if (m_defaultProfileAdapter) qWarning("PostMainMessageLoopRun is done, but global profile still exists !"); } -void WebEngineContext::addBrowserContext(ProfileAdapter *profileAdapter) +void WebEngineContext::addProfileAdapter(ProfileAdapter *profileAdapter) { Q_ASSERT(!m_profileAdapters.contains(profileAdapter)); const QString path = profileAdapter->dataPath(); @@ -205,7 +205,7 @@ void WebEngineContext::addBrowserContext(ProfileAdapter *profileAdapter) m_profileAdapters.append(profileAdapter); } -void WebEngineContext::removeBrowserContext(ProfileAdapter *profileAdapter) +void WebEngineContext::removeProfileAdapter(ProfileAdapter *profileAdapter) { m_profileAdapters.removeAll(profileAdapter); } diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index ce71984d4..604c85a61 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -82,9 +82,9 @@ public: #if QT_CONFIG(webengine_printing_and_pdf) printing::PrintJobManager* getPrintJobManager(); #endif - void destroyBrowserContext(); - void addBrowserContext(ProfileAdapter *profileAdapter); - void removeBrowserContext(ProfileAdapter *profileAdapter); + void destroyProfileAdapter(); + void addProfileAdapter(ProfileAdapter *profileAdapter); + void removeProfileAdapter(ProfileAdapter *profileAdapter); void destroy(); private: diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index a45f7048b..fc6287dd9 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -101,7 +101,7 @@ static KeyboardDriver keyboardDriverImpl() if (platformName == QLatin1Literal("xcb") || platformName == QLatin1Literal("wayland")) return KeyboardDriver::Xkb; -#if QT_CONFIG(libinput) && QT_CONFIG(xkbcommon_evdev) +#if QT_CONFIG(libinput) && QT_CONFIG(xkbcommon) // Based on QEglFSIntegration::createInputHandlers and QLibInputKeyboard::processKey. if (platformName == QLatin1Literal("eglfs") && !qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT")) return KeyboardDriver::Xkb; @@ -927,6 +927,74 @@ static ui::DomKey domKeyForQtKey(int qtKey) case Qt::Key_Zenkaku_Hankaku: return ui::DomKey::ZENKAKU_HANKAKU; + // Dead keys (ui/events/keycodes/keyboard_code_conversion_xkb.cc) + case Qt::Key_Dead_Grave: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0300); + case Qt::Key_Dead_Acute: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0301); + case Qt::Key_Dead_Circumflex: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0302); + case Qt::Key_Dead_Tilde: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0303); + case Qt::Key_Dead_Macron: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0304); + case Qt::Key_Dead_Breve: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0306); + case Qt::Key_Dead_Abovedot: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0307); + case Qt::Key_Dead_Diaeresis: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0308); + case Qt::Key_Dead_Abovering: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x030A); + case Qt::Key_Dead_Doubleacute: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x030B); + case Qt::Key_Dead_Caron: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x030C); + case Qt::Key_Dead_Cedilla: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0327); + case Qt::Key_Dead_Ogonek: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0328); + case Qt::Key_Dead_Iota: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0345); + case Qt::Key_Dead_Voiced_Sound: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x3099); + case Qt::Key_Dead_Semivoiced_Sound: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x309A); + case Qt::Key_Dead_Belowdot: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0323); + case Qt::Key_Dead_Hook: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0309); + case Qt::Key_Dead_Horn: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x031B); + case Qt::Key_Dead_Stroke: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0338); + case Qt::Key_Dead_Abovecomma: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0313); + case Qt::Key_Dead_Abovereversedcomma: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0314); + case Qt::Key_Dead_Doublegrave: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x030F); + case Qt::Key_Dead_Belowring: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0325); + case Qt::Key_Dead_Belowmacron: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0331); + case Qt::Key_Dead_Belowcircumflex: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x032D); + case Qt::Key_Dead_Belowtilde: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0330); + case Qt::Key_Dead_Belowbreve: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x032E); + case Qt::Key_Dead_Belowdiaeresis: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0324); + case Qt::Key_Dead_Invertedbreve: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0311); + case Qt::Key_Dead_Belowcomma: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x0326); + case Qt::Key_Dead_Currency: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x00A4); + case Qt::Key_Dead_Greek: + return ui::DomKey::DeadKeyFromCombiningCharacter(0x037E); + // General-Purpose Function Keys case Qt::Key_F1: return ui::DomKey::F1; @@ -1138,19 +1206,6 @@ static ui::DomKey domKeyForQtKey(int qtKey) } } -static inline base::TimeTicks currentTimeForEvent(const QEvent *event) -{ - Q_ASSERT(event); - - if (event->type() != QEvent::Leave) { - const QInputEvent *inputEvent = static_cast<const QInputEvent *>(event); - if (inputEvent->timestamp()) - return base::TimeTicks::FromInternalValue(inputEvent->timestamp() * 1000); - } - - return base::TimeTicks::Now(); -} - template<class T> static WebMouseEvent::Button mouseButtonForEvent(T *event) { @@ -1307,7 +1362,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale) mouseButtonForEvent<QMouseEvent>(ev), 0, modifiersForEvent(ev), - currentTimeForEvent(ev)); + base::TimeTicks::Now()); webKitEvent.pointer_type = WebPointerProperties::PointerType::kMouse; @@ -1317,7 +1372,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale) WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev, double dpiScale) { WebMouseEvent webKitEvent; - webKitEvent.SetTimeStamp(currentTimeForEvent(ev)); + webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); webKitEvent.SetType(webEventTypeForEvent(ev)); @@ -1338,7 +1393,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev, double dpiScale mouseButtonForEvent<QTabletEvent>(ev), 0, modifiersForEvent(ev), - currentTimeForEvent(ev)); + base::TimeTicks::Now()); webKitEvent.force = ev->pressure(); webKitEvent.tilt_x = ev->xTilt(); @@ -1355,7 +1410,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QEvent *ev) Q_ASSERT(ev->type() == QEvent::Leave || ev->type() == QEvent::HoverLeave); WebMouseEvent webKitEvent; - webKitEvent.SetTimeStamp(currentTimeForEvent(ev)); + webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetType(WebInputEvent::kMouseLeave); return webKitEvent; } @@ -1364,7 +1419,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QEvent *ev) WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev, double dpiScale) { WebGestureEvent webKitEvent; - webKitEvent.SetTimeStamp(currentTimeForEvent(ev)); + webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); webKitEvent.SetPositionInWidget(WebFloatPoint(ev->localPos().x() / dpiScale, @@ -1434,7 +1489,7 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub WebMouseWheelEvent webEvent; webEvent.SetType(webEventTypeForEvent(ev)); webEvent.SetModifiers(modifiersForEvent(ev)); - webEvent.SetTimeStamp(currentTimeForEvent(ev)); + webEvent.SetTimeStamp(base::TimeTicks::Now()); webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); @@ -1464,7 +1519,7 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, return false; #endif - webEvent.SetTimeStamp(currentTimeForEvent(ev)); + webEvent.SetTimeStamp(base::TimeTicks::Now()); webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); @@ -1478,7 +1533,7 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev) { content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev)); - webKitEvent.SetTimeStamp(currentTimeForEvent(ev)); + webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); webKitEvent.SetType(webEventTypeForEvent(ev)); @@ -1502,17 +1557,20 @@ content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *e // The dom_code field should contain the USB keycode of the *physical* key // that was pressed. Physical meaning independent of layout and modifiers. - // // Since this information is not available from QKeyEvent in portable form, - // we try to compute it from the native key code. If there's no native key - // code available either, then we assume a US layout and convert it from - // windows_key_code. The result will be incorrect on non-US layouts. + // we try to compute it from the native key code. if (webKitEvent.native_key_code) webKitEvent.dom_code = static_cast<int>( ui::KeycodeConverter::NativeKeycodeToDomCode(webKitEvent.native_key_code)); - else + + // The dom_code and windows_key_code can be converted to each other. The + // result will be incorrect on non-US layouts. + if (!webKitEvent.dom_code && webKitEvent.windows_key_code) webKitEvent.dom_code = static_cast<int>( - ui::UsLayoutKeyboardCodeToDomCode(static_cast<ui::KeyboardCode>(webKitEvent.windows_key_code))); + ui::UsLayoutKeyboardCodeToDomCode(static_cast<ui::KeyboardCode>(webKitEvent.windows_key_code))); + else if (webKitEvent.dom_code && !webKitEvent.windows_key_code) + webKitEvent.windows_key_code = + ui::DomCodeToUsLayoutKeyboardCode(static_cast<ui::DomCode>(webKitEvent.dom_code)); const ushort* text = qtText.utf16(); size_t textSize = std::min(sizeof(webKitEvent.text), size_t(qtText.length() * 2)); diff --git a/src/webengine/api/qquickwebengineaction.cpp b/src/webengine/api/qquickwebengineaction.cpp index f5b780ea6..69a05f29b 100644 --- a/src/webengine/api/qquickwebengineaction.cpp +++ b/src/webengine/api/qquickwebengineaction.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE \inqmlmodule QtWebEngine \since QtWebEngine 1.8 - \brief An action that represents a \l WebEngineView::WebAction + \brief An action that represents a \l WebEngineView::WebAction. A WebEngineAction is returned by the \l WebEngineView::action() method. It provides information about the action, such as diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index ed2600e49..ddc71602b 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -53,6 +53,8 @@ #include "renderer_host/user_resource_controller_host.h" #include "web_engine_settings.h" +#include <QtWebEngineCore/qwebengineurlscheme.h> + using QtWebEngineCore::ProfileAdapter; QT_BEGIN_NAMESPACE @@ -857,7 +859,7 @@ static bool checkInternalScheme(const QByteArray &scheme) /*! Registers a handler \a handler for custom URL scheme \a scheme in the profile. - It is recommended to first register the scheme with \l + It is necessary to first register the scheme with \l QWebEngineUrlScheme::registerScheme at application startup. */ void QQuickWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) @@ -875,6 +877,11 @@ void QQuickWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, Q qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); return; } + + if (QWebEngineUrlScheme::schemeByName(canonicalScheme) == QWebEngineUrlScheme()) + qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " + "before installing the custom scheme handler.", scheme.constData()); + d->profileAdapter()->addCustomUrlSchemeHandler(canonicalScheme, handler); connect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); } diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc index 59429ec5a..0b2aebfce 100644 --- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc +++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc @@ -41,7 +41,7 @@ \list \li \l{Qt for Windows - Requirements} \li \l{Qt for X11 Requirements} - \li \l{Qt for macOS - Requirements} + \li \l{Qt for macOS - Building from Source} \endlist In addition, the following tools are required for building the \l {Qt WebEngine} module: diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 537cf41fd..03ce5e0bc 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -52,6 +52,7 @@ #include "visited_links_manager_qt.h" #include "web_engine_settings.h" +#include <QtWebEngineCore/qwebengineurlscheme.h> QT_BEGIN_NAMESPACE @@ -688,7 +689,7 @@ static bool checkInternalScheme(const QByteArray &scheme) Registers a handler \a handler for custom URL scheme \a scheme in the profile. - It is recommended to first register the scheme with \l + It is necessary to first register the scheme with \l QWebEngineUrlScheme::registerScheme at application startup. */ void QWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) @@ -706,6 +707,11 @@ void QWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEn qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); return; } + + if (QWebEngineUrlScheme::schemeByName(canonicalScheme) == QWebEngineUrlScheme()) + qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " + "before installing the custom scheme handler.", scheme.constData()); + d->profileAdapter()->addCustomUrlSchemeHandler(canonicalScheme, handler); connect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); } diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/favicon.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/favicon.html new file mode 100644 index 000000000..5251d6ef7 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/favicon.html @@ -0,0 +1,7 @@ +<html> +<head> +<link type="image/png" href="icons/favicon.png" sizes="48x48" rel="icon" /> +</head> +<body> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/fontawesome.woff b/tests/auto/core/qwebengineurlrequestinterceptor/resources/fontawesome.woff Binary files differnew file mode 100644 index 000000000..239b9c94e --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/fontawesome.woff diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/icons/favicon.png b/tests/auto/core/qwebengineurlrequestinterceptor/resources/icons/favicon.png Binary files differnew file mode 100644 index 000000000..35717cca5 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/icons/favicon.png diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe.html new file mode 100644 index 000000000..f17027c7a --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe.html @@ -0,0 +1,6 @@ +<html> +<body> +<p>top</p> +<iframe src="iframe2.html" width="80%" height="30%"/> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe2.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe2.html new file mode 100644 index 000000000..758a44a2c --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe2.html @@ -0,0 +1,6 @@ +<html> +<body> +<p>another iframe</p> +<iframe src="iframe3.html" width="80%" height="30%"></iframe> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe3.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe3.html new file mode 100644 index 000000000..ed6ac5b94 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/iframe3.html @@ -0,0 +1,5 @@ +<html> +<body> +<p>inner</p> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/image.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/image.html new file mode 100644 index 000000000..b82e6aab2 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/image.html @@ -0,0 +1,5 @@ +<html> +<body> +<img src="icons/favicon.png"> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/image_in_iframe.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/image_in_iframe.html new file mode 100644 index 000000000..2a3ac117c --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/image_in_iframe.html @@ -0,0 +1,5 @@ +<html> +<body> +<iframe src="image.html"></iframe> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/media.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/media.html new file mode 100644 index 000000000..fd478a679 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/media.html @@ -0,0 +1,7 @@ +<html> +<body> +<video width="320" height="240" controls=""> + <source src="media.mp4" type="video/mp4"> +</video> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/media.mp4 b/tests/auto/core/qwebengineurlrequestinterceptor/resources/media.mp4 Binary files differnew file mode 100644 index 000000000..1431e98dd --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/media.mp4 diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/media_in_iframe.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/media_in_iframe.html new file mode 100644 index 000000000..39e9bd9bb --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/media_in_iframe.html @@ -0,0 +1,5 @@ +<html> +<body> +<iframe src="media.html"></iframe> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/resource.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/resource.html new file mode 100644 index 000000000..040acee00 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/resource.html @@ -0,0 +1,9 @@ +<html> +<head> +<link rel='stylesheet' href='style.css' type='text/css' /> +<script src="script.js"></script> +</head> +<body> +<p>some text</p> +</body> +</html diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/resource_in_iframe.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/resource_in_iframe.html new file mode 100644 index 000000000..573182668 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/resource_in_iframe.html @@ -0,0 +1,5 @@ +<html> +<body> +<iframe src="resource.html"></iframe> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/script.js b/tests/auto/core/qwebengineurlrequestinterceptor/resources/script.js new file mode 100644 index 000000000..e6e0e8e7d --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/script.js @@ -0,0 +1,3 @@ +var request = new XMLHttpRequest(); +request.open('GET', 'test', /* async = */ false); +request.send(); diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/style.css b/tests/auto/core/qwebengineurlrequestinterceptor/resources/style.css new file mode 100644 index 000000000..5ed3811e2 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/style.css @@ -0,0 +1,7 @@ +@font-face { + font-family: fontawesome; + src: url(fontawesome.woff); +} +p { + font-family: fontawesome; +} diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp index 50a3e6ff6..23bf88417 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp @@ -28,6 +28,7 @@ #include "../../widgets/util.h" #include <QtTest/QtTest> +#include <QtWebEngineCore/qwebengineurlrequestinfo.h> #include <QtWebEngineCore/qwebengineurlrequestinterceptor.h> #include <QtWebEngineWidgets/qwebenginepage.h> #include <QtWebEngineWidgets/qwebengineprofile.h> @@ -53,6 +54,11 @@ private Q_SLOTS: void requestedUrl(); void setUrlSameUrl(); void firstPartyUrl(); + void firstPartyUrlNestedIframes_data(); + void firstPartyUrlNestedIframes(); + void requestInterceptorByResourceType_data(); + void requestInterceptorByResourceType(); + void firstPartyUrlHttp(); }; tst_QWebEngineUrlRequestInterceptor::tst_QWebEngineUrlRequestInterceptor() @@ -79,11 +85,22 @@ void tst_QWebEngineUrlRequestInterceptor::cleanupTestCase() { } +struct RequestInfo { + RequestInfo(QWebEngineUrlRequestInfo &info) + : requestUrl(info.requestUrl()) + , firstPartyUrl(info.firstPartyUrl()) + , resourceType(info.resourceType()) + {} + + QUrl requestUrl; + QUrl firstPartyUrl; + int resourceType; +}; + class TestRequestInterceptor : public QWebEngineUrlRequestInterceptor { public: - QList<QUrl> observedUrls; - QList<QUrl> firstPartyUrls; + QList<RequestInfo> requestInfos; bool shouldIntercept; void interceptRequest(QWebEngineUrlRequestInfo &info) override @@ -95,9 +112,51 @@ public: if (shouldIntercept && info.requestUrl().toString().endsWith(QLatin1String("__placeholder__"))) info.redirect(QUrl("qrc:///resources/content.html")); - observedUrls.append(info.requestUrl()); - firstPartyUrls.append(info.firstPartyUrl()); + requestInfos.append(info); + } + + bool shouldSkipRequest(const RequestInfo &requestInfo) + { + if (requestInfo.resourceType == QWebEngineUrlRequestInfo::ResourceTypeMainFrame || + requestInfo.resourceType == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) + return false; + + // Skip import documents and sandboxed documents. + // See Document::SiteForCookies() in chromium/third_party/blink/renderer/core/dom/document.cc. + // + // TODO: Change this to empty URL during the next chromium update: + // https://chromium-review.googlesource.com/c/chromium/src/+/1213082/ + return requestInfo.firstPartyUrl == QUrl("data:,"); + } + + QList<RequestInfo> getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceType type) + { + QList<RequestInfo> infos; + + foreach (auto requestInfo, requestInfos) { + if (shouldSkipRequest(requestInfo)) + continue; + + if (type == requestInfo.resourceType) + infos.append(requestInfo); + } + + return infos; + } + + bool hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceType type) + { + foreach (auto requestInfo, requestInfos) { + if (shouldSkipRequest(requestInfo)) + continue; + + if (type == requestInfo.resourceType) + return true; + } + + return false; } + TestRequestInterceptor(bool intercept) : shouldIntercept(intercept) { @@ -135,7 +194,7 @@ void tst_QWebEngineUrlRequestInterceptor::interceptRequest() // The redirection for __placeholder__ should succeed. QVERIFY(success.toBool()); loadSpy.clear(); - QCOMPARE(interceptor.observedUrls.count(), 4); + QCOMPARE(interceptor.requestInfos.count(), 4); // Make sure that registering an observer does not modify the request. TestRequestInterceptor observer(/* intercept */ false); @@ -145,7 +204,7 @@ void tst_QWebEngineUrlRequestInterceptor::interceptRequest() success = loadSpy.takeFirst().takeFirst(); // Since we do not intercept, loading an invalid path should not succeed. QVERIFY(!success.toBool()); - QCOMPARE(observer.observedUrls.count(), 1); + QCOMPARE(observer.requestInfos.count(), 1); } class LocalhostContentProvider : public QWebEngineUrlRequestInterceptor @@ -203,19 +262,19 @@ void tst_QWebEngineUrlRequestInterceptor::requestedUrl() page.setUrl(QUrl("qrc:///resources/__placeholder__")); QVERIFY(spy.wait()); QTRY_COMPARE(spy.count(), 1); - QCOMPARE(interceptor.observedUrls.at(0), QUrl("qrc:///resources/content.html")); + QCOMPARE(interceptor.requestInfos.at(0).requestUrl, QUrl("qrc:///resources/content.html")); QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__")); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); page.setUrl(QUrl("qrc:/non-existent.html")); QTRY_COMPARE(spy.count(), 2); - QCOMPARE(interceptor.observedUrls.at(2), QUrl("qrc:/non-existent.html")); + QCOMPARE(interceptor.requestInfos.at(2).requestUrl, QUrl("qrc:/non-existent.html")); QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__")); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); page.setUrl(QUrl("http://abcdef.abcdef")); QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 3, 12000); - QCOMPARE(interceptor.observedUrls.at(3), QUrl("http://abcdef.abcdef/")); + QCOMPARE(interceptor.requestInfos.at(3).requestUrl, QUrl("http://abcdef.abcdef/")); QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__")); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); } @@ -262,12 +321,171 @@ void tst_QWebEngineUrlRequestInterceptor::firstPartyUrl() page.setUrl(QUrl("qrc:///resources/firstparty.html")); QVERIFY(spy.wait()); - QCOMPARE(interceptor.observedUrls.at(0), QUrl("qrc:///resources/firstparty.html")); - QCOMPARE(interceptor.observedUrls.at(1), QUrl("qrc:///resources/content.html")); - QCOMPARE(interceptor.firstPartyUrls.at(0), QUrl("qrc:///resources/firstparty.html")); - QCOMPARE(interceptor.firstPartyUrls.at(1), QUrl("qrc:///resources/firstparty.html")); + QCOMPARE(interceptor.requestInfos.at(0).requestUrl, QUrl("qrc:///resources/firstparty.html")); + QCOMPARE(interceptor.requestInfos.at(1).requestUrl, QUrl("qrc:///resources/content.html")); + QCOMPARE(interceptor.requestInfos.at(0).firstPartyUrl, QUrl("qrc:///resources/firstparty.html")); + QCOMPARE(interceptor.requestInfos.at(1).firstPartyUrl, QUrl("qrc:///resources/firstparty.html")); QCOMPARE(spy.count(), 1); } +void tst_QWebEngineUrlRequestInterceptor::firstPartyUrlNestedIframes_data() +{ + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/iframe.html")); + + QTest::addColumn<QUrl>("requestUrl"); + QTest::newRow("file") << url; + QTest::newRow("qrc") << QUrl("qrc:///resources/iframe.html"); +} + +void tst_QWebEngineUrlRequestInterceptor::firstPartyUrlNestedIframes() +{ + QFETCH(QUrl, requestUrl); + + if (requestUrl.scheme() == "file" && !QDir(TESTS_SOURCE_DIR).exists()) + W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); + + QString adjustedUrl = requestUrl.adjusted(QUrl::RemoveFilename).toString(); + + QWebEngineProfile profile; + TestRequestInterceptor interceptor(/* intercept */ false); + profile.setRequestInterceptor(&interceptor); + + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + page.setUrl(requestUrl); + QTRY_COMPARE(loadSpy.count(), 1); + + RequestInfo info = interceptor.requestInfos.at(0); + QCOMPARE(info.requestUrl, requestUrl); + QCOMPARE(info.firstPartyUrl, requestUrl); + QCOMPARE(info.resourceType, QWebEngineUrlRequestInfo::ResourceTypeMainFrame); + + info = interceptor.requestInfos.at(1); + QCOMPARE(info.requestUrl, QUrl(adjustedUrl + "iframe2.html")); + QCOMPARE(info.firstPartyUrl, requestUrl); + QCOMPARE(info.resourceType, QWebEngineUrlRequestInfo::ResourceTypeSubFrame); + + info = interceptor.requestInfos.at(2); + QCOMPARE(info.requestUrl, QUrl(adjustedUrl + "iframe3.html")); + QCOMPARE(info.firstPartyUrl, requestUrl); + QCOMPARE(info.resourceType, QWebEngineUrlRequestInfo::ResourceTypeSubFrame); +} + +void tst_QWebEngineUrlRequestInterceptor::requestInterceptorByResourceType_data() +{ + QUrl firstPartyUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/resource_in_iframe.html")); + QUrl styleRequestUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/style.css")); + QUrl scriptRequestUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/script.js")); + QUrl fontRequestUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/fontawesome.woff")); + QUrl xhrRequestUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/test")); + QUrl imageFirstPartyUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/image_in_iframe.html")); + QUrl imageRequestUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/icons/favicon.png")); + QUrl mediaFirstPartyUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/media_in_iframe.html")); + QUrl mediaRequestUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/media.mp4")); + QUrl faviconFirstPartyUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/favicon.html")); + QUrl faviconRequestUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebengineurlrequestinterceptor/resources/icons/favicon.png")); + + QTest::addColumn<QUrl>("requestUrl"); + QTest::addColumn<QUrl>("firstPartyUrl"); + QTest::addColumn<int>("resourceType"); + + QTest::newRow("StyleSheet") << styleRequestUrl << firstPartyUrl << static_cast<int>(QWebEngineUrlRequestInfo::ResourceTypeStylesheet); + QTest::newRow("Script") << scriptRequestUrl << firstPartyUrl << static_cast<int>(QWebEngineUrlRequestInfo::ResourceTypeScript); + QTest::newRow("Image") << imageRequestUrl << imageFirstPartyUrl << static_cast<int>(QWebEngineUrlRequestInfo::ResourceTypeImage); + QTest::newRow("FontResource") << fontRequestUrl << firstPartyUrl << static_cast<int>(QWebEngineUrlRequestInfo::ResourceTypeFontResource); + QTest::newRow("Media") << mediaRequestUrl << mediaFirstPartyUrl << static_cast<int>(QWebEngineUrlRequestInfo::ResourceTypeMedia); + QTest::newRow("Favicon") << faviconRequestUrl << faviconFirstPartyUrl << static_cast<int>(QWebEngineUrlRequestInfo::ResourceTypeFavicon); + QTest::newRow("Xhr") << xhrRequestUrl << firstPartyUrl << static_cast<int>(QWebEngineUrlRequestInfo::ResourceTypeXhr); +} + +void tst_QWebEngineUrlRequestInterceptor::requestInterceptorByResourceType() +{ + if (!QDir(TESTS_SOURCE_DIR).exists()) + W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); + + QFETCH(QUrl, requestUrl); + QFETCH(QUrl, firstPartyUrl); + QFETCH(int, resourceType); + + QWebEngineProfile profile; + TestRequestInterceptor interceptor(/* intercept */ false); + profile.setRequestInterceptor(&interceptor); + + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + page.setUrl(firstPartyUrl); + QTRY_COMPARE(loadSpy.count(), 1); + + QTRY_COMPARE(interceptor.getUrlRequestForType(static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType)).count(), 1); + QList<RequestInfo> infos = interceptor.getUrlRequestForType(static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType)); + QCOMPARE(infos.at(0).requestUrl, requestUrl); + QCOMPARE(infos.at(0).firstPartyUrl, firstPartyUrl); + QCOMPARE(infos.at(0).resourceType, resourceType); +} + +void tst_QWebEngineUrlRequestInterceptor::firstPartyUrlHttp() +{ + QWebEngineProfile profile; + TestRequestInterceptor interceptor(/* intercept */ false); + profile.setRequestInterceptor(&interceptor); + + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + QUrl firstPartyUrl = QUrl("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_video"); + page.setUrl(QUrl(firstPartyUrl)); + if (!loadSpy.wait(15000) || !loadSpy.at(0).at(0).toBool()) + QSKIP("Couldn't load page from network, skipping test."); + + QList<RequestInfo> infos; + + // SubFrame + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeSubFrame)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeSubFrame); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + // Stylesheet + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeStylesheet)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeStylesheet); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + // Script + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeScript)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeScript); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + // Image + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeImage)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeImage); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + // FontResource + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFontResource)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFontResource); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + // Media + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeMedia)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeMedia); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + // Favicon + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFavicon)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFavicon); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + // XMLHttpRequest + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeXhr)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeXhr); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); +} + QTEST_MAIN(tst_QWebEngineUrlRequestInterceptor) #include "tst_qwebengineurlrequestinterceptor.moc" diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc index ca045e7fc..13dbb134e 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc @@ -1,7 +1,22 @@ <!DOCTYPE RCC><RCC version="1.0"> -<qresource> - <file>resources/index.html</file> - <file>resources/content.html</file> - <file>resources/firstparty.html</file> -</qresource> + <qresource prefix="/"> + <file>resources/content.html</file> + <file>resources/favicon.html</file> + <file>resources/firstparty.html</file> + <file>resources/fontawesome.woff</file> + <file>resources/iframe.html</file> + <file>resources/iframe2.html</file> + <file>resources/iframe3.html</file> + <file>resources/image.html</file> + <file>resources/image_in_iframe.html</file> + <file>resources/index.html</file> + <file>resources/media.html</file> + <file>resources/media.mp4</file> + <file>resources/media_in_iframe.html</file> + <file>resources/resource.html</file> + <file>resources/resource_in_iframe.html</file> + <file>resources/script.js</file> + <file>resources/style.css</file> + <file>resources/icons/favicon.png</file> + </qresource> </RCC> diff --git a/tests/auto/core/tests.pri b/tests/auto/core/tests.pri index 885cf60d4..59d6c0865 100644 --- a/tests/auto/core/tests.pri +++ b/tests/auto/core/tests.pri @@ -12,4 +12,6 @@ exists($$_PRO_FILE_PWD_/$${TARGET}.qrc): RESOURCES += $${TARGET}.qrc QT += testlib network webenginewidgets widgets +# This define is used by some tests to look up resources in the source tree +DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\" include(../embed_info_plist.pri) diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 29df3444c..40a3bff5e 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -484,8 +484,8 @@ struct InputMethodInfo , selectedText(selectedText) {} - const int cursorPosition; - const int anchorPosition; + int cursorPosition; + int anchorPosition; QString surroundingText; QString selectedText; }; |