diff options
Diffstat (limited to 'src/core/net/proxying_url_loader_factory_qt.cpp')
-rw-r--r-- | src/core/net/proxying_url_loader_factory_qt.cpp | 173 |
1 files changed, 87 insertions, 86 deletions
diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp index 6b311d7fb..3a83ed7ea 100644 --- a/src/core/net/proxying_url_loader_factory_qt.cpp +++ b/src/core/net/proxying_url_loader_factory_qt.cpp @@ -1,56 +1,19 @@ -/**************************************************************************** -** -** 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/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/web_contents.h" #include "content/public/common/content_switches.h" #include "net/base/filename_util.h" #include "net/http/http_status_code.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" @@ -61,14 +24,25 @@ #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) @@ -107,6 +81,18 @@ 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 @@ -125,12 +111,10 @@ 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 {} @@ -143,8 +127,6 @@ public: void PauseReadingBodyFromNet() override; void ResumeReadingBodyFromNet() override; - static inline void cleanup(QWebEngineUrlRequestInfo *info) { delete info; } - private: void InterceptOnUIThread(); void ContinueAfterIntercept(); @@ -182,11 +164,18 @@ private: // 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_; - QScopedPointer<QWebEngineUrlRequestInfo, InterceptedRequest> request_info_; + 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_; @@ -209,6 +198,7 @@ InterceptedRequest::InterceptedRequest(ProfileAdapter *profile_adapter, , request_id_(request_id) , options_(options) , request_(request) + , request_body_(ResourceRequestBody(request_.request_body.get())) , traffic_annotation_(traffic_annotation) , proxied_loader_receiver_(this, std::move(loader_receiver)) , target_client_(std::move(client)) @@ -216,11 +206,7 @@ InterceptedRequest::InterceptedRequest(ProfileAdapter *profile_adapter, , weak_factory_(this) { const bool disable_web_security = base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebSecurity); - current_response_ = network::mojom::URLResponseHead::New(); - current_response_->response_type = network::cors::CalculateResponseType( - request_.mode, - disable_web_security || ( - request_.request_initiator && request_.request_initiator->IsSameOriginWith(url::Origin::Create(request_.url)))); + current_response_ = createResponse(request_); // If there is a client error, clean up the request. target_client_.set_disconnect_handler( base::BindOnce(&InterceptedRequest::OnURLLoaderClientError, base::Unretained(this))); @@ -277,15 +263,34 @@ void InterceptedRequest::Restart() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + 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; + } + // Check if non-local access is allowed if (!allow_remote_ && remote_access_) { - target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_NETWORK_ACCESS_DENIED)); - delete this; - return; + 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_) { - bool granted_special_access = false; // 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(); @@ -312,7 +317,6 @@ void InterceptedRequest::Restart() } auto resourceType = toQt(blink::mojom::ResourceType(request_.resource_type)); - auto navigationType = toQt(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(); @@ -324,8 +328,14 @@ void InterceptedRequest::Restart() else firstPartyUrl = toQt(request_.site_for_cookies.first_party_url()); // m_topDocumentUrl can be empty for the main-frame. - auto info = new QWebEngineUrlRequestInfoPrivate(resourceType, navigationType, originalUrl, firstPartyUrl, - initiator, QByteArray::fromStdString(request_.method)); + 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)); @@ -351,22 +361,21 @@ void InterceptedRequest::ContinueAfterIntercept() if (request_info_) { // cleanup in scope because of delete this and it's not needed else where after - decltype(request_info_) scoped_request_info(request_info_.take()); + 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 (info.changed) { if (info.shouldBlockRequest) return SendErrorAndCompleteImmediately(net::ERR_BLOCKED_BY_CLIENT); - for (auto header = info.extraHeaders.constBegin(); header != info.extraHeaders.constEnd(); ++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.shouldRedirectRequest) { net::RedirectInfo::FirstPartyURLPolicy first_party_url_policy = request_.update_first_party_url_on_redirect ? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT @@ -376,9 +385,6 @@ void InterceptedRequest::ContinueAfterIntercept() first_party_url_policy, request_.referrer_policy, request_.referrer.spec(), net::HTTP_TEMPORARY_REDIRECT, toGurl(info.url), absl::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; @@ -386,6 +392,11 @@ void InterceptedRequest::ContinueAfterIntercept() 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; } @@ -402,11 +413,11 @@ 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) @@ -426,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 |