Maybe<nsStyleLinkElement::SheetInfo> HTMLLinkElement::GetStyleSheetInfo() { nsAutoString rel; GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel); uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel); if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) { return Nothing(); } if (!IsCSSMimeTypeAttribute(*this)) { return Nothing(); } nsAutoString title; nsAutoString media; GetTitleAndMediaForElement(*this, title, media); bool alternate = linkTypes & nsStyleLinkElement::eALTERNATE; if (alternate && title.IsEmpty()) { // alternates must have title. return Nothing(); } nsAutoString href; GetAttr(kNameSpaceID_None, nsGkAtoms::href, href); if (href.IsEmpty()) { return Nothing(); } nsCOMPtr<nsIURI> uri = Link::GetURI(); nsCOMPtr<nsIPrincipal> prin = mTriggeringPrincipal; return Some(SheetInfo{ *OwnerDoc(), this, uri.forget(), prin.forget(), GetReferrerPolicyAsEnum(), GetCORSMode(), title, media, alternate ? HasAlternateRel::Yes : HasAlternateRel::No, IsInline::No, }); }
void HTMLLinkElement::UpdatePreconnect() { // rel type should be preconnect nsAutoString rel; if (!GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) { return; } uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, NodePrincipal()); if (!(linkTypes & ePRECONNECT)) { return; } nsIDocument *owner = OwnerDoc(); if (owner) { nsCOMPtr<nsIURI> uri = GetHrefURI(); if (uri) { owner->MaybePreconnect(uri, GetCORSMode()); } } }
void StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { StyleSheetInfo& info = SheetInfo(); if (aSubjectPrincipal.Subsumes(info.mPrincipal)) { return; } // Allow access only if CORS mode is not NONE if (GetCORSMode() == CORS_NONE) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } // Now make sure we set the principal of our inner to the subjectPrincipal. // We do this because we're in a situation where the caller would not normally // be able to access the sheet, but the sheet has opted in to being read. // Unfortunately, that means it's also opted in to being _edited_, and if the // caller now makes edits to the sheet we want the resulting resource loads, // if any, to look as if they are coming from the caller's principal, not the // original sheet principal. // // That means we need a unique inner, of course. But we don't want to do that // if we're not complete yet. Luckily, all the callers of this method throw // anyway if not complete, so we can just do that here too. if (!info.mComplete) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } WillDirty(); info.mPrincipal = &aSubjectPrincipal; DidDirty(); }
nsresult nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument, nsICSSLoaderObserver* aObserver, bool* aWillNotify, bool* aIsAlternate, bool aForceUpdate) { *aWillNotify = false; if (mStyleSheet && aOldDocument) { // We're removing the link element from the document, unload the // stylesheet. We want to do this even if updates are disabled, since // otherwise a sheet with a stale linking element pointer will be hanging // around -- not good! aOldDocument->BeginUpdate(UPDATE_STYLE); aOldDocument->RemoveStyleSheet(mStyleSheet); aOldDocument->EndUpdate(UPDATE_STYLE); nsStyleLinkElement::SetStyleSheet(nullptr); } nsCOMPtr<nsIContent> thisContent; QueryInterface(NS_GET_IID(nsIContent), getter_AddRefs(thisContent)); NS_ENSURE_TRUE(thisContent, NS_ERROR_FAILURE); // When static documents are created, stylesheets are cloned manually. if (mDontLoadStyle || !mUpdatesEnabled || thisContent->OwnerDoc()->IsStaticDocument()) { return NS_OK; } nsCOMPtr<nsIDocument> doc = thisContent->GetDocument(); if (!doc || !doc->CSSLoader()->GetEnabled()) { return NS_OK; } bool isInline; nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline); if (!aForceUpdate && mStyleSheet && !isInline && uri) { nsIURI* oldURI = mStyleSheet->GetSheetURI(); if (oldURI) { bool equal; nsresult rv = oldURI->Equals(uri, &equal); if (NS_SUCCEEDED(rv) && equal) { return NS_OK; // We already loaded this stylesheet } } } if (mStyleSheet) { doc->BeginUpdate(UPDATE_STYLE); doc->RemoveStyleSheet(mStyleSheet); doc->EndUpdate(UPDATE_STYLE); nsStyleLinkElement::SetStyleSheet(nullptr); } if (!uri && !isInline) { return NS_OK; // If href is empty and this is not inline style then just bail } nsAutoString title, type, media; bool isAlternate; GetStyleSheetInfo(title, type, media, &isAlternate); if (!type.LowerCaseEqualsLiteral("text/css")) { return NS_OK; } bool doneLoading = false; nsresult rv = NS_OK; if (isInline) { nsAutoString text; nsContentUtils::GetNodeTextContent(thisContent, false, text); // Parse the style sheet. rv = doc->CSSLoader()-> LoadInlineStyle(thisContent, text, mLineNumber, title, media, aObserver, &doneLoading, &isAlternate); } else { // XXXbz clone the URI here to work around content policies modifying URIs. nsCOMPtr<nsIURI> clonedURI; uri->Clone(getter_AddRefs(clonedURI)); NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY); rv = doc->CSSLoader()-> LoadStyleLink(thisContent, clonedURI, title, media, isAlternate, GetCORSMode(), aObserver, &isAlternate); if (NS_FAILED(rv)) { // Don't propagate LoadStyleLink() errors further than this, since some // consumers (e.g. nsXMLContentSink) will completely abort on innocuous // things like a stylesheet load being blocked by the security system. doneLoading = true; isAlternate = false; rv = NS_OK; } } NS_ENSURE_SUCCESS(rv, rv); *aWillNotify = !doneLoading; *aIsAlternate = isAlternate; return NS_OK; }
nsresult nsImageLoadingContent::LoadImage(nsIURI* aNewURI, bool aForce, bool aNotify, nsIDocument* aDocument, nsLoadFlags aLoadFlags) { if (!mLoadingEnabled) { // XXX Why fire an error here? seems like the callers to SetLoadingEnabled // don't want/need it. FireEvent(NS_LITERAL_STRING("error")); return NS_OK; } NS_ASSERTION(!aDocument || aDocument == GetOurDocument(), "Bogus document passed in"); // First, get a document (needed for security checks and the like) if (!aDocument) { aDocument = GetOurDocument(); if (!aDocument) { // No reason to bother, I think... return NS_OK; } } // URI equality check. // // We skip the equality check if our current image was blocked, since in that // case we really do want to try loading again. if (!aForce && NS_CP_ACCEPTED(mImageBlockingStatus)) { nsCOMPtr<nsIURI> currentURI; GetCurrentURI(getter_AddRefs(currentURI)); bool equal; if (currentURI && NS_SUCCEEDED(currentURI->Equals(aNewURI, &equal)) && equal) { // Nothing to do here. return NS_OK; } } // From this point on, our image state could change. Watch it. AutoStateChanger changer(this, aNotify); // Sanity check. // // We use the principal of aDocument to avoid having to QI |this| an extra // time. It should always be the same as the principal of this node. #ifdef DEBUG nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this); NS_ABORT_IF_FALSE(thisContent && thisContent->NodePrincipal() == aDocument->NodePrincipal(), "Principal mismatch?"); #endif // Are we blocked? PRInt16 cpDecision = nsIContentPolicy::REJECT_REQUEST; nsContentUtils::CanLoadImage(aNewURI, this, aDocument, aDocument->NodePrincipal(), &cpDecision); if (!NS_CP_ACCEPTED(cpDecision)) { FireEvent(NS_LITERAL_STRING("error")); SetBlockedRequest(aNewURI, cpDecision); return NS_OK; } nsLoadFlags loadFlags = aLoadFlags; PRInt32 corsmode = GetCORSMode(); if (corsmode == nsImageLoadingContent::CORS_ANONYMOUS) { loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS; } else if (corsmode == nsImageLoadingContent::CORS_USE_CREDENTIALS) { loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS; } // Not blocked. Do the load. nsCOMPtr<imgIRequest>& req = PrepareNextRequest(); nsresult rv; rv = nsContentUtils::LoadImage(aNewURI, aDocument, aDocument->NodePrincipal(), aDocument->GetDocumentURI(), this, loadFlags, getter_AddRefs(req)); if (NS_SUCCEEDED(rv)) { TrackImage(req); } else { // If we don't have a current URI, we might as well store this URI so people // know what we tried (and failed) to load. if (!mCurrentRequest) mCurrentURI = aNewURI; FireEvent(NS_LITERAL_STRING("error")); return NS_OK; } return NS_OK; }