diff options
Diffstat (limited to 'Source/WebCore/platform/network')
6 files changed, 184 insertions, 69 deletions
diff --git a/Source/WebCore/platform/network/qt/BlobUrlConversion.cpp b/Source/WebCore/platform/network/qt/BlobUrlConversion.cpp new file mode 100644 index 000000000..8f61eaeb9 --- /dev/null +++ b/Source/WebCore/platform/network/qt/BlobUrlConversion.cpp @@ -0,0 +1,98 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2017 Konstantin Tokarev <annulen@yandex.ru> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "BlobUrlConversion.h" + +#include "BlobData.h" +#include "BlobRegistryImpl.h" + +#include <QUrl> +#include <wtf/text/Base64.h> + +namespace WebCore { + +static bool appendBlobResolved(Vector<char>& out, const URL& url, QString* contentType = 0) +{ + RefPtr<BlobData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url); + if (!blobData) + return false; + + if (contentType) + *contentType = blobData->contentType(); + + BlobDataItemList::const_iterator it = blobData->items().begin(); + const BlobDataItemList::const_iterator itend = blobData->items().end(); + for (; it != itend; ++it) { + const BlobDataItem& blobItem = *it; + if (blobItem.type() == BlobDataItem::Type::Data) { + if (!out.tryAppend(reinterpret_cast<const char*>(blobItem.data().data()->data()) + blobItem.offset(), blobItem.length())) + return false; + } else if (blobItem.type() == BlobDataItem::Type::File) { + // File types are not allowed here, so just ignore it. + RELEASE_ASSERT_WITH_MESSAGE(false, "File types are not allowed here"); + } else + ASSERT_NOT_REACHED(); + } + return true; +} + +static QUrl resolveBlobUrl(const URL& url) +{ + RefPtr<BlobData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url); + if (!blobData) + return QUrl(); + + Vector<char> data; + QString contentType; + if (!appendBlobResolved(data, url, &contentType)) { + qWarning("Failed to convert blob data to base64: cannot allocate memory for continuous blob data"); + return QUrl(); + } + + // QByteArray::{from,to}Base64 are prone to integer overflow, this is the maximum size that can be safe + size_t maxBase64Size = std::numeric_limits<int>::max() / 3 - 1; + + Vector<char> base64; + WTF::base64Encode(data, base64, WTF::Base64URLPolicy); + if (base64.isEmpty() || base64.size() > maxBase64Size) { + qWarning("Failed to convert blob data to base64: data is too large"); + return QUrl(); + } + + QString dataUri(QStringLiteral("data:")); + dataUri.append(contentType); + dataUri.append(QStringLiteral(";base64,")); + dataUri.reserve(dataUri.size() + base64.size()); + dataUri.append(QLatin1String(base64.data(), base64.size())); + return QUrl(dataUri); +} + +QUrl convertBlobToDataUrl(const QUrl& url) +{ + QT_TRY { + return resolveBlobUrl(url); + } QT_CATCH(const std::bad_alloc &) { + qWarning("Failed to convert blob data to base64: not enough memory"); + } + return QUrl(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/network/qt/BlobUrlConversion.h b/Source/WebCore/platform/network/qt/BlobUrlConversion.h new file mode 100644 index 000000000..2dbd0a680 --- /dev/null +++ b/Source/WebCore/platform/network/qt/BlobUrlConversion.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2017 Konstantin Tokarev <annulen@yandex.ru> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +QT_BEGIN_NAMESPACE +class QUrl; +QT_END_NAMESPACE + +namespace WebCore { + +QUrl convertBlobToDataUrl(const QUrl&); + +} diff --git a/Source/WebCore/platform/network/qt/CookieJarQt.cpp b/Source/WebCore/platform/network/qt/CookieJarQt.cpp index 3b08c06cd..d1cf87fdd 100644 --- a/Source/WebCore/platform/network/qt/CookieJarQt.cpp +++ b/Source/WebCore/platform/network/qt/CookieJarQt.cpp @@ -42,12 +42,21 @@ #include <QNetworkCookie> #include <QStringList> #include <QVariant> +#include <wtf/text/StringBuilder.h> #include <wtf/text/WTFString.h> namespace WebCore { static SharedCookieJarQt* s_sharedCookieJarQt = 0; +static void appendCookie(StringBuilder& builder, const QNetworkCookie& cookie) +{ + if (!builder.isEmpty()) + builder.append("; "); + QByteArray rawData = cookie.toRawForm(QNetworkCookie::NameAndValueOnly); + builder.append(rawData.constData(), rawData.length()); +} + void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& value) { QNetworkCookieJar* jar = session.context() ? session.context()->networkAccessManager()->cookieJar() : SharedCookieJarQt::shared(); @@ -59,7 +68,8 @@ void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstPar if (!thirdPartyCookiePolicyPermits(session.context(), urlForCookies, firstPartyUrl)) return; - QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(QString(value).toLatin1()); + CString cookieString = value.latin1(); + QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(QByteArray::fromRawData(cookieString.data(), cookieString.length())); QList<QNetworkCookie>::Iterator it = cookies.begin(); while (it != cookies.end()) { if (it->isHttpOnly()) @@ -86,14 +96,13 @@ String cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty if (cookies.isEmpty()) return String(); - QStringList resultCookies; - foreach (const QNetworkCookie& networkCookie, cookies) { - if (networkCookie.isHttpOnly()) + StringBuilder builder; + for (const auto& cookie : cookies) { + if (cookie.isHttpOnly()) continue; - resultCookies.append(QString::fromLatin1(networkCookie.toRawForm(QNetworkCookie::NameAndValueOnly).constData())); + appendCookie(builder, cookie); } - - return resultCookies.join(QLatin1String("; ")); + return builder.toString(); } String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& url) @@ -106,11 +115,10 @@ String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const if (cookies.isEmpty()) return String(); - QStringList resultCookies; - foreach (QNetworkCookie networkCookie, cookies) - resultCookies.append(QString::fromLatin1(networkCookie.toRawForm(QNetworkCookie::NameAndValueOnly).constData())); - - return resultCookies.join(QLatin1String("; ")); + StringBuilder builder; + for (const auto& cookie : cookies) + appendCookie(builder, cookie); + return builder.toString(); } bool cookiesEnabled(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& /*url*/) diff --git a/Source/WebCore/platform/network/qt/DNSQt.cpp b/Source/WebCore/platform/network/qt/DNSQt.cpp index b12cbaa09..4559d17a0 100644 --- a/Source/WebCore/platform/network/qt/DNSQt.cpp +++ b/Source/WebCore/platform/network/qt/DNSQt.cpp @@ -24,6 +24,7 @@ #include <QHostInfo> #include <QObject> #include <QString> +#include <wtf/NeverDestroyed.h> #include <wtf/text/WTFString.h> namespace WebCore { @@ -34,7 +35,7 @@ public: DnsPrefetchHelper() : QObject() { } public Q_SLOTS: - void lookup(QString hostname) + void lookup(const String& hostname) { if (hostname.isEmpty()) { DNSResolveQueue::singleton().decrementRequestCount(); @@ -71,8 +72,8 @@ void DNSResolveQueue::updateIsUsingProxy() // This is called by the platform-independent DNSResolveQueue. void DNSResolveQueue::platformResolve(const String& hostname) { - static DnsPrefetchHelper dnsPrefetchHelper; - dnsPrefetchHelper.lookup(QString(hostname)); + static NeverDestroyed<DnsPrefetchHelper> dnsPrefetchHelper; + dnsPrefetchHelper.get().lookup(hostname); } } // namespace diff --git a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index cd096bfe7..1b60c5131 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -647,7 +647,10 @@ void QNetworkReplyHandler::redirect(ResourceResponse& response, const QUrl& redi { ASSERT(!m_queue.deferSignals()); - QUrl newUrl = m_replyWrapper->reply()->url().resolved(redirection); + QUrl currentUrl = m_replyWrapper->reply()->url(); + QUrl newUrl = currentUrl.resolved(redirection); + if (currentUrl.hasFragment()) + newUrl.setFragment(currentUrl.fragment()); ResourceHandleClient* client = m_resourceHandle->client(); ASSERT(client); diff --git a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp index 655724a4c..c54a8115b 100644 --- a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -18,18 +18,27 @@ */ #include "config.h" -#include "NetworkingContext.h" #include "ResourceRequest.h" -#include "ThirdPartyCookiesQt.h" - -#include "BlobData.h" -#include "BlobRegistryImpl.h" -#include <qglobal.h> +#include "BlobUrlConversion.h" +#include "NetworkingContext.h" +#include "ThirdPartyCookiesQt.h" #include <QNetworkRequest> #include <QUrl> +// HTTP/2 is implemented since Qt 5.8, but QTBUG-64359 makes it unusable in browser +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 4) +#define USE_HTTP2 1 +#endif + +// HTTP2AllowedAttribute enforces HTTP/2 instead of negotiating, see QTBUG-61397 +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) +#define HTTP2_IS_BUGGY_WITHOUT_HTTPS 1 +#else +#define HTTP2_IS_BUGGY_WITHOUT_HTTPS 0 +#endif + namespace WebCore { // The limit can be found in qhttpnetworkconnection.cpp. @@ -43,44 +52,11 @@ unsigned initializeMaximumHTTPConnectionCountPerHost() return 6 * (1 + 3 + 2); } -static void appendBlobResolved(QByteArray& data, const QUrl& url, QString* contentType = 0) +static QUrl toQUrl(const URL& url) { - RefPtr<BlobData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url); - if (!blobData) - return; - - if (contentType) - *contentType = blobData->contentType(); - - BlobDataItemList::const_iterator it = blobData->items().begin(); - const BlobDataItemList::const_iterator itend = blobData->items().end(); - for (; it != itend; ++it) { - const BlobDataItem& blobItem = *it; - if (blobItem.type() == BlobDataItem::Type::Data) - data.append(reinterpret_cast<const char*>(blobItem.data().data()->data()) + static_cast<int>(blobItem.offset()), static_cast<int>(blobItem.length())); - else if (blobItem.type() == BlobDataItem::Type::File) { - // File types are not allowed here, so just ignore it. - RELEASE_ASSERT_WITH_MESSAGE(false, "File types are not allowed here"); - } else - ASSERT_NOT_REACHED(); - } -} - -static void resolveBlobUrl(const QUrl& url, QUrl& resolvedUrl) -{ - RefPtr<BlobData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url); - if (!blobData) - return; - - QByteArray data; - QString contentType; - appendBlobResolved(data, url, &contentType); - - QString dataUri(QStringLiteral("data:")); - dataUri.append(contentType); - dataUri.append(QStringLiteral(";base64,")); - dataUri.append(QString::fromLatin1(data.toBase64())); - resolvedUrl = QUrl(dataUri); + if (url.protocolIsBlob()) + return convertBlobToDataUrl(url); + return url; } static inline QByteArray stringToByteArray(const String& string) @@ -93,19 +69,19 @@ static inline QByteArray stringToByteArray(const String& string) QNetworkRequest ResourceRequest::toNetworkRequest(NetworkingContext *context) const { QNetworkRequest request; - QUrl newurl = url(); - - if (newurl.scheme() == QLatin1String("blob")) - resolveBlobUrl(url(), newurl); - - request.setUrl(newurl); + const URL& originalUrl = url(); + request.setUrl(toQUrl(originalUrl)); request.setOriginatingObject(context ? context->originatingObject() : 0); -#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) - // HTTP2AllowedAttribute enforces HTTP/2 instead of negotiating, see QTBUG-61397 - if (newurl.scheme().toLower() == QLatin1String("https")) - request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); +#if USE(HTTP2) +#if HTTP2_IS_BUGGY_WITHOUT_HTTPS + if (originalUrl.protocolIs("https")) #endif + { + request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); + } +#endif // USE(HTTP2) + const HTTPHeaderMap &headers = httpHeaderFields(); for (HTTPHeaderMap::const_iterator it = headers.begin(), end = headers.end(); |