diff options
author | fqian@google.com <fqian@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-22 23:07:54 +0000 |
---|---|---|
committer | fqian@google.com <fqian@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-22 23:07:54 +0000 |
commit | 7747859358a1a201fc8d8e65664435b979f99c37 (patch) | |
tree | 5f25b6ca30524c16a7e399966b4d839c88fc70f7 /webkit | |
parent | 9bd6f38ddfe66712e8e04de142ae64fa70ea5ada (diff) | |
download | chromium_src-7747859358a1a201fc8d8e65664435b979f99c37.zip chromium_src-7747859358a1a201fc8d8e65664435b979f99c37.tar.gz chromium_src-7747859358a1a201fc8d8e65664435b979f99c37.tar.bz2 |
Second part of split window support in the binding part.
The major change is that when a frame is loading a new page,
the frame loader calls V8Proxy::clearWindowShell when it receives
the first piece of data. At that point, the global object is
detached from its current context. FrameLoader continues on
preparing new environment, including creating new DOMWindow
and security origin for the frame. When new DOMWindow is ready,
the frame loader calls ScriptController::notifyNewDOMWindowReady(),
which uses the existing global object to initialize the new context
for the frame. Between detaching global from old context and
creating new context using global, there should no JavaScript
executed.
The implication is that if the new page does not use JavaScript,
its JS context is still created. But the overhead should be very
small because V8 is warmed up already.
Review URL: http://codereview.chromium.org/7838
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3785 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/port/bindings/scripts/CodeGeneratorV8.pm | 6 | ||||
-rw-r--r-- | webkit/port/bindings/v8/ScriptController.cpp | 6 | ||||
-rw-r--r-- | webkit/port/bindings/v8/ScriptController.h | 1 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_collection.h | 14 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_custom.cpp | 78 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_index.h | 4 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.cpp | 474 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.h | 31 |
8 files changed, 352 insertions, 262 deletions
diff --git a/webkit/port/bindings/scripts/CodeGeneratorV8.pm b/webkit/port/bindings/scripts/CodeGeneratorV8.pm index 2121862..99e447c 100644 --- a/webkit/port/bindings/scripts/CodeGeneratorV8.pm +++ b/webkit/port/bindings/scripts/CodeGeneratorV8.pm @@ -374,7 +374,7 @@ END HolderToNative($dataNode, $implClassName, $classIndex); push(@implContentDecls, <<END); - if (!V8Proxy::IsFromSameOrigin(imp->frame(), false)) { + if (!V8Proxy::CanAccessFrame(imp->frame(), false)) { static v8::Persistent<v8::FunctionTemplate> shared_template = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); return shared_template->GetFunction(); @@ -765,7 +765,7 @@ END && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) { # We have not find real use cases yet. push(@implContentDecls, -" if (!V8Proxy::IsFromSameOrigin(imp->frame(), true)) {\n". +" if (!V8Proxy::CanAccessFrame(imp->frame(), true)) {\n". " return v8::Undefined();\n" . " }\n"); } @@ -1056,7 +1056,7 @@ END my $access_check = "/* no access check */"; if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) { - $access_check = "instance->SetAccessCheckCallbacks(V8Custom::v8${interfaceName}NamedSecurityCheck, V8Custom::v8${interfaceName}IndexedSecurityCheck, v8::External::New((void*)V8ClassIndex::${classIndex}));"; + $access_check = "instance->SetAccessCheckCallbacks(V8Custom::v8${interfaceName}NamedSecurityCheck, V8Custom::v8${interfaceName}IndexedSecurityCheck, v8::Integer::New(V8ClassIndex::ToInt(V8ClassIndex::${classIndex})));"; } # Generate the template configuration method diff --git a/webkit/port/bindings/v8/ScriptController.cpp b/webkit/port/bindings/v8/ScriptController.cpp index 6dfde2a..b0e356a 100644 --- a/webkit/port/bindings/v8/ScriptController.cpp +++ b/webkit/port/bindings/v8/ScriptController.cpp @@ -96,7 +96,7 @@ Frame* ScriptController::retrieveActiveFrame() bool ScriptController::isSafeScript(Frame* target) { - return V8Proxy::IsFromSameOrigin(target, true); + return V8Proxy::CanAccessFrame(target, true); } void ScriptController::gcProtectJSWrapper(void* dom_object) @@ -512,9 +512,7 @@ NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement void ScriptController::clearWindowShell() { - // TODO(eseidel): we don't yet have a split window implementation - // we need to clear the window object here. - m_proxy->clear(); + m_proxy->clearForNavigation(); } void ScriptController::attachDebugger(void*) diff --git a/webkit/port/bindings/v8/ScriptController.h b/webkit/port/bindings/v8/ScriptController.h index 19eb533..aa4a46b 100644 --- a/webkit/port/bindings/v8/ScriptController.h +++ b/webkit/port/bindings/v8/ScriptController.h @@ -231,6 +231,7 @@ public: void clearWindowShell(); void updateDocument(); + void notifyDOMWindowReady() { m_proxy->domWindowReady(); } void pauseTimeouts(OwnPtr<PausedTimeouts>&); void resumeTimeouts(OwnPtr<PausedTimeouts>&); diff --git a/webkit/port/bindings/v8/v8_collection.h b/webkit/port/bindings/v8/v8_collection.h index ef0b3c5..86718c7 100644 --- a/webkit/port/bindings/v8/v8_collection.h +++ b/webkit/port/bindings/v8/v8_collection.h @@ -12,10 +12,11 @@ namespace WebCore { static v8::Handle<v8::Value> GetV8Object( - void * result, + void* result, v8::Local<v8::Value> data) { if (!result) return v8::Handle<v8::Value>(); - V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(data); + V8ClassIndex::V8WrapperType type = + V8ClassIndex::FromInt(data->Int32Value()); if (type == V8ClassIndex::NODE) return V8Proxy::NodeToV8Object(static_cast<Node*>(result)); else @@ -161,7 +162,7 @@ static void SetCollectionIndexedGetter(v8::Handle<v8::FunctionTemplate> desc, 0, 0, CollectionIndexedPropertyEnumerator<T>, - v8::External::New(reinterpret_cast<void*>(type))); + v8::Integer::New(V8ClassIndex::ToInt(type))); } @@ -175,7 +176,7 @@ static void SetCollectionNamedGetter(v8::Handle<v8::FunctionTemplate> desc, 0, 0, 0, - v8::External::New(reinterpret_cast<void*>(type))); + v8::Integer::New(V8ClassIndex::ToInt(type))); } @@ -192,14 +193,14 @@ static void SetCollectionIndexedAndNamedGetters( 0, 0, 0, - v8::External::New(reinterpret_cast<void*>(type))); + v8::Integer::New(V8ClassIndex::ToInt(type))); desc->InstanceTemplate()->SetIndexedPropertyHandler( CollectionIndexedPropertyGetter<T, D>, 0, 0, 0, CollectionIndexedPropertyEnumerator<T>, - v8::External::New(reinterpret_cast<void*>(type))); + v8::Integer::New(V8ClassIndex::ToInt(type))); } @@ -220,4 +221,3 @@ static void SetCollectionStringOrNullIndexedGetter( } // namespace WebCore #endif // V8_PROPERTY_H__ - diff --git a/webkit/port/bindings/v8/v8_custom.cpp b/webkit/port/bindings/v8/v8_custom.cpp index 0904839..827323a 100644 --- a/webkit/port/bindings/v8/v8_custom.cpp +++ b/webkit/port/bindings/v8/v8_custom.cpp @@ -514,7 +514,7 @@ ACCESSOR_SETTER(DOMWindowOpener) { DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, info.Holder()); - if (!V8Proxy::IsFromSameOrigin(imp->frame(), true)) + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) return; // Opener can be shadowed if it is in the same domain. @@ -787,11 +787,8 @@ CALLBACK_FUNC_DECL(DOMWindowAddEventListener) { DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, args.Holder()); - // Fast check This argument with the global object of security context. - if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) && - !V8Proxy::IsFromSameOrigin(imp->frame(), true)) { + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) return v8::Undefined(); - } if (!imp->frame()) return v8::Undefined(); // DOMWindow could be disconnected from the frame @@ -823,11 +820,8 @@ CALLBACK_FUNC_DECL(DOMWindowRemoveEventListener) { DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, args.Holder()); - // Fast check This argument with the global object of security context. - if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) && - !V8Proxy::IsFromSameOrigin(imp->frame(), true)) { + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) return v8::Undefined(); - } if (!imp->frame()) return v8::Undefined(); @@ -1089,14 +1083,9 @@ CALLBACK_FUNC_DECL(DOMWindowOpen) { DOMWindow* parent = V8Proxy::ToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, args.Holder()); Frame* frame = parent->frame(); - if (!frame) - return v8::Undefined(); - // Fast check This argument with the global object of security context. - if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) && - !V8Proxy::IsFromSameOrigin(frame, true)) { + if (!V8Proxy::CanAccessFrame(frame, true)) return v8::Undefined(); - } Frame* active_frame = V8Proxy::retrieveActiveFrame(); if (!active_frame) @@ -2711,11 +2700,8 @@ v8::Handle<v8::Value> V8Custom::WindowSetTimeoutImpl(const v8::Arguments& args, DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, args.Holder()); - // Fast check This argument with the global object of security context. - if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) && - !V8Proxy::IsFromSameOrigin(imp->frame(), true)) { + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) return v8::Undefined(); - } v8::Handle<v8::Value> function = args[0]; @@ -3046,11 +3032,8 @@ CALLBACK_FUNC_DECL(DOMWindowAtob) { DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, args.Holder()); - // Fast check This argument with the global object of security context. - if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) && - !V8Proxy::IsFromSameOrigin(imp->frame(), true)) { + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) return v8::Undefined(); - } if (args.Length() < 1) { V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); @@ -3068,11 +3051,8 @@ CALLBACK_FUNC_DECL(DOMWindowBtoa) { DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( V8ClassIndex::DOMWINDOW, args.Holder()); - // Fast check This argument with the global object of security context. - if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) && - !V8Proxy::IsFromSameOrigin(imp->frame(), true)) { + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) return v8::Undefined(); - } if (args.Length() < 1) { V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); @@ -3534,8 +3514,12 @@ CALLBACK_FUNC_DECL(SVGMatrixRotateFromVector) { // --------------- Security Checks ------------------------- NAMED_ACCESS_CHECK(DOMWindow) { - ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::DOMWINDOW); - v8::Handle<v8::Value> window = host->GetPrototype(); + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::DOMWINDOW); + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return false; // the frame is gone. + DOMWindow* target_win = V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); @@ -3555,13 +3539,17 @@ NAMED_ACCESS_CHECK(DOMWindow) { } } - return V8Proxy::CanAccess(target); + return V8Proxy::CanAccessFrame(target, false); } INDEXED_ACCESS_CHECK(DOMWindow) { - ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::DOMWINDOW); - v8::Handle<v8::Value> window = host->GetPrototype(); + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::DOMWINDOW); + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return false; + DOMWindow* target_win = V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); @@ -3577,43 +3565,43 @@ INDEXED_ACCESS_CHECK(DOMWindow) { return true; } - return V8Proxy::CanAccess(target); + return V8Proxy::CanAccessFrame(target, false); } INDEXED_ACCESS_CHECK(History) { - ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::HISTORY); + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::HISTORY); // Only allow same origin access History* imp = V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); - return V8Proxy::IsFromSameOrigin(imp->frame(), false); + return V8Proxy::CanAccessFrame(imp->frame(), false); } NAMED_ACCESS_CHECK(History) { - ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::HISTORY); + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::HISTORY); // Only allow same origin access History* imp = V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); - return V8Proxy::IsFromSameOrigin(imp->frame(), false); + return V8Proxy::CanAccessFrame(imp->frame(), false); } INDEXED_ACCESS_CHECK(Location) { - ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::LOCATION); + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::LOCATION); // Only allow same origin access Location* imp = V8Proxy::ToNativeObject<Location>(V8ClassIndex::LOCATION, host); - return V8Proxy::IsFromSameOrigin(imp->frame(), false); + return V8Proxy::CanAccessFrame(imp->frame(), false); } NAMED_ACCESS_CHECK(Location) { - ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::LOCATION); + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::LOCATION); // Only allow same origin access Location* imp = V8Proxy::ToNativeObject<Location>(V8ClassIndex::LOCATION, host); - return V8Proxy::IsFromSameOrigin(imp->frame(), false); + return V8Proxy::CanAccessFrame(imp->frame(), false); } @@ -3629,9 +3617,13 @@ NAMED_ACCESS_CHECK(Location) { Frame* V8Custom::GetTargetFrame(v8::Local<v8::Object> host, v8::Local<v8::Value> data) { Frame* target = 0; - switch (V8ClassIndex::ToWrapperType(data)) { + switch (V8ClassIndex::FromInt(data->Int32Value())) { case V8ClassIndex::DOMWINDOW: { - v8::Handle<v8::Value> window = host->GetPrototype(); + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return target; + DOMWindow* target_win = V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); target = target_win->frame(); diff --git a/webkit/port/bindings/v8/v8_index.h b/webkit/port/bindings/v8/v8_index.h index 28c59d8..109f702 100644 --- a/webkit/port/bindings/v8/v8_index.h +++ b/webkit/port/bindings/v8/v8_index.h @@ -393,10 +393,6 @@ ALL_WRAPPER_TYPES(DEFINE_ENUM) #undef DEFINE_ENUM CLASSINDEX_END, }; - static inline V8WrapperType ToWrapperType(v8::Handle<v8::Value> obj) { - return static_cast<V8WrapperType>( - reinterpret_cast<int>(v8::Handle<v8::External>::Cast(obj)->Value())); - } static int ToInt(V8WrapperType type) { return static_cast<int>(type); } diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp index 81df91f..fe67a22 100644 --- a/webkit/port/bindings/v8/v8_proxy.cpp +++ b/webkit/port/bindings/v8/v8_proxy.cpp @@ -114,6 +114,7 @@ namespace WebCore { + // DOM binding algorithm: // // There are two kinds of DOM objects: @@ -179,7 +180,8 @@ static inline void USE_VAR(T) { } // The function is the place to set the break point to inspect // live global handles. Leaks are often come from leaked global handles. -static void EnumerateGlobalHandles() { +static void EnumerateGlobalHandles() +{ for (GlobalHandleMap::iterator it = global_handle_map().begin(), end = global_handle_map().end(); it != end; ++it) { GlobalHandleInfo* info = it->second; @@ -190,7 +192,8 @@ static void EnumerateGlobalHandles() { } void V8Proxy::RegisterGlobalHandle(GlobalHandleType type, void* host, - v8::Persistent<v8::Value> handle) { + v8::Persistent<v8::Value> handle) +{ ASSERT(!global_handle_map().contains(*handle)); global_handle_map().set(*handle, new GlobalHandleInfo(host, type)); } @@ -208,7 +211,8 @@ void V8Proxy::UnregisterGlobalHandle(void* host, v8::Persistent<v8::Value> handl void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst, v8::Handle<v8::ObjectTemplate> proto, const BatchedAttribute* attrs, - size_t num_attrs) { + size_t num_attrs) +{ for (size_t i = 0; i < num_attrs; ++i) { const BatchedAttribute* a = &attrs[i]; (a->on_proto ? proto : inst)->SetAccessor( @@ -226,7 +230,8 @@ void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst, void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc, v8::Handle<v8::ObjectTemplate> proto, const BatchedConstant* consts, - size_t num_consts) { + size_t num_consts) +{ for (size_t i = 0; i < num_consts; ++i) { const BatchedConstant* c = &consts[i]; desc->Set(v8::String::New(c->name), @@ -250,20 +255,23 @@ class DOMPeerableWrapperMap : public DOMWrapperMap<T> { DOMWrapperMap<T>(callback) { } // Get the JS wrapper object of an object. - v8::Persistent<v8::Object> get(T* obj) { + v8::Persistent<v8::Object> get(T* obj) + { v8::Object* peer = static_cast<v8::Object*>(obj->peer()); ASSERT(peer == this->map_.get(obj)); return peer ? v8::Persistent<v8::Object>(peer) : v8::Persistent<v8::Object>(); } - void set(T* obj, v8::Persistent<v8::Object> peer_handle) { + void set(T* obj, v8::Persistent<v8::Object> peer_handle) + { ASSERT(obj->peer() == 0); obj->setPeer(*peer_handle); DOMWrapperMap<T>::set(obj, peer_handle); } - void forget(T* obj) { + void forget(T* obj) + { v8::Object* peer = static_cast<v8::Object*>(obj->peer()); ASSERT(peer == this->map_.get(obj)); if (peer) @@ -276,14 +284,16 @@ class DOMPeerableWrapperMap : public DOMWrapperMap<T> { static void WeakPeerableCallback(v8::Persistent<v8::Object> obj, void* para); static void WeakNodeCallback(v8::Persistent<v8::Object> obj, void* para); // A map from DOM node to its JS wrapper. -static DOMWrapperMap<Node>& dom_node_map() { +static DOMWrapperMap<Node>& dom_node_map() +{ static DOMPeerableWrapperMap<Node> static_dom_node_map(&WeakNodeCallback); return static_dom_node_map; } // A map from a non-DOM node (peerable) to its JS wrapper. -static DOMWrapperMap<Peerable>& dom_object_map() { +static DOMWrapperMap<Peerable>& dom_object_map() +{ static DOMPeerableWrapperMap<Peerable> static_dom_object_map(&WeakPeerableCallback); return static_dom_object_map; @@ -294,14 +304,16 @@ static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Object> obj, void* param); // A map for SVGElementInstances, which are not peerable -static DOMWrapperMap<SVGElementInstance>& dom_svg_element_instance_map() { +static DOMWrapperMap<SVGElementInstance>& dom_svg_element_instance_map() +{ static DOMWrapperMap<SVGElementInstance> static_dom_svg_element_instance_map(&WeakSVGElementInstanceCallback); return static_dom_svg_element_instance_map; } static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Object> obj, - void* param) { + void* param) +{ SVGElementInstance* instance = static_cast<SVGElementInstance*>(param); ASSERT(dom_svg_element_instance_map().contains(instance)); @@ -310,7 +322,8 @@ static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Object> obj, } v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( - SVGElementInstance* instance) { + SVGElementInstance* instance) +{ if (!instance) return v8::Null(); @@ -377,7 +390,8 @@ v8::Handle<v8::Value> V8Proxy::SVGObjectWithContextToV8Object( } static void WeakSVGObjectWithContext(v8::Persistent<v8::Object> obj, - void* param) { + void* param) +{ Peerable* dom_obj = static_cast<Peerable*>(param); ASSERT(dom_svg_object_with_context_map().contains(dom_obj)); @@ -419,7 +433,8 @@ SVGElement* V8Proxy::GetSVGContext(void* obj) // Called when obj is near death (not reachable from JS roots) // It is time to remove the entry from the table and dispose // the handle. -static void WeakPeerableCallback(v8::Persistent<v8::Object> obj, void* para) { +static void WeakPeerableCallback(v8::Persistent<v8::Object> obj, void* para) +{ Peerable* dom_obj = static_cast<Peerable*>(para); ASSERT(dom_object_map().contains(dom_obj)); @@ -484,7 +499,8 @@ static void GCPrologue() } -static void GCEpilogue() { +static void GCEpilogue() +{ #ifndef NDEBUG // Check all survivals are weak. PeerableMap peer_map = dom_object_map().impl(); @@ -536,7 +552,8 @@ void V8Proxy::GCProtect(Peerable* dom_object) // static -void V8Proxy::GCUnprotect(Peerable* dom_object) { +void V8Proxy::GCUnprotect(Peerable* dom_object) +{ if (!dom_object) return; if (!gc_protected_map().contains(dom_object)) @@ -615,7 +632,8 @@ Vector<JavaScriptConsoleMessage>* ConsoleMessageManager::m_delayed = NULL; void ConsoleMessageManager::AddMessage( Page* page, - const JavaScriptConsoleMessage& message) { + const JavaScriptConsoleMessage& message) +{ // Process any delayed messages to make sure that messages // appear in the right order in the console. ProcessDelayedMessages(); @@ -636,32 +654,32 @@ void ConsoleMessageManager::AddDelayedMessage(const JavaScriptConsoleMessage& me void ConsoleMessageManager::ProcessDelayedMessages() { - // If we have a delayed vector it cannot be empty. - if (!m_delayed) - return; - ASSERT(!m_delayed->isEmpty()); - - // Add the delayed messages to the page of the active - // context. If that for some bizarre reason does not - // exist, we clear the list of delayed messages to avoid - // posting messages. We still deallocate the vector. - Frame* frame = V8Proxy::retrieveActiveFrame(); - Page* page = NULL; - if (frame) - page = frame->page(); - if (!page) - m_delayed->clear(); + // If we have a delayed vector it cannot be empty. + if (!m_delayed) + return; + ASSERT(!m_delayed->isEmpty()); + + // Add the delayed messages to the page of the active + // context. If that for some bizarre reason does not + // exist, we clear the list of delayed messages to avoid + // posting messages. We still deallocate the vector. + Frame* frame = V8Proxy::retrieveActiveFrame(); + Page* page = NULL; + if (frame) + page = frame->page(); + if (!page) + m_delayed->clear(); - // Iterate through all the delayed messages and add them - // to the console. - const int size = m_delayed->size(); - for (int i = 0; i < size; i++) { - m_delayed->at(i).AddToPage(page); - } + // Iterate through all the delayed messages and add them + // to the console. + const int size = m_delayed->size(); + for (int i = 0; i < size; i++) { + m_delayed->at(i).AddToPage(page); + } - // Deallocate the delayed vector. - delete m_delayed; - m_delayed = NULL; + // Deallocate the delayed vector. + delete m_delayed; + m_delayed = NULL; } @@ -683,7 +701,8 @@ void log_info(Frame* frame, const String& msg, const String& url) } static void HandleConsoleMessage(v8::Handle<v8::Message> message, - v8::Handle<v8::Value> data) { + v8::Handle<v8::Value> data) +{ // Use the frame where JavaScript is called from. Frame* frame = V8Proxy::retrieveActiveFrame(); if (!frame) @@ -714,21 +733,24 @@ enum DelayReporting { }; -static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) { +static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) +{ ASSERT(target); Document* targetDocument = target->document(); if (!targetDocument) return; Frame* source = V8Proxy::retrieveActiveFrame(); + if (!source || !source->document()) + return; // Ignore error if the source document is gone. + Document* sourceDocument = source->document(); - ASSERT(sourceDocument); // FIXME: This error message should contain more specifics of why the same // origin check has failed. String str = String::format("Unsafe JavaScript attempt to access frame " - "with URL %s from frame with URL %s. Domains, protocols and ports must " - "match.\n", + "with URL %s from frame with URL %s. " + "Domains, protocols and ports must match.\n", targetDocument->url().string().utf8().data(), sourceDocument->url().string().utf8().data()); @@ -754,7 +776,8 @@ static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) { static void ReportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, v8::AccessType type, - v8::Local<v8::Value> data) { + v8::Local<v8::Value> data) +{ // Do not report error if the access type is HAS. if (type == v8::ACCESS_HAS) return; @@ -782,7 +805,7 @@ static void HandleFatalErrorInV8() V8Proxy::~V8Proxy() { - clear(); + clearForClose(); DestroyGlobal(); } @@ -827,7 +850,8 @@ PassRefPtr<EventListener> V8Proxy::createSVGEventHandler(const String& functionN static V8EventListener* FindEventListenerInList(V8EventListenerList& list, v8::Local<v8::Value> listener, - bool html) { + bool html) +{ ASSERT(v8::Context::InContext()); if (!listener->IsObject()) @@ -895,15 +919,16 @@ PassRefPtr<V8EventListener> V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::V // The persistent reference is made weak in the constructor // of V8XHREventListener. -PassRefPtr<V8EventListener> V8Proxy::FindXHREventListener(v8::Local<v8::Value> listener, - bool html) { +PassRefPtr<V8EventListener> V8Proxy::FindXHREventListener( + v8::Local<v8::Value> listener, bool html) +{ return FindEventListenerInList(m_xhr_listeners, listener, html); } -PassRefPtr<V8EventListener> -V8Proxy::FindOrCreateXHREventListener(v8::Local<v8::Value> obj, - bool html) { +PassRefPtr<V8EventListener> V8Proxy::FindOrCreateXHREventListener( + v8::Local<v8::Value> obj, bool html) +{ ASSERT(v8::Context::InContext()); if (!obj->IsObject()) return 0; @@ -922,7 +947,8 @@ V8Proxy::FindOrCreateXHREventListener(v8::Local<v8::Value> obj, static void RemoveEventListenerFromList(V8EventListenerList& list, - V8EventListener* listener) { + V8EventListener* listener) +{ V8EventListenerList::iterator p = list.begin(); while (p != list.end()) { if (*p == listener) { @@ -934,17 +960,20 @@ static void RemoveEventListenerFromList(V8EventListenerList& list, } -void V8Proxy::RemoveV8EventListener(V8EventListener* listener) { +void V8Proxy::RemoveV8EventListener(V8EventListener* listener) +{ RemoveEventListenerFromList(m_event_listeners, listener); } -void V8Proxy::RemoveXHREventListener(V8XHREventListener* listener) { +void V8Proxy::RemoveXHREventListener(V8XHREventListener* listener) +{ RemoveEventListenerFromList(m_xhr_listeners, listener); } -static void DisconnectEventListenersInList(V8EventListenerList& list) { +static void DisconnectEventListenersInList(V8EventListenerList& list) +{ V8EventListenerList::iterator p = list.begin(); while (p != list.end()) { (*p)->disconnectFrame(); @@ -954,7 +983,8 @@ static void DisconnectEventListenersInList(V8EventListenerList& list) { } -void V8Proxy::DisconnectEventListeners() { +void V8Proxy::DisconnectEventListeners() +{ DisconnectEventListenersInList(m_event_listeners); DisconnectEventListenersInList(m_xhr_listeners); } @@ -985,7 +1015,7 @@ bool V8Proxy::HandleOutOfMemory() V8Proxy* proxy = V8Proxy::retrieve(frame); // Clean m_context, m_document, and event handlers. - proxy->clear(); + proxy->clearForClose(); // Destroy the global object. proxy->DestroyGlobal(); @@ -1020,7 +1050,8 @@ v8::Local<v8::Value> V8Proxy::Evaluate(const String& fileName, int baseLine, } v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script, - bool inline_code) { + bool inline_code) +{ if (script.IsEmpty()) return v8::Local<v8::Value>(); @@ -1082,7 +1113,8 @@ v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script, v8::Local<v8::Value> V8Proxy::CallFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, - v8::Handle<v8::Value> args[]) { + v8::Handle<v8::Value> args[]) +{ // For now, we don't put any artificial limitations on the depth // of recursion that stems from calling functions. This is in // contrast to the script evaluations. @@ -1108,7 +1140,8 @@ v8::Local<v8::Value> V8Proxy::CallFunction(v8::Handle<v8::Function> function, v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( - V8ClassIndex::V8WrapperType type) { + V8ClassIndex::V8WrapperType type) +{ v8::Persistent<v8::FunctionTemplate>* cache_cell = V8ClassIndex::GetCache(type); if (!(*cache_cell).IsEmpty()) return *cache_cell; @@ -1165,14 +1198,14 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( 0, 0, 0, - v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE))); + v8::Integer::New(V8ClassIndex::NODE)); desc->InstanceTemplate()->SetIndexedPropertyHandler( NodeCollectionIndexedPropertyGetter<HTMLSelectElement>, USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection), 0, 0, NodeCollectionIndexedPropertyEnumerator<HTMLSelectElement>, - v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE))); + v8::Integer::New(V8ClassIndex::NODE)); break; case V8ClassIndex::HTMLDOCUMENT: { desc->InstanceTemplate()->SetNamedPropertyHandler( @@ -1238,7 +1271,7 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( 0, 0, NodeCollectionIndexedPropertyEnumerator<HTMLFormElement>, - v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE))); + v8::Integer::New(V8ClassIndex::NODE)); break; case V8ClassIndex::CANVASPIXELARRAY: desc->InstanceTemplate()->SetIndexedPropertyHandler( @@ -1274,7 +1307,7 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( 0, 0, CollectionIndexedPropertyEnumerator<NamedNodeMap>, - v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE))); + v8::Integer::New(V8ClassIndex::NODE)); break; case V8ClassIndex::NODELIST: SetCollectionIndexedGetter<NodeList, Node>(desc, V8ClassIndex::NODE); @@ -1324,7 +1357,16 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( v8::Local<v8::ObjectTemplate> instance_template = desc->InstanceTemplate(); instance_template->SetInternalFieldCount( - V8Custom::kDOMWindowInternalFieldCount); + V8Custom::kDOMWindowInternalFieldCount); + + // Set access check callbacks, but turned off initially. + // When a context is detached from a frame, turn on the access check. + // Turning on checks also invalidates inline caches of the object. + instance_template->SetAccessCheckCallbacks( + V8Custom::v8DOMWindowNamedSecurityCheck, + V8Custom::v8DOMWindowIndexedSecurityCheck, + v8::Integer::New(V8ClassIndex::DOMWINDOW), + false); break; } case V8ClassIndex::LOCATION: { @@ -1374,31 +1416,36 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( return desc; } + bool V8Proxy::ContextInitialized() { return !m_context.IsEmpty(); } + DOMWindow* V8Proxy::retrieveWindow() { // TODO: This seems very fragile. How do we know that the global object // from the current context is something sensible? Do we need to use the // last entered here? Who calls this? v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global(); - if (global.IsEmpty()) - return 0; - v8::Handle<v8::Value> window = global->GetPrototype(); - return ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); + ASSERT(!global.IsEmpty()); + global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(!global.IsEmpty()); + return ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global); } + Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context) { v8::Handle<v8::Object> global = context->Global(); - v8::Handle<v8::Value> window_peer = global->GetPrototype(); - DOMWindow* window = ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window_peer); + global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(!global.IsEmpty()); + DOMWindow* window = ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global); return window->frame(); } + Frame* V8Proxy::retrieveActiveFrame() { v8::Handle<v8::Context> context = v8::Context::GetEntered(); @@ -1407,12 +1454,14 @@ Frame* V8Proxy::retrieveActiveFrame() return retrieveFrame(context); } + Frame* V8Proxy::retrieveFrame() { DOMWindow* window = retrieveWindow(); return window ? window->frame() : 0; } + V8Proxy* V8Proxy::retrieve() { DOMWindow* window = retrieveWindow(); @@ -1432,11 +1481,12 @@ void V8Proxy::disconnectFrame() // disconnect all event listeners DisconnectEventListeners(); - // clear all timeouts. + // remove all timeouts if (m_frame->domWindow()) - m_frame->domWindow()->clearAllTimeouts(); + m_frame->domWindow()->clearAllTimeouts(); } + bool V8Proxy::isEnabled() { Settings* settings = m_frame->settings(); @@ -1481,7 +1531,6 @@ bool V8Proxy::isEnabled() void V8Proxy::clearDocumentWrapper() { - v8::HandleScope handle_scope; v8::Local<v8::Context> context = GetContext(); if (context.IsEmpty()) return; // not initialize yet @@ -1499,56 +1548,90 @@ void V8Proxy::clearDocumentWrapper() void V8Proxy::DomainChanged(Frame* frame) { V8Proxy* proxy = retrieve(frame); - proxy->ClearSecurityToken(); + // Restore to default security token. + proxy->m_context->UseDefaultSecurityToken(); } -void V8Proxy::ClearSecurityToken() + +void V8Proxy::clearForClose() { - m_context->SetSecurityToken(m_global); + if (m_context.IsEmpty()) + return; + + { v8::HandleScope handle_scope; + clearDocumentWrapper(); + } + + m_context.Dispose(); + m_context.Clear(); } -void V8Proxy::clear() + +void V8Proxy::clearForNavigation() { if (m_context.IsEmpty()) return; - ClearSecurityToken(); + { v8::HandleScope handle; + clearDocumentWrapper(); - if (m_frame->domWindow()) - m_frame->domWindow()->clearAllTimeouts(); + // Turn on access check on the old DOMWindow wrapper. + v8::Handle<v8::Object> wrapper = + LookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global); + ASSERT(!wrapper.IsEmpty()); + wrapper->TurnOnAccessCheck(); - clearDocumentWrapper(); + // Clear all timeouts. + DOMWindow* domWindow = + ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, wrapper); + domWindow->clearAllTimeouts(); + + // Separate the context from its global object. + m_context->DetachGlobal(); + } // Corresponds to the context creation in initContextIfNeeded(). m_context.Dispose(); m_context.Clear(); } -// Check if two frames are from the same origin. -// This function is equivalent to -// KJS::Window::allowsAccessFrom(const JSGlobalObject*, -// SecurityOrigin::Reason&, String& message) const. -static bool SameOrigin(Frame* source, Frame* target, String& message) + +void V8Proxy::domWindowReady() { - if (!source || !target) - return false; + // Reinitialize context so the global object is reused by + // the new context. + if (!m_global.IsEmpty() && m_context.IsEmpty()) { + v8::HandleScope scope; + initContextIfNeeded(); + } +} - // Allow access if the frames the windows represent are the same. - if (source == target) - return true; - Document* target_document = target->document(); +// Check if the current execution context can access a target frame. +// First it checks same domain policy using the lexical context +// +// This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&). +bool V8Proxy::CanAccessPrivate(DOMWindow* target_window) +{ + ASSERT(target_window); + + String message; - // JS may be attempting to access the "window" object, which should be valid, - // even if the document hasn't been constructed yet. If the document doesn't - // exist yet allow JS to access the window object. - if (!target_document) + DOMWindow* origin_window = retrieveWindow(); + if (origin_window == target_window) return true; - Document* act_document = source->document(); + if (!origin_window) + return false; + + // JS may be attempting to access the "window" object, which should be + // valid, even if the document hasn't been constructed yet. + // If the document doesn't exist yet allow JS to access the window object. + if (!origin_window->document()) + return true; - const SecurityOrigin* active_security_origin = act_document->securityOrigin(); - const SecurityOrigin* target_security_origin = target_document->securityOrigin(); + const SecurityOrigin* active_security_origin = origin_window->securityOrigin(); + const SecurityOrigin* target_security_origin = target_window->securityOrigin(); String ui_resource_protocol = webkit_glue::StdStringToString(webkit_glue::GetUIResourceProtocol()); if (active_security_origin->protocol() == ui_resource_protocol) { @@ -1568,39 +1651,23 @@ static bool SameOrigin(Frame* source, Frame* target, String& message) if (active_security_origin->canAccess(target_security_origin)) return true; - return false; -} - -// Check if the current execution context can access a target frame. -// First it checks same domain policy using the security context -// (where the script is invoked), if domain check failed due to -// setting document.domain, using the lexical context of the function -// to check domain policy. -// -// This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&). -bool V8Proxy::CanAccess(Frame* target) -{ - String message; - - // Check dynamic (security) context first. - Frame* source = V8Proxy::retrieveFrame(v8::Context::GetCurrentSecurityContext()); - if (SameOrigin(source, target, message)) - return true; - - source = V8Proxy::retrieveFrame(v8::Context::GetCurrent()); - if (SameOrigin(source, target, message)) + // Allow access to a "about:blank" page if the dynamic context is a + // detached context of the same frame as the blank page. + if (target_security_origin->isEmpty() && + origin_window->frame() == target_window->frame()) return true; return false; } -bool V8Proxy::IsFromSameOrigin(Frame* target, bool report_error) + +bool V8Proxy::CanAccessFrame(Frame* target, bool report_error) { // The subject is detached from a frame, deny accesses. if (!target) return false; - if (!CanAccess(target)) { + if (!CanAccessPrivate(target->domWindow())) { if (report_error) ReportUnsafeAccessTo(target, REPORT_NOW); return false; @@ -1608,6 +1675,7 @@ bool V8Proxy::IsFromSameOrigin(Frame* target, bool report_error) return true; } + bool V8Proxy::CheckNodeSecurity(Node* node) { if (!node) @@ -1618,9 +1686,39 @@ bool V8Proxy::CheckNodeSecurity(Node* node) if (!target) return false; - return IsFromSameOrigin(target, true); + return CanAccessFrame(target, true); } + +static void GenerateSecurityToken(v8::Local<v8::Context> context) +{ + Document* document = V8Proxy::retrieveFrame(context)->document(); + if (!document) { + context->UseDefaultSecurityToken(); + return; + } + + // Ask the document's SecurityOrigin to generate a security token. + // If two tokens are equal, then the SecurityOrigins canAccess each other. + // If two tokens are not equal, then we have to call canAccess. + String token = document->securityOrigin()->securityToken(); + + // An empty token means we always have to call canAccess. In this case, we + // use the global object as the security token to avoid calling canAccess + // when a script accesses its own objects. + if (token.isEmpty()) { + context->UseDefaultSecurityToken(); + return; + } + + CString utf8_token = token.utf8(); + // NOTE: V8 does identity comparison in fast path, must use a symbol + // as the security token. + context->SetSecurityToken( + v8::String::NewSymbol(utf8_token.data(), utf8_token.length())); +} + + // Create a new environment and setup the global object. // // The global object corresponds to a DOMWindow instance. However, to @@ -1634,6 +1732,29 @@ bool V8Proxy::CheckNodeSecurity(Node* node) // from javascript. The javascript object that corresponds to a // DOMWindow instance is the shadow object. When mapping a DOMWindow // instance to a V8 object, we return the shadow object. +// +// To implement split-window, see +// 1) https://bugs.webkit.org/show_bug.cgi?id=17249 +// 2) https://wiki.mozilla.org/Gecko:SplitWindow +// 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639 +// we need to split the shadow object further into two objects: +// an outer window and an inner window. The inner window is the hidden +// prototype of the outer window. The inner window is the default +// global object of the context. A variable declared in the global +// scope is a property of the inner window. +// +// The outer window sticks to a Frame, it is exposed to JavaScript +// via window.window, window.self, window.parent, etc. The outer window +// has a security token which is the domain. The outer window cannot +// have its own properties. window.foo = 'x' is delegated to the +// inner window. +// +// When a frame navigates to a new page, the inner window is cut off +// the outer window, and the outer window identify is preserved for +// the frame. However, a new inner window is created for the new page. +// If there are JS code holds a closure to the old inner window, +// it won't be able to reach the outer window via its global object. + void V8Proxy::initContextIfNeeded() { // Bail out if the context has already been initialized. @@ -1673,18 +1794,12 @@ void V8Proxy::initContextIfNeeded() return; // Install a security handler with V8. - { - v8::Local<v8::External> external = - v8::External::New(reinterpret_cast<void*>(V8ClassIndex::DOMWINDOW)); - if (external.IsEmpty()) - return; - - global_template->SetAccessCheckCallbacks( - V8Custom::v8DOMWindowNamedSecurityCheck, - V8Custom::v8DOMWindowIndexedSecurityCheck, - external); - } + global_template->SetAccessCheckCallbacks( + V8Custom::v8DOMWindowNamedSecurityCheck, + V8Custom::v8DOMWindowIndexedSecurityCheck, + v8::Integer::New(V8ClassIndex::DOMWINDOW)); + // Create a new context. m_context = v8::Context::New(NULL, global_template, m_global); if (m_context.IsEmpty()) return; @@ -1712,9 +1827,6 @@ void V8Proxy::initContextIfNeeded() DOMWindow* window = m_frame->domWindow(); - // Get rid of the old window peer object if one exists. - dom_object_map().forget(window); - // Setup the peer object for the DOM window. dom_object_map().set(window, v8::Persistent<v8::Object>::New(window_peer)); // Wrap the window. @@ -1725,7 +1837,8 @@ void V8Proxy::initContextIfNeeded() v8::Handle<v8::Object> v8_global = context->Global(); v8_global->Set(v8::String::New("__proto__"), window_peer); - context->SetSecurityToken(GenerateSecurityToken(context)); + // Setup security origin and security token + GenerateSecurityToken(context); V8Proxy::retrieveFrame(context)->loader()->dispatchWindowObjectAvailable(); @@ -1752,30 +1865,6 @@ void V8Proxy::initContextIfNeeded() } -v8::Handle<v8::Value> V8Proxy::GenerateSecurityToken( - v8::Local<v8::Context> context) { - Document* document = V8Proxy::retrieveFrame(context)->document(); - if (!document) - return context->Global(); - - // Ask the document's SecurityOrigin to generate a security token. - // If two tokens are equal, then the SecurityOrigins canAccess each other. - // If two tokens are not equal, then we have to call canAccess. - String token = document->securityOrigin()->securityToken(); - - // An empty token means we always have to call canAccess. In this case, we - // use the global object as the security token to avoid calling canAccess - // when a script accesses its own objects. - if (token.isEmpty()) - return context->Global(); - - CString utf8_token = token.utf8(); - // NOTE: V8 does identity comparison in fast path, must use a symbol - // as the security token. - return v8::String::NewSymbol(utf8_token.data(), utf8_token.length()); -} - - void V8Proxy::SetDOMException(int exception_code) { if (exception_code <= 0) @@ -1922,7 +2011,8 @@ v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void void V8Proxy::SetHiddenWindowReference(Frame* frame, const int internal_index, - v8::Handle<v8::Object> jsobj) { + v8::Handle<v8::Object> jsobj) +{ // Get DOMWindow if (!frame) return; // Object might be detached from window v8::Handle<v8::Context> context = GetContext(frame); @@ -1931,9 +2021,9 @@ void V8Proxy::SetHiddenWindowReference(Frame* frame, ASSERT(internal_index < V8Custom::kDOMWindowInternalFieldCount); v8::Handle<v8::Object> global = context->Global(); - ASSERT(!global.IsEmpty()); // Look for real DOM wrapper. global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(!global.IsEmpty()); ASSERT(global->GetInternalField(internal_index)->IsUndefined()); global->SetInternalField(internal_index, jsobj); } @@ -1949,7 +2039,8 @@ V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object> ob void* V8Proxy::ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, - v8::Handle<v8::Value> object) { + v8::Handle<v8::Value> object) +{ // Native event listener is per frame, it cannot be handled // by this generic function. ASSERT(type != V8ClassIndex::EVENTLISTENER); @@ -2020,7 +2111,8 @@ PassRefPtr<NodeFilter> V8Proxy::ToNativeNodeFilter(v8::Handle<v8::Value> filter) v8::Local<v8::Object> V8Proxy::InstantiateV8Object( V8ClassIndex::V8WrapperType desc_type, V8ClassIndex::V8WrapperType cptr_type, - void* imp) { + void* imp) +{ // Make a special case for document.all if (desc_type == V8ClassIndex::HTMLCOLLECTION && static_cast<HTMLCollection*>(imp)->type() == HTMLCollection::DocAll) { @@ -2052,7 +2144,8 @@ v8::Handle<v8::Value> V8Proxy::CheckNewLegal(const v8::Arguments& args) return args.This(); } -void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) { +void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) +{ ASSERT(obj->InternalFieldCount() >= 2); obj->SetInternalField(V8Custom::kDOMWrapperObjectIndex, WrapCPointer(cptr)); obj->SetInternalField(V8Custom::kDOMWrapperTypeIndex, v8::Integer::New(type)); @@ -2060,7 +2153,8 @@ void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) { #ifndef NDEBUG -bool V8Proxy::MaybeDOMWrapper(v8::Handle<v8::Value> value) { +bool V8Proxy::MaybeDOMWrapper(v8::Handle<v8::Value> value) +{ if (value.IsEmpty() || !value->IsObject()) return false; v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); @@ -2084,14 +2178,16 @@ bool V8Proxy::MaybeDOMWrapper(v8::Handle<v8::Value> value) { #endif -bool V8Proxy::IsDOMEventWrapper(v8::Handle<v8::Value> value) { +bool V8Proxy::IsDOMEventWrapper(v8::Handle<v8::Value> value) +{ // All kinds of events use EVENT as dom type in JS wrappers. // See EventToV8Object return IsWrapperOfType(value, V8ClassIndex::EVENT); } bool V8Proxy::IsWrapperOfType(v8::Handle<v8::Value> value, - V8ClassIndex::V8WrapperType classType) { + V8ClassIndex::V8WrapperType classType) +{ if (value.IsEmpty() || !value->IsObject()) return false; v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); @@ -2186,7 +2282,8 @@ bool V8Proxy::IsWrapperOfType(v8::Handle<v8::Value> value, macro(ul, ULIST) \ macro(xmp, PRE) -V8ClassIndex::V8WrapperType V8Proxy::GetHTMLElementType(HTMLElement* element) { +V8ClassIndex::V8WrapperType V8Proxy::GetHTMLElementType(HTMLElement* element) +{ static HashMap<String, V8ClassIndex::V8WrapperType> map; if (map.isEmpty()) { #define ADD_TO_HASH_MAP(tag, name) \ @@ -2311,7 +2408,8 @@ FOR_EACH_TAG(ADD_TO_HASH_MAP) macro(view, VIEW) \ // end of macro -V8ClassIndex::V8WrapperType V8Proxy::GetSVGElementType(SVGElement* element) { +V8ClassIndex::V8WrapperType V8Proxy::GetSVGElementType(SVGElement* element) +{ static HashMap<String, V8ClassIndex::V8WrapperType> map; if (map.isEmpty()) { #define ADD_TO_HASH_MAP(tag, name) \ @@ -2389,7 +2487,8 @@ v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event) // Caller checks node is not null. -v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) { +v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) +{ if (!node) return v8::Null(); v8::Handle<v8::Object> peer = dom_node_map().get(node); @@ -2511,7 +2610,8 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) { } -void V8Proxy::UpdateDocumentHandle(v8::Local<v8::Object> handle) { +void V8Proxy::UpdateDocumentHandle(v8::Local<v8::Object> handle) +{ // If the old handle is not empty, release it. if (!m_document.IsEmpty()) { #ifndef NDEBUG @@ -2559,7 +2659,8 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) v8::Handle<v8::Value> V8Proxy::EventListenerToV8Object( - EventListener* listener) { + EventListener* listener) +{ if (listener == 0) return v8::Null(); // TODO(fqian): can a user take a lazy event listener and set to other places? @@ -2570,7 +2671,8 @@ v8::Handle<v8::Value> V8Proxy::EventListenerToV8Object( v8::Handle<v8::Value> V8Proxy::DOMImplementationToV8Object( - DOMImplementation* impl) { + DOMImplementation* impl) +{ v8::Handle<v8::Object> result = InstantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, V8ClassIndex::DOMIMPLEMENTATION, @@ -2584,7 +2686,8 @@ v8::Handle<v8::Value> V8Proxy::DOMImplementationToV8Object( } -v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) { +v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) +{ if (!sheet) return v8::Null(); v8::Handle<v8::Object> peer = dom_object_map().get(sheet); @@ -2614,7 +2717,8 @@ v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) { } -v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) { +v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) +{ if (!value) return v8::Null(); v8::Handle<v8::Object> peer = dom_object_map().get(value); @@ -2647,7 +2751,8 @@ v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) { } -v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) { +v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) +{ if (!rule) return v8::Null(); v8::Handle<v8::Object> peer = dom_object_map().get(rule); @@ -2698,7 +2803,8 @@ v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) { return result; } -v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window) { +v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window) +{ if (!window) return v8::Null(); // Initializes environment of a frame, and return the global object // of the frame. diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h index 0923570..f1b558f 100644 --- a/webkit/port/bindings/v8/v8_proxy.h +++ b/webkit/port/bindings/v8/v8_proxy.h @@ -11,6 +11,7 @@ #include "v8_utility.h" #include "Node.h" #include "NodeFilter.h" +#include "SecurityOrigin.h" // for WebCore::SecurityOrigin #include "PlatformString.h" // for WebCore::String #include <wtf/HashMap.h> // for HashMap #include <wtf/PassRefPtr.h> // so generated bindings don't have to @@ -157,18 +158,20 @@ class V8Proxy { ~V8Proxy(); - // Clear security token by setting the security token - // for the context to the global object. - void ClearSecurityToken(); + Frame* frame() { return m_frame; } + + // Clear page-specific data, but keep the global object identify. + void clearForNavigation(); - // Clear page-specific data, exception keep the global object identify. - void clear(); + // Clear data before closing the frame. + void clearForClose(); + + // Notify that a new DOMWindow object is ready. + void domWindowReady(); // Destroy the global object. void DestroyGlobal(); - Frame* frame() { return m_frame; } - // TODO(mpcomplete): Need comment. User Gesture related. bool inlineCode() const { return m_inlineCode; } void setInlineCode(bool value) { m_inlineCode = value; } @@ -262,21 +265,13 @@ class V8Proxy { // is disabled and it returns true. static bool HandleOutOfMemory(); - // Generate the security token for a context. - static v8::Handle<v8::Value> GenerateSecurityToken( - v8::Local<v8::Context> context); - - // Check if the active execution context is from the same origin - // as the target frame. - static bool IsFromSameOrigin(Frame* target, bool report_error); + // Check if the active execution context can access the target frame. + static bool CanAccessFrame(Frame* target, bool report_error); // Check if it is safe to access the given node from the // current security context. static bool CheckNodeSecurity(Node* node); - // Return true if the current security context can access the target frame. - static bool CanAccess(Frame* target); - static v8::Handle<v8::Value> CheckNewLegal(const v8::Arguments& args); // Create a V8 wrapper for a C pointer @@ -421,6 +416,8 @@ class V8Proxy { void initContextIfNeeded(); void DisconnectEventListeners(); + static bool CanAccessPrivate(DOMWindow* target); + // Check whether a V8 value is a DOM Event wrapper static bool IsDOMEventWrapper(v8::Handle<v8::Value> obj); |