Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Unified Diff: third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp

Issue 2620313002: Refactor WindowProxy into Local and Remote subclasses. (Closed)
Patch Set: explicit Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
diff --git a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
index 61471d3f5b944ef41bf07347bc90f7bb30894ebc..b750f2657faee14354032ea38feadde1dac1085d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
@@ -30,64 +30,18 @@
#include "bindings/core/v8/WindowProxy.h"
-#include "bindings/core/v8/ConditionalFeatures.h"
-#include "bindings/core/v8/DOMWrapperWorld.h"
-#include "bindings/core/v8/ScriptController.h"
-#include "bindings/core/v8/ToV8.h"
#include "bindings/core/v8/V8Binding.h"
-#include "bindings/core/v8/V8DOMActivityLogger.h"
-#include "bindings/core/v8/V8Document.h"
+#include "bindings/core/v8/V8DOMWrapper.h"
#include "bindings/core/v8/V8GCForContextDispose.h"
-#include "bindings/core/v8/V8HTMLCollection.h"
-#include "bindings/core/v8/V8HTMLDocument.h"
-#include "bindings/core/v8/V8HiddenValue.h"
-#include "bindings/core/v8/V8Initializer.h"
-#include "bindings/core/v8/V8ObjectConstructor.h"
#include "bindings/core/v8/V8PagePopupControllerBinding.h"
-#include "bindings/core/v8/V8PrivateProperty.h"
-#include "bindings/core/v8/V8Window.h"
-#include "core/frame/LocalFrame.h"
-#include "core/frame/csp/ContentSecurityPolicy.h"
-#include "core/html/DocumentNameCollection.h"
-#include "core/html/HTMLCollection.h"
-#include "core/html/HTMLIFrameElement.h"
-#include "core/inspector/InspectorInstrumentation.h"
-#include "core/inspector/MainThreadDebugger.h"
-#include "core/loader/DocumentLoader.h"
-#include "core/loader/FrameLoader.h"
-#include "core/loader/FrameLoaderClient.h"
-#include "core/origin_trials/OriginTrialContext.h"
-#include "platform/Histogram.h"
-#include "platform/RuntimeEnabledFeatures.h"
-#include "platform/ScriptForbiddenScope.h"
-#include "platform/heap/Handle.h"
-#include "platform/instrumentation/tracing/TraceEvent.h"
-#include "platform/weborigin/SecurityOrigin.h"
-#include "public/platform/Platform.h"
+#include "core/frame/DOMWindow.h"
+#include "core/frame/Frame.h"
#include "wtf/Assertions.h"
-#include "wtf/StringExtras.h"
-#include "wtf/text/CString.h"
-#include <algorithm>
#include <utility>
-#include <v8-debug.h>
#include <v8.h>
namespace blink {
-WindowProxy* WindowProxy::create(v8::Isolate* isolate,
- Frame* frame,
- DOMWrapperWorld& world) {
- return new WindowProxy(frame, &world, isolate);
-}
-
-WindowProxy::WindowProxy(Frame* frame,
- PassRefPtr<DOMWrapperWorld> world,
- v8::Isolate* isolate)
- : m_frame(frame),
- m_isolate(isolate),
- m_world(world),
- m_lifecycle(Lifecycle::ContextUninitialized) {}
-
WindowProxy::~WindowProxy() {
// clearForClose() or clearForNavigation() must be invoked before destruction
// starts.
@@ -98,23 +52,20 @@ DEFINE_TRACE(WindowProxy) {
visitor->trace(m_frame);
}
-void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) {
- if (m_lifecycle != Lifecycle::ContextInitialized)
- return;
+WindowProxy::WindowProxy(v8::Isolate* isolate,
+ Frame& frame,
+ RefPtr<DOMWrapperWorld> world)
+ : m_isolate(isolate),
+ m_frame(frame),
- ScriptState::Scope scope(m_scriptState.get());
- v8::Local<v8::Context> context = m_scriptState->context();
- if (m_frame->isLocalFrame()) {
- LocalFrame* frame = toLocalFrame(m_frame);
- // The embedder could run arbitrary code in response to the
- // willReleaseScriptContext callback, so all disposing should happen after
- // it returns.
- frame->loader().client()->willReleaseScriptContext(context,
- m_world->worldId());
- MainThreadDebugger::instance()->contextWillBeDestroyed(m_scriptState.get());
- }
+ m_world(std::move(world)),
+ m_lifecycle(Lifecycle::ContextUninitialized) {}
+
+void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) {
+ DCHECK(m_lifecycle == Lifecycle::ContextInitialized);
if (behavior == DetachGlobal) {
+ v8::Local<v8::Context> context = m_scriptState->context();
// Clean up state on the global proxy, which will be reused.
if (!m_globalProxy.isEmpty()) {
// TODO(yukishiino): This DCHECK failed on Canary (M57) and Dev (M56).
@@ -222,116 +173,9 @@ void WindowProxy::initializeIfNeeded() {
// proxy. This must be 'if(m_lifecycle == Lifecycle::ContextUninitialized)'.
if (m_lifecycle != Lifecycle::ContextInitialized) {
initialize();
- if (m_world->isMainWorld() && m_frame->isLocalFrame())
- toLocalFrame(m_frame)->loader().dispatchDidClearWindowObjectInMainWorld();
}
}
-void WindowProxy::initialize() {
- TRACE_EVENT1("v8", "WindowProxy::initialize", "isMainWindow",
- m_frame->isMainFrame());
- SCOPED_BLINK_UMA_HISTOGRAM_TIMER(
- m_frame->isMainFrame() ? "Blink.Binding.InitializeMainWindowProxy"
- : "Blink.Binding.InitializeNonMainWindowProxy");
-
- ScriptForbiddenScope::AllowUserAgentScript allowScript;
-
- v8::HandleScope handleScope(m_isolate);
-
- createContext();
-
- ScriptState::Scope scope(m_scriptState.get());
- v8::Local<v8::Context> context = m_scriptState->context();
- if (m_globalProxy.isEmpty()) {
- m_globalProxy.set(m_isolate, context->Global());
- CHECK(!m_globalProxy.isEmpty());
- }
-
- setupWindowPrototypeChain();
-
- SecurityOrigin* origin = 0;
- if (m_world->isMainWorld()) {
- // ActivityLogger for main world is updated within updateDocument().
- updateDocument();
- origin = m_frame->securityContext()->getSecurityOrigin();
- // FIXME: Can this be removed when CSP moves to browser?
- ContentSecurityPolicy* csp =
- m_frame->securityContext()->contentSecurityPolicy();
- context->AllowCodeGenerationFromStrings(
- csp->allowEval(0, ContentSecurityPolicy::SuppressReport));
- context->SetErrorMessageForCodeGenerationFromStrings(
- v8String(m_isolate, csp->evalDisabledErrorMessage()));
- } else {
- updateActivityLogger();
- origin = m_world->isolatedWorldSecurityOrigin();
- setSecurityToken(origin);
- }
-
- if (m_frame->isLocalFrame()) {
- LocalFrame* frame = toLocalFrame(m_frame);
- MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), frame,
- origin);
- frame->loader().client()->didCreateScriptContext(
- context, m_world->extensionGroup(), m_world->worldId());
- }
- // If conditional features for window have been queued before the V8 context
- // was ready, then inject them into the context now
- if (m_world->isMainWorld()) {
- installPendingConditionalFeaturesOnWindow(m_scriptState.get());
- }
-}
-
-void WindowProxy::createContext() {
- // Create a new v8::Context with the window object as the global object
- // (aka the inner global). Reuse the global proxy object (aka the outer
- // global) if it already exists. See the comments in
- // setupWindowPrototypeChain for the structure of the prototype chain of
- // the global object.
- v8::Local<v8::ObjectTemplate> globalTemplate =
- V8Window::domTemplate(m_isolate, *m_world)->InstanceTemplate();
- CHECK(!globalTemplate.IsEmpty());
-
- // FIXME: It's not clear what the right thing to do for remote frames is.
- // The extensions registered don't generally seem to make sense for remote
- // frames, so skip it for now.
- Vector<const char*> extensionNames;
- if (m_frame->isLocalFrame()) {
- LocalFrame* frame = toLocalFrame(m_frame);
- // Dynamically tell v8 about our extensions now.
- const V8Extensions& extensions = ScriptController::registeredExtensions();
- extensionNames.reserveInitialCapacity(extensions.size());
- int extensionGroup = m_world->extensionGroup();
- int worldId = m_world->worldId();
- for (const auto* extension : extensions) {
- if (!frame->loader().client()->allowScriptExtension(
- extension->name(), extensionGroup, worldId))
- continue;
-
- extensionNames.push_back(extension->name());
- }
- }
- v8::ExtensionConfiguration extensionConfiguration(extensionNames.size(),
- extensionNames.data());
-
- v8::Local<v8::Context> context;
- {
- V8PerIsolateData::UseCounterDisabledScope useCounterDisabled(
- V8PerIsolateData::from(m_isolate));
- context =
- v8::Context::New(m_isolate, &extensionConfiguration, globalTemplate,
- m_globalProxy.newLocal(m_isolate));
- }
- CHECK(!context.IsEmpty());
-
- m_scriptState = ScriptState::create(context, m_world);
-
- // TODO(haraken): Currently we cannot enable the following DCHECK because
- // an already detached window proxy can be re-initialized. This is wrong.
- // DCHECK(m_lifecycle == Lifecycle::ContextUninitialized);
- m_lifecycle = Lifecycle::ContextInitialized;
- DCHECK(m_scriptState->contextIsValid());
-}
-
void WindowProxy::setupWindowPrototypeChain() {
// Associate the window wrapper object and its prototype chain with the
// corresponding native DOMWindow object.
@@ -399,198 +243,4 @@ void WindowProxy::setupWindowPrototypeChain() {
windowWrapper);
}
-void WindowProxy::updateDocumentProperty() {
- DCHECK(m_world->isMainWorld());
-
- if (m_frame->isRemoteFrame())
- return;
-
- ScriptState::Scope scope(m_scriptState.get());
- v8::Local<v8::Context> context = m_scriptState->context();
- LocalFrame* frame = toLocalFrame(m_frame);
- v8::Local<v8::Value> documentWrapper =
- ToV8(frame->document(), context->Global(), m_isolate);
- DCHECK(documentWrapper->IsObject());
- // Update the cached accessor for window.document.
- CHECK(V8PrivateProperty::getWindowDocumentCachedAccessor(m_isolate).set(
- context, context->Global(), documentWrapper));
-}
-
-void WindowProxy::updateActivityLogger() {
- m_scriptState->perContextData()->setActivityLogger(
- V8DOMActivityLogger::activityLogger(
- m_world->worldId(),
- m_frame->isLocalFrame() && toLocalFrame(m_frame)->document()
- ? toLocalFrame(m_frame)->document()->baseURI()
- : KURL()));
-}
-
-void WindowProxy::setSecurityToken(SecurityOrigin* origin) {
- // If two tokens are equal, then the SecurityOrigins canAccess each other.
- // If two tokens are not equal, then we have to call canAccess.
- // Note: we can't use the HTTPOrigin if it was set from the DOM.
- String token;
- // There are two situations where v8 needs to do a full canAccess check,
- // so set an empty security token instead:
- // - document.domain was modified
- // - the frame is remote
- bool delaySet = m_frame->isRemoteFrame() ||
- (m_world->isMainWorld() && origin->domainWasSetInDOM());
- if (origin && !delaySet)
- token = origin->toString();
-
- // An empty or "null" token means we always have to call
- // canAccess. The toString method on securityOrigins returns the
- // string "null" for empty security origins and for security
- // origins that should only allow access to themselves. In this
- // case, we use the global object as the security token to avoid
- // calling canAccess when a script accesses its own objects.
- v8::HandleScope handleScope(m_isolate);
- v8::Local<v8::Context> context = m_scriptState->context();
- if (token.isEmpty() || token == "null") {
- context->UseDefaultSecurityToken();
- return;
- }
-
- if (m_world->isIsolatedWorld()) {
- SecurityOrigin* frameSecurityOrigin =
- m_frame->securityContext()->getSecurityOrigin();
- String frameSecurityToken = frameSecurityOrigin->toString();
- // We need to check the return value of domainWasSetInDOM() on the
- // frame's SecurityOrigin because, if that's the case, only
- // SecurityOrigin::m_domain would have been modified.
- // m_domain is not used by SecurityOrigin::toString(), so we would end
- // up generating the same token that was already set.
- if (frameSecurityOrigin->domainWasSetInDOM() ||
- frameSecurityToken.isEmpty() || frameSecurityToken == "null") {
- context->UseDefaultSecurityToken();
- return;
- }
- token = frameSecurityToken + token;
- }
-
- // NOTE: V8 does identity comparison in fast path, must use a symbol
- // as the security token.
- context->SetSecurityToken(v8AtomicString(m_isolate, token));
-}
-
-void WindowProxy::updateDocument() {
- DCHECK(m_world->isMainWorld());
- // For an uninitialized main window proxy, there's nothing we need
- // to update. The update is done when the window proxy gets initialized later.
- if (m_lifecycle == Lifecycle::ContextUninitialized)
- return;
- // TODO(yukishiino): Is it okay to not update document when the context
- // is detached? It's not trivial to fix this because udpateDocumentProperty
- // requires a not-yet-detached context to instantiate a document wrapper.
- if (m_lifecycle == Lifecycle::ContextDetached)
- return;
-
- updateActivityLogger();
- updateDocumentProperty();
- updateSecurityOrigin(m_frame->securityContext()->getSecurityOrigin());
-}
-
-static v8::Local<v8::Value> getNamedProperty(
- HTMLDocument* htmlDocument,
- const AtomicString& key,
- v8::Local<v8::Object> creationContext,
- v8::Isolate* isolate) {
- if (!htmlDocument->hasNamedItem(key) && !htmlDocument->hasExtraNamedItem(key))
- return v8Undefined();
-
- DocumentNameCollection* items = htmlDocument->documentNamedItems(key);
- if (items->isEmpty())
- return v8Undefined();
-
- if (items->hasExactlyOneItem()) {
- HTMLElement* element = items->item(0);
- ASSERT(element);
- Frame* frame = isHTMLIFrameElement(*element)
- ? toHTMLIFrameElement(*element).contentFrame()
- : 0;
- if (frame)
- return ToV8(frame->domWindow(), creationContext, isolate);
- return ToV8(element, creationContext, isolate);
- }
- return ToV8(items, creationContext, isolate);
-}
-
-static void getter(v8::Local<v8::Name> property,
- const v8::PropertyCallbackInfo<v8::Value>& info) {
- if (!property->IsString())
- return;
- // FIXME: Consider passing StringImpl directly.
- AtomicString name = toCoreAtomicString(property.As<v8::String>());
- HTMLDocument* htmlDocument = V8HTMLDocument::toImpl(info.Holder());
- ASSERT(htmlDocument);
- v8::Local<v8::Value> result =
- getNamedProperty(htmlDocument, name, info.Holder(), info.GetIsolate());
- if (!result.IsEmpty()) {
- v8SetReturnValue(info, result);
- return;
- }
- v8::Local<v8::Value> value;
- if (info.Holder()
- ->GetRealNamedPropertyInPrototypeChain(
- info.GetIsolate()->GetCurrentContext(), property.As<v8::String>())
- .ToLocal(&value))
- v8SetReturnValue(info, value);
-}
-
-void WindowProxy::namedItemAdded(HTMLDocument* document,
- const AtomicString& name) {
- DCHECK(m_world->isMainWorld());
-
- // Context must be initialized before this point.
- DCHECK(m_lifecycle >= Lifecycle::ContextInitialized);
- // TODO(yukishiino): Is it okay to not update named properties
- // after the context gets detached?
- if (m_lifecycle == Lifecycle::ContextDetached)
- return;
-
- ScriptState::Scope scope(m_scriptState.get());
- v8::Local<v8::Object> documentWrapper =
- m_world->domDataStore().get(document, m_isolate);
- // TODO(yukishiino,peria): We should check if the own property with the same
- // name already exists or not, and if it exists, we shouldn't define a new
- // accessor property (it fails).
- documentWrapper->SetAccessor(m_isolate->GetCurrentContext(),
- v8String(m_isolate, name), getter);
-}
-
-void WindowProxy::namedItemRemoved(HTMLDocument* document,
- const AtomicString& name) {
- DCHECK(m_world->isMainWorld());
-
- // Context must be initialized before this point.
- DCHECK(m_lifecycle >= Lifecycle::ContextInitialized);
- // TODO(yukishiino): Is it okay to not update named properties
- // after the context gets detached?
- if (m_lifecycle == Lifecycle::ContextDetached)
- return;
-
- if (document->hasNamedItem(name) || document->hasExtraNamedItem(name))
- return;
- ScriptState::Scope scope(m_scriptState.get());
- v8::Local<v8::Object> documentWrapper =
- m_world->domDataStore().get(document, m_isolate);
- documentWrapper
- ->Delete(m_isolate->GetCurrentContext(), v8String(m_isolate, name))
- .ToChecked();
-}
-
-void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) {
- // For an uninitialized main window proxy, there's nothing we need
- // to update. The update is done when the window proxy gets initialized later.
- if (m_lifecycle == Lifecycle::ContextUninitialized)
- return;
- // TODO(yukishiino): Is it okay to not update security origin when the context
- // is detached?
- if (m_lifecycle == Lifecycle::ContextDetached)
- return;
-
- setSecurityToken(origin);
-}
-
} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698