diff options
-rw-r--r-- | src/core/api/qwebengineurlscheme.cpp | 8 | ||||
-rw-r--r-- | src/core/api/qwebengineurlscheme.h | 1 | ||||
-rw-r--r-- | src/core/net/url_request_custom_job.cpp | 26 | ||||
-rw-r--r-- | src/core/net/url_request_custom_job.h | 3 | ||||
-rw-r--r-- | src/core/net/url_request_custom_job_proxy.cpp | 3 | ||||
-rw-r--r-- | tests/auto/widgets/origins/resources/redirect.css | 8 | ||||
-rw-r--r-- | tests/auto/widgets/origins/resources/redirect.html | 10 | ||||
-rw-r--r-- | tests/auto/widgets/origins/tst_origins.cpp | 55 |
8 files changed, 113 insertions, 1 deletions
diff --git a/src/core/api/qwebengineurlscheme.cpp b/src/core/api/qwebengineurlscheme.cpp index f4efad717..6c7d1780c 100644 --- a/src/core/api/qwebengineurlscheme.cpp +++ b/src/core/api/qwebengineurlscheme.cpp @@ -59,6 +59,7 @@ ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::NoAccessAllowed, url::CustomScheme::NoAc ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ServiceWorkersAllowed, url::CustomScheme::ServiceWorkersAllowed) ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ViewSourceAllowed, url::CustomScheme::ViewSourceAllowed) ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ContentSecurityPolicyIgnored, url::CustomScheme::ContentSecurityPolicyIgnored) +ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::CorsEnabled, url::CustomScheme::CorsEnabled) static bool g_schemesLocked = false; @@ -190,6 +191,13 @@ public: \value ContentSecurityPolicyIgnored Indicates that accesses to this scheme should bypass all Content-Security-Policy checks. + + \value CorsEnabled + Enables cross-origin resource sharing (CORS) for this scheme. This flag is + required in order to, for example, use the scheme with the \l + {https://fetch.spec.whatwg.org/}{Fetch API}, or to deliver CSS fonts to a + different origin. The appropriate CORS headers are generated automatically by + the QWebEngineUrlRequestJob class. (Added in Qt 5.14) */ QWebEngineUrlScheme::QWebEngineUrlScheme(QWebEngineUrlSchemePrivate *d) : d(d) {} diff --git a/src/core/api/qwebengineurlscheme.h b/src/core/api/qwebengineurlscheme.h index 095b47320..ecac44184 100644 --- a/src/core/api/qwebengineurlscheme.h +++ b/src/core/api/qwebengineurlscheme.h @@ -76,6 +76,7 @@ public: ServiceWorkersAllowed = 0x10, ViewSourceAllowed = 0x20, ContentSecurityPolicyIgnored = 0x40, + CorsEnabled = 0x80, }; Q_DECLARE_FLAGS(Flags, Flag) Q_FLAG(Flags) diff --git a/src/core/net/url_request_custom_job.cpp b/src/core/net/url_request_custom_job.cpp index cba9b4dc5..dd213d4f8 100644 --- a/src/core/net/url_request_custom_job.cpp +++ b/src/core/net/url_request_custom_job.cpp @@ -40,10 +40,13 @@ #include "url_request_custom_job.h" #include "url_request_custom_job_proxy.h" +#include "api/qwebengineurlscheme.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 "net/base/io_buffer.h" +#include "net/http/http_util.h" #include <QIODevice> @@ -62,6 +65,9 @@ URLRequestCustomJob::URLRequestCustomJob(URLRequest *request, , m_pendingReadSize(0) , m_pendingReadPos(0) , m_pendingReadBuffer(nullptr) + , m_corsEnabled(QWebEngineUrlScheme::schemeByName(QByteArray::fromStdString(scheme)) + .flags().testFlag(QWebEngineUrlScheme::CorsEnabled)) + , m_httpStatusCode(500) { } @@ -136,6 +142,26 @@ bool URLRequestCustomJob::GetCharset(std::string* charset) return false; } +void URLRequestCustomJob::GetResponseInfo(HttpResponseInfo* info) +{ + // Based on net::URLRequestRedirectJob::StartAsync() + + if (!m_corsEnabled) + return; + + std::string headers; + headers += base::StringPrintf("HTTP/1.1 %i OK\n", m_httpStatusCode); + if (m_redirect.is_valid()) + headers += base::StringPrintf("Location: %s\n", m_redirect.spec().c_str()); + std::string origin; + if (request_->extra_request_headers().GetHeader("Origin", &origin)) { + headers += base::StringPrintf("Access-Control-Allow-Origin: %s\n", origin.c_str()); + headers += "Access-Control-Allow-Credentials: true\n"; + } + + info->headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); +} + bool URLRequestCustomJob::IsRedirectResponse(GURL* location, int* http_status_code, bool* /*insecure_scheme_was_upgraded*/) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); diff --git a/src/core/net/url_request_custom_job.h b/src/core/net/url_request_custom_job.h index 16be76f29..e1e8e9fba 100644 --- a/src/core/net/url_request_custom_job.h +++ b/src/core/net/url_request_custom_job.h @@ -64,6 +64,7 @@ public: int ReadRawData(net::IOBuffer *buf, int buf_size) override; bool GetMimeType(std::string *mimeType) const override; bool GetCharset(std::string *charset) override; + void GetResponseInfo(net::HttpResponseInfo* info) override; bool IsRedirectResponse(GURL* location, int* http_status_code, bool* insecure_scheme_was_upgraded) override; protected: @@ -80,6 +81,8 @@ private: int m_pendingReadSize; int m_pendingReadPos; net::IOBuffer *m_pendingReadBuffer; + const bool m_corsEnabled; + int m_httpStatusCode; friend class URLRequestCustomJobProxy; diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp index 72d14450e..b9ccf7ea4 100644 --- a/src/core/net/url_request_custom_job_proxy.cpp +++ b/src/core/net/url_request_custom_job_proxy.cpp @@ -100,6 +100,7 @@ void URLRequestCustomJobProxy::reply(std::string mimeType, QIODevice *device) m_job->set_expected_content_size(size); if (m_job->m_device && m_job->m_device->isReadable()) { m_started = true; + m_job->m_httpStatusCode = 200; m_job->NotifyHeadersComplete(); } else { fail(ERR_INVALID_URL); @@ -114,6 +115,7 @@ void URLRequestCustomJobProxy::redirect(GURL url) if (m_job->m_device || m_job->m_error) return; m_job->m_redirect = url; + m_job->m_httpStatusCode = 303; m_started = true; m_job->NotifyHeadersComplete(); } @@ -138,6 +140,7 @@ void URLRequestCustomJobProxy::fail(int error) if (!m_job) return; m_job->m_error = error; + m_job->m_httpStatusCode = 500; if (m_job->m_device) m_job->m_device->close(); if (!m_started) diff --git a/tests/auto/widgets/origins/resources/redirect.css b/tests/auto/widgets/origins/resources/redirect.css new file mode 100644 index 000000000..41d7560cc --- /dev/null +++ b/tests/auto/widgets/origins/resources/redirect.css @@ -0,0 +1,8 @@ +@font-face { + font-family: 'MyWebFont'; + src: url('redirect1:/resources/Akronim-Regular.woff2') format('woff2'); +} + +body { + font-family: 'MyWebFont', Fallback, sans-serif; +} diff --git a/tests/auto/widgets/origins/resources/redirect.html b/tests/auto/widgets/origins/resources/redirect.html new file mode 100644 index 000000000..04948e14b --- /dev/null +++ b/tests/auto/widgets/origins/resources/redirect.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <title>redirect</title> + <link rel="stylesheet" href="redirect1:/resources/redirect.css"> + </head> + <body> + Text + </body> +</html> diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp index 8fed79975..02d5bfba3 100644 --- a/tests/auto/widgets/origins/tst_origins.cpp +++ b/tests/auto/widgets/origins/tst_origins.cpp @@ -122,6 +122,18 @@ void registerSchemes() scheme.setDefaultPort(42); QWebEngineUrlScheme::registerScheme(scheme); } + + { + QWebEngineUrlScheme scheme(QBAL("redirect1")); + scheme.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("redirect2")); + scheme.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(scheme); + } } Q_CONSTRUCTOR_FUNCTION(registerSchemes) @@ -145,13 +157,26 @@ public: profile->installUrlSchemeHandler(QBAL("HostSyntax-ContentSecurityPolicyIgnored"), this); profile->installUrlSchemeHandler(QBAL("HostAndPortSyntax"), this); profile->installUrlSchemeHandler(QBAL("HostPortAndUserInformationSyntax"), this); + profile->installUrlSchemeHandler(QBAL("redirect1"), this); + profile->installUrlSchemeHandler(QBAL("redirect2"), this); } + QVector<QUrl> &requests() { return m_requests; } + private: void requestStarted(QWebEngineUrlRequestJob *job) override { + QUrl url = job->requestUrl(); + m_requests << url; + + if (url.scheme() == QBAL("redirect1")) { + url.setScheme(QBAL("redirect2")); + job->redirect(url); + return; + } + QString pathPrefix = QSL(THIS_DIR); - QString pathSuffix = job->requestUrl().path(); + QString pathSuffix = url.path(); QFile *file = new QFile(pathPrefix + pathSuffix, job); if (!file->open(QIODevice::ReadOnly)) { job->fail(QWebEngineUrlRequestJob::RequestFailed); @@ -160,8 +185,12 @@ private: QByteArray mimeType = QBAL("text/html"); if (pathSuffix.endsWith(QSL(".js"))) mimeType = QBAL("application/javascript"); + else if (pathSuffix.endsWith(QSL(".css"))) + mimeType = QBAL("text/css"); job->reply(mimeType, file); } + + QVector<QUrl> m_requests; }; class tst_Origins final : public QObject { @@ -169,6 +198,7 @@ class tst_Origins final : public QObject { private Q_SLOTS: void initTestCase(); + void cleanup(); void cleanupTestCase(); void jsUrlCanon(); @@ -187,6 +217,7 @@ private Q_SLOTS: void serviceWorker(); void viewSource(); void createObjectURL(); + void redirect(); private: bool load(const QUrl &url) @@ -209,10 +240,19 @@ private: void tst_Origins::initTestCase() { + QTest::ignoreMessage( + QtWarningMsg, + QRegularExpression("Please register the custom scheme 'tst'.*")); + m_page = new QWebEnginePage(&m_profile, nullptr); m_handler = new TstUrlSchemeHandler(&m_profile); } +void tst_Origins::cleanup() +{ + m_handler->requests().clear(); +} + void tst_Origins::cleanupTestCase() { delete m_handler; @@ -772,5 +812,18 @@ void tst_Origins::createObjectURL() QVERIFY(eval(QSL("result")).toString().startsWith(QSL("blob:tst:"))); } +void tst_Origins::redirect() +{ + QVERIFY(load(QSL("redirect1:/resources/redirect.html"))); + QTRY_COMPARE(m_handler->requests().size(), 7); + QCOMPARE(m_handler->requests()[0], QUrl(QStringLiteral("redirect1:/resources/redirect.html"))); + QCOMPARE(m_handler->requests()[1], QUrl(QStringLiteral("redirect2:/resources/redirect.html"))); + QCOMPARE(m_handler->requests()[2], QUrl(QStringLiteral("redirect1:/resources/redirect.css"))); + QCOMPARE(m_handler->requests()[3], QUrl(QStringLiteral("redirect2:/resources/redirect.css"))); + QCOMPARE(m_handler->requests()[4], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2"))); + QCOMPARE(m_handler->requests()[5], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2"))); + QCOMPARE(m_handler->requests()[6], QUrl(QStringLiteral("redirect2:/resources/Akronim-Regular.woff2"))); +} + QTEST_MAIN(tst_Origins) #include "tst_origins.moc" |