blob: 279bd5077ff1ac24c9a52678a7ee07ccc7c8230c [file] [log] [blame]
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include "url_request_notification.h"
#include "base/supports_user_data.h"
#include "base/task/post_task.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request.h"
#include "web_contents_adapter_client.h"
#include "web_contents_view_qt.h"
#include "profile_io_data_qt.h"
#include "qwebengineurlrequestinfo_p.h"
#include "type_conversion.h"
#include <QVariant>
namespace QtWebEngineCore {
// Calls cancel() when the URLRequest is destroyed.
class UserData : public base::SupportsUserData::Data
{
public:
UserData(URLRequestNotification *ptr) : m_ptr(ptr) {}
~UserData() { m_ptr->cancel(); }
static const char key[];
private:
URLRequestNotification *m_ptr;
};
const char UserData::key[] = "QtWebEngineCore::URLRequestNotification";
static content::ResourceType fromQt(QWebEngineUrlRequestInfo::ResourceType resourceType)
{
return static_cast<content::ResourceType>(resourceType);
}
URLRequestNotification::URLRequestNotification(net::URLRequest *request, bool isMainFrameRequest, GURL *newUrl,
QWebEngineUrlRequestInfo &&requestInfo,
content::ResourceRequestInfo::WebContentsGetter webContentsGetter,
net::CompletionOnceCallback callback, QPointer<ProfileAdapter> adapter)
: m_request(request)
, m_isMainFrameRequest(isMainFrameRequest)
, m_newUrl(newUrl)
, m_originalUrl(requestInfo.requestUrl())
, m_requestInfo(std::move(requestInfo))
, m_webContentsGetter(webContentsGetter)
, m_callback(std::move(callback))
, m_profileAdapter(adapter)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
m_request->SetUserData(UserData::key, std::make_unique<UserData>(this));
base::PostTaskWithTraits(
FROM_HERE,
{content::BrowserThread::UI},
base::BindOnce(&URLRequestNotification::notify, base::Unretained(this)));
}
void URLRequestNotification::notify()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// May run concurrently with cancel() so no peeking at m_request here.
int result = net::OK;
content::WebContents *webContents = m_webContentsGetter.Run();
if (webContents) {
if (m_profileAdapter && m_profileAdapter->requestInterceptor()) {
QWebEngineUrlRequestInterceptor *interceptor = m_profileAdapter->requestInterceptor();
if (!interceptor->property("deprecated").toBool())
interceptor->interceptRequest(m_requestInfo);
}
WebContentsAdapterClient *client =
WebContentsViewQt::from(static_cast<content::WebContentsImpl*>(webContents)->GetView())->client();
if (!m_requestInfo.changed()) {
client->interceptRequest(m_requestInfo);
}
if (m_requestInfo.changed()) {
result = m_requestInfo.d_ptr->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
// We handle the rest of the changes later when we are back in I/O thread
}
// Only do navigationRequested on MAIN_FRAME and SUB_FRAME resources
if (result == net::OK && content::IsResourceTypeFrame(fromQt(m_requestInfo.resourceType()))) {
int navigationRequestAction = WebContentsAdapterClient::AcceptRequest;
client->navigationRequested(m_requestInfo.navigationType(),
m_requestInfo.requestUrl(),
navigationRequestAction,
m_isMainFrameRequest);
result = net::ERR_FAILED;
switch (static_cast<WebContentsAdapterClient::NavigationRequestAction>(navigationRequestAction)) {
case WebContentsAdapterClient::AcceptRequest:
result = net::OK;
break;
case WebContentsAdapterClient::IgnoreRequest:
result = net::ERR_ABORTED;
break;
}
DCHECK(result != net::ERR_FAILED);
}
}
// Run the callback on the IO thread.
base::PostTaskWithTraits(
FROM_HERE,
{content::BrowserThread::IO},
base::BindOnce(&URLRequestNotification::complete, base::Unretained(this), result));
}
void URLRequestNotification::cancel()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// May run concurrently with notify() but we only touch m_request here.
m_request = nullptr;
}
void URLRequestNotification::complete(int error)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (m_request) {
if (m_requestInfo.changed()) {
if (m_originalUrl != m_requestInfo.d_ptr->url)
*m_newUrl = toGurl(m_requestInfo.d_ptr->url);
if (!m_requestInfo.d_ptr->extraHeaders.isEmpty()) {
auto end = m_requestInfo.d_ptr->extraHeaders.constEnd();
for (auto header = m_requestInfo.d_ptr->extraHeaders.constBegin(); header != end; ++header) {
std::string h = header.key().toStdString();
if (base::LowerCaseEqualsASCII(h, "referer")) {
m_request->SetReferrer(header.value().toStdString());
} else {
m_request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true);
}
}
}
}
if (m_request->status().status() != net::URLRequestStatus::CANCELED)
std::move(m_callback).Run(error);
m_request->RemoveUserData(UserData::key);
}
delete this;
}
}