/* -*- 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/. */
class DynamicFrameEventFilter final : public nsIDOMEventListener { public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(DynamicFrameEventFilter)
nsCOMPtr<nsIDocShell> docShell = aWindow.get()->GetDocShell(); if (!docShell) {
aRv.Throw(NS_ERROR_FAILURE); return;
}
int32_t length;
aRv = docShell->GetInProcessChildCount(&length); if (aRv.Failed()) { return;
}
for (int32_t i = 0; i < length; ++i) {
nsCOMPtr<nsIDocShellTreeItem> item;
docShell->GetInProcessChildAt(i, getter_AddRefs(item)); if (!item) {
aRv.Throw(NS_ERROR_FAILURE); return;
}
RefPtr<BrowsingContext> context = item->GetBrowsingContext(); if (!context) {
aRv.Throw(NS_ERROR_FAILURE); return;
}
bool allowJavascript = true; for (const nsACString& token :
nsCCharSeparatedTokenizer(aDisallowCapabilities, ',').ToRange()) { if (token.EqualsLiteral("Javascript")) {
allowJavascript = false;
} elseif (token.EqualsLiteral("MetaRedirects")) {
aDocShell->SetAllowMetaRedirects(false);
} elseif (token.EqualsLiteral("Subframes")) {
aDocShell->SetAllowSubframes(false);
} elseif (token.EqualsLiteral("Images")) {
aDocShell->SetAllowImages(false);
} elseif (token.EqualsLiteral("Media")) {
aDocShell->SetAllowMedia(false);
} elseif (token.EqualsLiteral("DNSPrefetch")) {
aDocShell->SetAllowDNSPrefetch(false);
} elseif (token.EqualsLiteral("WindowControl")) {
aDocShell->SetAllowWindowControl(false);
} elseif (token.EqualsLiteral("ContentRetargeting")) { bool allow;
aDocShell->GetAllowContentRetargetingOnChildren(&allow);
aDocShell->SetAllowContentRetargeting( false); // will also set AllowContentRetargetingOnChildren
aDocShell->SetAllowContentRetargetingOnChildren(
allow); // restore the allowProp to original
} elseif (token.EqualsLiteral("ContentRetargetingOnChildren")) {
aDocShell->SetAllowContentRetargetingOnChildren(false);
}
}
if (!mozilla::SessionHistoryInParent()) { // With SessionHistoryInParent, this is set from the parent process.
BrowsingContext* bc = aDocShell->GetBrowsingContext();
Unused << bc->SetAllowJavascript(allowJavascript);
}
}
staticvoid CollectCurrentScrollPosition(JSContext* aCx, Document& aDocument,
Nullable<CollectedData>& aRetVal) {
PresShell* presShell = aDocument.GetPresShell(); if (!presShell) { return;
}
nsPoint scrollPos = presShell->GetVisualViewportOffset(); int scrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x); int scrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
nsCCharSeparatedTokenizer tokenizer(aScrollPosition, ',');
nsAutoCString token(tokenizer.nextToken()); int pos_X = atoi(token.get());
token = tokenizer.nextToken(); int pos_Y = atoi(token.get());
aWindow.ScrollTo(pos_X, pos_Y);
if (nsCOMPtr<Document> doc = aWindow.GetExtantDoc()) { if (nsPresContext* presContext = doc->GetPresContext()) { if (presContext->IsRootContentDocumentCrossProcess()) { // Use eMainThread so this takes precedence over session history // (ScrollFrameHelper::ScrollToRestoredPosition()).
presContext->PresShell()->ScrollToVisual(
CSSPoint::ToAppUnits(CSSPoint(pos_X, pos_Y)),
layers::FrameMetrics::eMainThread, ScrollMode::Instant);
}
}
}
}
// Implements the Luhn checksum algorithm as described at // http://wikipedia.org/wiki/Luhn_algorithm // Number digit lengths vary with network, but should fall within 12-19 range. // [2] More details at https://en.wikipedia.org/wiki/Payment_card_number staticbool IsValidCCNumber(nsAString& aValue) {
uint32_t total = 0;
uint32_t numLength = 0;
uint32_t strLen = aValue.Length(); for (uint32_t i = 0; i < strLen; ++i) {
uint32_t idx = strLen - i - 1; // ignore whitespace and dashes)
char16_t chr = aValue[idx]; if (IsSpaceCharacter(chr) || chr == '-') { continue;
} // If our number is too long, note that fact
++numLength; if (numLength > 19) { returnfalse;
} // Try to parse the character as a base-10 integer.
nsresult rv = NS_OK;
uint32_t val = Substring(aValue, idx, 1).ToInteger(&rv, 10); if (NS_FAILED(rv)) { returnfalse;
} if (i % 2 == 1) {
val *= 2; if (val > 9) {
val -= 9;
}
}
total += val;
}
return numLength >= 12 && total % 10 == 0;
}
// Limit the number of XPath expressions for performance reasons. See bug // 477564. staticconst uint16_t kMaxTraversedXPaths = 100;
// A helper function to append a element into mId or mXpath of CollectedData static Record<nsString, OwningStringOrBooleanOrObject>::EntryType*
AppendEntryToCollectedData(nsINode* aNode, const nsAString& aId,
uint16_t& aGeneratedCount,
Nullable<CollectedData>& aRetVal) {
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry; if (!aId.IsEmpty()) { if (!aRetVal.SetValue().mId.WasPassed()) {
aRetVal.SetValue().mId.Construct();
} auto& recordEntries = aRetVal.SetValue().mId.Value().Entries();
entry = recordEntries.AppendElement();
entry->mKey = aId;
} else { if (!aRetVal.SetValue().mXpath.WasPassed()) {
aRetVal.SetValue().mXpath.Construct();
} auto& recordEntries = aRetVal.SetValue().mXpath.Value().Entries();
entry = recordEntries.AppendElement();
nsAutoString xpath;
aNode->GenerateXPath(xpath);
aGeneratedCount++;
entry->mKey = xpath;
} return entry;
}
/* special handing for input element with string type */ staticvoid AppendValueToCollectedData(Document& aDocument, nsINode* aNode, const nsAString& aId, const nsString& aValue,
uint16_t& aGeneratedCount,
JSContext* aCx,
Nullable<CollectedData>& aRetVal) { if (!aId.IsEmpty()) { // We want to avoid saving data for about:sessionrestore as a string. // Since it's stored in the form as stringified JSON, stringifying // further causes an explosion of escape characters. cf. bug 467409 if (aId.EqualsLiteral("sessionData")) {
nsAutoCString url;
Unused << aDocument.GetDocumentURI()->GetSpecIgnoringRef(url); if (url.EqualsLiteral("about:sessionrestore") ||
url.EqualsLiteral("about:welcomeback")) {
JS::Rooted<JS::Value> jsval(aCx); if (JS_ParseJSON(aCx, aValue.get(), aValue.Length(), &jsval) &&
jsval.isObject()) {
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(aNode, aId, aGeneratedCount, aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
} else {
JS_ClearPendingException(aCx);
} return;
}
}
}
AppendValueToCollectedData(aNode, aId, aValue, aGeneratedCount, aRetVal);
}
static uint32_t CollectTextAreaElement(Document* aDocument,
sessionstore::FormData& aFormData) {
uint32_t size = 0;
RefPtr<nsContentList> textlist =
NS_GetContentList(aDocument, kNameSpaceID_XHTML, u"textarea"_ns);
uint32_t length = textlist->Length(); for (uint32_t i = 0; i < length; ++i) {
MOZ_ASSERT(textlist->Item(i), "null item in node list!");
auto* textArea = HTMLTextAreaElement::FromNodeOrNull(textlist->Item(i)); if (!textArea) { continue;
}
DOMString autocomplete;
textArea->GetAutocomplete(autocomplete); if (autocomplete.AsAString().EqualsLiteral("off")) { continue;
}
nsAutoString id;
textArea->GetId(id); if (id.IsEmpty() && (aFormData.xpath().Length() > kMaxTraversedXPaths)) { continue;
}
nsString value;
textArea->GetValue(value); // In order to reduce XPath generation (which is slow), we only save data // for form fields that have been changed. (cf. bug 537289) if (textArea->AttrValueIs(kNameSpaceID_None, nsGkAtoms::value, value,
eCaseMatters)) { continue;
}
if (!selected) { continue;
}
option->GetValue(*selectslist.AppendElement());
} // In order to reduce XPath generation (which is slow), we only save data // for form fields that have been changed. (cf. bug 537289) if (hasDefaultValue) { continue;
}
static already_AddRefed<nsContentList> GetFormAssociatedCustomElements(
nsINode* aRootNode) {
MOZ_ASSERT(aRootNode, "Content list has to have a root");
auto matchFunc = [](Element* aElement, int32_t aNamespace, nsAtom* aAtom, void* aData) -> bool { return aElement->HasCustomElementData() &&
aElement->GetCustomElementData()->IsFormAssociated();
};
RefPtr<nsContentList> list = new nsContentList(aRootNode, matchFunc, nullptr, nullptr); return list.forget();
}
static uint32_t CollectFormAssociatedCustomElement(
Document* aDocument, sessionstore::FormData& aFormData) {
uint32_t size = 0;
RefPtr<nsContentList> faceList = GetFormAssociatedCustomElements(aDocument);
uint32_t length = faceList->Length(); for (uint32_t i = 0; i < length; ++i) {
MOZ_ASSERT(faceList->Item(i), "null item in node list!");
RefPtr<Element> element = Element::FromNode(faceList->Item(i));
/* static */ template <typename... ArgsT> void SessionStoreUtils::CollectFromTextAreaElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args) {
RefPtr<nsContentList> textlist =
NS_GetContentList(&aDocument, kNameSpaceID_XHTML, u"textarea"_ns);
uint32_t length = textlist->Length(true); for (uint32_t i = 0; i < length; ++i) {
MOZ_ASSERT(textlist->Item(i), "null item in node list!");
HTMLTextAreaElement* textArea =
HTMLTextAreaElement::FromNodeOrNull(textlist->Item(i)); if (!textArea) { continue;
}
DOMString autocomplete;
textArea->GetAutocomplete(autocomplete); if (autocomplete.AsAString().EqualsLiteral("off")) { continue;
}
nsAutoString id;
textArea->GetId(id); if (id.IsEmpty() && (aGeneratedCount > kMaxTraversedXPaths)) { continue;
}
nsString value;
textArea->GetValue(value); // In order to reduce XPath generation (which is slow), we only save data // for form fields that have been changed. (cf. bug 537289) if (textArea->AttrValueIs(kNameSpaceID_None, nsGkAtoms::value, value,
eCaseMatters)) { continue;
}
AppendValueToCollectedData(textArea, id, value, aGeneratedCount,
std::forward<ArgsT>(args)...);
}
}
if (input->ControlType() == FormControlType::InputCheckbox ||
input->ControlType() == FormControlType::InputRadio) { bool checked = input->Checked(); if (checked == input->DefaultChecked()) { continue;
}
AppendValueToCollectedData(input, id, checked, aGeneratedCount,
std::forward<ArgsT>(args)...);
} elseif (input->ControlType() == FormControlType::InputFile) {
IgnoredErrorResult rv;
nsTArray<nsString> result;
input->MozGetFileNameArray(result, rv); if (rv.Failed() || result.Length() == 0) { continue;
}
AppendValueToCollectedData(input, id, u"file"_ns, result, aGeneratedCount,
std::forward<ArgsT>(args)...);
} else {
nsString value;
input->GetValue(value, CallerType::System); // In order to reduce XPath generation (which is slow), we only save data // for form fields that have been changed. (cf. bug 537289) // Also, don't want to collect credit card number. if (value.IsEmpty() || IsValidCCNumber(value) ||
input->HasBeenTypePassword() ||
input->AttrValueIs(kNameSpaceID_None, nsGkAtoms::value, value,
eCaseMatters)) { continue;
}
AppendValueToCollectedData(aDocument, input, id, value, aGeneratedCount,
std::forward<ArgsT>(args)...);
}
}
}
/* static */ template <typename... ArgsT> void SessionStoreUtils::CollectFromSelectElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args) {
RefPtr<nsContentList> selectlist =
NS_GetContentList(&aDocument, kNameSpaceID_XHTML, u"select"_ns);
uint32_t length = selectlist->Length(true); for (uint32_t i = 0; i < length; ++i) {
MOZ_ASSERT(selectlist->Item(i), "null item in node list!");
RefPtr<HTMLSelectElement> select =
HTMLSelectElement::FromNodeOrNull(selectlist->Item(i)); if (!select) { continue;
}
nsAutoString id;
select->GetId(id); if (id.IsEmpty() && (aGeneratedCount > kMaxTraversedXPaths)) { continue;
}
AutocompleteInfo aInfo;
select->GetAutocompleteInfo(aInfo); if (!aInfo.mCanAutomaticallyPersist) { continue;
}
nsAutoCString value; if (!select->Multiple()) { // <select>s without the multiple attribute are hard to determine the // default value, so assume we don't have the default.
DOMString selectVal;
select->GetValue(selectVal);
CollectedNonMultipleSelectValue val;
val.mSelectedIndex = select->SelectedIndex();
val.mValue = selectVal.AsAString();
AppendValueToCollectedData(select, id, val, aGeneratedCount,
std::forward<ArgsT>(args)...);
} else { // <select>s with the multiple attribute are easier to determine the // default value since each <option> has a defaultSelected property
HTMLOptionsCollection* options = select->GetOptions(); if (!options) { continue;
} bool hasDefaultValue = true;
nsTArray<nsString> selectslist;
uint32_t numOptions = options->Length(); for (uint32_t idx = 0; idx < numOptions; idx++) {
HTMLOptionElement* option = options->ItemAsOption(idx); bool selected = option->Selected(); if (!selected) { continue;
}
option->GetValue(*selectslist.AppendElement());
hasDefaultValue =
hasDefaultValue && (selected == option->DefaultSelected());
} // In order to reduce XPath generation (which is slow), we only save data // for form fields that have been changed. (cf. bug 537289) if (hasDefaultValue) { continue;
}
// Store the frame's current URL with its form data so that we can compare // it when restoring data to not inject form data into the wrong document.
nsIURI* uri = aDocument.GetDocumentURI(); if (uri) {
uri->GetSpecIgnoringRef(aRetVal.SetValue().mUrl.Construct());
}
}
MOZ_CAN_RUN_SCRIPT staticvoid SetElementAsString(Element* aElement, const nsAString& aValue) {
IgnoredErrorResult rv; if (auto* textArea = HTMLTextAreaElement::FromNode(aElement)) { // Known live because `aElement` is known live.
MOZ_KnownLive(textArea)->SetValue(aValue, rv); if (!rv.Failed()) {
nsContentUtils::DispatchInputEvent(aElement);
} return;
} if (auto* input = HTMLInputElement::FromNode(aElement)) {
input->SetValue(aValue, CallerType::NonSystem, rv); if (!rv.Failed()) {
nsContentUtils::DispatchInputEvent(aElement);
} return;
}
}
// Don't restore any data for the given frame if the URL // stored in the form data doesn't match its current URL.
nsAutoCString url;
Unused << aDocument.GetDocumentURI()->GetSpecIgnoringRef(url); if (!aData.mUrl.Value().Equals(url)) { returnfalse;
}
using Change = SessionStoreChangeListener::Change;
SessionStoreChangeListener::CollectSessionStoreData(
aDocument.GetWindowContext(), EnumSet<Change>(Change::Input));
if (aData.mInnerHTML.WasPassed()) {
SetInnerHTML(aDocument, aData.mInnerHTML.Value());
} if (aData.mId.WasPassed()) { for (auto& entry : aData.mId.Value().Entries()) {
RefPtr<Element> node = aDocument.GetElementById(entry.mKey); if (node == nullptr) { continue;
} if (entry.mValue.IsString()) {
SetElementAsString(node, entry.mValue.GetAsString());
} elseif (entry.mValue.IsBoolean()) {
SetElementAsBool(node, entry.mValue.GetAsBoolean());
} else { // For about:{sessionrestore,welcomeback} we saved the field as JSON to // avoid nested instances causing humongous sessionstore.js files. // cf. bug 467409
JSContext* cx = aGlobal.Context(); if (entry.mKey.EqualsLiteral("sessionData")) { if (url.EqualsLiteral("about:sessionrestore") ||
url.EqualsLiteral("about:welcomeback")) {
JS::Rooted<JS::Value> object(
cx, JS::ObjectValue(*entry.mValue.GetAsObject()));
SetSessionData(cx, node, &object); continue;
}
}
JS::Rooted<JS::Value> object(
cx, JS::ObjectValue(*entry.mValue.GetAsObject()));
SetElementAsObject(cx, node, object);
}
}
}
/** * A function that will recursively call |CollectorFunc| to collect data for all * non-dynamic frames in the current frame/docShell tree.
*/ staticvoid CollectFrameTreeData(JSContext* aCx,
BrowsingContext* aBrowsingContext,
Nullable<CollectedData>& aRetVal,
CollectorFunc aFunc) { if (aBrowsingContext->CreatedDynamically()) { return;
}
Document* document = window->GetExtantDoc(); if (!document) { return;
}
/* Collect data from current frame */
aFunc(aCx, *document, aRetVal);
/* Collect data from all child frame */
nsTArray<JSObject*> childrenData;
SequenceRooter<JSObject*> rooter(aCx, &childrenData);
uint32_t trailingNullCounter = 0;
// This is not going to work for fission. Bug 1572084 for tracking it. for (auto& child : aBrowsingContext->Children()) {
NullableRootedDictionary<CollectedData> data(aCx);
CollectFrameTreeData(aCx, child, data, aFunc); if (data.IsNull()) {
childrenData.AppendElement(nullptr);
trailingNullCounter++; continue;
}
JS::Rooted<JS::Value> jsval(aCx); if (!ToJSValue(aCx, data.SetValue(), &jsval)) {
JS_ClearPendingException(aCx); continue;
}
childrenData.AppendElement(&jsval.toObject());
trailingNullCounter = 0;
}
for (const CollectedInputDataValue& data : aData) {
id.AppendElement(data.id);
type.AppendElement(data.type);
if (data.value.is<mozilla::dom::CollectedNonMultipleSelectValue>()) {
valueIdx.AppendElement(selectVal.Length());
selectedIndex.AppendElement(
data.value.as<mozilla::dom::CollectedNonMultipleSelectValue>()
.mSelectedIndex);
selectVal.AppendElement(
data.value.as<mozilla::dom::CollectedNonMultipleSelectValue>()
.mValue);
} elseif (data.value.is<CopyableTArray<nsString>>()) { // The first valueIdx is "index of the first string value"
valueIdx.AppendElement(strVal.Length());
strVal.AppendElements(data.value.as<CopyableTArray<nsString>>()); // The second valueIdx is "index of the last string value" + 1
id.AppendElement(data.id);
type.AppendElement(data.type);
valueIdx.AppendElement(strVal.Length());
} elseif (data.value.is<nsString>()) {
valueIdx.AppendElement(strVal.Length());
strVal.AppendElement(data.value.as<nsString>());
} elseif (data.type.EqualsLiteral("bool")) {
valueIdx.AppendElement(boolVal.Length());
boolVal.AppendElement(data.value.as<bool>());
}
}
if (selectedIndex.Length() != 0) {
ret.mSelectedIndex.Construct(std::move(selectedIndex));
} if (valueIdx.Length() != 0) {
ret.mValueIdx.Construct(std::move(valueIdx));
} if (id.Length() != 0) {
ret.mId.Construct(std::move(id));
} if (selectVal.Length() != 0) {
ret.mSelectVal.Construct(std::move(selectVal));
} if (strVal.Length() != 0) {
ret.mStrVal.Construct(std::move(strVal));
} if (type.Length() != 0) {
ret.mType.Construct(std::move(type));
} if (boolVal.Length() != 0) {
ret.mBoolVal.Construct(std::move(boolVal));
}
}
already_AddRefed<nsISessionStoreRestoreData>
SessionStoreUtils::ConstructSessionStoreRestoreData( const GlobalObject& aGlobal) {
nsCOMPtr<nsISessionStoreRestoreData> data = new SessionStoreRestoreData(); return data.forget();
}
/* static */
already_AddRefed<Promise> SessionStoreUtils::InitializeRestore( const GlobalObject& aGlobal, CanonicalBrowsingContext& aContext,
nsISessionStoreRestoreData* aData, ErrorResult& aError) { if (!mozilla::SessionHistoryInParent()) {
MOZ_CRASH("why were we called?");
}
MOZ_DIAGNOSTIC_ASSERT(aContext.IsTop());
MOZ_DIAGNOSTIC_ASSERT(aData);
nsCOMPtr<SessionStoreRestoreData> data = do_QueryInterface(aData);
aContext.SetRestoreData(data, aError); if (aError.Failed()) { return nullptr;
}
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 und die Messung sind noch experimentell.