summaryrefslogtreecommitdiffstats
path: root/src/core/net/custom_url_loader_factory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/net/custom_url_loader_factory.cpp')
-rw-r--r--src/core/net/custom_url_loader_factory.cpp139
1 files changed, 65 insertions, 74 deletions
diff --git a/src/core/net/custom_url_loader_factory.cpp b/src/core/net/custom_url_loader_factory.cpp
index dca69c20f..4274def99 100644
--- a/src/core/net/custom_url_loader_factory.cpp
+++ b/src/core/net/custom_url_loader_factory.cpp
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** 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 "custom_url_loader_factory.h"
#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -51,9 +14,12 @@
#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/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "url/url_util.h"
+#include "url/url_util_qt.h"
#include "api/qwebengineurlscheme.h"
#include "net/url_request_custom_job_proxy.h"
@@ -66,6 +32,7 @@
#include <QtCore/qiodevice.h>
#include <QtCore/qmimedatabase.h>
#include <QtCore/qmimedata.h>
+#include <QtCore/qpointer.h>
#include <QtCore/qurl.h>
namespace QtWebEngineCore {
@@ -77,13 +44,13 @@ class CustomURLLoader : public network::mojom::URLLoader
{
public:
static void CreateAndStart(const network::ResourceRequest &request,
- network::mojom::URLLoaderRequest loader,
- network::mojom::URLLoaderClientPtrInfo client_info,
+ mojo::PendingReceiver<network::mojom::URLLoader> loader,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client_remote,
QPointer<ProfileAdapter> profileAdapter)
{
// CustomURLLoader will handle its own life-cycle, and delete when
// the client lets go.
- auto *customUrlLoader = new CustomURLLoader(request, std::move(loader), std::move(client_info), profileAdapter);
+ auto *customUrlLoader = new CustomURLLoader(request, std::move(loader), std::move(client_remote), profileAdapter);
customUrlLoader->Start();
}
@@ -91,13 +58,13 @@ public:
void FollowRedirect(const std::vector<std::string> &removed_headers,
const net::HttpRequestHeaders &modified_headers,
const net::HttpRequestHeaders &modified_cors_exempt_headers, // FIXME: do something with this?
- const base::Optional<GURL> &new_url) override
+ const absl::optional<GURL> &new_url) override
{
// We can be asked for follow our own redirect
scoped_refptr<URLRequestCustomJobProxy> proxy = new URLRequestCustomJobProxy(this, m_proxy->m_scheme, m_proxy->m_profileAdapter);
m_proxy->m_client = nullptr;
// m_taskRunner->PostTask(FROM_HERE, base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
- base::PostTask(FROM_HERE, { content::BrowserThread::UI },
+ content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
m_proxy = std::move(proxy);
if (new_url)
@@ -116,14 +83,14 @@ public:
private:
CustomURLLoader(const network::ResourceRequest &request,
- network::mojom::URLLoaderRequest loader,
- network::mojom::URLLoaderClientPtrInfo client_info,
+ mojo::PendingReceiver<network::mojom::URLLoader> loader,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client_remote,
QPointer<ProfileAdapter> profileAdapter)
// ### We can opt to run the url-loader on the UI thread instead
- : m_taskRunner(base::CreateSingleThreadTaskRunner({ content::BrowserThread::IO }))
+ : m_taskRunner(content::GetIOThreadTaskRunner({}))
, m_proxy(new URLRequestCustomJobProxy(this, request.url.scheme(), profileAdapter))
, m_receiver(this, std::move(loader))
- , m_client(std::move(client_info))
+ , m_client(std::move(client_remote))
, m_request(request)
{
DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
@@ -134,6 +101,7 @@ private:
m_error = 0;
QWebEngineUrlScheme scheme = QWebEngineUrlScheme::schemeByName(QByteArray::fromStdString(request.url.scheme()));
m_corsEnabled = scheme.flags().testFlag(QWebEngineUrlScheme::CorsEnabled);
+ m_isLocal = scheme.flags().testFlag(QWebEngineUrlScheme::LocalScheme);
}
~CustomURLLoader() override = default;
@@ -147,10 +115,21 @@ private:
if (!m_request.request_initiator)
return CompleteWithFailure(net::ERR_INVALID_ARGUMENT);
- // Custom schemes are not covered by CorsURLLoader, so we need to reject CORS requests manually.
- if (!m_corsEnabled && !m_request.request_initiator->IsSameOriginWith(url::Origin::Create(m_request.url)))
- return CompleteWithFailure(network::CorsErrorStatus(network::mojom::CorsError::kCorsDisabledScheme));
+ if (m_isLocal) {
+ std::string fromScheme = m_request.request_initiator->GetTupleOrPrecursorTupleIfOpaque().scheme();
+ const std::vector<std::string> &localSchemes = url::GetLocalSchemes();
+ bool fromLocal = base::Contains(localSchemes, fromScheme);
+ bool hasLocalAccess = fromLocal;
+ if (const url::CustomScheme *cs = url::CustomScheme::FindScheme(fromScheme))
+ hasLocalAccess = cs->flags & (url::CustomScheme::LocalAccessAllowed | url::CustomScheme::Local);
+ if (!hasLocalAccess)
+ return CompleteWithFailure(net::ERR_ACCESS_DENIED);
+ } else if (!m_corsEnabled && !m_request.request_initiator->IsSameOriginWith(url::Origin::Create(m_request.url))) {
+ // Custom schemes are not covered by CorsURLLoader, so we need to reject CORS requests manually.
+ return CompleteWithFailure(network::CorsErrorStatus(network::mojom::CorsError::kCorsDisabledScheme));
+ }
}
+
if (mojo::CreateDataPipe(nullptr, m_pipeProducerHandle, m_pipeConsumerHandle) != MOJO_RESULT_OK)
return CompleteWithFailure(net::ERR_FAILED);
@@ -172,9 +151,11 @@ private:
m_firstBytePosition = m_byteRange.first_byte_position();
// m_taskRunner->PostTask(FROM_HERE,
- base::PostTask(FROM_HERE, { content::BrowserThread::UI },
- base::BindOnce(&URLRequestCustomJobProxy::initialize, m_proxy,
- m_request.url, m_request.method, m_request.request_initiator, std::move(headers)));
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&URLRequestCustomJobProxy::initialize, m_proxy, m_request.url,
+ m_request.method, m_request.request_initiator, std::move(headers),
+ m_request.request_body));
}
void CompleteWithFailure(network::CorsErrorStatus cors_error)
@@ -225,7 +206,7 @@ private:
m_device->close();
m_device = nullptr;
// m_taskRunner->PostTask(FROM_HERE, base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
- base::PostTask(FROM_HERE, { content::BrowserThread::UI },
+ content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
if (!wait_for_loader_error || !m_receiver.is_bound())
delete this;
@@ -284,11 +265,17 @@ private:
headers += "Access-Control-Allow-Credentials: true\n";
}
}
+ for (auto it = m_additionalResponseHeaders.cbegin();
+ it != m_additionalResponseHeaders.cend(); ++it) {
+ headers += it.key().toLower().toStdString() + ": " + it.value().toLower().toStdString()
+ + "\n";
+ }
m_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(net::HttpUtil::AssembleRawHeaders(headers));
m_head->encoded_data_length = m_head->headers->raw_headers().length();
if (!m_redirect.is_empty()) {
- m_head->content_length = m_head->encoded_body_length = -1;
+ m_head->content_length = {};
+ m_head->encoded_body_length = {};
net::RedirectInfo::FirstPartyURLPolicy first_party_url_policy =
m_request.update_first_party_url_on_redirect ? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT
: net::RedirectInfo::FirstPartyURLPolicy::NEVER_CHANGE_URL;
@@ -297,7 +284,7 @@ private:
m_request.site_for_cookies,
first_party_url_policy, m_request.referrer_policy,
m_request.referrer.spec(), net::HTTP_SEE_OTHER,
- m_redirect, base::nullopt, false /*insecure_scheme_was_upgraded*/);
+ m_redirect, absl::nullopt, false /*insecure_scheme_was_upgraded*/);
m_client->OnReceiveRedirect(redirectInfo, std::move(m_head));
m_head = nullptr;
// ### should m_request be updated with RedirectInfo? (see FollowRedirect)
@@ -307,19 +294,17 @@ private:
m_head->mime_type = m_mimeType;
m_head->charset = m_charset;
m_headerBytesRead = m_head->headers->raw_headers().length();
- m_client->OnReceiveResponse(std::move(m_head));
- m_client->OnStartLoadingResponseBody(std::move(m_pipeConsumerHandle));
+ m_client->OnReceiveResponse(std::move(m_head), std::move(m_pipeConsumerHandle), absl::nullopt);
m_head = nullptr;
- if (readAvailableData()) // May delete this
- return;
-
m_watcher = std::make_unique<mojo::SimpleWatcher>(
- FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC, m_taskRunner);
+ FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, m_taskRunner);
m_watcher->Watch(m_pipeProducerHandle.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
MOJO_WATCH_CONDITION_SATISFIED,
base::BindRepeating(&CustomURLLoader::notifyReadyWrite,
m_weakPtrFactory.GetWeakPtr()));
+
+ readAvailableData(); // May delete this
}
void notifyCanceled() override
{
@@ -358,8 +343,9 @@ private:
}
m_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(net::HttpUtil::AssembleRawHeaders(headers));
m_head->encoded_data_length = m_head->headers->raw_headers().length();
- m_head->content_length = m_head->encoded_body_length = -1;
- m_client->OnReceiveResponse(std::move(m_head));
+ m_head->content_length = {};
+ m_head->encoded_body_length = {};
+ m_client->OnReceiveResponse(std::move(m_head), mojo::ScopedDataPipeConsumerHandle(), absl::nullopt);
CompleteWithFailure(net::Error(error));
}
void notifyReadyRead() override
@@ -387,8 +373,10 @@ private:
uint32_t bufferSize = 0;
MojoResult beginResult = m_pipeProducerHandle->BeginWriteData(
&buffer, &bufferSize, MOJO_BEGIN_WRITE_DATA_FLAG_NONE);
- if (beginResult == MOJO_RESULT_SHOULD_WAIT)
+ if (beginResult == MOJO_RESULT_SHOULD_WAIT) {
+ m_watcher->ArmOrNotify();
return false; // Wait for pipe watcher
+ }
if (beginResult != MOJO_RESULT_OK)
break;
if (m_maxBytesToRead > 0 && m_maxBytesToRead <= int64_t{std::numeric_limits<uint32_t>::max()})
@@ -400,13 +388,20 @@ private:
m_totalBytesRead += bytesRead;
m_client->OnTransferSizeUpdated(m_totalBytesRead);
- if (m_device->atEnd() || (m_maxBytesToRead > 0 && m_totalBytesRead >= m_maxBytesToRead)) {
+ const bool deviceAtEnd = m_device->atEnd();
+ if ((deviceAtEnd && !m_device->isSequential())
+ || (m_maxBytesToRead > 0 && m_totalBytesRead >= m_maxBytesToRead)) {
OnTransferComplete(MOJO_RESULT_OK);
return true; // Done with reading
}
if (readResult == 0)
return false; // Wait for readyRead
+ if (readResult < 0 && deviceAtEnd && m_device->isSequential()) {
+ // Failure on read, and sequential device claiming to be at end, so treat it as a successful end-of-data.
+ OnTransferComplete(MOJO_RESULT_OK);
+ return true; // Done with reading
+ }
if (readResult < 0)
break;
}
@@ -439,7 +434,7 @@ private:
scoped_refptr<URLRequestCustomJobProxy> m_proxy;
mojo::Receiver<network::mojom::URLLoader> m_receiver;
- network::mojom::URLLoaderClientPtr m_client;
+ mojo::Remote<network::mojom::URLLoaderClient> m_client;
mojo::ScopedDataPipeProducerHandle m_pipeProducerHandle;
mojo::ScopedDataPipeConsumerHandle m_pipeConsumerHandle;
std::unique_ptr<mojo::SimpleWatcher> m_watcher;
@@ -452,16 +447,15 @@ private:
qint64 m_headerBytesRead = 0;
qint64 m_totalBytesRead = 0;
bool m_corsEnabled;
+ bool m_isLocal;
base::WeakPtrFactory<CustomURLLoader> m_weakPtrFactory{this};
-
- DISALLOW_COPY_AND_ASSIGN(CustomURLLoader);
};
class CustomURLLoaderFactory : public network::mojom::URLLoaderFactory {
public:
CustomURLLoaderFactory(ProfileAdapter *profileAdapter, mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
- : m_taskRunner(base::CreateSequencedTaskRunner({ content::BrowserThread::IO }))
+ : m_taskRunner(content::GetIOThreadTaskRunner({}))
, m_profileAdapter(profileAdapter)
{
m_receivers.set_disconnect_handler(base::BindRepeating(
@@ -472,7 +466,6 @@ public:
// network::mojom::URLLoaderFactory:
void CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> loader,
- int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest &request,
@@ -480,7 +473,6 @@ public:
const net::MutableNetworkTrafficAnnotationTag &traffic_annotation) override
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- Q_UNUSED(routing_id);
Q_UNUSED(request_id);
Q_UNUSED(options);
Q_UNUSED(traffic_annotation);
@@ -513,7 +505,6 @@ public:
const scoped_refptr<base::SequencedTaskRunner> m_taskRunner;
mojo::ReceiverSet<network::mojom::URLLoaderFactory> m_receivers;
QPointer<ProfileAdapter> m_profileAdapter;
- DISALLOW_COPY_AND_ASSIGN(CustomURLLoaderFactory);
};
} // namespace