summaryrefslogtreecommitdiffstats
path: root/src/core/net/proxying_url_loader_factory_qt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/net/proxying_url_loader_factory_qt.cpp')
-rw-r--r--src/core/net/proxying_url_loader_factory_qt.cpp422
1 files changed, 244 insertions, 178 deletions
diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp
index d63659d2d..3a83ed7ea 100644
--- a/src/core/net/proxying_url_loader_factory_qt.cpp
+++ b/src/core/net/proxying_url_loader_factory_qt.cpp
@@ -1,75 +1,48 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "proxying_url_loader_factory_qt.h"
#include <utility>
-#include "base/bind.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
+#include "base/functional/bind.h"
#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/global_request_id.h"
-#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_constants.h"
-#include "content/public/common/url_utils.h"
-#include "net/base/load_flags.h"
+#include "content/public/common/content_switches.h"
+#include "net/base/filename_util.h"
#include "net/http/http_status_code.h"
-#include "net/http/http_util.h"
+#include "services/network/public/cpp/cors/cors.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/early_hints.mojom.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
+#include "url/url_util.h"
+#include "url/url_util_qt.h"
#include "api/qwebengineurlrequestinfo_p.h"
-#include "profile_qt.h"
#include "type_conversion.h"
+#include "web_contents_adapter.h"
#include "web_contents_adapter_client.h"
#include "web_contents_view_qt.h"
-
-#include <QVariant>
+#include "net/resource_request_body_qt.h"
// 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
// found in the LICENSE file.
+namespace {
+ network::mojom::URLResponseHeadPtr createResponse(const network::ResourceRequest &request) {
+ const bool disable_web_security = base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebSecurity);
+ network::mojom::URLResponseHeadPtr response = network::mojom::URLResponseHead::New();
+ response->response_type = network::cors::CalculateResponseType(
+ request.mode, disable_web_security || (
+ request.request_initiator && request.request_initiator->IsSameOriginWith(url::Origin::Create(request.url))));
+
+ return response;
+ }
+}
+
namespace QtWebEngineCore {
ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeMainFrame, blink::mojom::ResourceType::kMainFrame)
@@ -108,17 +81,28 @@ static QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::N
return static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType);
}
+static QHash<QByteArray, QByteArray> toQt(const net::HttpRequestHeaders &headers)
+{
+ const auto vector = headers.GetHeaderVector();
+ QHash<QByteArray, QByteArray> hash;
+
+ for (const auto &header : vector) {
+ hash.insert(QByteArray::fromStdString(header.key), QByteArray::fromStdString(header.value));
+ }
+
+ return hash;
+}
+
// Handles intercepted, in-progress requests/responses, so that they can be
// controlled and modified accordingly.
class InterceptedRequest : public network::mojom::URLLoader
, public network::mojom::URLLoaderClient
{
public:
- InterceptedRequest(int process_id, uint64_t request_id, int32_t routing_id, uint32_t options,
+ InterceptedRequest(ProfileAdapter *profile_adapter,
+ int frame_tree_node_id, int32_t request_id, uint32_t options,
const network::ResourceRequest &request,
const net::MutableNetworkTrafficAnnotationTag &traffic_annotation,
- QWebEngineUrlRequestInterceptor *profile_request_interceptor,
- QWebEngineUrlRequestInterceptor *page_request_interceptor,
mojo::PendingReceiver<network::mojom::URLLoader> loader,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory);
@@ -127,24 +111,24 @@ public:
void Restart();
// network::mojom::URLLoaderClient
- void OnReceiveResponse(network::mojom::URLResponseHeadPtr head) override;
+ void OnReceiveResponse(network::mojom::URLResponseHeadPtr head, mojo::ScopedDataPipeConsumerHandle, absl::optional<mojo_base::BigBuffer>) override;
void OnReceiveRedirect(const net::RedirectInfo &redirect_info, network::mojom::URLResponseHeadPtr head) override;
void OnUploadProgress(int64_t current_position, int64_t total_size, OnUploadProgressCallback callback) override;
- void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override;
void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
- void OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body) override;
void OnComplete(const network::URLLoaderCompletionStatus &status) override;
+ void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr) override {}
// network::mojom::URLLoader
void FollowRedirect(const std::vector<std::string> &removed_headers,
- const net::HttpRequestHeaders &modified_headers, const base::Optional<GURL> &new_url) override;
+ const net::HttpRequestHeaders &modified_headers,
+ const net::HttpRequestHeaders &modified_cors_exempt_headers,
+ const absl::optional<GURL> &new_url) override;
void SetPriority(net::RequestPriority priority, int32_t intra_priority_value) override;
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
private:
void InterceptOnUIThread();
- void InterceptOnIOThread(base::WaitableEvent *event);
void ContinueAfterIntercept();
// This is called when the original URLLoaderClient has a connection error.
@@ -160,25 +144,39 @@ private:
void SendErrorAndCompleteImmediately(int error_code);
- const int process_id_;
- const uint64_t request_id_;
- const int32_t routing_id_;
+ content::WebContents* webContents();
+ QWebEngineUrlRequestInterceptor* getProfileInterceptor();
+ QWebEngineUrlRequestInterceptor* getPageInterceptor();
+
+ QPointer<ProfileAdapter> profile_adapter_;
+ const int frame_tree_node_id_;
+ const int32_t request_id_;
const uint32_t options_;
- bool input_stream_previously_failed_ = false;
- bool request_was_redirected_ = false;
+ bool allow_local_ = false;
+ bool allow_remote_ = true;
+ bool local_access_ = false;
+ bool remote_access_ = true;
+
+ bool loader_error_seen_ = false;
// If the |target_loader_| called OnComplete with an error this stores it.
// That way the destructor can send it to OnReceivedError if safe browsing
// error didn't occur.
int error_status_ = net::OK;
network::ResourceRequest request_;
+ ResourceRequestBody request_body_;
network::mojom::URLResponseHeadPtr current_response_;
const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
- QWebEngineUrlRequestInfo request_info_;
- QPointer<QWebEngineUrlRequestInterceptor> profile_request_interceptor_;
- QPointer<QWebEngineUrlRequestInterceptor> page_request_interceptor_;
+ struct RequestInfoDeleter
+ {
+ void operator()(QWebEngineUrlRequestInfo *ptr) const
+ { delete ptr; }
+ };
+
+ std::unique_ptr<QWebEngineUrlRequestInfo, RequestInfoDeleter> request_info_;
+
mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_;
mojo::Remote<network::mojom::URLLoaderClient> target_client_;
mojo::Receiver<network::mojom::URLLoaderClient> proxied_client_receiver_{this};
@@ -186,36 +184,52 @@ private:
mojo::Remote<network::mojom::URLLoaderFactory> target_factory_;
base::WeakPtrFactory<InterceptedRequest> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(InterceptedRequest);
};
-InterceptedRequest::InterceptedRequest(int process_id, uint64_t request_id, int32_t routing_id, uint32_t options,
+InterceptedRequest::InterceptedRequest(ProfileAdapter *profile_adapter,
+ int frame_tree_node_id, int32_t request_id, uint32_t options,
const network::ResourceRequest &request,
const net::MutableNetworkTrafficAnnotationTag &traffic_annotation,
- QWebEngineUrlRequestInterceptor *profile_request_interceptor,
- QWebEngineUrlRequestInterceptor *page_request_interceptor,
mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory)
- : process_id_(process_id)
+ : profile_adapter_(profile_adapter)
+ , frame_tree_node_id_(frame_tree_node_id)
, request_id_(request_id)
- , routing_id_(routing_id)
, options_(options)
, request_(request)
+ , request_body_(ResourceRequestBody(request_.request_body.get()))
, traffic_annotation_(traffic_annotation)
- , profile_request_interceptor_(profile_request_interceptor)
- , page_request_interceptor_(page_request_interceptor)
, proxied_loader_receiver_(this, std::move(loader_receiver))
, target_client_(std::move(client))
, target_factory_(std::move(target_factory))
, weak_factory_(this)
{
- current_response_ = network::mojom::URLResponseHead::New();
+ const bool disable_web_security = base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebSecurity);
+ current_response_ = createResponse(request_);
// If there is a client error, clean up the request.
target_client_.set_disconnect_handler(
- base::BindOnce(&InterceptedRequest::OnURLLoaderClientError, weak_factory_.GetWeakPtr()));
+ base::BindOnce(&InterceptedRequest::OnURLLoaderClientError, base::Unretained(this)));
proxied_loader_receiver_.set_disconnect_with_reason_handler(
- base::BindOnce(&InterceptedRequest::OnURLLoaderError, weak_factory_.GetWeakPtr()));
+ base::BindOnce(&InterceptedRequest::OnURLLoaderError, base::Unretained(this)));
+ if (!disable_web_security && request_.request_initiator) {
+ const std::vector<std::string> &localSchemes = url::GetLocalSchemes();
+ const std::string fromScheme = request_.request_initiator->GetTupleOrPrecursorTupleIfOpaque().scheme();
+ const std::string toScheme = request_.url.scheme();
+ const bool fromLocal = base::Contains(localSchemes, fromScheme);
+ const bool toLocal = base::Contains(localSchemes, toScheme);
+ bool hasLocalAccess = false;
+ local_access_ = toLocal;
+ remote_access_ = !toLocal && (toScheme != "data") && (toScheme != "qrc");
+ if (const url::CustomScheme *cs = url::CustomScheme::FindScheme(fromScheme))
+ hasLocalAccess = cs->flags & url::CustomScheme::LocalAccessAllowed;
+ if (fromLocal || toLocal) {
+ content::WebContents *wc = webContents();
+ // local schemes must have universal access, or be accessing something local and have local access.
+ allow_local_ = hasLocalAccess || (fromLocal && wc && wc->GetOrCreateWebPreferences().allow_file_access_from_file_urls);
+ allow_remote_ = !fromLocal || (wc && wc->GetOrCreateWebPreferences().allow_remote_access_from_local_urls);
+ }
+ }
}
InterceptedRequest::~InterceptedRequest()
@@ -223,115 +237,175 @@ InterceptedRequest::~InterceptedRequest()
weak_factory_.InvalidateWeakPtrs();
}
+content::WebContents* InterceptedRequest::webContents()
+{
+ if (frame_tree_node_id_ == content::RenderFrameHost::kNoFrameTreeNodeId)
+ return nullptr;
+ return content::WebContents::FromFrameTreeNodeId(frame_tree_node_id_);
+}
+
+QWebEngineUrlRequestInterceptor* InterceptedRequest::getProfileInterceptor()
+{
+ return profile_adapter_ ? profile_adapter_->requestInterceptor() : nullptr;
+}
+
+QWebEngineUrlRequestInterceptor* InterceptedRequest::getPageInterceptor()
+{
+ if (auto wc = webContents()) {
+ auto view = static_cast<content::WebContentsImpl *>(wc)->GetView();
+ if (WebContentsAdapterClient *client = WebContentsViewQt::from(view)->client())
+ return client->webContentsAdapter()->requestInterceptor();
+ }
+ return nullptr;
+}
+
void InterceptedRequest::Restart()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- blink::mojom::ResourceType resourceType = blink::mojom::ResourceType(request_.resource_type);
- WebContentsAdapterClient::NavigationType navigationType =
- pageTransitionToNavigationType(ui::PageTransition(request_.transition_type));
- const QUrl originalUrl = toQt(request_.url);
- const QUrl initiator = request_.request_initiator.has_value() ? toQt(request_.request_initiator->GetURL()) : QUrl();
+ bool granted_special_access = false;
+ auto navigationType = toQt(pageTransitionToNavigationType(ui::PageTransition(request_.transition_type)));
+ switch (navigationType) {
+ case QWebEngineUrlRequestInfo::NavigationTypeLink:
+ case QWebEngineUrlRequestInfo::NavigationTypeTyped:
+ if (blink::mojom::ResourceType(request_.resource_type) == blink::mojom::ResourceType::kMainFrame && request_.has_user_gesture)
+ granted_special_access = true; // allow normal explicit navigation
+ break;
+ case QWebEngineUrlRequestInfo::NavigationTypeBackForward:
+ case QWebEngineUrlRequestInfo::NavigationTypeReload:
+ if (blink::mojom::ResourceType(request_.resource_type) == blink::mojom::ResourceType::kMainFrame)
+ granted_special_access = true;
+ break;
+ default:
+ break;
+ }
- content::WebContents *webContents = nullptr;
- if (process_id_) {
- content::RenderFrameHost *frameHost = content::RenderFrameHost::FromID(process_id_, request_.render_frame_id);
- webContents = content::WebContents::FromRenderFrameHost(frameHost);
- } else {
- webContents = content::WebContents::FromFrameTreeNodeId(request_.render_frame_id);
+ // Check if non-local access is allowed
+ if (!allow_remote_ && remote_access_) {
+ if (!granted_special_access) {
+ target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_NETWORK_ACCESS_DENIED));
+ delete this;
+ return;
+ }
+ }
+
+ // Check if local access is allowed
+ if (!allow_local_ && local_access_) {
+ // Check for specifically granted file access:
+ if (auto *frame_tree = content::FrameTreeNode::GloballyFindByID(frame_tree_node_id_)) {
+ const int renderer_id = frame_tree->current_frame_host()->GetProcess()->GetID();
+ base::FilePath file_path;
+ if (net::FileURLToFilePath(request_.url, &file_path)) {
+ if (content::ChildProcessSecurityPolicy::GetInstance()->CanReadFile(renderer_id, file_path))
+ granted_special_access = true;
+ }
+ }
+ if (!granted_special_access) {
+ target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_ACCESS_DENIED));
+ delete this;
+ return;
+ }
+ }
+
+ // MEMO since all codepatch leading to Restart scheduled and executed as asynchronous tasks in main thread,
+ // interceptors may change in meantime and also during intercept call, so they should be resolved anew.
+ // Set here only profile's interceptor since it runs first without going to user code.
+ auto profileInterceptor = getProfileInterceptor();
+ if (!profileInterceptor && !getPageInterceptor()) {
+ ContinueAfterIntercept();
+ return;
}
- GURL top_document_url = webContents ? webContents->GetVisibleURL() : GURL();
+ auto resourceType = toQt(blink::mojom::ResourceType(request_.resource_type));
+ const QUrl originalUrl = toQt(request_.url);
+ const QUrl initiator = request_.request_initiator.has_value() ? toQt(request_.request_initiator->GetURL()) : QUrl();
+
+ auto wc = webContents();
+ GURL top_document_url = wc ? wc->GetVisibleURL() : GURL();
QUrl firstPartyUrl;
if (!top_document_url.is_empty())
firstPartyUrl = toQt(top_document_url);
else
- firstPartyUrl = toQt(request_.site_for_cookies.RepresentativeUrl()); // m_topDocumentUrl can be empty for the main-frame.
-
- QWebEngineUrlRequestInfoPrivate *infoPrivate =
- new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), toQt(navigationType), originalUrl, firstPartyUrl,
- initiator, QByteArray::fromStdString(request_.method));
- request_info_ = QWebEngineUrlRequestInfo(infoPrivate);
-
- // TODO: remove for Qt6
- if (profile_request_interceptor_ && profile_request_interceptor_->property("deprecated").toBool()) {
- // sync call supports depracated call of an interceptor on io thread
- base::WaitableEvent event;
- base::PostTask(FROM_HERE, { content::BrowserThread::IO },
- base::BindOnce(&InterceptedRequest::InterceptOnIOThread, base::Unretained(this), &event));
- event.Wait();
- if (request_info_.changed()) {
- ContinueAfterIntercept();
- return;
- }
- }
+ firstPartyUrl = toQt(request_.site_for_cookies.first_party_url()); // m_topDocumentUrl can be empty for the main-frame.
+
+ QHash<QByteArray, QByteArray> headers = toQt(request_.headers);
+
+ if (!request_.referrer.is_empty())
+ headers.insert("Referer", toQt(request_.referrer).toEncoded());
+
+ auto info = new QWebEngineUrlRequestInfoPrivate(
+ resourceType, navigationType, originalUrl, firstPartyUrl, initiator,
+ QByteArray::fromStdString(request_.method), &request_body_, headers);
+ Q_ASSERT(!request_info_);
+ request_info_.reset(new QWebEngineUrlRequestInfo(info));
+
InterceptOnUIThread();
ContinueAfterIntercept();
}
-void InterceptedRequest::InterceptOnIOThread(base::WaitableEvent *event)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (profile_request_interceptor_)
- profile_request_interceptor_->interceptRequest(request_info_);
- event->Signal();
-}
-
void InterceptedRequest::InterceptOnUIThread()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (profile_request_interceptor_ && !profile_request_interceptor_->property("deprecated").toBool())
- profile_request_interceptor_->interceptRequest(request_info_);
+ if (auto interceptor = getProfileInterceptor())
+ interceptor->interceptRequest(*request_info_);
- if (!request_info_.changed() && page_request_interceptor_)
- page_request_interceptor_->interceptRequest(request_info_);
+ if (!request_info_->changed()) {
+ if (auto interceptor = getPageInterceptor())
+ interceptor->interceptRequest(*request_info_);
+ }
}
void InterceptedRequest::ContinueAfterIntercept()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (request_info_.changed()) {
- if (request_info_.d_ptr->shouldBlockRequest)
- return SendErrorAndCompleteImmediately(net::ERR_BLOCKED_BY_CLIENT);
- if (request_info_.d_ptr->shouldRedirectRequest) {
- net::URLRequest::FirstPartyURLPolicy first_party_url_policy =
- request_.update_first_party_url_on_redirect ? net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT
- : net::URLRequest::NEVER_CHANGE_FIRST_PARTY_URL;
- net::RedirectInfo redirectInfo = net::RedirectInfo::ComputeRedirectInfo(
- request_.method, request_.url, request_.site_for_cookies,
- first_party_url_policy, request_.referrer_policy, request_.referrer.spec(),
- net::HTTP_TEMPORARY_REDIRECT, toGurl(request_info_.requestUrl()), base::nullopt,
- false /*insecure_scheme_was_upgraded*/);
-
- // FIXME: Should probably create a new header.
- current_response_->encoded_data_length = 0;
- request_.method = redirectInfo.new_method;
- request_.url = redirectInfo.new_url;
- request_.site_for_cookies = redirectInfo.new_site_for_cookies;
- request_.referrer = GURL(redirectInfo.new_referrer);
- request_.referrer_policy = redirectInfo.new_referrer_policy;
- if (request_.method == net::HttpRequestHeaders::kGetMethod)
- request_.request_body = nullptr;
- target_client_->OnReceiveRedirect(redirectInfo, std::move(current_response_));
- return;
+ if (request_info_) {
+ // cleanup in scope because of delete this and it's not needed else where after
+ const auto scoped_request_info = std::move(request_info_);
+ QWebEngineUrlRequestInfoPrivate &info = *scoped_request_info->d_ptr;
+
+ for (auto header = info.extraHeaders.constBegin(); header != info.extraHeaders.constEnd(); ++header) {
+ std::string h = header.key().toStdString();
+ if (base::EqualsCaseInsensitiveASCII(h, "referer"))
+ request_.referrer = GURL(header.value().toStdString());
+ else
+ request_.headers.SetHeader(h, header.value().toStdString());
}
- if (!request_info_.d_ptr->extraHeaders.isEmpty()) {
- auto end = request_info_.d_ptr->extraHeaders.constEnd();
- for (auto header = request_info_.d_ptr->extraHeaders.constBegin(); header != end; ++header) {
- std::string h = header.key().toStdString();
- if (base::LowerCaseEqualsASCII(h, "referer")) {
- request_.referrer = GURL(header.value().toStdString());
- } else {
- request_.headers.SetHeader(h, header.value().toStdString());
- }
+ if (info.changed) {
+ if (info.shouldBlockRequest)
+ return SendErrorAndCompleteImmediately(net::ERR_BLOCKED_BY_CLIENT);
+
+ if (info.shouldRedirectRequest) {
+ net::RedirectInfo::FirstPartyURLPolicy first_party_url_policy =
+ request_.update_first_party_url_on_redirect ? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT
+ : net::RedirectInfo::FirstPartyURLPolicy::NEVER_CHANGE_URL;
+ net::RedirectInfo redirectInfo = net::RedirectInfo::ComputeRedirectInfo(
+ request_.method, request_.url, request_.site_for_cookies,
+ first_party_url_policy, request_.referrer_policy, request_.referrer.spec(),
+ net::HTTP_TEMPORARY_REDIRECT, toGurl(info.url), absl::nullopt,
+ false /*insecure_scheme_was_upgraded*/);
+ request_.method = redirectInfo.new_method;
+ request_.url = redirectInfo.new_url;
+ request_.site_for_cookies = redirectInfo.new_site_for_cookies;
+ request_.referrer = GURL(redirectInfo.new_referrer);
+ request_.referrer_policy = redirectInfo.new_referrer_policy;
+ if (request_.method == net::HttpRequestHeaders::kGetMethod)
+ request_.request_body = nullptr;
+ // In case of multiple sequential rediredts, current_response_ has previously been moved to target_client_
+ // so we create a new one using the redirect url.
+ if (!current_response_)
+ current_response_ = createResponse(request_);
+ current_response_->encoded_data_length = 0;
+ target_client_->OnReceiveRedirect(redirectInfo, std::move(current_response_));
+ return;
}
}
}
if (!target_loader_ && target_factory_) {
- target_factory_->CreateLoaderAndStart(target_loader_.BindNewPipeAndPassReceiver(), routing_id_, request_id_,
+ loader_error_seen_ = false;
+ target_factory_->CreateLoaderAndStart(target_loader_.BindNewPipeAndPassReceiver(), request_id_,
options_, request_, proxied_client_receiver_.BindNewPipeAndPassRemote(),
traffic_annotation_);
}
@@ -339,17 +413,16 @@ void InterceptedRequest::ContinueAfterIntercept()
// URLLoaderClient methods.
-void InterceptedRequest::OnReceiveResponse(network::mojom::URLResponseHeadPtr head)
+void InterceptedRequest::OnReceiveResponse(network::mojom::URLResponseHeadPtr head, mojo::ScopedDataPipeConsumerHandle handle, absl::optional<mojo_base::BigBuffer> buffer)
{
current_response_ = head.Clone();
- target_client_->OnReceiveResponse(std::move(head));
+ target_client_->OnReceiveResponse(std::move(head), std::move(handle), std::move(buffer));
}
void InterceptedRequest::OnReceiveRedirect(const net::RedirectInfo &redirect_info, network::mojom::URLResponseHeadPtr head)
{
// TODO(timvolodine): handle redirect override.
- request_was_redirected_ = true;
current_response_ = head.Clone();
target_client_->OnReceiveRedirect(redirect_info, std::move(head));
request_.url = redirect_info.new_url;
@@ -364,21 +437,11 @@ void InterceptedRequest::OnUploadProgress(int64_t current_position, int64_t tota
target_client_->OnUploadProgress(current_position, total_size, std::move(callback));
}
-void InterceptedRequest::OnReceiveCachedMetadata(mojo_base::BigBuffer data)
-{
- target_client_->OnReceiveCachedMetadata(std::move(data));
-}
-
void InterceptedRequest::OnTransferSizeUpdated(int32_t transfer_size_diff)
{
target_client_->OnTransferSizeUpdated(transfer_size_diff);
}
-void InterceptedRequest::OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body)
-{
- target_client_->OnStartLoadingResponseBody(std::move(body));
-}
-
void InterceptedRequest::OnComplete(const network::URLLoaderCompletionStatus &status)
{
// Only wait for the original loader to possibly have a custom error if the
@@ -391,10 +454,11 @@ void InterceptedRequest::OnComplete(const network::URLLoaderCompletionStatus &st
void InterceptedRequest::FollowRedirect(const std::vector<std::string> &removed_headers,
const net::HttpRequestHeaders &modified_headers,
- const base::Optional<GURL> &new_url)
+ const net::HttpRequestHeaders &modified_cors_exempt_headers,
+ const absl::optional<GURL> &new_url)
{
if (target_loader_)
- target_loader_->FollowRedirect(removed_headers, modified_headers, new_url);
+ target_loader_->FollowRedirect(removed_headers, modified_headers, modified_cors_exempt_headers, new_url);
// If |OnURLLoaderClientError| was called then we're just waiting for the
// connection error handler of |proxied_loader_binding_|. Don't restart the
@@ -436,6 +500,8 @@ void InterceptedRequest::OnURLLoaderError(uint32_t custom_reason, const std::str
// If CallOnComplete was already called, then this object is ready to be deleted.
if (!target_client_)
delete this;
+ else
+ loader_error_seen_ = true;
}
void InterceptedRequest::CallOnComplete(const network::URLLoaderCompletionStatus &status, bool wait_for_loader_error)
@@ -449,7 +515,7 @@ void InterceptedRequest::CallOnComplete(const network::URLLoaderCompletionStatus
if (target_client_)
target_client_->OnComplete(status);
- if (proxied_loader_receiver_.is_bound() && wait_for_loader_error) {
+ if (proxied_loader_receiver_.is_bound() && wait_for_loader_error && !loader_error_seen_) {
// Since the original client is gone no need to continue loading the
// request.
proxied_client_receiver_.reset();
@@ -478,10 +544,10 @@ void InterceptedRequest::SendErrorAndCompleteImmediately(int error_code)
delete this;
}
-ProxyingURLLoaderFactoryQt::ProxyingURLLoaderFactoryQt(int process_id, QWebEngineUrlRequestInterceptor *profile, QWebEngineUrlRequestInterceptor *page,
+ProxyingURLLoaderFactoryQt::ProxyingURLLoaderFactoryQt(ProfileAdapter *adapter, int frame_tree_node_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_info)
- : m_processId(process_id), m_profileRequestInterceptor(profile), m_pageRequestInterceptor(page), m_weakFactory(this)
+ : m_profileAdapter(adapter), m_frameTreeNodeId(frame_tree_node_id), m_weakFactory(this)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (target_factory_info) {
@@ -499,8 +565,8 @@ ProxyingURLLoaderFactoryQt::~ProxyingURLLoaderFactoryQt()
m_weakFactory.InvalidateWeakPtrs();
}
-void ProxyingURLLoaderFactoryQt::CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> loader, int32_t routing_id,
- int32_t request_id, uint32_t options, const network::ResourceRequest &request,
+void ProxyingURLLoaderFactoryQt::CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> loader, int32_t request_id,
+ uint32_t options, const network::ResourceRequest &request,
mojo::PendingRemote<network::mojom::URLLoaderClient> url_loader_client,
const net::MutableNetworkTrafficAnnotationTag &traffic_annotation)
{
@@ -510,8 +576,8 @@ void ProxyingURLLoaderFactoryQt::CreateLoaderAndStart(mojo::PendingReceiver<netw
m_targetFactory->Clone(target_factory_clone.InitWithNewPipeAndPassReceiver());
// Will manage its own lifetime
- InterceptedRequest *req = new InterceptedRequest(m_processId, request_id, routing_id, options, request, traffic_annotation,
- m_profileRequestInterceptor, m_pageRequestInterceptor, std::move(loader),
+ InterceptedRequest *req = new InterceptedRequest(m_profileAdapter, m_frameTreeNodeId, request_id, options,
+ request, traffic_annotation, std::move(loader),
std::move(url_loader_client), std::move(target_factory_clone));
req->Restart();
}