Bug 1673682 - Accept functors rather than a virtual function override in URLParams::Parse. r=valentin,necko-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D96428
This commit is contained in:
Simon Giesecke 2020-11-13 08:12:12 +00:00
parent 0138da753c
commit f355f05fec
7 changed files with 165 additions and 255 deletions

View file

@ -269,91 +269,6 @@ void OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const {
attrs.CreateSuffix(aStr);
}
namespace {
class MOZ_STACK_CLASS PopulateFromSuffixIterator final
: public URLParams::ForEachIterator {
public:
explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes)
: mOriginAttributes(aOriginAttributes) {
MOZ_ASSERT(aOriginAttributes);
// If a non-default mPrivateBrowsingId is passed and is not present in the
// suffix, then it will retain the id when it should be default according
// to the suffix. Set to default before iterating to fix this.
mOriginAttributes->mPrivateBrowsingId =
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
}
bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) override {
if (aName.EqualsLiteral("inBrowser")) {
if (!aValue.EqualsLiteral("1")) {
return false;
}
mOriginAttributes->mInIsolatedMozBrowser = true;
return true;
}
if (aName.EqualsLiteral("addonId") || aName.EqualsLiteral("appId")) {
// No longer supported. Silently ignore so that legacy origin strings
// don't cause failures.
return true;
}
if (aName.EqualsLiteral("userContextId")) {
nsresult rv;
int64_t val = aValue.ToInteger64(&rv);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(val <= UINT32_MAX, false);
mOriginAttributes->mUserContextId = static_cast<uint32_t>(val);
return true;
}
if (aName.EqualsLiteral("privateBrowsingId")) {
nsresult rv;
int64_t val = aValue.ToInteger64(&rv);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false);
mOriginAttributes->mPrivateBrowsingId = static_cast<uint32_t>(val);
return true;
}
if (aName.EqualsLiteral("firstPartyDomain")) {
MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty());
nsAutoString firstPartyDomain(aValue);
firstPartyDomain.ReplaceChar(kSanitizedChar, kSourceChar);
mOriginAttributes->mFirstPartyDomain.Assign(firstPartyDomain);
return true;
}
if (aName.EqualsLiteral("geckoViewUserContextId")) {
MOZ_RELEASE_ASSERT(
mOriginAttributes->mGeckoViewSessionContextId.IsEmpty());
mOriginAttributes->mGeckoViewSessionContextId.Assign(aValue);
return true;
}
if (aName.EqualsLiteral("partitionKey")) {
MOZ_RELEASE_ASSERT(mOriginAttributes->mPartitionKey.IsEmpty());
nsAutoString partitionKey(aValue);
partitionKey.ReplaceChar(kSanitizedChar, kSourceChar);
mOriginAttributes->mPartitionKey.Assign(partitionKey);
return true;
}
// No other attributes are supported.
return false;
}
private:
OriginAttributes* mOriginAttributes;
};
} // namespace
bool OriginAttributes::PopulateFromSuffix(const nsACString& aStr) {
if (aStr.IsEmpty()) {
return true;
@ -363,8 +278,74 @@ bool OriginAttributes::PopulateFromSuffix(const nsACString& aStr) {
return false;
}
PopulateFromSuffixIterator iterator(this);
return URLParams::Parse(Substring(aStr, 1, aStr.Length() - 1), iterator);
// If a non-default mPrivateBrowsingId is passed and is not present in the
// suffix, then it will retain the id when it should be default according
// to the suffix. Set to default before iterating to fix this.
mPrivateBrowsingId = nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
return URLParams::Parse(
Substring(aStr, 1, aStr.Length() - 1),
[this](const nsAString& aName, const nsAString& aValue) {
if (aName.EqualsLiteral("inBrowser")) {
if (!aValue.EqualsLiteral("1")) {
return false;
}
mInIsolatedMozBrowser = true;
return true;
}
if (aName.EqualsLiteral("addonId") || aName.EqualsLiteral("appId")) {
// No longer supported. Silently ignore so that legacy origin strings
// don't cause failures.
return true;
}
if (aName.EqualsLiteral("userContextId")) {
nsresult rv;
int64_t val = aValue.ToInteger64(&rv);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(val <= UINT32_MAX, false);
mUserContextId = static_cast<uint32_t>(val);
return true;
}
if (aName.EqualsLiteral("privateBrowsingId")) {
nsresult rv;
int64_t val = aValue.ToInteger64(&rv);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false);
mPrivateBrowsingId = static_cast<uint32_t>(val);
return true;
}
if (aName.EqualsLiteral("firstPartyDomain")) {
MOZ_RELEASE_ASSERT(mFirstPartyDomain.IsEmpty());
nsAutoString firstPartyDomain(aValue);
firstPartyDomain.ReplaceChar(kSanitizedChar, kSourceChar);
mFirstPartyDomain.Assign(firstPartyDomain);
return true;
}
if (aName.EqualsLiteral("geckoViewUserContextId")) {
MOZ_RELEASE_ASSERT(mGeckoViewSessionContextId.IsEmpty());
mGeckoViewSessionContextId.Assign(aValue);
return true;
}
if (aName.EqualsLiteral("partitionKey")) {
MOZ_RELEASE_ASSERT(mPartitionKey.IsEmpty());
nsAutoString partitionKey(aValue);
partitionKey.ReplaceChar(kSanitizedChar, kSourceChar);
mPartitionKey.Assign(partitionKey);
return true;
}
// No other attributes are supported.
return false;
});
}
bool OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin,

