зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
fe777f8462
Коммит
2294c78986
|
@ -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));
|
||||
|
|
Загрузка…
Ссылка в новой задаче