--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -9979,30 +9979,34 @@ public:
}
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS(StubCSSLoaderObserver, nsICSSLoaderObserver)
} // namespace
void
-nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset,
+nsDocument::PreloadStyle(nsIURI* uri,
+ const Encoding* aEncoding,
const nsAString& aCrossOriginAttr,
const ReferrerPolicy aReferrerPolicy,
const nsAString& aIntegrity)
{
// The CSSLoader will retain this object after we return.
nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
// Charset names are always ASCII.
- CSSLoader()->LoadSheet(uri, true, NodePrincipal(),
- NS_LossyConvertUTF16toASCII(charset),
+ CSSLoader()->LoadSheet(uri,
+ true,
+ NodePrincipal(),
+ aEncoding,
obs,
Element::StringToCORSMode(aCrossOriginAttr),
- aReferrerPolicy, aIntegrity);
+ aReferrerPolicy,
+ aIntegrity);
}
nsresult
nsDocument::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
RefPtr<mozilla::StyleSheet>* aSheet)
{
css::SheetParsingMode mode =
isAgentSheet ? css::eAgentSheetFeatures
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -831,17 +831,18 @@ public:
ReferrerPolicy aReferrerPolicy,
bool aIsImgSet) override;
virtual void ForgetImagePreload(nsIURI* aURI) override;
virtual void MaybePreconnect(nsIURI* uri,
mozilla::CORSMode aCORSMode) override;
- virtual void PreloadStyle(nsIURI* uri, const nsAString& charset,
+ virtual void PreloadStyle(nsIURI* uri,
+ const mozilla::Encoding* aEncoding,
const nsAString& aCrossOriginAttr,
ReferrerPolicy aReferrerPolicy,
const nsAString& aIntegrity) override;
virtual nsresult LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
RefPtr<mozilla::StyleSheet>* aSheet) override;
virtual nsISupports* GetCurrentContentSink() override;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2459,17 +2459,18 @@ public:
*/
virtual void ForgetImagePreload(nsIURI* aURI) = 0;
/**
* Called by nsParser to preload style sheets. Can also be merged into the
* parser if and when the parser is merged with libgklayout. aCrossOriginAttr
* should be a void string if the attr is not present.
*/
- virtual void PreloadStyle(nsIURI* aURI, const nsAString& aCharset,
+ virtual void PreloadStyle(nsIURI* aURI,
+ const mozilla::Encoding* aEncoding,
const nsAString& aCrossOriginAttr,
ReferrerPolicyEnum aReferrerPolicy,
const nsAString& aIntegrity) = 0;
/**
* Called by the chrome registry to load style sheets. Can be put
* back there if and when when that module is merged with libgklayout.
*
--- a/dom/security/SRICheck.cpp
+++ b/dom/security/SRICheck.cpp
@@ -177,47 +177,40 @@ SRICheck::IntegrityMetadata(const nsAStr
SRILOG(("SRICheck::IntegrityMetadata, no valid metadata found"));
}
}
return NS_OK;
}
/* static */ nsresult
SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
- nsIUnicharStreamLoader* aLoader,
- const nsAString& aString,
+ nsIChannel* aChannel,
+ const nsACString& aBytes,
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter)
{
- NS_ENSURE_ARG_POINTER(aLoader);
NS_ENSURE_ARG_POINTER(aReporter);
- nsCOMPtr<nsIChannel> channel;
- aLoader->GetChannel(getter_AddRefs(channel));
-
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
nsAutoCString requestURL;
nsCOMPtr<nsIURI> originalURI;
- if (channel &&
- NS_SUCCEEDED(channel->GetOriginalURI(getter_AddRefs(originalURI))) &&
+ if (aChannel &&
+ NS_SUCCEEDED(aChannel->GetOriginalURI(getter_AddRefs(originalURI))) &&
originalURI) {
originalURI->GetAsciiSpec(requestURL);
}
SRILOG(("SRICheck::VerifyIntegrity (unichar stream)"));
}
SRICheckDataVerifier verifier(aMetadata, aSourceFileURI, aReporter);
- nsresult rv;
- nsDependentCString rawBuffer;
- rv = aLoader->GetRawBuffer(rawBuffer);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = verifier.Update(rawBuffer.Length(), (const uint8_t*)rawBuffer.get());
+ nsresult rv =
+ verifier.Update(aBytes.Length(), (const uint8_t*)aBytes.BeginReading());
NS_ENSURE_SUCCESS(rv, rv);
- return verifier.Verify(aMetadata, channel, aSourceFileURI, aReporter);
+ return verifier.Verify(aMetadata, aChannel, aSourceFileURI, aReporter);
}
//////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////
SRICheckDataVerifier::SRICheckDataVerifier(const SRIMetadata& aMetadata,
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter)
--- a/dom/security/SRICheck.h
+++ b/dom/security/SRICheck.h
@@ -6,17 +6,16 @@
#ifndef mozilla_dom_SRICheck_h
#define mozilla_dom_SRICheck_h
#include "nsCOMPtr.h"
#include "nsICryptoHash.h"
class nsIChannel;
-class nsIUnicharStreamLoader;
class nsIConsoleReportCollector;
namespace mozilla {
namespace dom {
class SRIMetadata;
class SRICheck final
@@ -34,18 +33,18 @@ public:
nsIConsoleReportCollector* aReporter,
SRIMetadata* outMetadata);
/**
* Process the integrity attribute of the element. A result of false
* must prevent the resource from loading.
*/
static nsresult VerifyIntegrity(const SRIMetadata& aMetadata,
- nsIUnicharStreamLoader* aLoader,
- const nsAString& aString,
+ nsIChannel* aChannel,
+ const nsACString& aBytes,
const nsACString& aSourceFileURI,
nsIConsoleReportCollector* aReporter);
};
// The SRICheckDataVerifier can be used in 2 different mode:
//
// 1. The streaming mode involves reading bytes from an input, and to use
// the |Update| function to stream new bytes, and to use the |Verify|
--- a/dom/xbl/nsXBLResourceLoader.cpp
+++ b/dom/xbl/nsXBLResourceLoader.cpp
@@ -146,17 +146,17 @@ nsXBLResourceLoader::LoadResources(nsICo
{
rv = StyleSheetLoaded(sheet, false, NS_OK);
NS_ASSERTION(NS_SUCCEEDED(rv), "Processing the style sheet failed!!!");
}
}
}
else
{
- rv = cssLoader->LoadSheet(url, false, docPrincipal, EmptyCString(), this);
+ rv = cssLoader->LoadSheet(url, false, docPrincipal, nullptr, this);
if (NS_SUCCEEDED(rv))
++mPendingSheets;
}
}
}
mInLoadResourcesFunc = false;
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -3733,20 +3733,18 @@ XULDocument::AddPrototypeSheets()
nsresult rv;
const nsCOMArray<nsIURI>& sheets = mCurrentPrototype->GetStyleSheetReferences();
for (int32_t i = 0; i < sheets.Count(); i++) {
nsCOMPtr<nsIURI> uri = sheets[i];
RefPtr<StyleSheet> incompleteSheet;
- rv = CSSLoader()->LoadSheet(uri,
- mCurrentPrototype->DocumentPrincipal(),
- EmptyCString(), this,
- &incompleteSheet);
+ rv = CSSLoader()->LoadSheet(
+ uri, mCurrentPrototype->DocumentPrincipal(), this, &incompleteSheet);
// XXXldb We need to prevent bogus sheets from being held in the
// prototype's list, but until then, don't propagate the failure
// from LoadSheet (and thus exit the loop).
if (NS_SUCCEEDED(rv)) {
++mPendingSheets;
if (!mOverlaySheets.AppendElement(incompleteSheet)) {
return NS_ERROR_OUT_OF_MEMORY;
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -2837,18 +2837,18 @@ HTMLEditor::ReplaceStyleSheet(const nsAS
}
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIURI> uaURI;
nsresult rv = NS_NewURI(getter_AddRefs(uaURI), aURL);
NS_ENSURE_SUCCESS(rv, rv);
- return ps->GetDocument()->CSSLoader()->
- LoadSheet(uaURI, false, nullptr, EmptyCString(), this);
+ return ps->GetDocument()->CSSLoader()->LoadSheet(
+ uaURI, false, nullptr, nullptr, this);
}
NS_IMETHODIMP
HTMLEditor::RemoveStyleSheet(const nsAString& aURL)
{
RefPtr<StyleSheet> sheet = GetStyleSheetForURL(aURL);
NS_ENSURE_TRUE(sheet, NS_ERROR_UNEXPECTED);
--- a/intl/Encoding.h
+++ b/intl/Encoding.h
@@ -84,16 +84,24 @@ mozilla_encoding_decode_to_nscstring_wit
nsresult
mozilla_encoding_decode_to_nscstring_without_bom_handling(
mozilla::Encoding const* encoding,
nsACString const* src,
nsACString* dst);
nsresult
+mozilla_encoding_decode_from_slice_to_nscstring_without_bom_handling(
+ mozilla::Encoding const* encoding,
+ uint8_t const* src,
+ size_t src_len,
+ nsACString* dst,
+ size_t already_validated);
+
+nsresult
mozilla_encoding_decode_to_nscstring_without_bom_handling_and_without_replacement(
mozilla::Encoding const* encoding,
nsACString const* src,
nsACString* dst);
nsresult
mozilla_encoding_encode_from_nscstring(mozilla::Encoding const** encoding,
nsACString const* src,
@@ -548,16 +556,51 @@ public:
return mozilla_encoding_decode_to_nscstring_without_bom_handling_and_without_replacement(
this, &temp, out);
}
return mozilla_encoding_decode_to_nscstring_without_bom_handling_and_without_replacement(
this, bytes, out);
}
/**
+ * Decode complete input to `nsACString` _without BOM handling_ and
+ * with malformed sequences replaced with the REPLACEMENT CHARACTER when
+ * the entire input is available as a single buffer (i.e. the end of the
+ * buffer marks the end of the stream) _asserting that a number of bytes
+ * from the start are already known to be valid UTF-8_.
+ *
+ * The use case for this method is avoiding copying when dealing with
+ * input that has a UTF-8 BOM. _When in doubt, do not use this method._
+ *
+ * When invoked on `UTF_8`, this method implements the (non-streaming
+ * version of) the _UTF-8 decode without BOM_
+ * (https://encoding.spec.whatwg.org/#utf-8-decode-without-bom) spec concept.
+ *
+ * Returns `NS_ERROR_OUT_OF_MEMORY` upon OOM, `NS_OK_HAD_REPLACEMENTS`
+ * if there were malformed sequences (that were replaced with the
+ * REPLACEMENT CHARACTER) and `NS_OK` otherwise.
+ *
+ * _Note:_ It is wrong to use this when the input buffer represents only
+ * a segment of the input instead of the whole input. Use
+ * `NewDecoderWithoutBOMHandling()` when decoding segmented input.
+ *
+ * # Safety
+ *
+ * The first `aAlreadyValidated` bytes of `aBytes` _must_ be valid UTF-8.
+ * `aBytes` _must not_ alias the buffer (if any) of `aOut`.
+ */
+ inline nsresult DecodeWithoutBOMHandling(Span<const uint8_t> aBytes,
+ nsACString& aOut,
+ size_t aAlreadyValidated) const
+ {
+ return mozilla_encoding_decode_from_slice_to_nscstring_without_bom_handling(
+ this, aBytes.Elements(), aBytes.Length(), &aOut, aAlreadyValidated);
+ }
+
+ /**
* Decode complete input to `nsAString` _without BOM handling_ and
* _with malformed sequences treated as fatal_ when the entire input is
* available as a single buffer (i.e. the end of the buffer marks the end
* of the stream).
*
* When invoked on `UTF_8`, this method implements the (non-streaming
* version of) the _UTF-8 decode without BOM or fail_
* (https://encoding.spec.whatwg.org/#utf-8-decode-without-bom-or-fail)
--- a/intl/encoding_glue/src/lib.rs
+++ b/intl/encoding_glue/src/lib.rs
@@ -416,16 +416,21 @@ pub fn decode_to_nscstring_without_bom_h
if dst.fallible_assign(src).is_err() {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
decode_from_slice_to_nscstring_without_bom_handling(encoding, src, dst, valid_up_to)
}
+#[no_mangle]
+pub unsafe extern "C" fn mozilla_encoding_decode_from_slice_to_nscstring_without_bom_handling(encoding: *const Encoding, src: *const u8, src_len: usize, dst: *mut nsACString, already_validated: usize) -> nsresult {
+ decode_from_slice_to_nscstring_without_bom_handling(&*encoding, slice::from_raw_parts(src, src_len), &mut *dst, already_validated)
+}
+
fn decode_from_slice_to_nscstring_without_bom_handling(encoding: &'static Encoding,
src: &[u8],
dst: &mut nsACString,
already_validated: usize)
-> nsresult {
let bytes = src;
let mut decoder = encoding.new_decoder_without_bom_handling();
let rounded_without_replacement =
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -48,31 +48,35 @@
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/URL.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/ConsoleReportCollector.h"
#include "mozilla/ServoUtils.h"
+#include "mozilla/css/StreamLoader.h"
#ifdef MOZ_XUL
#include "nsXULPrototypeCache.h"
#endif
#include "nsIDOMStyleSheet.h"
#include "nsError.h"
#include "nsIContentSecurityPolicy.h"
#include "mozilla/dom/SRICheck.h"
#include "mozilla/Encoding.h"
using namespace mozilla::dom;
+// 1024 bytes is specified in https://drafts.csswg.org/css-syntax/
+#define SNIFFING_BUFFER_SIZE 1024
+
/**
* OVERALL ARCHITECTURE
*
* The CSS Loader gets requests to load various sorts of style sheets:
* inline style from <style> elements, linked style, @import-ed child
* sheets, non-document sheets. The loader handles the following tasks:
* 1) Creation of the actual style sheet objects: CreateSheet()
* 2) setting of the right media, title, enabled state, etc on the
@@ -92,172 +96,16 @@ using namespace mozilla::dom;
* this class handles listening for the stream
* loader completion and also handles charset
* determination.
*/
namespace mozilla {
namespace css {
-/*********************************************
- * Data needed to properly load a stylesheet *
- *********************************************/
-
-static_assert(eAuthorSheetFeatures == 0 &&
- eUserSheetFeatures == 1 &&
- eAgentSheetFeatures == 2,
- "sheet parsing mode constants won't fit "
- "in SheetLoadData::mParsingMode");
-
-class SheetLoadData final : public nsIRunnable,
- public nsIUnicharStreamLoaderObserver,
- public nsIThreadObserver
-{
-protected:
- virtual ~SheetLoadData(void);
-
-public:
- // Data for loading a sheet linked from a document
- SheetLoadData(Loader* aLoader,
- const nsAString& aTitle,
- nsIURI* aURI,
- StyleSheet* aSheet,
- nsIStyleSheetLinkingElement* aOwningElement,
- bool aIsAlternate,
- nsICSSLoaderObserver* aObserver,
- nsIPrincipal* aLoaderPrincipal,
- nsINode* aRequestingNode);
-
- // Data for loading a sheet linked from an @import rule
- SheetLoadData(Loader* aLoader,
- nsIURI* aURI,
- StyleSheet* aSheet,
- SheetLoadData* aParentData,
- nsICSSLoaderObserver* aObserver,
- nsIPrincipal* aLoaderPrincipal,
- nsINode* aRequestingNode);
-
- // Data for loading a non-document sheet
- SheetLoadData(Loader* aLoader,
- nsIURI* aURI,
- StyleSheet* aSheet,
- bool aSyncLoad,
- bool aUseSystemPrincipal,
- const nsCString& aCharset,
- nsICSSLoaderObserver* aObserver,
- nsIPrincipal* aLoaderPrincipal,
- nsINode* aRequestingNode);
-
- already_AddRefed<nsIURI> GetReferrerURI();
-
- void ScheduleLoadEventIfNeeded(nsresult aStatus);
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSIRUNNABLE
- NS_DECL_NSITHREADOBSERVER
- NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
-
- // Hold a ref to the CSSLoader so we can call back to it to let it
- // know the load finished
- RefPtr<Loader> mLoader;
-
- // Title needed to pull datas out of the pending datas table when
- // the preferred title is changed
- nsString mTitle;
-
- // Charset we decided to use for the sheet
- nsCString mCharset;
-
- // URI we're loading. Null for inline sheets
- nsCOMPtr<nsIURI> mURI;
-
- // Should be 1 for non-inline sheets.
- uint32_t mLineNumber;
-
- // The sheet we're loading data for
- RefPtr<StyleSheet> mSheet;
-
- // Linked list of datas for the same URI as us
- SheetLoadData* mNext; // strong ref
-
- // Load data for the sheet that @import-ed us if we were @import-ed
- // during the parse
- RefPtr<SheetLoadData> mParentData;
-
- // Number of sheets we @import-ed that are still loading
- uint32_t mPendingChildren;
-
- // mSyncLoad is true when the load needs to be synchronous -- right
- // now only for LoadSheetSync and children of sync loads.
- bool mSyncLoad : 1;
-
- // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
- // LoadSheet or an @import from such a sheet. Non-document sheet loads can
- // proceed even if we have no document.
- bool mIsNonDocumentSheet : 1;
-
- // mIsLoading is true from the moment we are placed in the loader's
- // "loading datas" table (right after the async channel is opened)
- // to the moment we are removed from said table (due to the load
- // completing or being cancelled).
- bool mIsLoading : 1;
-
- // mIsCancelled is set to true when a sheet load is stopped by
- // Stop() or StopLoadingSheet() (which was removed in Bug 556446).
- // SheetLoadData::OnStreamComplete() checks this to avoid parsing
- // sheets that have been cancelled and such.
- bool mIsCancelled : 1;
-
- // mMustNotify is true if the load data is being loaded async and
- // the original function call that started the load has returned.
- // This applies only to observer notifications; load/error events
- // are fired for any SheetLoadData that has a non-null
- // mOwningElement.
- bool mMustNotify : 1;
-
- // mWasAlternate is true if the sheet was an alternate when the load data was
- // created.
- bool mWasAlternate : 1;
-
- // mUseSystemPrincipal is true if the system principal should be used for
- // this sheet, no matter what the channel principal is. Only true for sync
- // loads.
- bool mUseSystemPrincipal : 1;
-
- // If true, this SheetLoadData is being used as a way to handle
- // async observer notification for an already-complete sheet.
- bool mSheetAlreadyComplete : 1;
-
- // This is the element that imported the sheet. Needed to get the
- // charset set on it and to fire load/error events.
- nsCOMPtr<nsIStyleSheetLinkingElement> mOwningElement;
-
- // The observer that wishes to be notified of load completion
- nsCOMPtr<nsICSSLoaderObserver> mObserver;
-
- // The principal that identifies who started loading us.
- nsCOMPtr<nsIPrincipal> mLoaderPrincipal;
-
- // The node that identifies who started loading us.
- nsCOMPtr<nsINode> mRequestingNode;
-
- // The charset to use if the transport and sheet don't indicate one.
- // May be empty. Must be empty if mOwningElement is non-null.
- nsCString mCharsetHint;
-
- // The status our load ended up with; this determines whether we
- // should fire error events or load events. This gets initialized
- // by ScheduleLoadEventIfNeeded, and is only used after that has
- // been called.
- MOZ_INIT_OUTSIDE_CTOR nsresult mStatus;
-
-private:
- void FireLoadEvent(nsIThreadInternal* aThread);
-};
-
#include "mozilla/Logging.h"
static mozilla::LazyLogModule sCssLoaderLog("nsCSSLoader");
static mozilla::LazyLogModule gSriPRLog("SRI");
#define LOG_ERROR(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Error, args)
#define LOG_WARN(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Warning, args)
@@ -296,65 +144,69 @@ SheetLoadData::SheetLoadData(Loader* aLo
const nsAString& aTitle,
nsIURI* aURI,
StyleSheet* aSheet,
nsIStyleSheetLinkingElement* aOwningElement,
bool aIsAlternate,
nsICSSLoaderObserver* aObserver,
nsIPrincipal* aLoaderPrincipal,
nsINode* aRequestingNode)
- : mLoader(aLoader),
- mTitle(aTitle),
- mURI(aURI),
- mLineNumber(1),
- mSheet(aSheet),
- mNext(nullptr),
- mPendingChildren(0),
- mSyncLoad(false),
- mIsNonDocumentSheet(false),
- mIsLoading(false),
- mIsCancelled(false),
- mMustNotify(false),
- mWasAlternate(aIsAlternate),
- mUseSystemPrincipal(false),
- mSheetAlreadyComplete(false),
- mOwningElement(aOwningElement),
- mObserver(aObserver),
- mLoaderPrincipal(aLoaderPrincipal),
- mRequestingNode(aRequestingNode)
+ : mLoader(aLoader)
+ , mTitle(aTitle)
+ , mEncoding(nullptr)
+ , mURI(aURI)
+ , mLineNumber(1)
+ , mSheet(aSheet)
+ , mNext(nullptr)
+ , mPendingChildren(0)
+ , mSyncLoad(false)
+ , mIsNonDocumentSheet(false)
+ , mIsLoading(false)
+ , mIsCancelled(false)
+ , mMustNotify(false)
+ , mWasAlternate(aIsAlternate)
+ , mUseSystemPrincipal(false)
+ , mSheetAlreadyComplete(false)
+ , mOwningElement(aOwningElement)
+ , mObserver(aObserver)
+ , mLoaderPrincipal(aLoaderPrincipal)
+ , mRequestingNode(aRequestingNode)
+ , mPreloadEncoding(nullptr)
{
NS_PRECONDITION(mLoader, "Must have a loader!");
}
SheetLoadData::SheetLoadData(Loader* aLoader,
nsIURI* aURI,
StyleSheet* aSheet,
SheetLoadData* aParentData,
nsICSSLoaderObserver* aObserver,
nsIPrincipal* aLoaderPrincipal,
nsINode* aRequestingNode)
- : mLoader(aLoader),
- mURI(aURI),
- mLineNumber(1),
- mSheet(aSheet),
- mNext(nullptr),
- mParentData(aParentData),
- mPendingChildren(0),
- mSyncLoad(false),
- mIsNonDocumentSheet(false),
- mIsLoading(false),
- mIsCancelled(false),
- mMustNotify(false),
- mWasAlternate(false),
- mUseSystemPrincipal(false),
- mSheetAlreadyComplete(false),
- mOwningElement(nullptr),
- mObserver(aObserver),
- mLoaderPrincipal(aLoaderPrincipal),
- mRequestingNode(aRequestingNode)
+ : mLoader(aLoader)
+ , mEncoding(nullptr)
+ , mURI(aURI)
+ , mLineNumber(1)
+ , mSheet(aSheet)
+ , mNext(nullptr)
+ , mParentData(aParentData)
+ , mPendingChildren(0)
+ , mSyncLoad(false)
+ , mIsNonDocumentSheet(false)
+ , mIsLoading(false)
+ , mIsCancelled(false)
+ , mMustNotify(false)
+ , mWasAlternate(false)
+ , mUseSystemPrincipal(false)
+ , mSheetAlreadyComplete(false)
+ , mOwningElement(nullptr)
+ , mObserver(aObserver)
+ , mLoaderPrincipal(aLoaderPrincipal)
+ , mRequestingNode(aRequestingNode)
+ , mPreloadEncoding(nullptr)
{
NS_PRECONDITION(mLoader, "Must have a loader!");
if (mParentData) {
mSyncLoad = mParentData->mSyncLoad;
mIsNonDocumentSheet = mParentData->mIsNonDocumentSheet;
mUseSystemPrincipal = mParentData->mUseSystemPrincipal;
++(mParentData->mPendingChildren);
}
@@ -363,39 +215,40 @@ SheetLoadData::SheetLoadData(Loader* aLo
"Shouldn't use system principal for async loads");
}
SheetLoadData::SheetLoadData(Loader* aLoader,
nsIURI* aURI,
StyleSheet* aSheet,
bool aSyncLoad,
bool aUseSystemPrincipal,
- const nsCString& aCharset,
+ const Encoding* aPreloadEncoding,
nsICSSLoaderObserver* aObserver,
nsIPrincipal* aLoaderPrincipal,
nsINode* aRequestingNode)
- : mLoader(aLoader),
- mURI(aURI),
- mLineNumber(1),
- mSheet(aSheet),
- mNext(nullptr),
- mPendingChildren(0),
- mSyncLoad(aSyncLoad),
- mIsNonDocumentSheet(true),
- mIsLoading(false),
- mIsCancelled(false),
- mMustNotify(false),
- mWasAlternate(false),
- mUseSystemPrincipal(aUseSystemPrincipal),
- mSheetAlreadyComplete(false),
- mOwningElement(nullptr),
- mObserver(aObserver),
- mLoaderPrincipal(aLoaderPrincipal),
- mRequestingNode(aRequestingNode),
- mCharsetHint(aCharset)
+ : mLoader(aLoader)
+ , mEncoding(nullptr)
+ , mURI(aURI)
+ , mLineNumber(1)
+ , mSheet(aSheet)
+ , mNext(nullptr)
+ , mPendingChildren(0)
+ , mSyncLoad(aSyncLoad)
+ , mIsNonDocumentSheet(true)
+ , mIsLoading(false)
+ , mIsCancelled(false)
+ , mMustNotify(false)
+ , mWasAlternate(false)
+ , mUseSystemPrincipal(aUseSystemPrincipal)
+ , mSheetAlreadyComplete(false)
+ , mOwningElement(nullptr)
+ , mObserver(aObserver)
+ , mLoaderPrincipal(aLoaderPrincipal)
+ , mRequestingNode(aRequestingNode)
+ , mPreloadEncoding(aPreloadEncoding)
{
NS_PRECONDITION(mLoader, "Must have a loader!");
NS_POSTCONDITION(!mUseSystemPrincipal || mSyncLoad,
"Shouldn't use system principal for async loads");
}
SheetLoadData::~SheetLoadData()
{
@@ -640,158 +493,151 @@ static bool GetCharsetFromData(const cha
aCharset.Append(c);
}
// Did not see end quote or semicolon
aCharset.Truncate();
return false;
}
+NotNull<const Encoding*>
+SheetLoadData::DetermineNonBOMEncoding(nsACString const& aSegment,
+ nsIChannel* aChannel)
+{
+ const Encoding* encoding;
+ nsAutoCString label;
+
+ // Check HTTP
+ if (aChannel && NS_SUCCEEDED(aChannel->GetContentCharset(label))) {
+ encoding = Encoding::ForLabel(label);
+ if (encoding) {
+ return WrapNotNull(encoding);
+ }
+ }
+
+ // Check @charset
+ auto sniffingLength = aSegment.Length();
+ if (sniffingLength > SNIFFING_BUFFER_SIZE) {
+ sniffingLength = SNIFFING_BUFFER_SIZE;
+ }
+ if (GetCharsetFromData(aSegment.BeginReading(), sniffingLength, label)) {
+ encoding = Encoding::ForLabel(label);
+ if (encoding == UTF_16BE_ENCODING || encoding == UTF_16LE_ENCODING) {
+ return UTF_8_ENCODING;
+ }
+ if (encoding) {
+ return WrapNotNull(encoding);
+ }
+ }
+
+ // Now try the charset on the <link> or processing instruction
+ // that loaded us
+ if (mOwningElement) {
+ nsAutoString label16;
+ mOwningElement->GetCharset(label16);
+ encoding = Encoding::ForLabel(label16);
+ if (encoding) {
+ return WrapNotNull(encoding);
+ }
+ }
+
+ // In the preload case, the value of the charset attribute on <link> comes
+ // in via mPreloadEncoding instead.
+ if (mPreloadEncoding) {
+ return WrapNotNull(mPreloadEncoding);
+ }
+
+ // Try charset from the parent stylesheet.
+ if (mParentData) {
+ encoding = mParentData->mEncoding;
+ if (encoding) {
+ return WrapNotNull(encoding);
+ }
+ }
+
+ if (mLoader->mDocument) {
+ // Use the document charset.
+ return mLoader->mDocument->GetDocumentCharacterSet();
+ }
+
+ return UTF_8_ENCODING;
+}
+
+/*
+ * Encoding decision for the old style system
+ */
NS_IMETHODIMP
SheetLoadData::OnDetermineCharset(nsIUnicharStreamLoader* aLoader,
nsISupports* aContext,
nsACString const& aSegment,
nsACString& aCharset)
{
- NS_PRECONDITION(!mOwningElement || mCharsetHint.IsEmpty(),
- "Can't have element _and_ charset hint");
-
- LOG_URI("SheetLoadData::OnDetermineCharset for '%s'", mURI);
-
- // The precedence is (per CSS3 Syntax 2012-11-08 ED):
- // BOM
- // Channel
- // @charset rule
- // charset attribute on the referrer
- // encoding of the referrer
- // UTF-8
-
- aCharset.Truncate();
-
const Encoding* encoding;
size_t bomLength;
Tie(encoding, bomLength) = Encoding::ForBOM(aSegment);
Unused << bomLength;
- if (encoding) {
- encoding->Name(aCharset);
- // aCharset is now either "UTF-16BE", "UTF-16BE" or "UTF-8"
- // which will swallow the BOM.
- mCharset.Assign(aCharset);
- LOG((" Setting from BOM to: %s", PromiseFlatCString(aCharset).get()));
- return NS_OK;
- }
-
- nsCOMPtr<nsIChannel> channel;
- nsAutoCString specified;
- aLoader->GetChannel(getter_AddRefs(channel));
- if (channel) {
- channel->GetContentCharset(specified);
- encoding = Encoding::ForLabel(specified);
- if (encoding) {
- encoding->Name(aCharset);
- mCharset.Assign(aCharset);
- LOG((" Setting from HTTP to: %s", PromiseFlatCString(aCharset).get()));
- return NS_OK;
- }
- }
-
- if (GetCharsetFromData(aSegment.BeginReading(),
- aSegment.Length(),
- specified)) {
- encoding = Encoding::ForLabel(specified);
- if (encoding) {
- encoding->Name(aCharset);
- if (encoding == UTF_16BE_ENCODING ||
- encoding == UTF_16LE_ENCODING) {
- // Be consistent with HTML <meta> handling in face of impossibility.
- // When the @charset rule itself evidently was not UTF-16-encoded,
- // it saying UTF-16 has to be a lie.
- aCharset.AssignLiteral("UTF-8");
- }
- mCharset.Assign(aCharset);
- LOG((" Setting from @charset rule to: %s",
- PromiseFlatCString(aCharset).get()));
- return NS_OK;
- }
+ if (!encoding) {
+ nsCOMPtr<nsIChannel> channel;
+ aLoader->GetChannel(getter_AddRefs(channel));
+ encoding = DetermineNonBOMEncoding(aSegment, channel);
}
- // Now try the charset on the <link> or processing instruction
- // that loaded us
- if (mOwningElement) {
- nsAutoString specified16;
- mOwningElement->GetCharset(specified16);
- encoding = Encoding::ForLabel(specified16);
- if (encoding) {
- encoding->Name(aCharset);
- mCharset.Assign(aCharset);
- LOG((" Setting from charset attribute to: %s",
- PromiseFlatCString(aCharset).get()));
- return NS_OK;
- }
- }
-
- // In the preload case, the value of the charset attribute on <link> comes
- // in via mCharsetHint instead.
- encoding = Encoding::ForLabel(mCharsetHint);
- if (encoding) {
- encoding->Name(aCharset);
- mCharset.Assign(aCharset);
- LOG((" Setting from charset attribute (preload case) to: %s",
- PromiseFlatCString(aCharset).get()));
- return NS_OK;
- }
-
- // Try charset from the parent stylesheet.
- if (mParentData) {
- aCharset = mParentData->mCharset;
- if (!aCharset.IsEmpty()) {
- mCharset.Assign(aCharset);
- LOG((" Setting from parent sheet to: %s",
- PromiseFlatCString(aCharset).get()));
- return NS_OK;
- }
- }
-
- if (mLoader->mDocument) {
- // no useful data on charset. Try the document charset.
- auto encoding = mLoader->mDocument->GetDocumentCharacterSet();
- encoding->Name(aCharset);
- mCharset.Assign(aCharset);
- LOG((" Setting from document to: %s", PromiseFlatCString(aCharset).get()));
- return NS_OK;
- }
-
- aCharset.AssignLiteral("UTF-8");
- mCharset = aCharset;
- LOG((" Setting from default to: %s", PromiseFlatCString(aCharset).get()));
+ encoding->Name(aCharset);
+ mEncoding = encoding;
return NS_OK;
}
already_AddRefed<nsIURI>
SheetLoadData::GetReferrerURI()
{
nsCOMPtr<nsIURI> uri;
if (mParentData)
uri = mParentData->mSheet->GetSheetURI();
if (!uri && mLoader->mDocument)
uri = mLoader->mDocument->GetDocumentURI();
return uri.forget();
}
/*
- * Here we need to check that the load did not give us an http error
- * page and check the mimetype on the channel to make sure we're not
- * loading non-text/css data in standards mode.
+ * Load completion for the old style system.
*/
NS_IMETHODIMP
SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
nsISupports* aContext,
nsresult aStatus,
const nsAString& aBuffer)
{
+ nsCOMPtr<nsIChannel> channel;
+ aLoader->GetChannel(getter_AddRefs(channel));
+ nsCString bytes;
+ aLoader->GetRawBuffer(bytes);
+
+ nsresult rv = VerifySheetReadyToParse(aStatus, bytes, channel);
+ if (rv != NS_OK_PARSE_SHEET) {
+ return rv;
+ }
+
+ bool completed;
+ rv = mLoader->ParseSheet(aBuffer, Span<const uint8_t>(), this, completed);
+ NS_ASSERTION(completed || !mSyncLoad, "sync load did not complete");
+ return rv;
+}
+
+/*
+ * Stream completion code shared by Stylo and the old style system.
+ *
+ * Here we need to check that the load did not give us an http error
+ * page and check the mimetype on the channel to make sure we're not
+ * loading non-text/css data in standards mode.
+ */
+nsresult
+SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
+ const nsACString& aBytes,
+ nsIChannel* aChannel)
+{
LOG(("SheetLoadData::OnStreamComplete"));
NS_ASSERTION(!mLoader->mSyncCallback, "Synchronous callback from necko");
if (mIsCancelled) {
// Just return. Don't call SheetComplete -- it's already been
// called and calling it again will lead to an extra NS_RELEASE on
// this data and a likely crash.
return NS_OK;
@@ -821,83 +667,79 @@ SheetLoadData::OnStreamComplete(nsIUnich
doc->AddBlockedTrackingNode(content);
}
}
}
mLoader->SheetComplete(this, aStatus);
return NS_OK;
}
- nsCOMPtr<nsIChannel> channel;
- nsresult result = aLoader->GetChannel(getter_AddRefs(channel));
- if (NS_FAILED(result)) {
- LOG_WARN((" No channel from loader"));
- mLoader->SheetComplete(this, result);
+ if (!aChannel) {
+ mLoader->SheetComplete(this, NS_OK);
return NS_OK;
}
nsCOMPtr<nsIURI> originalURI;
- channel->GetOriginalURI(getter_AddRefs(originalURI));
+ aChannel->GetOriginalURI(getter_AddRefs(originalURI));
// If the channel's original URI is "chrome:", we want that, since
// the observer code in nsXULPrototypeCache depends on chrome stylesheets
// having a chrome URI. (Whether or not chrome stylesheets come through
// this codepath seems nondeterministic.)
// Otherwise we want the potentially-HTTP-redirected URI.
nsCOMPtr<nsIURI> channelURI;
- NS_GetFinalChannelURI(channel, getter_AddRefs(channelURI));
+ NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
if (!channelURI || !originalURI) {
NS_ERROR("Someone just violated the nsIRequest contract");
LOG_WARN((" Channel without a URI. Bad!"));
mLoader->SheetComplete(this, NS_ERROR_UNEXPECTED);
return NS_OK;
}
nsCOMPtr<nsIPrincipal> principal;
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
- result = NS_ERROR_NOT_AVAILABLE;
+ nsresult result = NS_ERROR_NOT_AVAILABLE;
if (secMan) { // Could be null if we already shut down
if (mUseSystemPrincipal) {
result = secMan->GetSystemPrincipal(getter_AddRefs(principal));
} else {
- result = secMan->GetChannelResultPrincipal(channel, getter_AddRefs(principal));
+ result =
+ secMan->GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
}
}
if (NS_FAILED(result)) {
LOG_WARN((" Couldn't get principal"));
mLoader->SheetComplete(this, result);
return NS_OK;
}
mSheet->SetPrincipal(principal);
// If it's an HTTP channel, we want to make sure this is not an
// error document we got.
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
+ nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
if (httpChannel) {
bool requestSucceeded;
result = httpChannel->GetRequestSucceeded(&requestSucceeded);
if (NS_SUCCEEDED(result) && !requestSucceeded) {
LOG((" Load returned an error page"));
mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
nsAutoCString sourceMapURL;
if (nsContentUtils::GetSourceMapURL(httpChannel, sourceMapURL)) {
mSheet->SetSourceMapURL(NS_ConvertUTF8toUTF16(sourceMapURL));
}
}
nsAutoCString contentType;
- if (channel) {
- channel->GetContentType(contentType);
- }
+ aChannel->GetContentType(contentType);
// In standards mode, a style sheet must have one of these MIME
// types to be processed at all. In quirks mode, we accept any
// MIME type, but only if the style sheet is same-origin with the
// requesting document or parent sheet. See bug 524223.
bool validType = contentType.EqualsLiteral("text/css") ||
contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
@@ -944,17 +786,17 @@ SheetLoadData::OnStreamComplete(nsIUnich
mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
}
SRIMetadata sriMetadata;
mSheet->GetIntegrity(sriMetadata);
if (sriMetadata.IsEmpty()) {
- nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
if (loadInfo && loadInfo->GetEnforceSRI()) {
LOG((" Load was blocked by SRI"));
MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
("css::Loader::OnStreamComplete, required SRI not found"));
mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
// log the failed load to web console
nsCOMPtr<nsIContentSecurityPolicy> csp;
loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
@@ -967,21 +809,21 @@ SheetLoadData::OnStreamComplete(nsIUnich
0, EmptyString(), EmptyString());
return NS_OK;
}
} else {
nsAutoCString sourceUri;
if (mLoader->mDocument && mLoader->mDocument->GetDocumentURI()) {
mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
}
- nsresult rv = SRICheck::VerifyIntegrity(sriMetadata, aLoader, aBuffer,
- sourceUri, mLoader->mReporter);
+ nsresult rv = SRICheck::VerifyIntegrity(
+ sriMetadata, aChannel, aBytes, sourceUri, mLoader->mReporter);
nsCOMPtr<nsILoadGroup> loadGroup;
- channel->GetLoadGroup(getter_AddRefs(loadGroup));
+ aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup) {
mLoader->mReporter->FlushConsoleReports(loadGroup);
} else {
mLoader->mReporter->FlushConsoleReports(mLoader->mDocument);
}
if (NS_FAILED(rv)) {
LOG((" Load was blocked by SRI"));
@@ -990,21 +832,17 @@ SheetLoadData::OnStreamComplete(nsIUnich
mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
return NS_OK;
}
}
// Enough to set the URIs on mSheet, since any sibling datas we have share
// the same mInner as mSheet and will thus get the same URI.
mSheet->SetURIs(channelURI, originalURI, channelURI);
-
- bool completed;
- result = mLoader->ParseSheet(aBuffer, this, completed);
- NS_ASSERTION(completed || !mSyncLoad, "sync load did not complete");
- return result;
+ return NS_OK_PARSE_SHEET;
}
bool
Loader::IsAlternate(const nsAString& aTitle, bool aHasAlternateRel)
{
// A sheet is alternate if it has a nonempty title that doesn't match the
// currently selected style set. But if there _is_ no currently selected
// style set, the sheet wasn't marked as an alternate explicitly, and aTitle
@@ -1464,22 +1302,29 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
LOG((" Synchronous load"));
NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
NS_ASSERTION(aSheetState == eSheetNeedsParser,
"Sync loads can't reuse existing async loads");
// Create a nsIUnicharStreamLoader instance to which we will feed
// the data from the sync load. Do this before creating the
// channel to make error recovery simpler.
- nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
- rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader), aLoadData);
- if (NS_FAILED(rv)) {
- LOG_ERROR((" Failed to create stream loader for sync load"));
- SheetComplete(aLoadData, rv);
- return rv;
+ nsCOMPtr<nsIStreamListener> streamLoader;
+ if (aLoadData->mSheet->IsGecko()) {
+ nsCOMPtr<nsIUnicharStreamLoader> unicharStreamLoader;
+ rv = NS_NewUnicharStreamLoader(getter_AddRefs(unicharStreamLoader),
+ aLoadData);
+ streamLoader = unicharStreamLoader;
+ if (NS_FAILED(rv)) {
+ LOG_ERROR((" Failed to create stream loader for sync load"));
+ SheetComplete(aLoadData, rv);
+ return rv;
+ }
+ } else {
+ streamLoader = new StreamLoader(aLoadData);
}
if (mDocument) {
mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
mDocument);
}
@@ -1702,25 +1547,32 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
// Now tell the channel we expect text/css data back.... We do
// this before opening it, so it's only treated as a hint.
channel->SetContentType(NS_LITERAL_CSTRING("text/css"));
// We don't have to hold on to the stream loader. The ownership
// model is: Necko owns the stream loader, which owns the load data,
// which owns us
- nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
- rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader), aLoadData);
- if (NS_FAILED(rv)) {
+ nsCOMPtr<nsIStreamListener> streamLoader;
+ if (aLoadData->mSheet->IsGecko()) {
+ nsCOMPtr<nsIUnicharStreamLoader> unicharStreamLoader;
+ rv =
+ NS_NewUnicharStreamLoader(getter_AddRefs(unicharStreamLoader), aLoadData);
+ streamLoader = unicharStreamLoader;
+ if (NS_FAILED(rv)) {
#ifdef DEBUG
- mSyncCallback = false;
+ mSyncCallback = false;
#endif
- LOG_ERROR((" Failed to create stream loader"));
- SheetComplete(aLoadData, rv);
- return rv;
+ LOG_ERROR((" Failed to create stream loader"));
+ SheetComplete(aLoadData, rv);
+ return rv;
+ }
+ } else {
+ streamLoader = new StreamLoader(aLoadData);
}
if (mDocument) {
mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
mDocument);
}
@@ -1744,17 +1596,18 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
/**
* ParseSheet handles parsing the data stream. The main idea here is
* to push the current load data onto the parse stack before letting
* the CSS parser at the data stream. That lets us handle @import
* correctly.
*/
nsresult
-Loader::ParseSheet(const nsAString& aInput,
+Loader::ParseSheet(const nsAString& aUTF16,
+ Span<const uint8_t> aUTF8,
SheetLoadData* aLoadData,
bool& aCompleted)
{
LOG(("css::Loader::ParseSheet"));
NS_PRECONDITION(aLoadData, "Must have load data");
NS_PRECONDITION(aLoadData->mSheet, "Must have sheet to parse into");
aCompleted = false;
@@ -1763,26 +1616,30 @@ Loader::ParseSheet(const nsAString& aInp
mParsingDatas.AppendElement(aLoadData);
nsIURI* sheetURI = aLoadData->mSheet->GetSheetURI();
nsIURI* baseURI = aLoadData->mSheet->GetBaseURI();
nsresult rv;
if (aLoadData->mSheet->IsGecko()) {
nsCSSParser parser(this, aLoadData->mSheet->AsGecko());
- rv = parser.ParseSheet(aInput, sheetURI, baseURI,
+ rv = parser.ParseSheet(aUTF16,
+ sheetURI,
+ baseURI,
aLoadData->mSheet->Principal(),
aLoadData->mLineNumber);
} else {
- rv =
- aLoadData->mSheet->AsServo()->ParseSheet(this,
- aInput, sheetURI, baseURI,
- aLoadData->mSheet->Principal(),
- aLoadData->mLineNumber,
- GetCompatibilityMode());
+ rv = aLoadData->mSheet->AsServo()->ParseSheet(
+ this,
+ aUTF8.IsEmpty() ? NS_ConvertUTF16toUTF8(aUTF16) : aUTF8,
+ sheetURI,
+ baseURI,
+ aLoadData->mSheet->Principal(),
+ aLoadData->mLineNumber,
+ GetCompatibilityMode());
}
mParsingDatas.RemoveElementAt(mParsingDatas.Length() - 1);
if (NS_FAILED(rv)) {
LOG_ERROR((" Low-level error in parser!"));
SheetComplete(aLoadData, rv);
return rv;
@@ -2031,17 +1888,17 @@ Loader::LoadInlineStyle(nsIContent* aEle
aObserver, nullptr, static_cast<nsINode*>(aElement));
// We never actually load this, so just set its principal directly
sheet->SetPrincipal(aElement->NodePrincipal());
NS_ADDREF(data);
data->mLineNumber = aLineNumber;
// Parse completion releases the load data
- rv = ParseSheet(aBuffer, data, *aCompleted);
+ rv = ParseSheet(aBuffer, Span<const uint8_t>(), data, *aCompleted);
NS_ENSURE_SUCCESS(rv, rv);
// If aCompleted is true, |data| may well be deleted by now.
if (!*aCompleted) {
data->mMustNotify = true;
}
return rv;
}
@@ -2307,75 +2164,92 @@ Loader::LoadChildSheet(StyleSheet* aPare
nsresult
Loader::LoadSheetSync(nsIURI* aURL,
SheetParsingMode aParsingMode,
bool aUseSystemPrincipal,
RefPtr<StyleSheet>* aSheet)
{
LOG(("css::Loader::LoadSheetSync"));
return InternalLoadNonDocumentSheet(aURL,
- false, aParsingMode, aUseSystemPrincipal,
- nullptr, EmptyCString(),
- aSheet, nullptr);
+ false,
+ aParsingMode,
+ aUseSystemPrincipal,
+ nullptr,
+ nullptr,
+ aSheet,
+ nullptr);
}
nsresult
Loader::LoadSheet(nsIURI* aURL,
SheetParsingMode aParsingMode,
bool aUseSystemPrincipal,
nsICSSLoaderObserver* aObserver,
RefPtr<StyleSheet>* aSheet)
{
LOG(("css::Loader::LoadSheet(aURL, aParsingMode, aUseSystemPrincipal, aObserver, aSheet)"));
return InternalLoadNonDocumentSheet(aURL,
- false, aParsingMode, aUseSystemPrincipal,
- nullptr, EmptyCString(),
- aSheet, aObserver);
+ false,
+ aParsingMode,
+ aUseSystemPrincipal,
+ nullptr,
+ nullptr,
+ aSheet,
+ aObserver);
}
nsresult
Loader::LoadSheet(nsIURI* aURL,
nsIPrincipal* aOriginPrincipal,
- const nsCString& aCharset,
nsICSSLoaderObserver* aObserver,
RefPtr<StyleSheet>* aSheet)
{
LOG(("css::Loader::LoadSheet(aURL, aObserver, aSheet) api call"));
NS_PRECONDITION(aSheet, "aSheet is null");
return InternalLoadNonDocumentSheet(aURL,
- false, eAuthorSheetFeatures, false,
- aOriginPrincipal, aCharset,
- aSheet, aObserver);
+ false,
+ eAuthorSheetFeatures,
+ false,
+ aOriginPrincipal,
+ nullptr,
+ aSheet,
+ aObserver);
}
nsresult
Loader::LoadSheet(nsIURI* aURL,
bool aIsPreload,
nsIPrincipal* aOriginPrincipal,
- const nsCString& aCharset,
+ const Encoding* aPreloadEncoding,
nsICSSLoaderObserver* aObserver,
CORSMode aCORSMode,
ReferrerPolicy aReferrerPolicy,
const nsAString& aIntegrity)
{
LOG(("css::Loader::LoadSheet(aURL, aObserver) api call"));
return InternalLoadNonDocumentSheet(aURL,
- aIsPreload, eAuthorSheetFeatures, false,
- aOriginPrincipal, aCharset,
- nullptr, aObserver,
- aCORSMode, aReferrerPolicy, aIntegrity);
+ aIsPreload,
+ eAuthorSheetFeatures,
+ false,
+ aOriginPrincipal,
+ aPreloadEncoding,
+ nullptr,
+ aObserver,
+ aCORSMode,
+ aReferrerPolicy,
+ aIntegrity);
}
nsresult
Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
bool aIsPreload,
SheetParsingMode aParsingMode,
bool aUseSystemPrincipal,
nsIPrincipal* aOriginPrincipal,
- const nsCString& aCharset,
+ const Encoding* aPreloadEncoding,
RefPtr<StyleSheet>* aSheet,
nsICSSLoaderObserver* aObserver,
CORSMode aCORSMode,
ReferrerPolicy aReferrerPolicy,
const nsAString& aIntegrity)
{
NS_PRECONDITION(aURL, "Must have a URI to load");
NS_PRECONDITION(aSheet || aObserver, "Sheet and observer can't both be null");
@@ -2416,20 +2290,25 @@ Loader::InternalLoadNonDocumentSheet(nsI
rv = PostLoadEvent(aURL, sheet, aObserver, false, nullptr);
}
if (aSheet) {
sheet.swap(*aSheet);
}
return rv;
}
- SheetLoadData* data =
- new SheetLoadData(this, aURL, sheet, syncLoad,
- aUseSystemPrincipal, aCharset, aObserver,
- aOriginPrincipal, mDocument);
+ SheetLoadData* data = new SheetLoadData(this,
+ aURL,
+ sheet,
+ syncLoad,
+ aUseSystemPrincipal,
+ aPreloadEncoding,
+ aObserver,
+ aOriginPrincipal,
+ mDocument);
NS_ADDREF(data);
rv = LoadSheet(data, state, aIsPreload);
NS_ENSURE_SUCCESS(rv, rv);
if (aSheet) {
sheet.swap(*aSheet);
}
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -370,40 +370,34 @@ public:
* sheet is loaded and marked complete. This method can be used to load
* sheets not associated with a document. This method cannot be used to
* load user or agent sheets.
*
* @param aURL the URL of the sheet to load
* @param aOriginPrincipal the principal to use for security checks. This
* can be null to indicate that these checks should
* be skipped.
- * @param aCharset the encoding to use for converting the sheet data
- * from bytes to Unicode. May be empty to indicate that the
- * charset of the CSSLoader's document should be used. This
- * is only used if neither the network transport nor the
- * sheet itself indicate an encoding.
* @param aObserver the observer to notify when the load completes.
* Must not be null.
* @param [out] aSheet the sheet to load. Note that the sheet may well
* not be loaded by the time this method returns.
*/
nsresult LoadSheet(nsIURI* aURL,
nsIPrincipal* aOriginPrincipal,
- const nsCString& aCharset,
nsICSSLoaderObserver* aObserver,
RefPtr<StyleSheet>* aSheet);
/**
* Same as above, to be used when the caller doesn't care about the
* not-yet-loaded sheet.
*/
nsresult LoadSheet(nsIURI* aURL,
bool aIsPreload,
nsIPrincipal* aOriginPrincipal,
- const nsCString& aCharset,
+ const Encoding* aPreloadEncoding,
nsICSSLoaderObserver* aObserver,
CORSMode aCORSMode = CORS_NONE,
ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Unset,
const nsAString& aIntegrity = EmptyString());
/**
* Stop loading all sheets. All nsICSSLoaderObservers involved will be
* notified with NS_BINDING_ABORTED as the status, possibly synchronously.
@@ -472,16 +466,17 @@ public:
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
// Marks all the sheets at the given URI obsolete, and removes them from the
// cache.
nsresult ObsoleteSheet(nsIURI* aURI);
private:
friend class SheetLoadData;
+ friend class StreamLoader;
nsresult CheckContentPolicy(nsIPrincipal* aSourcePrincipal,
nsIURI* aTargetURI,
nsISupports* aContext,
bool aIsPreload);
// For inline style, the aURI param is null, but the aLinkingContent
// must be non-null then. The loader principal must never be null
@@ -515,27 +510,28 @@ private:
nsresult InsertSheetInDoc(StyleSheet* aSheet,
nsIContent* aLinkingContent,
nsIDocument* aDocument);
nsresult InsertChildSheet(StyleSheet* aSheet,
StyleSheet* aParentSheet,
ImportRule* aGeckoParentRule);
- nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
- bool aIsPreload,
- SheetParsingMode aParsingMode,
- bool aUseSystemPrincipal,
- nsIPrincipal* aOriginPrincipal,
- const nsCString& aCharset,
- RefPtr<StyleSheet>* aSheet,
- nsICSSLoaderObserver* aObserver,
- CORSMode aCORSMode = CORS_NONE,
- ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Unset,
- const nsAString& aIntegrity = EmptyString());
+ nsresult InternalLoadNonDocumentSheet(
+ nsIURI* aURL,
+ bool aIsPreload,
+ SheetParsingMode aParsingMode,
+ bool aUseSystemPrincipal,
+ nsIPrincipal* aOriginPrincipal,
+ const Encoding* aPreloadEncoding,
+ RefPtr<StyleSheet>* aSheet,
+ nsICSSLoaderObserver* aObserver,
+ CORSMode aCORSMode = CORS_NONE,
+ ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Unset,
+ const nsAString& aIntegrity = EmptyString());
// Post a load event for aObserver to be notified about aSheet. The
// notification will be sent with status NS_OK unless the load event is
// canceled at some point (in which case it will be sent with
// NS_BINDING_ABORTED). aWasAlternate indicates the state when the load was
// initiated, not the state at some later time. aURI should be the URI the
// sheet was loaded from (may be null for inline sheets). aElement is the
// owning element for this sheet.
@@ -552,21 +548,23 @@ private:
void HandleLoadEvent(SheetLoadData* aEvent);
// Note: LoadSheet is responsible for releasing aLoadData and setting the
// sheet to complete on failure.
nsresult LoadSheet(SheetLoadData* aLoadData,
StyleSheetState aSheetState,
bool aIsPreLoad);
- // Parse the stylesheet in aLoadData. The sheet data comes from aInput.
- // Set aCompleted to true if the parse finished, false otherwise (e.g. if the
+ // Parse the stylesheet in aLoadData. The sheet data comes from aUTF16 if
+ // UTF-16 and from aUTF8 if UTF-8.
+ // Sets aCompleted to true if the parse finished, false otherwise (e.g. if the
// sheet had an @import). If aCompleted is true when this returns, then
// ParseSheet also called SheetComplete on aLoadData.
- nsresult ParseSheet(const nsAString& aInput,
+ nsresult ParseSheet(const nsAString& aUTF16,
+ Span<const uint8_t> aUTF8,
SheetLoadData* aLoadData,
bool& aCompleted);
// The load of the sheet in aLoadData is done, one way or another. Do final
// cleanup, including releasing aLoadData.
void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
// The guts of SheetComplete. This may be called recursively on parent datas
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -33,20 +33,22 @@ SERVO_BINDING_FUNC(Servo_Element_HasPseu
SERVO_BINDING_FUNC(Servo_Element_GetPseudoComputedValues,
ServoStyleContextStrong,
RawGeckoElementBorrowed node, size_t index)
SERVO_BINDING_FUNC(Servo_Element_IsDisplayNone,
bool,
RawGeckoElementBorrowed element)
// Styleset and Stylesheet management
-SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetContentsStrong,
+SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes,
+ RawServoStyleSheetContentsStrong,
mozilla::css::Loader* loader,
mozilla::ServoStyleSheet* gecko_stylesheet,
- const nsACString* data,
+ const uint8_t* data,
+ size_t data_len,
mozilla::css::SheetParsingMode parsing_mode,
RawGeckoURLExtraData* extra_data,
uint32_t line_number_offset,
nsCompatibility quirks_mode,
mozilla::css::LoaderReusableStyleSheets* reusable_sheets)
SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetContentsStrong,
mozilla::css::SheetParsingMode parsing_mode)
SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -190,34 +190,38 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
bool
ServoStyleSheet::HasRules() const
{
return Servo_StyleSheet_HasRules(Inner()->mContents);
}
nsresult
ServoStyleSheet::ParseSheet(css::Loader* aLoader,
- const nsAString& aInput,
+ Span<const uint8_t> aInput,
nsIURI* aSheetURI,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
uint32_t aLineNumber,
nsCompatibility aCompatMode,
css::LoaderReusableStyleSheets* aReusableSheets)
{
MOZ_ASSERT(!mMedia || mMedia->IsServo());
RefPtr<URLExtraData> extraData =
new URLExtraData(aBaseURI, aSheetURI, aSheetPrincipal);
- NS_ConvertUTF16toUTF8 input(aInput);
- Inner()->mContents =
- Servo_StyleSheet_FromUTF8Bytes(
- aLoader, this, &input, mParsingMode, extraData,
- aLineNumber, aCompatMode, aReusableSheets
- ).Consume();
+ Inner()->mContents = Servo_StyleSheet_FromUTF8Bytes(aLoader,
+ this,
+ aInput.Elements(),
+ aInput.Length(),
+ mParsingMode,
+ extraData,
+ aLineNumber,
+ aCompatMode,
+ aReusableSheets)
+ .Consume();
Inner()->mURLData = extraData.forget();
return NS_OK;
}
nsresult
ServoStyleSheet::ReparseSheet(const nsAString& aInput)
{
@@ -286,19 +290,24 @@ ServoStyleSheet::ReparseSheet(const nsAS
// If detached, don't process any more rules.
break;
}
}
}
DropRuleList();
- nsresult rv = ParseSheet(loader, aInput, mInner->mSheetURI, mInner->mBaseURI,
- mInner->mPrincipal, lineNumber,
- eCompatibility_FullStandards, &reusableSheets);
+ nsresult rv = ParseSheet(loader,
+ NS_ConvertUTF16toUTF8(aInput),
+ mInner->mSheetURI,
+ mInner->mBaseURI,
+ mInner->mPrincipal,
+ lineNumber,
+ eCompatibility_FullStandards,
+ &reusableSheets);
DidDirty();
NS_ENSURE_SUCCESS(rv, rv);
// Notify mDocument that all our new rules are added.
if (mDocument) {
// Get the rule list (which will need to be regenerated after ParseSheet).
ServoCSSRuleList* ruleList = GetCssRulesInternal();
MOZ_ASSERT(ruleList);
--- a/layout/style/ServoStyleSheet.h
+++ b/layout/style/ServoStyleSheet.h
@@ -79,24 +79,25 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoStyleSheet, StyleSheet)
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SERVO_STYLE_SHEET_IMPL_CID)
bool HasRules() const;
- MOZ_MUST_USE nsresult ParseSheet(css::Loader* aLoader,
- const nsAString& aInput,
- nsIURI* aSheetURI,
- nsIURI* aBaseURI,
- nsIPrincipal* aSheetPrincipal,
- uint32_t aLineNumber,
- nsCompatibility aCompatMode,
- css::LoaderReusableStyleSheets* aReusableSheets = nullptr);
+ MOZ_MUST_USE nsresult
+ ParseSheet(css::Loader* aLoader,
+ Span<const uint8_t> aInput,
+ nsIURI* aSheetURI,
+ nsIURI* aBaseURI,
+ nsIPrincipal* aSheetPrincipal,
+ uint32_t aLineNumber,
+ nsCompatibility aCompatMode,
+ css::LoaderReusableStyleSheets* aReusableSheets = nullptr);
nsresult ReparseSheet(const nsAString& aInput);
const RawServoStyleSheetContents* RawContents() const {
return Inner()->mContents;
}
void SetContentsForImport(const RawServoStyleSheetContents* aContents) {
new file mode 100644
--- /dev/null
+++ b/layout/style/SheetLoadData.h
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: ft=cpp tw=78 sw=2 et ts=2
+ *
+ * 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_css_SheetLoadData_h
+#define mozilla_css_SheetLoadData_h
+
+#include "nsIUnicharStreamLoader.h"
+#include "nsIThreadInternal.h"
+
+namespace mozilla {
+namespace css {
+
+/*********************************************
+ * Data needed to properly load a stylesheet *
+ *********************************************/
+
+static_assert(eAuthorSheetFeatures == 0 && eUserSheetFeatures == 1 &&
+ eAgentSheetFeatures == 2,
+ "sheet parsing mode constants won't fit "
+ "in SheetLoadData::mParsingMode");
+
+class SheetLoadData final
+ : public nsIRunnable
+ , public nsIUnicharStreamLoaderObserver
+ , public nsIThreadObserver
+{
+protected:
+ virtual ~SheetLoadData(void);
+
+public:
+ // Data for loading a sheet linked from a document
+ SheetLoadData(Loader* aLoader,
+ const nsAString& aTitle,
+ nsIURI* aURI,
+ StyleSheet* aSheet,
+ nsIStyleSheetLinkingElement* aOwningElement,
+ bool aIsAlternate,
+ nsICSSLoaderObserver* aObserver,
+ nsIPrincipal* aLoaderPrincipal,
+ nsINode* aRequestingNode);
+
+ // Data for loading a sheet linked from an @import rule
+ SheetLoadData(Loader* aLoader,
+ nsIURI* aURI,
+ StyleSheet* aSheet,
+ SheetLoadData* aParentData,
+ nsICSSLoaderObserver* aObserver,
+ nsIPrincipal* aLoaderPrincipal,
+ nsINode* aRequestingNode);
+
+ // Data for loading a non-document sheet
+ SheetLoadData(Loader* aLoader,
+ nsIURI* aURI,
+ StyleSheet* aSheet,
+ bool aSyncLoad,
+ bool aUseSystemPrincipal,
+ const Encoding* aPreloadEncoding,
+ nsICSSLoaderObserver* aObserver,
+ nsIPrincipal* aLoaderPrincipal,
+ nsINode* aRequestingNode);
+
+ already_AddRefed<nsIURI> GetReferrerURI();
+
+ void ScheduleLoadEventIfNeeded(nsresult aStatus);
+
+ NotNull<const Encoding*> DetermineNonBOMEncoding(nsACString const& aSegment,
+ nsIChannel* aChannel);
+
+ nsresult VerifySheetReadyToParse(nsresult aStatus,
+ const nsACString& aBytes,
+ nsIChannel* aChannel);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+ NS_DECL_NSITHREADOBSERVER
+ NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
+
+ // Hold a ref to the CSSLoader so we can call back to it to let it
+ // know the load finished
+ RefPtr<Loader> mLoader;
+
+ // Title needed to pull datas out of the pending datas table when
+ // the preferred title is changed
+ nsString mTitle;
+
+ // The encoding we decided to use for the sheet
+ const Encoding* mEncoding;
+
+ // URI we're loading. Null for inline sheets
+ nsCOMPtr<nsIURI> mURI;
+
+ // Should be 1 for non-inline sheets.
+ uint32_t mLineNumber;
+
+ // The sheet we're loading data for
+ RefPtr<StyleSheet> mSheet;
+
+ // Linked list of datas for the same URI as us
+ SheetLoadData* mNext; // strong ref
+
+ // Load data for the sheet that @import-ed us if we were @import-ed
+ // during the parse
+ RefPtr<SheetLoadData> mParentData;
+
+ // Number of sheets we @import-ed that are still loading
+ uint32_t mPendingChildren;
+
+ // mSyncLoad is true when the load needs to be synchronous -- right
+ // now only for LoadSheetSync and children of sync loads.
+ bool mSyncLoad : 1;
+
+ // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
+ // LoadSheet or an @import from such a sheet. Non-document sheet loads can
+ // proceed even if we have no document.
+ bool mIsNonDocumentSheet : 1;
+
+ // mIsLoading is true from the moment we are placed in the loader's
+ // "loading datas" table (right after the async channel is opened)
+ // to the moment we are removed from said table (due to the load
+ // completing or being cancelled).
+ bool mIsLoading : 1;
+
+ // mIsCancelled is set to true when a sheet load is stopped by
+ // Stop() or StopLoadingSheet() (which was removed in Bug 556446).
+ // SheetLoadData::OnStreamComplete() checks this to avoid parsing
+ // sheets that have been cancelled and such.
+ bool mIsCancelled : 1;
+
+ // mMustNotify is true if the load data is being loaded async and
+ // the original function call that started the load has returned.
+ // This applies only to observer notifications; load/error events
+ // are fired for any SheetLoadData that has a non-null
+ // mOwningElement.
+ bool mMustNotify : 1;
+
+ // mWasAlternate is true if the sheet was an alternate when the load data was
+ // created.
+ bool mWasAlternate : 1;
+
+ // mUseSystemPrincipal is true if the system principal should be used for
+ // this sheet, no matter what the channel principal is. Only true for sync
+ // loads.
+ bool mUseSystemPrincipal : 1;
+
+ // If true, this SheetLoadData is being used as a way to handle
+ // async observer notification for an already-complete sheet.
+ bool mSheetAlreadyComplete : 1;
+
+ // This is the element that imported the sheet. Needed to get the
+ // charset set on it and to fire load/error events.
+ nsCOMPtr<nsIStyleSheetLinkingElement> mOwningElement;
+
+ // The observer that wishes to be notified of load completion
+ nsCOMPtr<nsICSSLoaderObserver> mObserver;
+
+ // The principal that identifies who started loading us.
+ nsCOMPtr<nsIPrincipal> mLoaderPrincipal;
+
+ // The node that identifies who started loading us.
+ nsCOMPtr<nsINode> mRequestingNode;
+
+ // The encoding to use for preloading Must be empty if mOwningElement
+ // is non-null.
+ const Encoding* mPreloadEncoding;
+
+ // The status our load ended up with; this determines whether we
+ // should fire error events or load events. This gets initialized
+ // by ScheduleLoadEventIfNeeded, and is only used after that has
+ // been called.
+ MOZ_INIT_OUTSIDE_CTOR nsresult mStatus;
+
+private:
+ void FireLoadEvent(nsIThreadInternal* aThread);
+};
+
+} // namespace css
+} // namespace mozilla
+
+#endif // mozilla_css_SheetLoadData_h
new file mode 100644
--- /dev/null
+++ b/layout/style/StreamLoader.cpp
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "mozilla/css/StreamLoader.h"
+
+#include "mozilla/IntegerTypeTraits.h"
+#include "mozilla/Encoding.h"
+#include "nsIChannel.h"
+#include "nsIInputStream.h"
+
+using namespace mozilla;
+
+namespace mozilla {
+namespace css {
+
+StreamLoader::StreamLoader(mozilla::css::SheetLoadData* aSheetLoadData)
+ : mSheetLoadData(aSheetLoadData)
+ , mStatus(NS_OK)
+{
+ MOZ_ASSERT(!aSheetLoadData->mSheet->IsGecko());
+}
+
+StreamLoader::~StreamLoader()
+{
+}
+
+NS_IMPL_ISUPPORTS(StreamLoader, nsIStreamListener)
+
+/* nsIRequestObserver implementation */
+NS_IMETHODIMP
+StreamLoader::OnStartRequest(nsIRequest* aRequest, nsISupports*)
+{
+ // It's kinda bad to let Web content send a number that results
+ // in a potentially large allocation directly, but efficiency of
+ // compression bombs is so great that it doesn't make much sense
+ // to require a site to send one before going ahead and allocating.
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+ if (channel) {
+ int64_t length;
+ nsresult rv = channel->GetContentLength(&length);
+ if (NS_SUCCEEDED(rv) && length > 0) {
+ if (length > MaxValue<nsACString::size_type>::value) {
+ return (mStatus = NS_ERROR_OUT_OF_MEMORY);
+ }
+ if (!mBytes.SetCapacity(length, mozilla::fallible_t())) {
+ return (mStatus = NS_ERROR_OUT_OF_MEMORY);
+ }
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StreamLoader::OnStopRequest(nsIRequest* aRequest,
+ nsISupports* aContext,
+ nsresult aStatus)
+{
+ // Decoded data
+ nsCString utf8String;
+ // How many bytes of decoded data to skip (3 when skipping UTF-8 BOM needed,
+ // 0 otherwise)
+ size_t skip = 0;
+
+ const Encoding* encoding;
+
+ nsresult rv = NS_OK;
+
+ {
+ // Hold the nsStringBuffer for the bytes from the stack to ensure release
+ // no matter which return branch is taken.
+ nsCString bytes(mBytes);
+ mBytes.Truncate();
+
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+
+ if (NS_FAILED(mStatus)) {
+ mSheetLoadData->VerifySheetReadyToParse(mStatus, EmptyCString(), channel);
+ return mStatus;
+ }
+
+ nsresult rv =
+ mSheetLoadData->VerifySheetReadyToParse(aStatus, bytes, channel);
+ if (rv != NS_OK_PARSE_SHEET) {
+ return rv;
+ }
+
+ rv = NS_OK;
+
+ size_t bomLength;
+ Tie(encoding, bomLength) = Encoding::ForBOM(bytes);
+ if (!encoding) {
+ // No BOM
+ encoding = mSheetLoadData->DetermineNonBOMEncoding(bytes, channel);
+
+ rv = encoding->DecodeWithoutBOMHandling(bytes, utf8String);
+ } else if (encoding == UTF_8_ENCODING) {
+ // UTF-8 BOM; handling this manually because mozilla::Encoding
+ // can't handle this without copying with C++ types and uses
+ // infallible allocation with Rust types (which could avoid
+ // the copy).
+
+ // First, chop off the BOM.
+ auto tail = Span<const uint8_t>(bytes).From(bomLength);
+ size_t upTo = Encoding::UTF8ValidUpTo(tail);
+ if (upTo == tail.Length()) {
+ // No need to copy
+ skip = bomLength;
+ utf8String.Assign(bytes);
+ } else {
+ rv = encoding->DecodeWithoutBOMHandling(tail, utf8String, upTo);
+ }
+ } else {
+ // UTF-16LE or UTF-16BE
+ rv = encoding->DecodeWithBOMRemoval(bytes, utf8String);
+ }
+ } // run destructor for `bytes`
+
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // For reasons I don't understand, factoring the below lines into
+ // a method on SheetLoadData resulted in a linker error. Hence,
+ // accessing fields of mSheetLoadData from here.
+ mSheetLoadData->mEncoding = encoding;
+ bool dummy;
+ return mSheetLoadData->mLoader->ParseSheet(
+ EmptyString(),
+ Span<const uint8_t>(utf8String).From(skip),
+ mSheetLoadData,
+ dummy);
+}
+
+/* nsIStreamListener implementation */
+NS_IMETHODIMP
+StreamLoader::OnDataAvailable(nsIRequest*,
+ nsISupports*,
+ nsIInputStream* aInputStream,
+ uint64_t,
+ uint32_t aCount)
+{
+ if (NS_FAILED(mStatus)) {
+ return mStatus;
+ }
+ uint32_t dummy;
+ return aInputStream->ReadSegments(WriteSegmentFun, this, aCount, &dummy);
+}
+
+nsresult
+StreamLoader::WriteSegmentFun(nsIInputStream*,
+ void* aClosure,
+ const char* aSegment,
+ uint32_t,
+ uint32_t aCount,
+ uint32_t* aWriteCount)
+{
+ StreamLoader* self = static_cast<StreamLoader*>(aClosure);
+ if (NS_FAILED(self->mStatus)) {
+ return self->mStatus;
+ }
+ if (!self->mBytes.Append(aSegment, aCount, mozilla::fallible_t())) {
+ self->mBytes.Truncate();
+ return (self->mStatus = NS_ERROR_OUT_OF_MEMORY);
+ }
+ *aWriteCount = aCount;
+ return NS_OK;
+}
+
+} // namespace css
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/StreamLoader.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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_css_StreamLoader_h
+#define mozilla_css_StreamLoader_h
+
+#include "nsString.h"
+#include "mozilla/css/SheetLoadData.h"
+
+class nsIInputStream;
+
+namespace mozilla {
+namespace css {
+
+class StreamLoader : public nsIStreamListener
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSISTREAMLISTENER
+
+ explicit StreamLoader(mozilla::css::SheetLoadData* aSheetLoadData);
+
+private:
+ virtual ~StreamLoader();
+
+ /**
+ * callback method used for ReadSegments
+ */
+ static nsresult WriteSegmentFun(nsIInputStream*,
+ void*,
+ const char*,
+ uint32_t,
+ uint32_t,
+ uint32_t*);
+
+ RefPtr<mozilla::css::SheetLoadData> mSheetLoadData;
+ nsCString mBytes;
+ nsresult mStatus;
+};
+
+} // namespace css
+} // namespace mozilla
+
+#endif // mozilla_css_StreamLoader_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -165,17 +165,19 @@ EXPORTS.mozilla.css += [
'Declaration.h',
'ErrorReporter.h',
'GroupRule.h',
'ImageLoader.h',
'ImportRule.h',
'Loader.h',
'NameSpaceRule.h',
'Rule.h',
+ 'SheetLoadData.h',
'SheetParsingMode.h',
+ 'StreamLoader.h',
'StyleRule.h',
'URLMatchingFunction.h',
]
UNIFIED_SOURCES += [
'AnimationCollection.cpp',
'BindingStyleRule.cpp',
'CounterStyleManager.cpp',
@@ -261,16 +263,17 @@ UNIFIED_SOURCES += [
'ServoNamespaceRule.cpp',
'ServoPageRule.cpp',
'ServoSpecifiedValues.cpp',
'ServoStyleContext.cpp',
'ServoStyleRule.cpp',
'ServoStyleSet.cpp',
'ServoStyleSheet.cpp',
'ServoSupportsRule.cpp',
+ 'StreamLoader.cpp',
'StyleAnimationValue.cpp',
'StylePrefs.cpp',
'StyleRule.cpp',
'StyleSheet.cpp',
'URLExtraData.cpp',
]
# - nsLayoutStylesheetCache.cpp needs to be built separately because it uses
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -902,17 +902,17 @@ nsLayoutStylesheetCache::BuildPreference
NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr);
MOZ_ASSERT(uri, "URI creation shouldn't fail");
sheet->SetURIs(uri, uri, uri);
sheet->SetComplete();
static const uint32_t kPreallocSize = 1024;
- nsString sheetText;
+ nsCString sheetText;
sheetText.SetCapacity(kPreallocSize);
#define NS_GET_R_G_B(color_) \
NS_GET_R(color_), NS_GET_G(color_), NS_GET_B(color_)
sheetText.AppendLiteral(
"@namespace url(http://www.w3.org/1999/xhtml);\n"
"@namespace svg url(http://www.w3.org/2000/svg);\n");
@@ -985,23 +985,22 @@ nsLayoutStylesheetCache::BuildPreference
NS_GET_R_G_B(focusBG));
}
NS_ASSERTION(sheetText.Length() <= kPreallocSize,
"kPreallocSize should be big enough to build preference style "
"sheet without reallocation");
if (sheet->IsGecko()) {
- sheet->AsGecko()->ReparseSheet(sheetText);
+ sheet->AsGecko()->ReparseSheet(NS_ConvertUTF8toUTF16(sheetText));
} else {
ServoStyleSheet* servoSheet = sheet->AsServo();
// NB: The pref sheet never has @import rules.
- nsresult rv =
- servoSheet->ParseSheet(nullptr, sheetText, uri, uri, nullptr, 0,
- eCompatibility_FullStandards);
+ nsresult rv = servoSheet->ParseSheet(
+ nullptr, sheetText, uri, uri, nullptr, 0, eCompatibility_FullStandards);
// Parsing the about:PreferenceStyleSheet URI can only fail on OOM. If we
// are OOM before we parsed any documents we might as well abort.
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
#undef NS_GET_R_G_B
}
--- a/layout/style/test/gtest/StyloParsingBench.cpp
+++ b/layout/style/test/gtest/StyloParsingBench.cpp
@@ -5,41 +5,47 @@
#include "gtest/gtest.h"
#include "gtest/MozGTestBench.h"
#include "nsString.h"
#include "ExampleStylesheet.h"
#include "ServoBindings.h"
#include "NullPrincipalURI.h"
#include "nsCSSParser.h"
+#include "mozilla/Encoding.h"
using namespace mozilla;
using namespace mozilla::css;
using namespace mozilla::dom;
using namespace mozilla::net;
#define PARSING_REPETITIONS 20
#define SETPROPERTY_REPETITIONS (1000 * 1000)
#define GETPROPERTY_REPETITIONS (1000 * 1000)
#ifdef MOZ_STYLO
static void ServoParsingBench() {
- NS_NAMED_LITERAL_CSTRING(css_, EXAMPLE_STYLESHEET);
- const nsACString& css = css_;
- ASSERT_TRUE(IsUTF8(css));
+ auto css = AsBytes(MakeStringSpan(EXAMPLE_STYLESHEET));
+ ASSERT_EQ(Encoding::UTF8ValidUpTo(css), css.Length());
RefPtr<URLExtraData> data = new URLExtraData(
NullPrincipalURI::Create(), nullptr, NullPrincipal::Create());
for (int i = 0; i < PARSING_REPETITIONS; i++) {
RefPtr<RawServoStyleSheetContents> stylesheet =
- Servo_StyleSheet_FromUTF8Bytes(
- nullptr, nullptr, &css, eAuthorSheetFeatures,
- data, 0, eCompatibility_FullStandards, nullptr
- ).Consume();
+ Servo_StyleSheet_FromUTF8Bytes(nullptr,
+ nullptr,
+ css.Elements(),
+ css.Length(),
+ eAuthorSheetFeatures,
+ data,
+ 0,
+ eCompatibility_FullStandards,
+ nullptr)
+ .Consume();
}
}
MOZ_GTEST_BENCH(Stylo, Servo_StyleSheet_FromUTF8Bytes_Bench, ServoParsingBench);
#endif
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -979,17 +979,20 @@ nsHtml5TreeOpExecutor::PreloadStyle(cons
mozilla::net::ReferrerPolicy referrerPolicy = mSpeculationReferrerPolicy;
mozilla::net::ReferrerPolicy styleReferrerPolicy =
mozilla::net::AttributeReferrerPolicyFromString(aReferrerPolicy);
if (styleReferrerPolicy != mozilla::net::RP_Unset) {
referrerPolicy = styleReferrerPolicy;
}
- mDocument->PreloadStyle(uri, aCharset, aCrossOrigin, referrerPolicy,
+ mDocument->PreloadStyle(uri,
+ Encoding::ForLabel(aCharset),
+ aCrossOrigin,
+ referrerPolicy,
aIntegrity);
}
void
nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL,
const nsAString& aCrossOrigin,
const nsAString& aSrcset,
const nsAString& aSizes,
--- a/xpcom/base/ErrorList.py
+++ b/xpcom/base/ErrorList.py
@@ -248,17 +248,17 @@ with modules["NETWORK"]:
# These error codes are commonly passed through callback methods to indicate
# the status of some requested async request.
#
# For example, see nsIRequestObserver::onStopRequest.
# The async request completed successfully.
errors["NS_BINDING_SUCCEEDED"] = errors["NS_OK"]
- # The async request failed for some unknown reason.
+ # The async request failed for some unknown reason.
errors["NS_BINDING_FAILED"] = FAILURE(1)
# The async request failed because it was aborted by some user action.
errors["NS_BINDING_ABORTED"] = FAILURE(2)
# The async request has been "redirected" to a different async request.
# (e.g., an HTTP redirect occurred).
#
# This error code is used with load groups to notify the load group observer
# when a request in the load group is redirected to another request.
@@ -309,17 +309,17 @@ with modules["NETWORK"]:
# The connection is already established. XXX unused - consider removing.
errors["NS_ERROR_ALREADY_CONNECTED"] = FAILURE(11)
# The connection does not exist. XXX unused - consider removing.
errors["NS_ERROR_NOT_CONNECTED"] = FAILURE(12)
# The connection attempt failed, for example, because no server was
# listening at specified host:port.
errors["NS_ERROR_CONNECTION_REFUSED"] = FAILURE(13)
- # The connection was lost due to a timeout error.
+ # The connection was lost due to a timeout error.
errors["NS_ERROR_NET_TIMEOUT"] = FAILURE(14)
# The requested action could not be completed while the networking library
# is in the offline state.
errors["NS_ERROR_OFFLINE"] = FAILURE(16)
# The requested action was prohibited because it would have caused the
# networking library to establish a connection to an unsafe or otherwise
# banned port.
errors["NS_ERROR_PORT_ACCESS_NOT_ALLOWED"] = FAILURE(19)
@@ -334,17 +334,17 @@ with modules["NETWORK"]:
# HTTP/2 detected invalid TLS configuration
errors["NS_ERROR_NET_INADEQUATE_SECURITY"] = FAILURE(82)
# XXX really need to better rationalize these error codes. are consumers of
# necko really expected to know how to discern the meaning of these??
# This request is not resumable, but it was tried to resume it, or to
# request resume-specific data.
errors["NS_ERROR_NOT_RESUMABLE"] = FAILURE(25)
- # The request failed as a result of a detected redirection loop.
+ # The request failed as a result of a detected redirection loop.
errors["NS_ERROR_REDIRECT_LOOP"] = FAILURE(31)
# It was attempted to resume the request, but the entity has changed in the
# meantime.
errors["NS_ERROR_ENTITY_CHANGED"] = FAILURE(32)
# The request failed because the content type returned by the server was not
# a type expected by the channel (for nested channels such as the JAR
# channel).
errors["NS_ERROR_UNSAFE_CONTENT_TYPE"] = FAILURE(74)
@@ -469,16 +469,18 @@ with modules["PLUGINS"]:
# =======================================================================
# 8: NS_ERROR_MODULE_LAYOUT
# =======================================================================
with modules["LAYOUT"]:
# Return code for nsITableLayout
errors["NS_TABLELAYOUT_CELL_NOT_FOUND"] = SUCCESS(0)
+ # Return code for SheetLoadData::VerifySheetReadyToParse
+ errors["NS_OK_PARSE_SHEET"] = SUCCESS(1)
# Return code for nsFrame::GetNextPrevLineFromeBlockFrame
errors["NS_POSITION_BEFORE_TABLE"] = SUCCESS(3)
# Return codes for nsPresState::GetProperty()
# Returned if the property exists
errors["NS_STATE_PROPERTY_EXISTS"] = errors["NS_OK"]
# Returned if the property does not exist
errors["NS_STATE_PROPERTY_NOT_THERE"] = SUCCESS(5)