diff options
author | Yigit Akcay <yigit.akcay@qt.io> | 2023-02-15 20:43:25 +0100 |
---|---|---|
committer | Yigit Akcay <yigit.akcay@qt.io> | 2023-03-10 17:13:32 +0100 |
commit | 5e257fb57a211f95556ec387fe6f262a60cbb6fe (patch) | |
tree | 330abbb7f84f8664fbd44b80d573265da4cc2bcb /src/core/net | |
parent | 28a2cfe4116f7218b33df811b79536c0593ddda6 (diff) |
QWebEngineUrlResponseInterceptor: Implement new URL response interceptor
This patch adds the QWebEngineUrlResponseInterceptor abstract class,
which, when implemented, allows a user to intercept response headers and
modify them in any way they like.
A response interceptor can be set via
QWebEngineProfile::setUrlResponseInterceptor(),
QQuickWebEngineProfile::setUrlResponseInterceptor() or
QWebEnginePage::setUrlResponseInterceptor().
Also, the QWebEngineUrlResponseInfo class is implemented, which contains
the request and response data to be used with the response interceptor.
If a response interceptor is set in the profile and page, the one in the
profile takes precedence.
Fixes: QTBUG-61071
Change-Id: I484d14373ff597b1d531541c066f0102bae28c72
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'src/core/net')
-rw-r--r-- | src/core/net/proxying_url_loader_factory_qt.cpp | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp index 70ec61b34..aa333ae02 100644 --- a/src/core/net/proxying_url_loader_factory_qt.cpp +++ b/src/core/net/proxying_url_loader_factory_qt.cpp @@ -20,11 +20,14 @@ #include "url/url_util_qt.h" #include "api/qwebengineurlrequestinfo_p.h" +#include "api/qwebengineurlresponseinfo_p.h" #include "type_conversion.h" #include "web_contents_adapter.h" #include "web_contents_adapter_client.h" #include "web_contents_view_qt.h" +#include <QtWebEngineCore/QWebEngineUrlResponseInfo> + // originally based on aw_proxying_url_loader_factory.cc: // Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -148,6 +151,11 @@ private: content::WebContents* webContents(); QWebEngineUrlRequestInterceptor* getProfileInterceptor(); QWebEngineUrlRequestInterceptor* getPageInterceptor(); + QWebEngineUrlResponseInterceptor *getProfileResponseInterceptor(); + QWebEngineUrlResponseInterceptor *getPageResponseInterceptor(); + + void interceptResponseHeaders(QWebEngineUrlResponseInterceptor *const interceptor, + net::HttpResponseHeaders *const responseHeadersPtr); QPointer<ProfileAdapter> profile_adapter_; const int frame_tree_node_id_; @@ -252,6 +260,59 @@ QWebEngineUrlRequestInterceptor* InterceptedRequest::getPageInterceptor() return nullptr; } +QWebEngineUrlResponseInterceptor* InterceptedRequest::getProfileResponseInterceptor() +{ + return profile_adapter_ ? profile_adapter_->responseInterceptor() : nullptr; +} + +QWebEngineUrlResponseInterceptor* InterceptedRequest::getPageResponseInterceptor() +{ + if (auto wc = webContents()) { + auto view = static_cast<content::WebContentsImpl *>(wc)->GetView(); + if (WebContentsAdapterClient *client = WebContentsViewQt::from(view)->client()) + return client->webContentsAdapter()->responseInterceptor(); + } + return nullptr; +} + +void InterceptedRequest::interceptResponseHeaders( + QWebEngineUrlResponseInterceptor *const interceptor, + net::HttpResponseHeaders *const responseHeadersPtr) +{ + QHash<QByteArray, QByteArray> responseHeaders; + std::unordered_set<std::string> headersToRemove; + { + std::size_t iter = 0; + std::string name; + std::string value; + while (responseHeadersPtr->EnumerateHeaderLines(&iter, &name, &value)) { + responseHeaders.insert(QByteArray::fromStdString(name), + QByteArray::fromStdString(value)); + headersToRemove.insert(name); + } + } + + const QUrl requestUrl = QUrl::fromEncoded(QByteArray::fromStdString(request_.url.spec())); + const QHash<QByteArray, QByteArray> requestHeaders = + [](const net::HttpRequestHeaders &headers) { + QHash<QByteArray, QByteArray> result; + for (const auto &header : headers.GetHeaderVector()) { + result.insert(QByteArray::fromStdString(header.key), + QByteArray::fromStdString(header.value)); + } + return result; + }(request_.headers); + + QWebEngineUrlResponseInfo info(requestUrl, requestHeaders, responseHeaders); + interceptor->interceptResponseHeaders(info); + + if (info.d_ptr->isModified) { + responseHeadersPtr->RemoveHeaders(headersToRemove); + for (auto it = info.responseHeaders().cbegin(); it != info.responseHeaders().cend(); ++it) + responseHeadersPtr->AddHeader(it.key().toStdString(), it.value().toStdString()); + } +} + void InterceptedRequest::Restart() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -404,6 +465,12 @@ void InterceptedRequest::ContinueAfterIntercept() void InterceptedRequest::OnReceiveResponse(network::mojom::URLResponseHeadPtr head, mojo::ScopedDataPipeConsumerHandle handle, absl::optional<mojo_base::BigBuffer> buffer) { + QWebEngineUrlResponseInterceptor *const responseInterceptor = getProfileResponseInterceptor() + ? getProfileResponseInterceptor() + : getPageResponseInterceptor(); + if (responseInterceptor) + interceptResponseHeaders(responseInterceptor, head->headers.get()); + current_response_ = head.Clone(); target_client_->OnReceiveResponse(std::move(head), std::move(handle), std::move(buffer)); |