/* -*- 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/. */
// Reads over a CRLF and positions start after it. staticbool PushOverLine(nsACString::const_iterator& aStart, const nsACString::const_iterator& aEnd) { if (*aStart == nsCRT::CR && (aEnd - aStart > 1) && *(++aStart) == nsCRT::LF) {
++aStart; // advance to after CRLF returntrue;
}
if (innerWindow) {
Document* doc = innerWindow->GetExtantDoc(); if (doc) {
loadGroup = doc->GetDocumentLoadGroup();
}
}
return loadGroup;
}
// static bool FetchUtil::ExtractHeader(nsACString::const_iterator& aStart,
nsACString::const_iterator& aEnd,
nsCString& aHeaderName, nsCString& aHeaderValue, bool* aWasEmptyHeader) {
MOZ_ASSERT(aWasEmptyHeader); // Set it to a valid value here so we don't forget later.
*aWasEmptyHeader = false;
ReferrerPolicy policy = aRequest.ReferrerPolicy_();
nsCOMPtr<nsIReferrerInfo> referrerInfo; if (referrer.IsEmpty()) { // This is the case request’s referrer is "no-referrer"
referrerInfo = new ReferrerInfo(nullptr, ReferrerPolicy::No_referrer);
} elseif (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
referrerInfo = ReferrerInfo::CreateForFetch(aPrincipal, aDoc); // In the first step, we should use referrer info from requetInit
referrerInfo = static_cast<ReferrerInfo*>(referrerInfo.get())
->CloneWithNewPolicy(policy);
} else { // From "Determine request's Referrer" step 3 // "If request's referrer is a URL, let referrerSource be request's // referrer."
nsCOMPtr<nsIURI> referrerURI;
rv = NS_NewURI(getter_AddRefs(referrerURI), referrer);
NS_ENSURE_SUCCESS(rv, rv);
referrerInfo = new ReferrerInfo(referrerURI, policy);
}
// Step 8 https://fetch.spec.whatwg.org/#main-fetch // If request’s referrer is not "no-referrer", set request’s referrer to // the result of invoking determine request’s referrer.
aRequest.SetReferrer(computedReferrerSpec);
return NS_OK;
}
class StoreOptimizedEncodingRunnable final : public Runnable {
nsMainThreadPtrHandle<nsICacheInfoChannel> mCache;
Vector<uint8_t> mBytes;
class WindowStreamOwner final : public GlobalTeardownObserver { private: // Read from any thread but only set/cleared on the main thread. The lifecycle // of WindowStreamOwner prevents concurrent read/clear.
nsCOMPtr<nsIAsyncInputStream> mStream;
// mStream->Close() will call JSStreamConsumer::OnInputStreamReady which may // then destory itself, but GTO should be strongly grabbing us right as it's // calling DisconnectFromOwner.
self->mWorkerRef =
StrongWorkerRef::Create(aWorker, "JSStreamConsumer", [self]() { if (self->mStream) { // If this Close() calls JSStreamConsumer::OnInputStreamReady and // drops the last reference to the JSStreamConsumer, 'this' will not // be destroyed since ~JSStreamConsumer() only enqueues a release // proxy.
self->mStream->Close();
self->mStream = nullptr;
}
});
// Read from any thread but only set/cleared on the worker thread. The // lifecycle of WorkerStreamOwner prevents concurrent read/clear.
nsCOMPtr<nsIAsyncInputStream> mStream;
RefPtr<StrongWorkerRef> mWorkerRef;
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
};
class JSStreamConsumer final : public nsIInputStreamCallback, public JS::OptimizedEncodingListener { // A LengthPrefixType is stored at the start of the compressed optimized // encoding, allowing the decompressed buffer to be allocated to exactly // the right size. using LengthPrefixType = uint32_t; staticconstunsigned PrefixBytes = sizeof(LengthPrefixType);
// Bug 1733674: these annotations currently do nothing, because they are // member variables and the annotation mechanism only applies to locals. But // the analysis could be extended so that these could replace the big-hammer // ~JSStreamConsumer annotation and thus the analysis could check that // nothing is added that might GC for a different reason.
JS_HAZ_VALUE_IS_GC_SAFE(mWindowStreamOwner);
JS_HAZ_VALUE_IS_GC_SAFE(mWorkerStreamOwner);
}
if (self->mOptimizedEncoding) { if (!self->mZStreamInitialized) { // mOptimizedEncodingBytes is used as temporary storage until we have // the full prefix.
MOZ_ASSERT(self->mOptimizedEncodingBytes.length() < PrefixBytes);
uint32_t remain = PrefixBytes - self->mOptimizedEncodingBytes.length();
uint32_t consume = std::min(remain, aCount);
if (!self->mOptimizedEncodingBytes.append(aFromSegment, consume)) { return NS_ERROR_UNEXPECTED;
}
if (consume == remain) { // Initialize zlib once all prefix bytes are loaded.
LengthPrefixType length;
memcpy(&length, self->mOptimizedEncodingBytes.begin(), PrefixBytes);
if (!self->mOptimizedEncodingBytes.resizeUninitialized(length)) { return NS_ERROR_UNEXPECTED;
}
RefPtr<JSStreamConsumer> consumer; if (aMaybeWorker) {
RefPtr<WorkerStreamOwner> owner = WorkerStreamOwner::Create(
asyncStream, aMaybeWorker, aGlobal->SerialEventTarget()); if (!owner) { returnfalse;
}
consumer = new JSStreamConsumer(std::move(owner), aGlobal, aConsumer,
std::move(aCache), aOptimizedEncoding);
} else {
RefPtr<WindowStreamOwner> owner = new WindowStreamOwner(asyncStream, aGlobal); if (!owner) { returnfalse;
}
consumer = new JSStreamConsumer(owner.forget(), aGlobal, aConsumer,
std::move(aCache), aOptimizedEncoding);
}
// This AsyncWait() creates a ref-cycle between asyncStream and consumer: // // asyncStream -> consumer -> (Window|Worker)StreamOwner -> asyncStream // // The cycle is broken when the stream completes or errors out and // asyncStream drops its reference to consumer. return NS_SUCCEEDED(asyncStream->AsyncWait(consumer, 0, 0, nullptr));
}
// nsIInputStreamCallback:
NS_IMETHOD
OnInputStreamReady(nsIAsyncInputStream* aStream) override { // Can be called on any stream. The JS API calls made below explicitly // support being called from any thread.
MOZ_DIAGNOSTIC_ASSERT(!mConsumerAborted);
nsresult rv;
uint64_t available = 0;
rv = aStream->Available(&available); if (NS_SUCCEEDED(rv) && available == 0) {
rv = NS_BASE_STREAM_CLOSED;
}
if (rv == NS_BASE_STREAM_CLOSED) { if (mOptimizedEncoding) { // Gracefully handle corruption of compressed data stream in release. // From on investigations in bug 1738987, the incomplete data cases // mostly happen during shutdown. Some corruptions in the cache entry // can still happen and will be handled in the WriteSegment above. bool ok = mZStreamInitialized && mZStream.avail_out == 0; if (!ok) {
mConsumer->streamError(size_t(NS_ERROR_UNEXPECTED)); return NS_OK;
}
mConsumer->consumeOptimizedEncoding(mOptimizedEncodingBytes.begin(),
mOptimizedEncodingBytes.length());
} else { // If there is cache entry associated with this stream, then listen for // an optimized encoding so we can store it in the alt data. By JS API // contract, the compilation process will hold a refcount to 'this' // until it's done, optionally calling storeOptimizedEncoding().
mConsumer->streamEnd(mCache ? this : nullptr);
} return NS_OK;
}
if (NS_FAILED(rv)) {
mConsumer->streamError(size_t(rv)); return NS_OK;
}
// Check mConsumerAborted before NS_FAILED to avoid calling streamError() // if consumeChunk() returned false per JS API contract.
uint32_t written = 0;
rv = aStream->ReadSegments(WriteSegment, this, available, &written); if (mConsumerAborted) { return NS_OK;
} if (NS_WARN_IF(NS_FAILED(rv))) {
mConsumer->streamError(size_t(rv)); return NS_OK;
}
// The wins from increasing compression levels are tiny, while the time // to compress increases drastically. For example, for a 148mb alt-data // produced by a 40mb .wasm file, the level 2 takes 2.5s to get a 3.7x size // reduction while level 9 takes 22.5s to get a 4x size reduction. Read-time // wins from smaller compressed cache files are not found to be // significant, thus the fastest compression level is used. (On test // workloads, level 2 actually was faster *and* smaller than level 1.) constint COMPRESSION = 2; if (deflateInit(&zstream, COMPRESSION) != Z_OK) { return;
} auto autoDestroy = MakeScopeExit([&]() { deflateEnd(&zstream); });
Vector<uint8_t> dstBytes; if (!dstBytes.resizeUninitialized(PrefixBytes +
deflateBound(&zstream, aSrcLength))) { return;
}
nsAutoCString altDataType; if (NS_SUCCEEDED(cache->GetAlternativeDataType(altDataType)) &&
WasmAltDataType.Equals(altDataType)) {
optimizedEncoding = true;
rv = cache->GetAlternativeDataInputStream(getter_AddRefs(stream)); if (NS_WARN_IF(NS_FAILED(rv))) { return ThrowException(aCx, JSMSG_OUT_OF_MEMORY);
} if (ir->HasBeenCloned()) { // If `Response` is cloned, clone alternative data stream instance. // The cache entry does not clone automatically, and multiple // JSStreamConsumer instances will collide during read if not cloned.
nsCOMPtr<nsICloneableInputStream> original = do_QueryInterface(stream); if (NS_WARN_IF(!original)) { return ThrowException(aCx, JSMSG_OUT_OF_MEMORY);
}
rv = original->Clone(getter_AddRefs(stream)); if (NS_WARN_IF(NS_FAILED(rv))) { return ThrowException(aCx, JSMSG_OUT_OF_MEMORY);
}
}
}
}
if (!optimizedEncoding) {
ir->GetUnfilteredBody(getter_AddRefs(stream)); if (!stream) {
aConsumer->streamEnd(); returntrue;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.