diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml
index be1e42c733472dfc9dfb37ca9892da4ac993aa5d..15a8d96fe5ced3912db803252cd070fa8ff9982f 100644
--- a/examples/webengine/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml
@@ -445,6 +445,11 @@ ApplicationWindow {
                         request.reject();
                 }
 
+                onRegisterProtocolHandlerPermissionRequested: {
+                    print("accepting registerProtocolHandler permission request for " + request.protocol + " from " + request.origin);
+                    request.accept();
+                }
+
                 onRenderProcessTerminated: {
                     var status = "";
                     switch (terminationStatus) {
diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp
index 903956419d911058fb4cb24e17c506ad74f01f46..ef55fd33d2a0cdc53bfc6bae437c5a01eb2298ba 100644
--- a/examples/webenginewidgets/simplebrowser/webpage.cpp
+++ b/examples/webenginewidgets/simplebrowser/webpage.cpp
@@ -63,6 +63,7 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
 {
     connect(this, &QWebEnginePage::authenticationRequired, this, &WebPage::handleAuthenticationRequired);
     connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, &WebPage::handleProxyAuthenticationRequired);
+    connect(this, &QWebEnginePage::registerProtocolHandlerPermissionRequested, this, &WebPage::handleRegisterProtocolHandlerPermissionRequested);
 }
 
 bool WebPage::certificateError(const QWebEngineCertificateError &error)
@@ -141,3 +142,19 @@ void WebPage::handleProxyAuthenticationRequired(const QUrl &, QAuthenticator *au
         *auth = QAuthenticator();
     }
 }
+
+//! [registerProtocolHandlerPermissionRequested]
+void WebPage::handleRegisterProtocolHandlerPermissionRequested(QWebEngineRegisterProtocolHandlerPermissionRequest request)
+{
+    auto answer = QMessageBox::question(
+        view()->window(),
+        tr("Permission Request"),
+        tr("Allow %1 to open all %2 links?")
+        .arg(request.origin().host())
+        .arg(request.protocol()));
+    if (answer == QMessageBox::Yes)
+        request.accept();
+    else
+        request.reject();
+}
+//! [registerProtocolHandlerPermissionRequested]
diff --git a/examples/webenginewidgets/simplebrowser/webpage.h b/examples/webenginewidgets/simplebrowser/webpage.h
index 797943249992743d13d1aa4bb12be81f7a8595a4..d44c79358bae722c5946f7231223013917efb564 100644
--- a/examples/webenginewidgets/simplebrowser/webpage.h
+++ b/examples/webenginewidgets/simplebrowser/webpage.h
@@ -52,6 +52,7 @@
 #define WEBPAGE_H
 
 #include <QWebEnginePage>
+#include <QWebEngineRegisterProtocolHandlerPermissionRequest>
 
 class WebPage : public QWebEnginePage
 {
@@ -66,6 +67,7 @@ protected:
 private slots:
     void handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth);
     void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth, const QString &proxyHost);
+    void handleRegisterProtocolHandlerPermissionRequested(QWebEngineRegisterProtocolHandlerPermissionRequest request);
 };
 
 #endif // WEBPAGE_H
diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri
index 1b2f2edb16816dcfe902b7fc0fec96629a6e90c0..e62ffdbfbaf9c9f3a6df9bb4eac4117446b32cc0 100644
--- a/src/core/core_chromium.pri
+++ b/src/core/core_chromium.pri
@@ -79,6 +79,7 @@ SOURCES = \
         qrc_protocol_handler_qt.cpp \
         quota_permission_context_qt.cpp \
         quota_permission_controller_impl.cpp \
+        register_protocol_handler_permission_controller_impl.cpp \
         render_view_context_menu_qt.cpp \
         render_view_observer_host_qt.cpp \
         render_widget_host_view_qt.cpp \
@@ -163,6 +164,8 @@ HEADERS = \
         quota_permission_context_qt.h \
         quota_permission_controller.h \
         quota_permission_controller_impl.h \
+        register_protocol_handler_permission_controller.h \
+        register_protocol_handler_permission_controller_impl.h \
         render_view_context_menu_qt.h \
         render_view_observer_host_qt.h \
         render_widget_host_view_qt.h \
diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni
index 6d17838a64af16080988e1584addbc59ba5f243b..bdedf11d39ab3e4f78291dfa1b5e2397f17daa56 100644
--- a/src/core/qtwebengine_sources.gni
+++ b/src/core/qtwebengine_sources.gni
@@ -43,6 +43,12 @@ source_set("qtwebengine_sources") {
       "//extensions/features:features",
   ]
   sources = [
+    "//chrome/common/custom_handlers/protocol_handler.cc",
+    "//chrome/common/custom_handlers/protocol_handler.h",
+    "//chrome/browser/custom_handlers/protocol_handler_registry.cc",
+    "//chrome/browser/custom_handlers/protocol_handler_registry.h",
+    "//chrome/browser/custom_handlers/protocol_handler_registry_factory.cc",
+    "//chrome/browser/custom_handlers/protocol_handler_registry_factory.h",
     "//chrome/browser/media/webrtc/desktop_media_list.h",
     "//chrome/browser/media/webrtc/desktop_streams_registry.cc",
     "//chrome/browser/media/webrtc/desktop_streams_registry.h",
diff --git a/src/core/register_protocol_handler_permission_controller.h b/src/core/register_protocol_handler_permission_controller.h
new file mode 100644
index 0000000000000000000000000000000000000000..54e16f56993eda308e808aa0b52bd948a2845ceb
--- /dev/null
+++ b/src/core/register_protocol_handler_permission_controller.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REGISTER_PROTOCOL_HANDLER_PERMISSION_CONTROLLER_H
+#define REGISTER_PROTOCOL_HANDLER_PERMISSION_CONTROLLER_H
+
+#include "permission_controller.h"
+
+namespace QtWebEngineCore {
+
+class QWEBENGINE_EXPORT RegisterProtocolHandlerPermissionController : public PermissionController {
+public:
+    RegisterProtocolHandlerPermissionController(QUrl origin, QString protocol)
+        : PermissionController(std::move(origin))
+        , m_protocol(std::move(protocol))
+    {}
+
+    QString protocol() const { return m_protocol; }
+
+private:
+    QString m_protocol;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // REGISTER_PROTOCOL_HANDLER_PERMISSION_CONTROLLER_H
diff --git a/src/core/register_protocol_handler_permission_controller_impl.cpp b/src/core/register_protocol_handler_permission_controller_impl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..96f2edb87e61de1d60314d4f54efc3ab55f3c8f6
--- /dev/null
+++ b/src/core/register_protocol_handler_permission_controller_impl.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "register_protocol_handler_permission_controller_impl.h"
+
+#include "type_conversion.h"
+
+namespace QtWebEngineCore {
+
+RegisterProtocolHandlerPermissionControllerImpl::RegisterProtocolHandlerPermissionControllerImpl(
+    ProtocolHandlerRegistry *registry,
+    ProtocolHandler handler)
+    : RegisterProtocolHandlerPermissionController(
+        toQt(handler.url()),
+        toQt(handler.protocol()))
+    , m_registry(registry)
+    , m_handler(handler)
+{}
+
+void RegisterProtocolHandlerPermissionControllerImpl::accepted()
+{
+    m_registry->OnAcceptRegisterProtocolHandler(m_handler);
+}
+
+void RegisterProtocolHandlerPermissionControllerImpl::rejected()
+{
+    m_registry->OnIgnoreRegisterProtocolHandler(m_handler);
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/register_protocol_handler_permission_controller_impl.h b/src/core/register_protocol_handler_permission_controller_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..57a094fd940714b7c142cf46cb2f4a7a5b65cefb
--- /dev/null
+++ b/src/core/register_protocol_handler_permission_controller_impl.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REGISTER_PROTOCOL_HANDLER_PERMISSION_CONTROLLER_IMPL_H
+#define REGISTER_PROTOCOL_HANDLER_PERMISSION_CONTROLLER_IMPL_H
+
+#include "register_protocol_handler_permission_controller.h"
+
+#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
+#include "chrome/common/custom_handlers/protocol_handler.h"
+
+class ProtocolHandlerRegistry;
+
+namespace QtWebEngineCore {
+
+class RegisterProtocolHandlerPermissionControllerImpl final : public RegisterProtocolHandlerPermissionController {
+public:
+    RegisterProtocolHandlerPermissionControllerImpl(
+        ProtocolHandlerRegistry *registry,
+        ProtocolHandler handler);
+
+protected:
+    void accepted() override;
+    void rejected() override;
+
+private:
+    ProtocolHandlerRegistry *m_registry;
+    ProtocolHandler m_handler;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // REGISTER_PROTOCOL_HANDLER_PERMISSION_CONTROLLER_IMPL_H
diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp
index fd0f247353f81dafbc5a0ab76ea302ccc2b1a631..2622cb09e8f91424e2f1103d032be1aaa367c52a 100644
--- a/src/core/url_request_context_getter_qt.cpp
+++ b/src/core/url_request_context_getter_qt.cpp
@@ -44,6 +44,7 @@
 #include "base/strings/string_util.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
 #include "content/network/proxy_service_mojo.h"
 #include "content/public/browser/browser_thread.h"
@@ -81,6 +82,7 @@
 
 #include "api/qwebengineurlschemehandler.h"
 #include "browser_context_adapter.h"
+#include "browser_context_qt.h"
 #include "custom_protocol_handler.h"
 #include "cookie_monster_delegate_qt.h"
 #include "content_client_qt.h"
@@ -111,6 +113,14 @@ URLRequestContextGetterQt::URLRequestContextGetterQt(QSharedPointer<BrowserConte
 {
     std::swap(m_protocolHandlers, *protocolHandlers);
 
+    // The ProtocolHandlerRegistry and it's JobInterceptorFactory need to be
+    // created on the UI thread:
+    ProtocolHandlerRegistry* protocolHandlerRegistry =
+        ProtocolHandlerRegistryFactory::GetForBrowserContext(browserContext->browserContext());
+    DCHECK(protocolHandlerRegistry);
+    m_protocolHandlerInterceptor =
+        protocolHandlerRegistry->CreateJobInterceptorFactory();
+
     QMutexLocker lock(&m_mutex);
     m_cookieDelegate->setClient(browserContext->cookieStore());
     setFullConfiguration(browserContext);
@@ -583,6 +593,11 @@ void URLRequestContextGetterQt::generateJobFactory()
 
     m_requestInterceptors.clear();
 
+    if (m_protocolHandlerInterceptor) {
+        m_protocolHandlerInterceptor->Chain(std::move(topJobFactory));
+        topJobFactory = std::move(m_protocolHandlerInterceptor);
+    }
+
     m_jobFactory = std::move(topJobFactory);
 
     m_urlRequestContext->set_job_factory(m_jobFactory.get());
diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h
index 4a97a139897aefc51bfccb346c39aa42e22bef7a..fd80d62c2fe522e4561cc46a5487fed008f4f6d1 100644
--- a/src/core/url_request_context_getter_qt.h
+++ b/src/core/url_request_context_getter_qt.h
@@ -45,6 +45,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
+#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/url_constants.h"
@@ -120,6 +121,7 @@ private:
     std::unique_ptr<NetworkDelegateQt> m_networkDelegate;
     std::unique_ptr<net::URLRequestContextStorage> m_storage;
     std::unique_ptr<net::URLRequestJobFactory> m_jobFactory;
+    std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> m_protocolHandlerInterceptor;
     net::URLRequestJobFactoryImpl *m_baseJobFactory;
     std::unique_ptr<net::DhcpProxyScriptFetcherFactory> m_dhcpProxyScriptFetcherFactory;
     scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate;
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index dfb2dddcc46856d54a2455d6b7b6f4a48051a219..495be3d843a3d6705b668119baea27befb2a03a7 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -65,6 +65,7 @@ class ColorChooserController;
 class FilePickerController;
 class JavaScriptDialogController;
 class QuotaPermissionController;
+class RegisterProtocolHandlerPermissionController;
 class RenderWidgetHostViewQt;
 class RenderWidgetHostViewQtDelegate;
 class RenderWidgetHostViewQtDelegateClient;
@@ -437,6 +438,7 @@ public:
     virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) = 0;
     virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0;
     virtual void runQuotaPermissionRequest(QSharedPointer<QuotaPermissionController>) = 0;
+    virtual void runRegisterProtocolHandlerPermissionRequest(QSharedPointer<RegisterProtocolHandlerPermissionController>) = 0;
     virtual WebEngineSettings *webEngineSettings() const = 0;
     virtual void showValidationMessage(const QRect &anchor, const QString &mainText, const QString &subText) = 0;
     virtual void hideValidationMessage() = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 09cca943ef3fdb9f2d1d583daeddf58a136ca990..3d2337884aea6bb25505e1fed6ecbe945bd5a1aa 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -58,9 +58,12 @@
 #include "web_contents_adapter_p.h"
 #include "web_engine_context.h"
 #include "web_engine_settings.h"
+#include "register_protocol_handler_permission_controller_impl.h"
 
+#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "components/web_cache/browser/web_cache_manager.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/invalidate_type.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
@@ -608,6 +611,39 @@ bool WebContentsDelegateQt::CheckMediaAccessPermission(content::WebContents *web
     }
 }
 
+void WebContentsDelegateQt::RegisterProtocolHandler(content::WebContents *webContents, const std::string &protocol, const GURL &url, bool)
+{
+    content::BrowserContext *context = webContents->GetBrowserContext();
+    if (context->IsOffTheRecord())
+        return;
+
+    ProtocolHandler handler =
+        ProtocolHandler::CreateProtocolHandler(protocol, url);
+
+    ProtocolHandlerRegistry *registry =
+        ProtocolHandlerRegistryFactory::GetForBrowserContext(context);
+    if (registry->SilentlyHandleRegisterHandlerRequest(handler))
+        return;
+
+    QSharedPointer<RegisterProtocolHandlerPermissionController> controller(
+        new RegisterProtocolHandlerPermissionControllerImpl(registry, handler));
+    m_viewClient->runRegisterProtocolHandlerPermissionRequest(std::move(controller));
+}
+
+void WebContentsDelegateQt::UnregisterProtocolHandler(content::WebContents *webContents, const std::string &protocol, const GURL &url, bool)
+{
+    content::BrowserContext* context = webContents->GetBrowserContext();
+    if (context->IsOffTheRecord())
+        return;
+
+    ProtocolHandler handler =
+        ProtocolHandler::CreateProtocolHandler(protocol, url);
+
+    ProtocolHandlerRegistry* registry =
+        ProtocolHandlerRegistryFactory::GetForBrowserContext(context);
+    registry->RemoveHandler(handler);
+}
+
 FaviconManager *WebContentsDelegateQt::faviconManager()
 {
     return m_faviconManager.data();
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 8a3331163c87fe28b0bf88c5fb53bd2215e6b6be..e649ca727ea805951500c2092d13994f69c717e3 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -128,6 +128,8 @@ public:
     void MoveValidationMessage(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view) override;
     void BeforeUnloadFired(content::WebContents* tab, bool proceed, bool* proceed_to_fire_unload) override;
     bool CheckMediaAccessPermission(content::WebContents *web_contents, const GURL& security_origin, content::MediaStreamType type) override;
+    void RegisterProtocolHandler(content::WebContents* web_contents, const std::string& protocol, const GURL& url, bool user_gesture) override;
+    void UnregisterProtocolHandler(content::WebContents* web_contents, const std::string& protocol, const GURL& url, bool user_gesture) override;
 
     // WebContentsObserver overrides
     void RenderFrameDeleted(content::RenderFrameHost *render_frame_host) override;
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 617b999da4023e2e71d7f306920ab06887cd5e20..91ae20481912825a73e4ad5938eadefab3896489 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -46,6 +46,7 @@
 #include "file_picker_controller.h"
 #include "javascript_dialog_controller.h"
 #include "quota_permission_controller.h"
+#include "register_protocol_handler_permission_controller.h"
 #include "qquickwebenginehistory_p.h"
 #include "qquickwebenginecertificateerror_p.h"
 #include "qquickwebenginecontextmenurequest_p.h"
@@ -599,6 +600,13 @@ void QQuickWebEngineViewPrivate::runQuotaPermissionRequest(QSharedPointer<QtWebE
     Q_EMIT q->quotaPermissionRequested(request);
 }
 
+void QQuickWebEngineViewPrivate::runRegisterProtocolHandlerPermissionRequest(QSharedPointer<RegisterProtocolHandlerPermissionController> controller)
+{
+    Q_Q(QQuickWebEngineView);
+    QQuickWebEngineRegisterProtocolHandlerPermissionRequest request(std::move(controller));
+    Q_EMIT q->registerProtocolHandlerPermissionRequested(request);
+}
+
 QObject *QQuickWebEngineViewPrivate::accessibilityParentObject()
 {
     Q_Q(QQuickWebEngineView);
@@ -1828,6 +1836,31 @@ qint64 QQuickWebEngineQuotaPermissionRequest::requestedSize() const
     return d_ptr->requestedSize();
 }
 
+QQuickWebEngineRegisterProtocolHandlerPermissionRequest::QQuickWebEngineRegisterProtocolHandlerPermissionRequest(
+    QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController> d_ptr)
+    : d_ptr(std::move(d_ptr))
+{}
+
+void QQuickWebEngineRegisterProtocolHandlerPermissionRequest::accept()
+{
+    d_ptr->accept();
+}
+
+void QQuickWebEngineRegisterProtocolHandlerPermissionRequest::reject()
+{
+    d_ptr->reject();
+}
+
+QUrl QQuickWebEngineRegisterProtocolHandlerPermissionRequest::origin() const
+{
+    return d_ptr->origin();
+}
+
+QString QQuickWebEngineRegisterProtocolHandlerPermissionRequest::protocol() const
+{
+    return d_ptr->protocol();
+}
+
 QQuickContextMenuBuilder::QQuickContextMenuBuilder(const QtWebEngineCore::WebEngineContextMenuData &data,
                                                    QQuickWebEngineView *view,
                                                    QObject *menu)
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index 8bda609c0d7ad9b08552d77917fe4de07598baef..5b018b8a847e513ee213f7cf6d6fe4b862193770 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -59,6 +59,7 @@
 
 namespace QtWebEngineCore {
     class QuotaPermissionController;
+    class RegisterProtocolHandlerPermissionController;
 }
 
 
@@ -123,6 +124,24 @@ private:
     QSharedPointer<QtWebEngineCore::QuotaPermissionController> d_ptr;
 };
 
+class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineRegisterProtocolHandlerPermissionRequest {
+    Q_GADGET
+    Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL)
+    Q_PROPERTY(QString protocol READ protocol CONSTANT FINAL)
+public:
+    QQuickWebEngineRegisterProtocolHandlerPermissionRequest() {}
+    QQuickWebEngineRegisterProtocolHandlerPermissionRequest(
+        QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController>);
+
+    Q_INVOKABLE void accept();
+    Q_INVOKABLE void reject();
+    QUrl origin() const;
+    QString protocol() const;
+
+private:
+    QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController> d_ptr;
+};
+
 #define LATEST_WEBENGINEVIEW_REVISION 7
 
 class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
@@ -567,6 +586,7 @@ Q_SIGNALS:
     Q_REVISION(7) void geometryChangeRequested(const QRect &geometry, const QRect &frameGeometry);
     Q_REVISION(7) void inspectedViewChanged();
     Q_REVISION(7) void devToolsViewChanged();
+    Q_REVISION(7) void registerProtocolHandlerPermissionRequested(const QQuickWebEngineRegisterProtocolHandlerPermissionRequest &request);
 
 #ifdef ENABLE_QML_TESTSUPPORT_API
     void testSupportChanged();
@@ -597,5 +617,6 @@ QT_END_NAMESPACE
 QML_DECLARE_TYPE(QQuickWebEngineView)
 Q_DECLARE_METATYPE(QQuickWebEngineFullScreenRequest)
 Q_DECLARE_METATYPE(QQuickWebEngineQuotaPermissionRequest)
+Q_DECLARE_METATYPE(QQuickWebEngineRegisterProtocolHandlerPermissionRequest)
 
 #endif // QQUICKWEBENGINEVIEW_P_H
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index cfe99a0d4a2c15b5b76a2b7adcb80b88cc54a6cf..1b718a3daeab09e1cbd691a04bbdd0dde8b59373 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -132,6 +132,7 @@ public:
     void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) override;
     void runMouseLockPermissionRequest(const QUrl &securityOrigin) override;
     void runQuotaPermissionRequest(QSharedPointer<QtWebEngineCore::QuotaPermissionController>) override;
+    void runRegisterProtocolHandlerPermissionRequest(QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController>) override;
     QObject *accessibilityParentObject() override;
     QtWebEngineCore::WebEngineSettings *webEngineSettings() const override;
     void allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) override;
diff --git a/src/webengine/doc/src/external-resources.qdoc b/src/webengine/doc/src/external-resources.qdoc
index c2faaa8d41e61a600edd4979db182197fd558798..7ff6eea6b224b77df0bf62ca7a4f134fdea21912 100644
--- a/src/webengine/doc/src/external-resources.qdoc
+++ b/src/webengine/doc/src/external-resources.qdoc
@@ -141,3 +141,8 @@
     \externalpage https://wiki.greasespot.net/Metadata_Block#.40name
     \title Metadata Block
 */
+
+/*!
+    \externalpage https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler
+    \title registerProtocolHandler
+*/
diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc
index c6985b0822218d9c8f63c9c53e1165a6a88677e9..104397bf775cb7455540f73b9eafe230eb225cc7 100644
--- a/src/webengine/doc/src/webengineview_lgpl.qdoc
+++ b/src/webengine/doc/src/webengineview_lgpl.qdoc
@@ -1356,6 +1356,55 @@
     Rejects a quota permission request.
 */
 
+/*!
+    \qmlsignal WebEngineView::registerProtocolHandlerPermissionRequested(RegisterProtocolHandlerPermissionRequest request)
+    \since QtWebEngine 1.7
+
+    This signal is emitted when the web page tries to register a custom protocol
+    using the \l registerProtocolHandler API.
+
+    \sa RegisterProtocolHandlerPermissionRequest
+*/
+
+/*!
+    \qmltype RegisterProtocolHandlerPermissionRequest
+    \instantiates QQuickWebEngineRegisterProtocolHandlerPermissionRequest
+    \inqmlmodule QtWebEngine
+    \since QtWebEngine 1.7
+    \brief The RegisterProtocolHandlerPermissionRequest type enables accepting
+    or rejecting requests from the \l registerProtocolHandler API.
+
+    \sa WebEngineView::registerProtocolHandlerPermissionRequested()
+*/
+
+/*!
+    \qmlproperty url RegisterProtocolHandlerPermissionRequest::origin
+    \brief The URL template for the protocol handler.
+
+    This is the second parameter from the \l registerProtocolHandler call.
+*/
+
+/*!
+    \qmlproperty string RegisterProtocolHandlerPermissionRequest::protocol
+    \brief The URL scheme for the protocol handler.
+
+    This is the first parameter from the \l registerProtocolHandler call.
+*/
+
+/*!
+    \qmlmethod void RegisterProtocolHandlerPermissionRequest::accept()
+    \brief Accepts the request.
+
+    Subsequent calls to accept() and reject() are ignored.
+*/
+
+/*!
+    \qmlmethod void RegisterProtocolHandlerPermissionRequest::reject()
+    \brief Accepts the request.
+
+    Subsequent calls to accept() and reject() are ignored.
+*/
+
 /*!
     \qmlsignal WebEngineView::geometryChangeRequested(rect geometry, rect frameGeometry)
     \since QtWebEngine 1.7
diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp
index 5f9d16158b2c39a2937dd935a42aab1a98766433..a9f406d49050a7a79e7a4867f1a9e011289b8772 100644
--- a/src/webengine/plugin/plugin.cpp
+++ b/src/webengine/plugin/plugin.cpp
@@ -139,6 +139,8 @@ public:
                                                                          msgUncreatableType("FormValidationMessageRequest"));
         qmlRegisterUncreatableType<QQuickWebEngineQuotaPermissionRequest>(uri, 1, 7, "QuotaPermissionRequest",
             tr("Cannot create a separate instance of QuotaPermissionRequest"));
+        qmlRegisterUncreatableType<QQuickWebEngineRegisterProtocolHandlerPermissionRequest>(uri, 1, 7, "RegisterProtocolHandlerPermissionRequest",
+            tr("Cannot create a separate instance of RegisterProtocolHandlerPermissionRequest"));
     }
 
 private:
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 67d55b20ff649c5bfba8a0256e877c078affdd5b..ec35ea6ce2df0a6b5f1009a04a61e7db4fbd8cb4 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -54,6 +54,7 @@
 #include "qwebengineprofile.h"
 #include "qwebengineprofile_p.h"
 #include "qwebenginequotapermissionrequest.h"
+#include "qwebengineregisterprotocolhandlerpermissionrequest.h"
 #include "qwebenginescriptcollection_p.h"
 #include "qwebenginesettings.h"
 #include "qwebengineview.h"
@@ -578,6 +579,13 @@ void QWebEnginePagePrivate::runQuotaPermissionRequest(QSharedPointer<QtWebEngine
     Q_EMIT q->quotaPermissionRequested(request);
 }
 
+void QWebEnginePagePrivate::runRegisterProtocolHandlerPermissionRequest(QSharedPointer<RegisterProtocolHandlerPermissionController> controller)
+{
+    Q_Q(QWebEnginePage);
+    QWebEngineRegisterProtocolHandlerPermissionRequest request(std::move(controller));
+    Q_EMIT q->registerProtocolHandlerPermissionRequested(request);
+}
+
 QObject *QWebEnginePagePrivate::accessibilityParentObject()
 {
     return view;
@@ -749,6 +757,18 @@ QWebEnginePage::QWebEnginePage(QObject* parent)
     The request object \a request can be used to accept or reject the request.
 */
 
+/*!
+    \fn QWebEnginePage::registerProtocolHandlerPermissionRequested(QWebEngineRegisterProtocolHandlerPermissionRequest request)
+    \since 5.11
+
+    This signal is emitted when the web page tries to register a custom protocol
+    using the \l registerProtocolHandler API.
+
+    The request object \a request can be used to accept or reject the request:
+
+    \snippet webenginewidgets/simplebrowser/webpage.cpp registerProtocolHandlerPermissionRequested
+*/
+
 /*!
     \fn void QWebEnginePage::pdfPrintingFinished(const QString &filePath, bool success)
     \since 5.9
diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h
index 7ce72258b4292cb505c2a537781d62a61005a4c6..d716765fe01e58cc14cd68829538e70f758d3ed7 100644
--- a/src/webenginewidgets/api/qwebenginepage.h
+++ b/src/webenginewidgets/api/qwebenginepage.h
@@ -66,6 +66,7 @@ class QWebEnginePage;
 class QWebEnginePagePrivate;
 class QWebEngineProfile;
 class QWebEngineQuotaPermissionRequest;
+class QWebEngineRegisterProtocolHandlerPermissionRequest;
 class QWebEngineScriptCollection;
 class QWebEngineSettings;
 
@@ -338,6 +339,7 @@ Q_SIGNALS:
     void featurePermissionRequestCanceled(const QUrl &securityOrigin, QWebEnginePage::Feature feature);
     void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest);
     void quotaPermissionRequested(QWebEngineQuotaPermissionRequest quotaPermissionRequest);
+    void registerProtocolHandlerPermissionRequested(QWebEngineRegisterProtocolHandlerPermissionRequest request);
 
     void authenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator);
     void proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator, const QString &proxyHost);
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index 301028e391f42d9349d6a592b202068c9ad4dec3..61092fa6aeb5a3777fd3abeca7fec8ed875dafbe 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -130,6 +130,7 @@ public:
     void runGeolocationPermissionRequest(const QUrl &securityOrigin) override;
     void runMouseLockPermissionRequest(const QUrl &securityOrigin) override;
     void runQuotaPermissionRequest(QSharedPointer<QtWebEngineCore::QuotaPermissionController>) override;
+    void runRegisterProtocolHandlerPermissionRequest(QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController>) override;
     QObject *accessibilityParentObject() override;
     QtWebEngineCore::WebEngineSettings *webEngineSettings() const override;
     void allowCertificateError(const QSharedPointer<CertificateErrorController> &controller) override;
diff --git a/src/webenginewidgets/api/qwebengineregisterprotocolhandlerpermissionrequest.cpp b/src/webenginewidgets/api/qwebengineregisterprotocolhandlerpermissionrequest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad1398daf992db415cafd0f2e3614ed985e5f890
--- /dev/null
+++ b/src/webenginewidgets/api/qwebengineregisterprotocolhandlerpermissionrequest.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwebengineregisterprotocolhandlerpermissionrequest.h"
+
+#include "register_protocol_handler_permission_controller.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class QWebEngineRegisterProtocolHandlerPermissionRequest
+    \inmodule QtWebEngineWidgets
+    \since 5.11
+    \brief The QWebEngineRegisterProtocolHandlerPermissionRequest type enables
+    accepting or rejecting requests from the \l registerProtocolHandler API.
+
+    \sa QWebEnginePage::registerProtocolHandlerPermissionRequested
+*/
+
+static void registerMetaTypes()
+{
+    qRegisterMetaType<QWebEngineRegisterProtocolHandlerPermissionRequest>();
+}
+
+Q_CONSTRUCTOR_FUNCTION(registerMetaTypes)
+
+/*! \fn QWebEngineRegisterProtocolHandlerPermissionRequest::QWebEngineRegisterProtocolHandlerPermissionRequest()
+    \internal
+*/
+
+/*! \internal */
+QWebEngineRegisterProtocolHandlerPermissionRequest::QWebEngineRegisterProtocolHandlerPermissionRequest(
+    QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController> d_ptr)
+    : d_ptr(std::move(d_ptr))
+{}
+
+/*!
+    Rejects the request.
+
+    Subsequent calls to accept() and reject() are ignored.
+*/
+void QWebEngineRegisterProtocolHandlerPermissionRequest::reject()
+{
+    d_ptr->reject();
+}
+
+/*!
+    Accepts the request
+
+    Subsequent calls to accept() and reject() are ignored.
+*/
+void QWebEngineRegisterProtocolHandlerPermissionRequest::accept()
+{
+    d_ptr->accept();
+}
+
+/*!
+    \property QWebEngineRegisterProtocolHandlerPermissionRequest::origin
+    \brief The URL template for the protocol handler.
+
+    This is the second parameter from the \l registerProtocolHandler call.
+*/
+QUrl QWebEngineRegisterProtocolHandlerPermissionRequest::origin() const
+{
+    return d_ptr->origin();
+}
+
+/*!
+    \property QWebEngineRegisterProtocolHandlerPermissionRequest::protocol
+    \brief The URL scheme for the protocol handler.
+
+    This is the first parameter from the \l registerProtocolHandler call.
+*/
+QString QWebEngineRegisterProtocolHandlerPermissionRequest::protocol() const
+{
+    return d_ptr->protocol();
+}
+
+QT_END_NAMESPACE
diff --git a/src/webenginewidgets/api/qwebengineregisterprotocolhandlerpermissionrequest.h b/src/webenginewidgets/api/qwebengineregisterprotocolhandlerpermissionrequest.h
new file mode 100644
index 0000000000000000000000000000000000000000..592eabb34171d60b56fdcfcaf2e2c72ba1eaeda1
--- /dev/null
+++ b/src/webenginewidgets/api/qwebengineregisterprotocolhandlerpermissionrequest.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWEBENGINEREGISTERPROTOCOLHANDLERPERMISSIONREQUEST_H
+#define QWEBENGINEREGISTERPROTOCOLHANDLERPERMISSIONREQUEST_H
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qurl.h>
+#include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h>
+
+namespace QtWebEngineCore {
+    class RegisterProtocolHandlerPermissionController;
+}
+
+QT_BEGIN_NAMESPACE
+
+class QWEBENGINEWIDGETS_EXPORT QWebEngineRegisterProtocolHandlerPermissionRequest {
+    Q_GADGET
+    Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL)
+    Q_PROPERTY(QString protocol READ protocol CONSTANT FINAL)
+public:
+    QWebEngineRegisterProtocolHandlerPermissionRequest() {}
+    QWebEngineRegisterProtocolHandlerPermissionRequest(
+        QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController>);
+    Q_INVOKABLE void accept();
+    Q_INVOKABLE void reject();
+    QUrl origin() const;
+    QString protocol() const;
+
+private:
+    QSharedPointer<QtWebEngineCore::RegisterProtocolHandlerPermissionController> d_ptr;
+};
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QWebEngineRegisterProtocolHandlerPermissionRequest)
+
+#endif // QWEBENGINEREGISTERPROTOCOLHANDLERPERMISSIONREQUEST_H
diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro
index 37cb7a1f0e0079b418e8823edba29a840b72c209..c3132b64014d06587d33a00a1b172875970c389b 100644
--- a/src/webenginewidgets/webenginewidgets.pro
+++ b/src/webenginewidgets/webenginewidgets.pro
@@ -20,6 +20,7 @@ SOURCES = \
         api/qwebenginepage.cpp \
         api/qwebengineprofile.cpp \
         api/qwebenginequotapermissionrequest.cpp \
+        api/qwebengineregisterprotocolhandlerpermissionrequest.cpp \
         api/qwebenginescript.cpp \
         api/qwebenginescriptcollection.cpp \
         api/qwebenginesettings.cpp \
@@ -39,6 +40,7 @@ HEADERS = \
         api/qwebengineprofile.h \
         api/qwebengineprofile_p.h \
         api/qwebenginequotapermissionrequest.h \
+        api/qwebengineregisterprotocolhandlerpermissionrequest.h \
         api/qwebenginescriptcollection.h \
         api/qwebenginescriptcollection_p.h \
         api/qwebenginesettings.h \
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index 032324e4561caca3d0cc2b664f78857a04e05931..52d8a0b4178d369ff055b34b2d59f9360fc9ed3e 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -67,6 +67,7 @@ static QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *>()
     << &QQuickWebEngineSettings::staticMetaObject
     << &QQuickWebEngineFullScreenRequest::staticMetaObject
     << &QQuickWebEngineQuotaPermissionRequest::staticMetaObject
+    << &QQuickWebEngineRegisterProtocolHandlerPermissionRequest::staticMetaObject
     << &QQuickWebEngineSingleton::staticMetaObject
     << &QQuickWebEngineAuthenticationDialogRequest::staticMetaObject
     << &QQuickWebEngineJavaScriptDialogRequest::staticMetaObject
@@ -295,6 +296,10 @@ static QStringList expectedAPI = QStringList()
     << "QQuickWebEngineQuotaPermissionRequest.origin --> QUrl"
     << "QQuickWebEngineQuotaPermissionRequest.reject() --> void"
     << "QQuickWebEngineQuotaPermissionRequest.requestedSize --> qlonglong"
+    << "QQuickWebEngineRegisterProtocolHandlerPermissionRequest.accept() --> void"
+    << "QQuickWebEngineRegisterProtocolHandlerPermissionRequest.origin --> QUrl"
+    << "QQuickWebEngineRegisterProtocolHandlerPermissionRequest.protocol --> QString"
+    << "QQuickWebEngineRegisterProtocolHandlerPermissionRequest.reject() --> void"
     << "QQuickWebEngineScript.ApplicationWorld --> ScriptWorldId"
     << "QQuickWebEngineScript.Deferred --> InjectionPoint"
     << "QQuickWebEngineScript.DocumentCreation --> InjectionPoint"
@@ -653,6 +658,7 @@ static QStringList expectedAPI = QStringList()
     << "QQuickWebEngineView.quotaPermissionRequested(QQuickWebEngineQuotaPermissionRequest) --> void"
     << "QQuickWebEngineView.recentlyAudible --> bool"
     << "QQuickWebEngineView.recentlyAudibleChanged(bool) --> void"
+    << "QQuickWebEngineView.registerProtocolHandlerPermissionRequested(QQuickWebEngineRegisterProtocolHandlerPermissionRequest) --> void"
     << "QQuickWebEngineView.reload() --> void"
     << "QQuickWebEngineView.reloadAndBypassCache() --> void"
     << "QQuickWebEngineView.renderProcessTerminated(RenderProcessTerminationStatus,int) --> void"
diff --git a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
index 47c09e1ced73b29db1b7318e62e32521c0162f08..8e74538276a1631cb840f4d1fff7c793f0fc17cf 100644
--- a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
+++ b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro
@@ -1,4 +1,5 @@
 include(../tests.pri)
+include(../../shared/http.pri)
 QT *= core-private
 
 qtConfig(webengine-printing-and-pdf): DEFINES+=QWEBENGINEPAGE_PDFPRINTINGENABLED
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index a32d96b3a9cc0440c26dbb3ee58ee1e978a2ace1..fbed89dd393eb23cf6513a916167a0d44f005506 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -40,6 +40,7 @@
 #include <QtTest/QtTest>
 #include <QTextCharFormat>
 #include <QWebChannel>
+#include <httpserver.h>
 #include <qnetworkcookiejar.h>
 #include <qnetworkreply.h>
 #include <qnetworkrequest.h>
@@ -49,6 +50,7 @@
 #include <qwebenginepage.h>
 #include <qwebengineprofile.h>
 #include <qwebenginequotapermissionrequest.h>
+#include <qwebengineregisterprotocolhandlerpermissionrequest.h>
 #include <qwebenginescript.h>
 #include <qwebenginescriptcollection.h>
 #include <qwebenginesettings.h>
@@ -210,6 +212,8 @@ private Q_SLOTS:
     void viewSourceURL_data();
     void viewSourceURL();
     void proxyConfigWithUnexpectedHostPortPair();
+    void registerProtocolHandler_data();
+    void registerProtocolHandler();
 
 private:
     static QPoint elementCenter(QWebEnginePage *page, const QString &id);
@@ -4202,6 +4206,67 @@ void tst_QWebEnginePage::proxyConfigWithUnexpectedHostPortPair()
     QTRY_COMPARE(loadFinishedSpy.count(), 1);
 }
 
+void tst_QWebEnginePage::registerProtocolHandler_data()
+{
+    QTest::addColumn<bool>("permission");
+    QTest::newRow("accept") << true;
+    QTest::newRow("reject") << false;
+}
+
+void tst_QWebEnginePage::registerProtocolHandler()
+{
+    QFETCH(bool, permission);
+
+    HttpServer server;
+    QWebEnginePage page;
+    QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+    QSignalSpy permissionSpy(&page, &QWebEnginePage::registerProtocolHandlerPermissionRequested);
+
+    page.setUrl(server.url("/"));
+    auto rr1 = waitForRequest(&server);
+    QVERIFY(rr1);
+    rr1->setResponseBody(QByteArrayLiteral("<html><body><a id=\"link\" href=\"mailto:foo@bar.com\">some text here</a></body></html>"));
+    rr1->sendResponse();
+    auto rr2 = waitForRequest(&server);
+    QVERIFY(rr2);
+    QCOMPARE(rr2->requestMethod(), QByteArrayLiteral("GET"));
+    QCOMPARE(rr2->requestPath(), QByteArrayLiteral("/favicon.ico"));
+    rr2->setResponseStatus(404);
+    rr2->sendResponse();
+    QTRY_COMPARE(loadSpy.count(), 1);
+    QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true);
+
+    QString callFormat = QStringLiteral("window.navigator.registerProtocolHandler(\"%1\", \"%2\", \"%3\")");
+    QString protocol = QStringLiteral("mailto");
+    QString url = server.url("/mail").toString() + QStringLiteral("?uri=%s");
+    QString title;
+    QString call = callFormat.arg(protocol).arg(url).arg(title);
+    page.runJavaScript(call);
+
+    QTRY_COMPARE(permissionSpy.count(), 1);
+    auto request = permissionSpy.takeFirst().value(0).value<QWebEngineRegisterProtocolHandlerPermissionRequest>();
+    QCOMPARE(request.origin(), QUrl(url));
+    QCOMPARE(request.protocol(), protocol);
+    if (permission)
+        request.accept();
+    else
+        request.reject();
+
+    page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()"));
+
+    std::unique_ptr<HttpReqRep> rr3;
+    if (permission) {
+        rr3 = waitForRequest(&server);
+        QVERIFY(rr3);
+        QCOMPARE(rr3->requestMethod(), QByteArrayLiteral("GET"));
+        QCOMPARE(rr3->requestPath(), QByteArrayLiteral("/mail?uri=mailto%3Afoo%40bar.com"));
+        rr3->sendResponse();
+    }
+
+    QTRY_COMPARE(loadSpy.count(), 1);
+    QCOMPARE(loadSpy.takeFirst().value(0).toBool(), permission);
+}
+
 static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")};
 W_QTEST_MAIN(tst_QWebEnginePage, params)
 
