fune/toolkit/components/sessionstore/SessionStoreDataCollector.cpp
Andreas Farre 41d87c3aac Bug 1727367 - Part 2: Limit the size of form fields collected in session store. r=kashav
We need two limits, one for the size of values, and one for the total
size collected.

Differential Revision: https://phabricator.services.mozilla.com/D125196
2021-09-14 15:02:20 +00:00

179 lines
5 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SessionStoreDataCollector.h"
#include "mozilla/Assertions.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/sessionstore/SessionStoreTypes.h"
#include "mozilla/dom/SessionStoreUtils.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "nsGenericHTMLElement.h"
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION(SessionStoreDataCollector, mWindowChild, mTimer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStoreDataCollector)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_ENTRY(nsINamed)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStoreDataCollector)
NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStoreDataCollector)
NS_IMETHODIMP
SessionStoreDataCollector::GetName(nsACString& aName) {
aName.AssignLiteral("SessionStoreDataCollector");
return NS_OK;
}
NS_IMETHODIMP
SessionStoreDataCollector::Notify(nsITimer* aTimer) {
Collect();
return NS_OK;
}
/* static */ already_AddRefed<SessionStoreDataCollector>
SessionStoreDataCollector::CollectSessionStoreData(
WindowGlobalChild* aWindowChild) {
MOZ_RELEASE_ASSERT(SessionStoreUtils::NATIVE_LISTENER);
MOZ_DIAGNOSTIC_ASSERT(aWindowChild);
RefPtr<SessionStoreDataCollector> listener =
aWindowChild->GetSessionStoreDataCollector();
uint32_t epoch =
aWindowChild->BrowsingContext()->Top()->GetSessionStoreEpoch();
if (listener) {
MOZ_DIAGNOSTIC_ASSERT_IF(
!StaticPrefs::browser_sessionstore_debug_no_auto_updates(),
listener->mTimer);
if (listener->mEpoch == epoch) {
return listener.forget();
}
if (listener->mTimer) {
listener->mTimer->Cancel();
}
}
listener = new SessionStoreDataCollector(aWindowChild, epoch);
if (!StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
auto result = NS_NewTimerWithCallback(
listener, StaticPrefs::browser_sessionstore_interval(),
nsITimer::TYPE_ONE_SHOT);
if (result.isErr()) {
return nullptr;
}
listener->mTimer = result.unwrap();
}
aWindowChild->SetSessionStoreDataCollector(listener);
return listener.forget();
}
void SessionStoreDataCollector::RecordInputChange() { mInputChanged = true; }
void SessionStoreDataCollector::RecordScrollChange() { mScrollChanged = true; }
void SessionStoreDataCollector::Flush() { Collect(); }
void SessionStoreDataCollector::Cancel() {
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
mWindowChild->SetSessionStoreDataCollector(nullptr);
}
void SessionStoreDataCollector::Collect() {
if (this != mWindowChild->GetSessionStoreDataCollector()) {
return;
}
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
nsGlobalWindowInner* inner = mWindowChild->GetWindowGlobal();
if (!inner) {
return;
}
Document* document = inner->GetDocument();
if (!document) {
return;
}
Maybe<sessionstore::FormData> maybeFormData;
if (mInputChanged) {
maybeFormData.emplace();
auto& formData = maybeFormData.ref();
uint32_t size = SessionStoreUtils::CollectFormData(document, formData);
Element* body = document->GetBody();
if (document->HasFlag(NODE_IS_EDITABLE) && body) {
IgnoredErrorResult result;
body->GetInnerHTML(formData.innerHTML(), result);
size += formData.innerHTML().Length();
if (!result.Failed()) {
formData.hasData() = true;
}
}
if (size > StaticPrefs::browser_sessionstore_dom_form_max_limit()) {
maybeFormData = Nothing();
}
}
PresShell* presShell = document->GetPresShell();
Maybe<nsPoint> maybeScroll;
if (mScrollChanged && presShell) {
maybeScroll = Some(presShell->GetVisualViewportOffset());
}
if (!mWindowChild->CanSend()) {
return;
}
if (RefPtr<WindowGlobalParent> windowParent =
mWindowChild->GetParentActor()) {
windowParent->WriteFormDataAndScrollToSessionStore(maybeFormData,
maybeScroll, mEpoch);
} else {
mWindowChild->SendUpdateSessionStore(maybeFormData, maybeScroll, mEpoch);
}
mWindowChild->SetSessionStoreDataCollector(nullptr);
}
SessionStoreDataCollector::SessionStoreDataCollector(
WindowGlobalChild* aWindowChild, uint32_t aEpoch)
: mWindowChild(aWindowChild),
mTimer(nullptr),
mEpoch(aEpoch),
mInputChanged(false),
mScrollChanged(false) {}
SessionStoreDataCollector::~SessionStoreDataCollector() {
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
}
} // namespace mozilla::dom