blob: 0b3ec59fbb1db4bbecc2cc8d5b42e8b4674f325c [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/frame/OriginsUsingFeatures.h"
#include "bindings/core/v8/ScriptState.h"
#include "core/dom/Document.h"
#include "core/page/Page.h"
#include "public/platform/Platform.h"
namespace blink {
OriginsUsingFeatures::~OriginsUsingFeatures()
{
updateMeasurementsAndClear();
}
OriginsUsingFeatures::Value::Value()
: m_countBits(0)
{
}
void OriginsUsingFeatures::countAnyWorld(Document& document, Feature feature)
{
document.originsUsingFeaturesValue().count(feature);
}
void OriginsUsingFeatures::countMainWorldOnly(const ScriptState* scriptState, Document& document, Feature feature)
{
if (!scriptState || !scriptState->world().isMainWorld())
return;
countAnyWorld(document, feature);
}
static Document* documentFromEventTarget(EventTarget& target)
{
ExecutionContext* executionContext = target.executionContext();
if (!executionContext)
return nullptr;
if (executionContext->isDocument())
return toDocument(executionContext);
if (LocalDOMWindow* executingWindow = executionContext->executingWindow())
return executingWindow->document();
return nullptr;
}
void OriginsUsingFeatures::countOriginOrIsolatedWorldHumanReadableName(const ScriptState* scriptState, EventTarget& target, Feature feature)
{
if (!scriptState)
return;
Document* document = documentFromEventTarget(target);
if (!document)
return;
if (scriptState->world().isMainWorld()) {
document->originsUsingFeaturesValue().count(feature);
return;
}
if (Page* page = document->page())
page->originsUsingFeatures().countName(feature, scriptState->world().isolatedWorldHumanReadableName());
}
void OriginsUsingFeatures::Value::count(Feature feature)
{
ASSERT(feature < Feature::NumberOfFeatures);
m_countBits |= 1 << static_cast<unsigned>(feature);
}
void OriginsUsingFeatures::countName(Feature feature, const String& name)
{
auto result = m_valueByName.add(name, Value());
result.storedValue->value.count(feature);
}
void OriginsUsingFeatures::clear()
{
m_originAndValues.clear();
m_valueByName.clear();
}
void OriginsUsingFeatures::documentDetached(Document& document)
{
OriginsUsingFeatures::Value counter = document.originsUsingFeaturesValue();
if (counter.isEmpty())
return;
const KURL& url = document.url();
if (!url.protocolIsInHTTPFamily())
return;
m_originAndValues.append(std::make_pair(url.host(), counter));
document.originsUsingFeaturesValue().clear();
ASSERT(document.originsUsingFeaturesValue().isEmpty());
}
void OriginsUsingFeatures::updateMeasurementsAndClear()
{
if (!m_originAndValues.isEmpty())
recordOriginsToRappor();
if (!m_valueByName.isEmpty())
recordNamesToRappor();
}
void OriginsUsingFeatures::recordOriginsToRappor()
{
ASSERT(!m_originAndValues.isEmpty());
// Aggregate values by origins.
HashMap<String, OriginsUsingFeatures::Value> aggregatedByOrigin;
for (const auto& originAndValue : m_originAndValues) {
ASSERT(!originAndValue.first.isEmpty());
auto result = aggregatedByOrigin.add(originAndValue.first, originAndValue.second);
if (!result.isNewEntry)
result.storedValue->value.aggregate(originAndValue.second);
}
// Report to RAPPOR.
for (auto& originAndValue : aggregatedByOrigin)
originAndValue.value.recordOriginToRappor(originAndValue.key);
m_originAndValues.clear();
}
void OriginsUsingFeatures::recordNamesToRappor()
{
ASSERT(!m_valueByName.isEmpty());
for (auto& nameAndValue : m_valueByName)
nameAndValue.value.recordNameToRappor(nameAndValue.key);
m_valueByName.clear();
}
void OriginsUsingFeatures::Value::aggregate(OriginsUsingFeatures::Value other)
{
m_countBits |= other.m_countBits;
}
void OriginsUsingFeatures::Value::recordOriginToRappor(const String& origin)
{
if (get(Feature::ElementCreateShadowRoot))
Platform::current()->recordRappor("WebComponents.ElementCreateShadowRoot", origin);
if (get(Feature::ElementAttachShadow))
Platform::current()->recordRappor("WebComponents.ElementAttachShadow", origin);
if (get(Feature::DocumentRegisterElement))
Platform::current()->recordRappor("WebComponents.DocumentRegisterElement", origin);
if (get(Feature::EventPath))
Platform::current()->recordRappor("WebComponents.EventPath", origin);
if (get(Feature::DeviceMotionInsecureOrigin))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.DeviceMotion.Insecure", origin);
if (get(Feature::DeviceOrientationInsecureOrigin))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.DeviceOrientation.Insecure", origin);
if (get(Feature::FullscreenInsecureOrigin))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.Fullscreen.Insecure", origin);
if (get(Feature::GeolocationInsecureOrigin))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.Geolocation.Insecure", origin);
if (get(Feature::GetUserMediaInsecureOrigin))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.GetUserMedia.Insecure", origin);
if (get(Feature::GetUserMediaSecureOrigin))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.GetUserMedia.Secure", origin);
}
void OriginsUsingFeatures::Value::recordNameToRappor(const String& name)
{
if (get(Feature::EventPath))
Platform::current()->recordRappor("WebComponents.EventPath.Extensions", name);
}
} // namespace blink