View file

@ -44,25 +44,6 @@ static bool PushOverLine(nsACString::const_iterator& aStart,
return false;
}
class MOZ_STACK_CLASS FillFormIterator final
: public URLParams::ForEachIterator {
public:
explicit FillFormIterator(FormData* aFormData) : mFormData(aFormData) {
MOZ_ASSERT(aFormData);
}
bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) override {
ErrorResult rv;
mFormData->Append(aName, aValue, rv);
MOZ_ASSERT(!rv.Failed());
return true;
}
private:
FormData* mFormData;
};
/**
* A simple multipart/form-data parser as defined in RFC 2388 and RFC 2046.
* This does not respect any encoding specified per entry, using UTF-8
@ -452,8 +433,13 @@ already_AddRefed<FormData> BodyUtil::ConsumeFormData(nsIGlobalObject* aParent,
if (isValidUrlEncodedMimeType) {
RefPtr<FormData> fd = new FormData(aParent);
FillFormIterator iterator(fd);
DebugOnly<bool> status = URLParams::Parse(aStr, iterator);
DebugOnly<bool> status = URLParams::Parse(
aStr, [&fd](const nsAString& aName, const nsAString& aValue) {
ErrorResult rv;
fd->Append(aName, aValue, rv);
MOZ_ASSERT(!rv.Failed());
return true;
});
MOZ_ASSERT(status);
return fd.forget();

View file

@ -11572,27 +11572,19 @@ Result<bool, nsresult> UpgradeStorageFrom1_0To2_0Helper::MaybeRemoveAppsData(
// https+++developer.cdn.mozilla.net^inBrowser=1
// instead of just removing them.
class MOZ_STACK_CLASS ParamsIterator final
: public URLParams::ForEachIterator {
public:
bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) override {
if (aName.EqualsLiteral("appId")) {
return false;
}
return true;
}
};
const nsCString& originalSuffix = aOriginProps.mOriginalSuffix;
if (!originalSuffix.IsEmpty()) {
MOZ_ASSERT(originalSuffix[0] == '^');
ParamsIterator iterator;
if (!URLParams::Parse(
Substring(originalSuffix, 1, originalSuffix.Length() - 1),
iterator)) {
[](const nsAString& aName, const nsAString& aValue) {
if (aName.EqualsLiteral("appId")) {
return false;
}
return true;
})) {
QM_TRY(RemoveObsoleteOrigin(aOriginProps));
return true;

View file

@ -1022,77 +1022,44 @@ void URLParams::DecodeString(const nsACString& aInput, nsAString& aOutput) {
}
/* static */
bool URLParams::Parse(const nsACString& aInput, ForEachIterator& aIterator) {
const auto* start = aInput.BeginReading();
const auto* const end = aInput.EndReading();
const auto* iter = start;
bool URLParams::ParseNextInternal(const char*& aStart, const char* const aEnd,
nsAString* aOutDecodedName,
nsAString* aOutDecodedValue) {
nsDependentCSubstring string;
while (start != end) {
nsDependentCSubstring string;
iter = std::find(iter, end, '&');
if (iter != end) {
string.Rebind(start, iter);
start = ++iter;
} else {
string.Rebind(start, end);
start = end;
}
if (string.IsEmpty()) {
continue;
}
const auto* const eqStart = string.BeginReading();
const auto* const eqEnd = string.EndReading();
const auto* eqIter = eqStart;
nsDependentCSubstring name;
nsDependentCSubstring value;
eqIter = std::find(eqIter, eqEnd, '=');
if (eqIter != eqEnd) {
name.Rebind(eqStart, eqIter);
++eqIter;
value.Rebind(eqIter, eqEnd);
} else {
name.Rebind(string, 0);
}
nsAutoString decodedName;
DecodeString(name, decodedName);
nsAutoString decodedValue;
DecodeString(value, decodedValue);
if (!aIterator.URLParamsIterator(decodedName, decodedValue)) {
return false;
}
const char* const iter = std::find(aStart, aEnd, '&');
if (iter != aEnd) {
string.Rebind(aStart, iter);
aStart = iter + 1;
} else {
string.Rebind(aStart, aEnd);
aStart = aEnd;
}
if (string.IsEmpty()) {
return false;
}
const auto* const eqStart = string.BeginReading();
const auto* const eqEnd = string.EndReading();
const auto* const eqIter = std::find(eqStart, eqEnd, '=');
nsDependentCSubstring name;
nsDependentCSubstring value;
if (eqIter != eqEnd) {
name.Rebind(eqStart, eqIter);
value.Rebind(eqIter + 1, eqEnd);
} else {
name.Rebind(string, 0);
}
DecodeString(name, *aOutDecodedName);
DecodeString(value, *aOutDecodedValue);
return true;
}
class MOZ_STACK_CLASS ExtractURLParam final
: public URLParams::ForEachIterator {
public:
explicit ExtractURLParam(const nsAString& aName, nsAString& aValue)
: mName(aName), mValue(aValue) {}
bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) override {
if (mName == aName) {
mValue = aValue;
return false;
}
return true;
}
private:
const nsAString& mName;
nsAString& mValue;
};
/**
* Extracts the first form-urlencoded parameter named `aName` from `aInput`.
* @param aRange The input to parse.
@ -1104,33 +1071,24 @@ class MOZ_STACK_CLASS ExtractURLParam final
bool URLParams::Extract(const nsACString& aInput, const nsAString& aName,
nsAString& aValue) {
aValue.SetIsVoid(true);
ExtractURLParam iterator(aName, aValue);
return !URLParams::Parse(aInput, iterator);
return !URLParams::Parse(
aInput, [&aName, &aValue](const nsAString& name, nsString&& value) {
if (aName == name) {
aValue = std::move(value);
return false;
}
return true;
});
}
class MOZ_STACK_CLASS PopulateIterator final
: public URLParams::ForEachIterator {
public:
explicit PopulateIterator(URLParams* aParams) : mParams(aParams) {
MOZ_ASSERT(aParams);
}
bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) override {
mParams->Append(aName, aValue);
return true;
}
private:
URLParams* mParams;
};
void URLParams::ParseInput(const nsACString& aInput) {
// Remove all the existing data before parsing a new input.
DeleteAll();
PopulateIterator iter(this);
URLParams::Parse(aInput, iter);
URLParams::Parse(aInput, [this](nsString&& name, nsString&& value) {
mParams.AppendElement(Param{std::move(name), std::move(value)});
return true;
});
}
namespace {

View file

@ -229,13 +229,25 @@ class URLParams final {
~URLParams() { DeleteAll(); }
class ForEachIterator {
public:
virtual bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) = 0;
};
template <typename ParamHandler>
static bool Parse(const nsACString& aInput, ParamHandler aParamHandler) {
const char* start = aInput.BeginReading();
const char* const end = aInput.EndReading();
static bool Parse(const nsACString& aInput, ForEachIterator& aIterator);
while (start != end) {
nsAutoString decodedName;
nsAutoString decodedValue;
if (!ParseNextInternal(start, end, &decodedName, &decodedValue)) {
continue;
}
if (!aParamHandler(std::move(decodedName), std::move(decodedValue))) {
return false;
}
}
return true;
}
static bool Extract(const nsACString& aInput, const nsAString& aName,
nsAString& aValue);
@ -275,6 +287,9 @@ class URLParams final {
private:
static void DecodeString(const nsACString& aInput, nsAString& aOutput);
static void ConvertString(const nsACString& aInput, nsAString& aOutput);
static bool ParseNextInternal(const char*& aStart, const char* aEnd,
nsAString* aOutDecodedName,
nsAString* aOutDecodedValue);
struct Param {
nsString mKey;

View file

@ -768,19 +768,6 @@ nsresult Connection::initialize(nsIFile* aDatabaseFile) {
return NS_OK;
}
static bool HasKeyParam(const nsACString& aQuery) {
class MOZ_STACK_CLASS ParamsIterator final
: public URLParams::ForEachIterator {
public:
bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) override {
return aName.EqualsLiteral("key");
}
} paramsIterator;
return URLParams::Parse(aQuery, paramsIterator);
}
nsresult Connection::initialize(nsIFileURL* aFileURL,
const nsACString& aTelemetryFilename) {
NS_ASSERTION(aFileURL, "Passed null file URL!");
@ -812,8 +799,13 @@ nsresult Connection::initialize(nsIFileURL* aFileURL,
nsAutoCString query;
rv = aFileURL->GetQuery(query);
NS_ENSURE_SUCCESS(rv, rv);
const char* const vfs = HasKeyParam(query) ? GetObfuscatingVFSName()
: GetTelemetryVFSName(exclusive);
const char* const vfs =
URLParams::Parse(query,
[](const nsAString& aName, const nsAString& aValue) {
return aName.EqualsLiteral("key");
})
? GetObfuscatingVFSName()
: GetTelemetryVFSName(exclusive);
int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, vfs);
if (srv != SQLITE_OK) {
mDBConn = nullptr;

View file

@ -239,28 +239,6 @@ getSharedUTF8String(mozIStorageValueArray* aValues, uint32_t aIndex) {
return nsDependentCString(str, len);
}
class MOZ_STACK_CLASS GetQueryParamIterator final
: public URLParams::ForEachIterator {
public:
explicit GetQueryParamIterator(const nsCString& aParamName,
nsVariant* aResult)
: mParamName(aParamName), mResult(aResult) {}
bool URLParamsIterator(const nsAString& aName,
const nsAString& aValue) override {
NS_ConvertUTF16toUTF8 name(aName);
if (!mParamName.Equals(name)) {
return true;
}
mResult->SetAsAString(aValue);
return false;
}
private:
const nsCString& mParamName;
nsVariant* mResult;
};
/**
* Gets the length of the prefix in a URI spec. "Prefix" is defined to be the
* scheme, colon, and, if present, two slashes.
@ -1003,8 +981,16 @@ GetQueryParamFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
RefPtr<nsVariant> result = new nsVariant();
if (!queryString.IsEmpty() && !paramName.IsEmpty()) {
GetQueryParamIterator iterator(paramName, result);
URLParams::Parse(queryString, iterator);
URLParams::Parse(
queryString,
[&paramName, &result](const nsAString& aName, const nsAString& aValue) {
NS_ConvertUTF16toUTF8 name(aName);
if (!paramName.Equals(name)) {
return true;
}
result->SetAsAString(aValue);
return false;
});
}
result.forget(_result);