diff --git a/dom/file/uri/BlobURLChannel.cpp b/dom/file/uri/BlobURLChannel.cpp new file mode 100644 index 000000000000..da4ae283f650 --- /dev/null +++ b/dom/file/uri/BlobURLChannel.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BlobURLChannel.h" + +using namespace mozilla::dom; + +BlobURLChannel::BlobURLChannel(nsIURI* aURI, + nsILoadInfo* aLoadInfo) + : mInitialized(false) +{ + SetURI(aURI); + SetOriginalURI(aURI); + SetLoadInfo(aLoadInfo); + + // If we're sandboxed, make sure to clear any owner the channel + // might already have. + if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) { + SetOwner(nullptr); + } +} + +BlobURLChannel::~BlobURLChannel() = default; + +void +BlobURLChannel::InitFailed() +{ + MOZ_ASSERT(!mInitialized); + MOZ_ASSERT(!mInputStream); + mInitialized = true; +} + +void +BlobURLChannel::Initialize(BlobImpl* aBlobImpl) +{ + MOZ_ASSERT(!mInitialized); + + nsAutoString contentType; + aBlobImpl->GetType(contentType); + SetContentType(NS_ConvertUTF16toUTF8(contentType)); + + if (aBlobImpl->IsFile()) { + nsString filename; + aBlobImpl->GetName(filename); + SetContentDispositionFilename(filename); + } + + ErrorResult rv; + uint64_t size = aBlobImpl->GetSize(rv); + if (NS_WARN_IF(rv.Failed())) { + InitFailed(); + return; + } + + SetContentLength(size); + + aBlobImpl->CreateInputStream(getter_AddRefs(mInputStream), rv); + if (NS_WARN_IF(rv.Failed())) { + InitFailed(); + return; + } + + MOZ_ASSERT(mInputStream); + mInitialized = true; +} + +nsresult +BlobURLChannel::OpenContentStream(bool aAsync, nsIInputStream** aResult, + nsIChannel** aChannel) +{ + MOZ_ASSERT(mInitialized); + + if (!mInputStream) { + return NS_ERROR_MALFORMED_URI; + } + + EnableSynthesizedProgressEvents(true); + + nsCOMPtr stream = mInputStream; + stream.forget(aResult); + + return NS_OK; +} + +void +BlobURLChannel::OnChannelDone() +{ + mInputStream = nullptr; +} diff --git a/dom/file/uri/BlobURLChannel.h b/dom/file/uri/BlobURLChannel.h new file mode 100644 index 000000000000..0fdf2efd1888 --- /dev/null +++ b/dom/file/uri/BlobURLChannel.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_BlobURLChannel_h +#define mozilla_dom_BlobURLChannel_h + +#include "nsBaseChannel.h" +#include "nsCOMPtr.h" +#include "nsIInputStream.h" + +class nsIURI; + +namespace mozilla { +namespace dom { + +class BlobImpl; + +class BlobURLChannel final : public nsBaseChannel +{ +public: + BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo); + + // This method is called when there is not a valid BlobImpl for this channel. + // This method will make ::OpenContentStream to return NS_ERROR_MALFORMED_URI. + void InitFailed(); + + // There is a valid BlobImpl for the channel. The blob's inputStream will be + // used when ::OpenContentStream is called. + void Initialize(BlobImpl* aBlobImpl); + +private: + ~BlobURLChannel(); + + nsresult OpenContentStream(bool aAsync, nsIInputStream** aResult, + nsIChannel** aChannel) override; + + void OnChannelDone() override; + + // If Initialize() is called, this will contain the blob's inputStream. + nsCOMPtr mInputStream; + + // This boolean is used to check that InitFailed() or Initialize() are called + // just once. + bool mInitialized; +}; + +} // dom namespace +} // mozilla namespace + +#endif /* mozilla_dom_BlobURLChannel_h */ diff --git a/dom/file/uri/BlobURLProtocolHandler.cpp b/dom/file/uri/BlobURLProtocolHandler.cpp index 3a323570bd51..7037486f6df7 100644 --- a/dom/file/uri/BlobURLProtocolHandler.cpp +++ b/dom/file/uri/BlobURLProtocolHandler.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "BlobURLProtocolHandler.h" +#include "BlobURLChannel.h" #include "mozilla/dom/BlobURL.h" #include "mozilla/dom/ChromeUtils.h" @@ -841,29 +842,34 @@ BlobURLProtocolHandler::NewURI(const nsACString& aSpec, } NS_IMETHODIMP -BlobURLProtocolHandler::NewChannel2(nsIURI* uri, +BlobURLProtocolHandler::NewChannel2(nsIURI* aURI, nsILoadInfo* aLoadInfo, - nsIChannel** result) + nsIChannel** aResult) { - *result = nullptr; + RefPtr channel = new BlobURLChannel(aURI, aLoadInfo); - DataInfo* info = GetDataInfoFromURI(uri, true /*aAlsoIfRevoked */); + auto raii = MakeScopeExit([&] { + channel->InitFailed(); + channel.forget(aResult); + }); + + DataInfo* info = GetDataInfoFromURI(aURI, true /*aAlsoIfRevoked */); if (!info || info->mObjectType != DataInfo::eBlobImpl || !info->mBlobImpl) { - return NS_ERROR_DOM_BAD_URI; + return NS_OK; } RefPtr blobImpl = info->mBlobImpl; - nsCOMPtr uriPrinc = do_QueryInterface(uri); + nsCOMPtr uriPrinc = do_QueryInterface(aURI); if (!uriPrinc) { - return NS_ERROR_DOM_BAD_URI; + return NS_OK; } nsCOMPtr principal; nsresult rv = uriPrinc->GetPrincipal(getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_SUCCESS(rv, NS_OK); if (!principal) { - return NS_ERROR_DOM_BAD_URI; + return NS_OK; } MOZ_ASSERT(info->mPrincipal == principal); @@ -881,47 +887,13 @@ BlobURLProtocolHandler::NewChannel2(nsIURI* uri, !nsContentUtils::IsSystemPrincipal(aLoadInfo->LoadingPrincipal()) && !ChromeUtils::IsOriginAttributesEqualIgnoringFPD(aLoadInfo->GetOriginAttributes(), BasePrincipal::Cast(principal)->OriginAttributesRef())) { - return NS_ERROR_DOM_BAD_URI; + return NS_OK; } - ErrorResult error; - nsCOMPtr stream; - blobImpl->CreateInputStream(getter_AddRefs(stream), error); - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - - nsAutoString contentType; - blobImpl->GetType(contentType); - - nsCOMPtr channel; - rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), - uri, - stream.forget(), - NS_ConvertUTF16toUTF8(contentType), - EmptyCString(), // aContentCharset - aLoadInfo); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (blobImpl->IsFile()) { - nsString filename; - blobImpl->GetName(filename); - channel->SetContentDispositionFilename(filename); - } - - uint64_t size = blobImpl->GetSize(error); - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - - channel->SetOriginalURI(uri); - channel->SetContentType(NS_ConvertUTF16toUTF8(contentType)); - channel->SetContentLength(size); - - channel.forget(result); + raii.release(); + channel->Initialize(blobImpl); + channel.forget(aResult); return NS_OK; } diff --git a/dom/file/uri/moz.build b/dom/file/uri/moz.build index b237f81a6b8f..1bf3b9ccc673 100644 --- a/dom/file/uri/moz.build +++ b/dom/file/uri/moz.build @@ -15,12 +15,14 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'BlobURL.cpp', + 'BlobURLChannel.cpp', 'BlobURLProtocolHandler.cpp', 'FontTableURIProtocolHandler.cpp', ] LOCAL_INCLUDES += [ '/dom/file', + '/netwerk/base', ] include('/ipc/chromium/chromium-config.mozbuild') diff --git a/testing/web-platform/meta/FileAPI/url/url-with-xhr.any.js.ini b/testing/web-platform/meta/FileAPI/url/url-with-xhr.any.js.ini index 5330c65262c1..7f46e91d255f 100644 --- a/testing/web-platform/meta/FileAPI/url/url-with-xhr.any.js.ini +++ b/testing/web-platform/meta/FileAPI/url/url-with-xhr.any.js.ini @@ -1,34 +1,27 @@ [url-with-xhr.any.worker.html] - expected: TIMEOUT - [XHR of a revoked URL should fail] - expected: TIMEOUT - [Only exact matches should revoke URLs, using XHR] - expected: NOTRUN + expected: FAIL [Appending a query string should cause XHR to fail] - expected: NOTRUN - - [Appending a path should cause XHR to fail] - expected: NOTRUN + expected: FAIL [XHR with method "HEAD" should fail] - expected: NOTRUN + expected: FAIL [XHR with method "POST" should fail] - expected: NOTRUN + expected: FAIL [XHR with method "DELETE" should fail] - expected: NOTRUN + expected: FAIL [XHR with method "OPTIONS" should fail] - expected: NOTRUN + expected: FAIL [XHR with method "PUT" should fail] - expected: NOTRUN + expected: FAIL [XHR with method "CUSTOM" should fail] - expected: NOTRUN + expected: FAIL [url-with-xhr.any.html]