Bug 1952914 - Part 1: Reduce complexity of GetSiteOriginNoSuffix, r=ckerschb
The most expensive step in ValidatePrincipal is currently building a SiteOriginNoSuffix from a ContentPrincipal. This codepath has become more hot due to new checks using ValidatePrincipal. This refactors the code to avoid doing any work on the principal in more cases. The new codepath only computes a different siteOrigin for http(s) URIs, which I believe should be correct. It also does manual parsing of the origin which was built by GenerateOriginNoSuffixForURI in order to avoid unnecessary calls to the URI parser. Differential Revision: https://phabricator.services.mozilla.com/D242420
This commit is contained in:
@@ -440,71 +440,62 @@ ContentPrincipal::GetSiteOriginNoSuffix(nsACString& aSiteOrigin) {
|
||||
nsresult rv = GetOriginNoSuffix(aSiteOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// It is possible for two principals with the same origin to have different
|
||||
// mURI values. In order to ensure that two principals with matching origins
|
||||
// also have matching siteOrigins, we derive the siteOrigin entirely from the
|
||||
// origin string and do not rely on mURI at all here.
|
||||
nsCOMPtr<nsIURI> origin;
|
||||
rv = NS_NewURI(getter_AddRefs(origin), aSiteOrigin);
|
||||
if (NS_FAILED(rv)) {
|
||||
// We got an error parsing the origin as a URI? siteOrigin == origin
|
||||
// aSiteOrigin was already filled with `OriginNoSuffix`
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Handle some special URIs first.
|
||||
nsAutoCString baseDomain;
|
||||
bool handled;
|
||||
rv = GetSpecialBaseDomain(origin, &handled, baseDomain);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (handled) {
|
||||
// This is a special URI ("file:", "about:", "view-source:", etc). Just
|
||||
// return the origin.
|
||||
// The originNoSuffix is already normalized when being generated by
|
||||
// GenerateOriginNoSuffixFromURI. Avoid re-parsing the URI here.
|
||||
//
|
||||
// For all URIs which are not http(s), the site-origin matches the full
|
||||
// origin, so can immediately return.
|
||||
int32_t schemeEnd = aSiteOrigin.Find("://");
|
||||
if (schemeEnd == kNotFound) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// For everything else, we ask the TLD service. Note that, unlike in
|
||||
// GetBaseDomain, we don't use ThirdPartyUtil.getBaseDomain because if the
|
||||
// host is an IP address that returns the raw address and we can't use it with
|
||||
// SetHost below because SetHost expects '[' and ']' around IPv6 addresses.
|
||||
// See bug 1491728.
|
||||
// Check for a http(s) scheme. For all URIs which are not http(s), the
|
||||
// site-origin matches the full origin, so we can immediately return.
|
||||
nsDependentCSubstring scheme(aSiteOrigin, 0, schemeEnd);
|
||||
if (scheme != "http"_ns && scheme != "https"_ns) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The site-origin never includes a port (:[0-9]*), so remove it.
|
||||
// NOTE: This avoids using RFindChar to avoid false-positives.
|
||||
const char* portStart = aSiteOrigin.EndReading() - 1;
|
||||
while ('0' <= *portStart && *portStart <= '9') {
|
||||
--portStart;
|
||||
}
|
||||
if (*portStart == ':') {
|
||||
aSiteOrigin.Truncate(portStart - aSiteOrigin.BeginReading());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
if (!tldService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool gotBaseDomain = false;
|
||||
rv = tldService->GetBaseDomain(origin, 0, baseDomain);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
gotBaseDomain = true;
|
||||
} else {
|
||||
// If this is an IP address or something like "localhost", we just continue
|
||||
// with gotBaseDomain = false.
|
||||
// Get the base-domain from the host. We use the "fromHost" variant to avoid
|
||||
// unnecessary changes to the site-origin.
|
||||
nsAutoCString baseDomain;
|
||||
int32_t hostStart = schemeEnd + 3;
|
||||
nsDependentCSubstring host(aSiteOrigin, hostStart);
|
||||
rv = tldService->GetBaseDomainFromHost(host, 0, baseDomain);
|
||||
if (NS_FAILED(rv)) {
|
||||
// If this is an IP address or something like "localhost", there's nothing
|
||||
// else to be done.
|
||||
if (rv != NS_ERROR_HOST_IS_IP_ADDRESS &&
|
||||
rv != NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS &&
|
||||
rv != NS_ERROR_INVALID_ARG) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// NOTE: Calling `SetHostPort` with a portless domain is insufficient to clear
|
||||
// the port, so an extra `SetPort` call has to be made.
|
||||
nsCOMPtr<nsIURI> siteUri;
|
||||
NS_MutateURI mutator(origin);
|
||||
mutator.SetUserPass(""_ns).SetPort(-1);
|
||||
if (gotBaseDomain) {
|
||||
mutator.SetHost(baseDomain);
|
||||
// Replace the host in aSiteOrigin with baseDomain.
|
||||
if (baseDomain != host) {
|
||||
aSiteOrigin.Replace(hostStart, aSiteOrigin.Length() - hostStart,
|
||||
baseDomain);
|
||||
}
|
||||
rv = mutator.Finalize(siteUri);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteUri");
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aSiteOrigin.Truncate();
|
||||
rv = GenerateOriginNoSuffixFromURI(siteUri, aSiteOrigin);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create siteOriginNoSuffix");
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ContentPrincipal::GetSiteIdentifier(SiteIdentifier& aSite) {
|
||||
|
||||
Reference in New Issue
Block a user