mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 15:28:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
759
dom/fetch/Fetch.cpp
Normal file
759
dom/fetch/Fetch.cpp
Normal file
|
|
@ -0,0 +1,759 @@
|
|||
/* -*- 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 "Fetch.h"
|
||||
#include "FetchConsumer.h"
|
||||
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsIThreadRetargetableRequest.h"
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsIUnicodeEncoder.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsDOMString.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BodyUtil.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/FetchDriver.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FormData.h"
|
||||
#include "mozilla/dom/Headers.h"
|
||||
#include "mozilla/dom/MutableBlobStreamListener.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "InternalRequest.h"
|
||||
#include "InternalResponse.h"
|
||||
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerScope.h"
|
||||
#include "Workers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace workers;
|
||||
|
||||
class WorkerFetchResolver final : public FetchDriverObserver
|
||||
{
|
||||
friend class MainThreadFetchRunnable;
|
||||
friend class WorkerFetchResponseEndRunnable;
|
||||
friend class WorkerFetchResponseRunnable;
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
public:
|
||||
// Returns null if worker is shutting down.
|
||||
static already_AddRefed<WorkerFetchResolver>
|
||||
Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
|
||||
if (!proxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<WorkerFetchResolver> r = new WorkerFetchResolver(proxy);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
void
|
||||
OnResponseAvailableInternal(InternalResponse* aResponse) override;
|
||||
|
||||
void
|
||||
OnResponseEnd() override;
|
||||
|
||||
private:
|
||||
explicit WorkerFetchResolver(PromiseWorkerProxy* aProxy)
|
||||
: mPromiseProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
}
|
||||
|
||||
~WorkerFetchResolver()
|
||||
{}
|
||||
|
||||
virtual void
|
||||
FlushConsoleReport() override;
|
||||
};
|
||||
|
||||
class MainThreadFetchResolver final : public FetchDriverObserver
|
||||
{
|
||||
RefPtr<Promise> mPromise;
|
||||
RefPtr<Response> mResponse;
|
||||
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
public:
|
||||
explicit MainThreadFetchResolver(Promise* aPromise);
|
||||
|
||||
void
|
||||
OnResponseAvailableInternal(InternalResponse* aResponse) override;
|
||||
|
||||
void SetDocument(nsIDocument* aDocument)
|
||||
{
|
||||
mDocument = aDocument;
|
||||
}
|
||||
|
||||
virtual void OnResponseEnd() override
|
||||
{
|
||||
FlushConsoleReport();
|
||||
}
|
||||
|
||||
private:
|
||||
~MainThreadFetchResolver();
|
||||
|
||||
void FlushConsoleReport() override
|
||||
{
|
||||
mReporter->FlushConsoleReports(mDocument);
|
||||
}
|
||||
};
|
||||
|
||||
class MainThreadFetchRunnable : public Runnable
|
||||
{
|
||||
RefPtr<WorkerFetchResolver> mResolver;
|
||||
RefPtr<InternalRequest> mRequest;
|
||||
|
||||
public:
|
||||
MainThreadFetchRunnable(WorkerFetchResolver* aResolver,
|
||||
InternalRequest* aRequest)
|
||||
: mResolver(aResolver)
|
||||
, mRequest(aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mResolver);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
RefPtr<FetchDriver> fetch;
|
||||
RefPtr<PromiseWorkerProxy> proxy = mResolver->mPromiseProxy;
|
||||
|
||||
{
|
||||
// Acquire the proxy mutex while getting data from the WorkerPrivate...
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
NS_WARNING("Aborting Fetch because worker already shut down");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = proxy->GetWorkerPrivate()->GetPrincipal();
|
||||
MOZ_ASSERT(principal);
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = proxy->GetWorkerPrivate()->GetLoadGroup();
|
||||
MOZ_ASSERT(loadGroup);
|
||||
fetch = new FetchDriver(mRequest, principal, loadGroup);
|
||||
nsAutoCString spec;
|
||||
if (proxy->GetWorkerPrivate()->GetBaseURI()) {
|
||||
proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
|
||||
}
|
||||
fetch->SetWorkerScript(spec);
|
||||
}
|
||||
|
||||
// ...but release it before calling Fetch, because mResolver's callback can
|
||||
// be called synchronously and they want the mutex, too.
|
||||
return fetch->Fetch(mResolver);
|
||||
}
|
||||
};
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Double check that we have chrome privileges if the Request's content
|
||||
// policy type has been overridden. Note, we must do this before
|
||||
// entering the global below. Otherwise the IsCallerChrome() will
|
||||
// always fail.
|
||||
MOZ_ASSERT_IF(aInput.IsRequest() &&
|
||||
aInput.GetAsRequest().IsContentPolicyTypeOverridden(),
|
||||
nsContentUtils::IsCallerChrome());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(aGlobal)) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> jsGlobal(cx, aGlobal->GetGlobalJSObject());
|
||||
GlobalObject global(cx, jsGlobal);
|
||||
|
||||
RefPtr<Request> request = Request::Constructor(global, aInput, aInit, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> r = request->GetInternalRequest();
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsIPrincipal* principal;
|
||||
if (window) {
|
||||
doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
principal = doc->NodePrincipal();
|
||||
loadGroup = doc->GetDocumentLoadGroup();
|
||||
} else {
|
||||
principal = aGlobal->PrincipalOrNull();
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
|
||||
|
||||
RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
|
||||
RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
|
||||
fetch->SetDocument(doc);
|
||||
resolver->SetDocument(doc);
|
||||
aRv = fetch->Fetch(resolver);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
|
||||
Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0);
|
||||
|
||||
if (worker->IsServiceWorker()) {
|
||||
r->SetSkipServiceWorker();
|
||||
}
|
||||
|
||||
RefPtr<WorkerFetchResolver> resolver = WorkerFetchResolver::Create(worker, p);
|
||||
if (!resolver) {
|
||||
NS_WARNING("Could not add WorkerFetchResolver workerHolder to worker");
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(resolver, r);
|
||||
worker->DispatchToMainThread(run.forget());
|
||||
}
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise)
|
||||
: mPromise(aPromise)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (aResponse->Type() != ResponseType::Error) {
|
||||
nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
|
||||
mResponse = new Response(go, aResponse);
|
||||
mPromise->MaybeResolve(mResponse);
|
||||
} else {
|
||||
ErrorResult result;
|
||||
result.ThrowTypeError<MSG_FETCH_FAILED>();
|
||||
mPromise->MaybeReject(result);
|
||||
}
|
||||
}
|
||||
|
||||
MainThreadFetchResolver::~MainThreadFetchResolver()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
|
||||
}
|
||||
|
||||
class WorkerFetchResponseRunnable final : public MainThreadWorkerRunnable
|
||||
{
|
||||
RefPtr<WorkerFetchResolver> mResolver;
|
||||
// Passed from main thread to worker thread after being initialized.
|
||||
RefPtr<InternalResponse> mInternalResponse;
|
||||
public:
|
||||
WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
WorkerFetchResolver* aResolver,
|
||||
InternalResponse* aResponse)
|
||||
: MainThreadWorkerRunnable(aWorkerPrivate)
|
||||
, mResolver(aResolver)
|
||||
, mInternalResponse(aResponse)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
|
||||
|
||||
if (mInternalResponse->Type() != ResponseType::Error) {
|
||||
RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
|
||||
RefPtr<Response> response = new Response(global, mInternalResponse);
|
||||
promise->MaybeResolve(response);
|
||||
} else {
|
||||
ErrorResult result;
|
||||
result.ThrowTypeError<MSG_FETCH_FAILED>();
|
||||
promise->MaybeReject(result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class WorkerFetchResponseEndBase
|
||||
{
|
||||
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
public:
|
||||
explicit WorkerFetchResponseEndBase(PromiseWorkerProxy* aPromiseProxy)
|
||||
: mPromiseProxy(aPromiseProxy)
|
||||
{
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerRunInternal(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
mPromiseProxy->CleanUp();
|
||||
}
|
||||
};
|
||||
|
||||
class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable
|
||||
, public WorkerFetchResponseEndBase
|
||||
{
|
||||
public:
|
||||
explicit WorkerFetchResponseEndRunnable(PromiseWorkerProxy* aPromiseProxy)
|
||||
: MainThreadWorkerRunnable(aPromiseProxy->GetWorkerPrivate())
|
||||
, WorkerFetchResponseEndBase(aPromiseProxy)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
WorkerRunInternal(aWorkerPrivate);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Cancel() override
|
||||
{
|
||||
// Execute Run anyway to make sure we cleanup our promise proxy to avoid
|
||||
// leaking the worker thread
|
||||
Run();
|
||||
return WorkerRunnable::Cancel();
|
||||
}
|
||||
};
|
||||
|
||||
class WorkerFetchResponseEndControlRunnable final : public MainThreadWorkerControlRunnable
|
||||
, public WorkerFetchResponseEndBase
|
||||
{
|
||||
public:
|
||||
explicit WorkerFetchResponseEndControlRunnable(PromiseWorkerProxy* aPromiseProxy)
|
||||
: MainThreadWorkerControlRunnable(aPromiseProxy->GetWorkerPrivate())
|
||||
, WorkerFetchResponseEndBase(aPromiseProxy)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
WorkerRunInternal(aWorkerPrivate);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Control runnable cancel already calls Run().
|
||||
};
|
||||
|
||||
void
|
||||
WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<WorkerFetchResponseRunnable> r =
|
||||
new WorkerFetchResponseRunnable(mPromiseProxy->GetWorkerPrivate(), this,
|
||||
aResponse);
|
||||
|
||||
if (!r->Dispatch()) {
|
||||
NS_WARNING("Could not dispatch fetch response");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkerFetchResolver::OnResponseEnd()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FlushConsoleReport();
|
||||
|
||||
RefPtr<WorkerFetchResponseEndRunnable> r =
|
||||
new WorkerFetchResponseEndRunnable(mPromiseProxy);
|
||||
|
||||
if (!r->Dispatch()) {
|
||||
RefPtr<WorkerFetchResponseEndControlRunnable> cr =
|
||||
new WorkerFetchResponseEndControlRunnable(mPromiseProxy);
|
||||
// This can fail if the worker thread is canceled or killed causing
|
||||
// the PromiseWorkerProxy to give up its WorkerHolder immediately,
|
||||
// allowing the worker thread to become Dead.
|
||||
if (!cr->Dispatch()) {
|
||||
NS_WARNING("Failed to dispatch WorkerFetchResponseEndControlRunnable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkerFetchResolver::FlushConsoleReport()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
|
||||
if(!mReporter) {
|
||||
return;
|
||||
}
|
||||
|
||||
workers::WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
|
||||
if (!worker) {
|
||||
mReporter->FlushConsoleReports((nsIDocument*)nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (worker->IsServiceWorker()) {
|
||||
// Flush to service worker
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
if (!swm) {
|
||||
mReporter->FlushConsoleReports((nsIDocument*)nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
swm->FlushReportsToAllClients(worker->WorkerName(), mReporter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (worker->IsSharedWorker()) {
|
||||
// Flush to shared worker
|
||||
worker->FlushReportsToSharedWorkers(mReporter);
|
||||
return;
|
||||
}
|
||||
|
||||
// Flush to dedicated worker
|
||||
mReporter->FlushConsoleReports(worker->GetDocument());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
ExtractFromArrayBuffer(const ArrayBuffer& aBuffer,
|
||||
nsIInputStream** aStream,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
aBuffer.ComputeLengthAndData();
|
||||
aContentLength = aBuffer.Length();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
return NS_NewByteInputStream(aStream,
|
||||
reinterpret_cast<char*>(aBuffer.Data()),
|
||||
aBuffer.Length(), NS_ASSIGNMENT_COPY);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromArrayBufferView(const ArrayBufferView& aBuffer,
|
||||
nsIInputStream** aStream,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
aBuffer.ComputeLengthAndData();
|
||||
aContentLength = aBuffer.Length();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
return NS_NewByteInputStream(aStream,
|
||||
reinterpret_cast<char*>(aBuffer.Data()),
|
||||
aBuffer.Length(), NS_ASSIGNMENT_COPY);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromBlob(const Blob& aBlob,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
RefPtr<BlobImpl> impl = aBlob.Impl();
|
||||
ErrorResult rv;
|
||||
aContentLength = impl->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
impl->GetInternalStream(aStream, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
nsAutoString type;
|
||||
impl->GetType(type);
|
||||
aContentType = NS_ConvertUTF16toUTF8(type);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromFormData(FormData& aFormData,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
nsAutoCString unusedCharset;
|
||||
return aFormData.GetSendInfo(aStream, &aContentLength,
|
||||
aContentType, unusedCharset);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromUSVString(const nsString& aStr,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
|
||||
if (!encoder) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t destBufferLen;
|
||||
nsresult rv = encoder->GetMaxLength(aStr.get(), aStr.Length(), &destBufferLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCString encoded;
|
||||
if (!encoded.SetCapacity(destBufferLen, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char* destBuffer = encoded.BeginWriting();
|
||||
int32_t srcLen = (int32_t) aStr.Length();
|
||||
int32_t outLen = destBufferLen;
|
||||
rv = encoder->Convert(aStr.get(), &srcLen, destBuffer, &outLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(outLen <= destBufferLen);
|
||||
encoded.SetLength(outLen);
|
||||
|
||||
aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8");
|
||||
aContentLength = outLen;
|
||||
|
||||
return NS_NewCStringInputStream(aStream, encoded);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromURLSearchParams(const URLSearchParams& aParams,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
nsAutoString serialized;
|
||||
aParams.Stringify(serialized);
|
||||
aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
|
||||
aContentLength = serialized.Length();
|
||||
return NS_NewCStringInputStream(aStream, NS_ConvertUTF16toUTF8(serialized));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
|
||||
if (aBodyInit.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
|
||||
return ExtractFromArrayBuffer(buf, aStream, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsArrayBufferView()) {
|
||||
const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
|
||||
return ExtractFromArrayBufferView(buf, aStream, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsBlob()) {
|
||||
const Blob& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsFormData()) {
|
||||
FormData& form = aBodyInit.GetAsFormData();
|
||||
return ExtractFromFormData(form, aStream, aContentType, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsUSVString()) {
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsUSVString());
|
||||
return ExtractFromUSVString(str, aStream, aContentType, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType, aContentLength);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Should never reach here");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(!*aStream);
|
||||
|
||||
if (aBodyInit.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
|
||||
return ExtractFromArrayBuffer(buf, aStream, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsArrayBufferView()) {
|
||||
const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
|
||||
return ExtractFromArrayBufferView(buf, aStream, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsBlob()) {
|
||||
const Blob& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsFormData()) {
|
||||
FormData& form = aBodyInit.GetAsFormData();
|
||||
return ExtractFromFormData(form, aStream, aContentType, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsUSVString()) {
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsUSVString());
|
||||
return ExtractFromUSVString(str, aStream, aContentType, aContentLength);
|
||||
}
|
||||
if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType, aContentLength);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Should never reach here");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
FetchBody<Derived>::FetchBody()
|
||||
: mWorkerPrivate(nullptr)
|
||||
, mBodyUsed(false)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
FetchBody<Request>::FetchBody();
|
||||
|
||||
template
|
||||
FetchBody<Response>::FetchBody();
|
||||
|
||||
template <class Derived>
|
||||
FetchBody<Derived>::~FetchBody()
|
||||
{
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
|
||||
{
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SetBodyUsed();
|
||||
|
||||
RefPtr<Promise> promise =
|
||||
FetchBodyConsumer<Derived>::Create(DerivedClass()->GetParentObject(),
|
||||
this, aType, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
template
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Request>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
template
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Response>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBody<Derived>::SetMimeType()
|
||||
{
|
||||
// Extract mime type.
|
||||
ErrorResult result;
|
||||
nsCString contentTypeValues;
|
||||
MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
|
||||
DerivedClass()->GetInternalHeaders()->Get(NS_LITERAL_CSTRING("Content-Type"),
|
||||
contentTypeValues, result);
|
||||
MOZ_ALWAYS_TRUE(!result.Failed());
|
||||
|
||||
// HTTP ABNF states Content-Type may have only one value.
|
||||
// This is from the "parse a header value" of the fetch spec.
|
||||
if (!contentTypeValues.IsVoid() && contentTypeValues.Find(",") == -1) {
|
||||
mMimeType = contentTypeValues;
|
||||
ToLowerCase(mMimeType);
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::SetMimeType();
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::SetMimeType();
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Loading…
Add table
Add a link
Reference in a new issue