diff --git a/tools/scripts/take_snapshot.py b/tools/scripts/take_snapshot.py
index 69e22d5a6bcc5e497fedd793797e85ea61429813..a6274f0aa72c3a77ecd730ac19a1ed7cf5bcdab2 100755
--- a/tools/scripts/take_snapshot.py
+++ b/tools/scripts/take_snapshot.py
@@ -92,6 +92,8 @@ def isInChromiumBlacklist(file_path):
             not 'third_party/chromevox' in file_path and
             not 'media/webrtc/desktop_media_list.h' in file_path and
             not 'media/webrtc/desktop_streams_registry.' in file_path and
+            not 'browser/custom_handlers/protocol_handler_registry.' in file_path and
+            not 'browser/custom_handlers/protocol_handler_registry_factory.' in file_path and
             not 'browser/net/chrome_mojo_proxy_resolver_factory.' in file_path and
             not '/browser/devtools/' in file_path and
             not '/browser/ui/webui/' in file_path and
@@ -99,6 +101,7 @@ def isInChromiumBlacklist(file_path):
             not 'common/chrome_paths' in file_path and
             not 'common/chrome_switches.' in file_path and
             not 'common/content_restriction.h' in file_path and
+            not 'common/custom_handlers/protocol_handler.' in file_path and
             not 'common/spellcheck_' in file_path and
             not 'common/url_constants' in file_path and
             not '/extensions/api/' in file_path and