Bug 1491504 - shortcut blob responses from XHR and fetch when the URL is a blob URL; r=baku

shortcut blob responses from XHR and fetch when the URL is a blob URL

Differential Revision: https://phabricator.services.mozilla.com/D7253

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Thomas Wisniewski 2018-10-05 20:23:55 +00:00
Родитель fe777f8462
Коммит 2294c78986
10 изменённых файлов: 172 добавлений и 9 удалений

Просмотреть файл

@ -1252,6 +1252,21 @@ template
void
FetchBody<Response>::SetMimeType();
template <class Derived>
const nsACString&
FetchBody<Derived>::BodyBlobURISpec() const
{
return DerivedClass()->BodyBlobURISpec();
}
template
const nsACString&
FetchBody<Request>::BodyBlobURISpec() const;
template
const nsACString&
FetchBody<Response>::BodyBlobURISpec() const;
template <class Derived>
const nsAString&
FetchBody<Derived>::BodyLocalPath() const

Просмотреть файл

@ -187,6 +187,9 @@ public:
JS::MutableHandle<JSObject*> aBodyOut,
ErrorResult& aRv);
const nsACString&
BodyBlobURISpec() const;
const nsAString&
BodyLocalPath() const;

Просмотреть файл

@ -434,6 +434,7 @@ FetchBodyConsumer<Derived>::FetchBodyConsumer(nsIEventTarget* aMainThreadEventTa
#endif
, mBodyStream(aBodyStream)
, mBlobStorageType(MutableBlobStorage::eOnlyInMemory)
, mBodyBlobURISpec(aBody ? aBody->BodyBlobURISpec() : VoidCString())
, mBodyLocalPath(aBody ? aBody->BodyLocalPath() : VoidString())
, mGlobal(aGlobalObject)
, mConsumeType(aType)
@ -597,11 +598,26 @@ FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread(ThreadSafeWorkerRef* aWor
return;
}
// If we're trying to consume a blob, and the request was for a local
// file, then generate and return a File blob.
if (mConsumeType == CONSUME_BLOB) {
nsresult rv;
// If we're trying to consume a blob, and the request was for a blob URI,
// then just consume that URI's blob instance.
if (!mBodyBlobURISpec.IsEmpty()) {
RefPtr<BlobImpl> blobImpl;
rv = NS_GetBlobForBlobURISpec(mBodyBlobURISpec, getter_AddRefs(blobImpl));
if (NS_WARN_IF(NS_FAILED(rv)) || !blobImpl) {
return;
}
autoReject.DontFail();
ContinueConsumeBlobBody(blobImpl);
return;
}
// If we're trying to consume a blob, and the request was for a local
// file, then generate and return a File blob.
nsCOMPtr<nsIFile> file;
nsresult rv = GetBodyLocalFile(getter_AddRefs(file));
rv = GetBodyLocalFile(getter_AddRefs(file));
if (!NS_WARN_IF(NS_FAILED(rv)) && file) {
ChromeFilePropertyBag bag;
bag.mType = NS_ConvertUTF8toUTF16(mBodyMimeType);

Просмотреть файл

@ -102,6 +102,7 @@ private:
MutableBlobStorage::MutableBlobStorageType mBlobStorageType;
nsCString mBodyMimeType;
nsCString mBodyBlobURISpec;
nsString mBodyLocalPath;
nsCOMPtr<nsIGlobalObject> mGlobal;

Просмотреть файл

@ -48,6 +48,31 @@ namespace dom {
namespace {
void
GetBlobURISpecFromChannel(nsIRequest* aRequest, nsCString& aBlobURISpec)
{
MOZ_ASSERT(aRequest);
aBlobURISpec.SetIsVoid(true);
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (!channel) {
return;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = channel->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) {
return;
}
if (!dom::IsBlobURI(uri)) {
return;
}
uri->GetSpec(aBlobURISpec);
}
bool
ShouldCheckSRI(const InternalRequest* const aRequest,
const InternalResponse* const aResponse)
@ -962,6 +987,14 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
file->GetPath(path);
response->SetBodyLocalPath(path);
}
} else {
// If the request is a blob URI, then remember that URI so that we
// can later just use that blob instance instead of cloning it.
nsCString blobURISpec;
GetBlobURISpecFromChannel(aRequest, blobURISpec);
if (!blobURISpec.IsVoid()) {
response->SetBodyBlobURISpec(blobURISpec);
}
}
response->InitChannelInfo(channel);

Просмотреть файл

@ -490,6 +490,18 @@ public:
}
}
void
SetBodyBlobURISpec(nsACString& aBlobURISpec)
{
mBodyBlobURISpec = aBlobURISpec;
}
const nsACString&
BodyBlobURISpec() const
{
return mBodyBlobURISpec;
}
void
SetBodyLocalPath(nsAString& aLocalPath)
{
@ -608,6 +620,7 @@ private:
// mURLList: a list of one or more fetch URLs
nsTArray<nsCString> mURLList;
RefPtr<InternalHeaders> mHeaders;
nsCString mBodyBlobURISpec;
nsString mBodyLocalPath;
nsCOMPtr<nsIInputStream> mBodyStream;
int64_t mBodyLength;

Просмотреть файл

@ -219,6 +219,21 @@ public:
GetUnfilteredBody(aStream, aBodySize);
}
void
SetBodyBlobURISpec(nsACString& aBlobURISpec)
{
mBodyBlobURISpec = aBlobURISpec;
}
const nsACString&
BodyBlobURISpec() const
{
if (mWrappedResponse) {
return mWrappedResponse->BodyBlobURISpec();
}
return mBodyBlobURISpec;
}
void
SetBodyLocalPath(nsAString& aLocalPath)
{
@ -388,6 +403,7 @@ private:
const nsCString mStatusText;
RefPtr<InternalHeaders> mHeaders;
nsCOMPtr<nsIInputStream> mBody;
nsCString mBodyBlobURISpec;
nsString mBodyLocalPath;
int64_t mBodySize;
// It's used to passed to the CacheResponse to generate padding size. Once, we

Просмотреть файл

@ -143,6 +143,14 @@ public:
mRequest->SetBody(aStream, aBodyLength);
}
using FetchBody::BodyBlobURISpec;
const nsACString&
BodyBlobURISpec() const
{
return mRequest->BodyBlobURISpec();
}
using FetchBody::BodyLocalPath;
const nsAString&

Просмотреть файл

@ -112,6 +112,14 @@ public:
using FetchBody::GetBody;
using FetchBody::BodyBlobURISpec;
const nsACString&
BodyBlobURISpec() const
{
return mInternalResponse->BodyBlobURISpec();
}
using FetchBody::BodyLocalPath;
const nsAString&

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/DOMString.h"
#include "mozilla/dom/File.h"
@ -1185,11 +1186,13 @@ XMLHttpRequestMainThread::GetResponseHeader(const nsACString& header,
// Even non-http channels supply content type and content length.
// Remember we don't leak header information from denied cross-site
// requests.
// requests. However, we handle file: and blob: URLs for blob response
// types by canceling them with a specific error, so we have to allow
// them to pass through this check.
nsresult status;
if (!mChannel ||
NS_FAILED(mChannel->GetStatus(&status)) ||
NS_FAILED(status)) {
(NS_FAILED(status) && status != NS_ERROR_FILE_ALREADY_EXISTS)) {
return;
}
@ -1655,6 +1658,32 @@ XMLHttpRequestMainThread::StreamReaderFunc(nsIInputStream* in,
namespace {
void
GetBlobURIFromChannel(nsIRequest* aRequest, nsIURI** aURI)
{
MOZ_ASSERT(aRequest);
MOZ_ASSERT(aURI);
*aURI = nullptr;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (!channel) {
return;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = channel->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) {
return;
}
if (!dom::IsBlobURI(uri)) {
return;
}
uri.forget(aURI);
}
nsresult
GetLocalFileFromChannel(nsIRequest* aRequest, nsIFile** aFile)
{
@ -1771,14 +1800,29 @@ XMLHttpRequestMainThread::OnDataAvailable(nsIRequest *request,
nsresult rv;
nsCOMPtr<nsIFile> localFile;
if (mResponseType == XMLHttpRequestResponseType::Blob) {
rv = GetLocalFileFromChannel(request, getter_AddRefs(localFile));
nsCOMPtr<nsIFile> localFile;
nsCOMPtr<nsIURI> blobURI;
GetBlobURIFromChannel(request, getter_AddRefs(blobURI));
if (blobURI) {
RefPtr<BlobImpl> blobImpl;
rv = NS_GetBlobForBlobURI(blobURI, getter_AddRefs(blobImpl));
if (NS_SUCCEEDED(rv)) {
if (blobImpl) {
mResponseBlob = Blob::Create(GetOwner(), blobImpl);
}
if (!mResponseBlob) {
rv = NS_ERROR_FILE_NOT_FOUND;
}
}
} else {
rv = GetLocalFileFromChannel(request, getter_AddRefs(localFile));
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (localFile) {
if (mResponseBlob || localFile) {
mBlobStorage = nullptr;
NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
@ -2141,12 +2185,18 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
return NS_OK;
}
// If we were just reading a blob URL, we're already done
if (status == NS_ERROR_FILE_ALREADY_EXISTS && mResponseBlob) {
ChangeStateToDone();
return NS_OK;
}
bool waitingForBlobCreation = false;
// If we have this error, we have to deal with a file: URL + responseType =
// blob. We have this error because we canceled the channel. The status will
// be set to NS_OK.
if (status == NS_ERROR_FILE_ALREADY_EXISTS &&
if (!mResponseBlob && status == NS_ERROR_FILE_ALREADY_EXISTS &&
mResponseType == XMLHttpRequestResponseType::Blob) {
nsCOMPtr<nsIFile> file;
nsresult rv = GetLocalFileFromChannel(request, getter_AddRefs(file));