Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 1001 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1012 { | 1012 { |
| 1013 v8::Local<v8::Context> context = v8::Context::GetCurrent(); | 1013 v8::Local<v8::Context> context = v8::Context::GetCurrent(); |
| 1014 | 1014 |
| 1015 if (!context->HasOutOfMemoryException()) | 1015 if (!context->HasOutOfMemoryException()) |
| 1016 return false; | 1016 return false; |
| 1017 | 1017 |
| 1018 // Warning, error, disable JS for this frame? | 1018 // Warning, error, disable JS for this frame? |
| 1019 Frame* frame = V8Proxy::retrieveFrame(context); | 1019 Frame* frame = V8Proxy::retrieveFrame(context); |
| 1020 | 1020 |
| 1021 V8Proxy* proxy = V8Proxy::retrieve(frame); | 1021 V8Proxy* proxy = V8Proxy::retrieve(frame); |
| 1022 // Clean m_context, m_document, and event handlers. | 1022 // Clean m_context, and event handlers. |
| 1023 proxy->clearForClose(); | 1023 proxy->clearForClose(); |
| 1024 // Destroy the global object. | 1024 // Destroy the global object. |
| 1025 proxy->DestroyGlobal(); | 1025 proxy->DestroyGlobal(); |
| 1026 | 1026 |
| 1027 webkit_glue::NotifyJSOutOfMemory(frame); | 1027 webkit_glue::NotifyJSOutOfMemory(frame); |
| 1028 | 1028 |
| 1029 // Disable JS. | 1029 // Disable JS. |
| 1030 Settings* settings = frame->settings(); | 1030 Settings* settings = frame->settings(); |
| 1031 ASSERT(settings); | 1031 ASSERT(settings); |
| 1032 settings->setJavaScriptEnabled(false); | 1032 settings->setJavaScriptEnabled(false); |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1549 for (size_t i = 0; i < arraysize(kDirProtocols); ++i) { | 1549 for (size_t i = 0; i < arraysize(kDirProtocols); ++i) { |
| 1550 if (origin->protocol() == kDirProtocols[i]) { | 1550 if (origin->protocol() == kDirProtocols[i]) { |
| 1551 ASSERT(url.SchemeIs(kDirProtocols[i])); | 1551 ASSERT(url.SchemeIs(kDirProtocols[i])); |
| 1552 return url.ExtractFileName().empty(); | 1552 return url.ExtractFileName().empty(); |
| 1553 } | 1553 } |
| 1554 } | 1554 } |
| 1555 | 1555 |
| 1556 return false; // Other protocols fall through to here | 1556 return false; // Other protocols fall through to here |
| 1557 } | 1557 } |
| 1558 | 1558 |
| 1559 void V8Proxy::clearDocumentWrapper() | |
| 1560 { | |
| 1561 v8::Local<v8::Context> context = GetContext(); | |
| 1562 if (context.IsEmpty()) | |
| 1563 return; // not initialize yet | |
| 1564 | |
| 1565 if (!m_document.IsEmpty()) { | |
| 1566 #ifndef NDEBUG | |
| 1567 UnregisterGlobalHandle(this, m_document); | |
| 1568 #endif | |
| 1569 m_document.Dispose(); | |
| 1570 m_document.Clear(); | |
| 1571 } | |
| 1572 } | |
| 1573 | 1559 |
| 1574 // static | 1560 // static |
| 1575 void V8Proxy::DomainChanged(Frame* frame) | 1561 void V8Proxy::DomainChanged(Frame* frame) |
| 1576 { | 1562 { |
| 1577 V8Proxy* proxy = retrieve(frame); | 1563 V8Proxy* proxy = retrieve(frame); |
| 1578 // Restore to default security token. | 1564 // Restore to default security token. |
| 1579 proxy->m_context->UseDefaultSecurityToken(); | 1565 proxy->m_context->UseDefaultSecurityToken(); |
| 1580 } | 1566 } |
| 1581 | 1567 |
| 1582 | 1568 |
| 1583 void V8Proxy::clearForClose() | 1569 void V8Proxy::clearForClose() |
| 1584 { | 1570 { |
| 1585 if (m_context.IsEmpty()) | 1571 if (m_context.IsEmpty()) |
| 1586 return; | 1572 return; |
| 1587 | 1573 |
| 1588 { v8::HandleScope handle_scope; | |
| 1589 clearDocumentWrapper(); | |
| 1590 } | |
| 1591 | |
| 1592 m_context.Dispose(); | 1574 m_context.Dispose(); |
| 1593 m_context.Clear(); | 1575 m_context.Clear(); |
| 1594 } | 1576 } |
| 1595 | 1577 |
| 1596 | 1578 |
| 1597 void V8Proxy::clearForNavigation() | 1579 void V8Proxy::clearForNavigation() |
| 1598 { | 1580 { |
| 1599 if (m_context.IsEmpty()) | 1581 if (m_context.IsEmpty()) |
| 1600 return; | 1582 return; |
| 1601 | 1583 |
| 1602 { v8::HandleScope handle; | 1584 { v8::HandleScope handle; |
| 1603 clearDocumentWrapper(); | 1585 |
| 1586 v8::Context::Scope context_scope(m_context); | |
| 1604 | 1587 |
| 1605 // Turn on access check on the old DOMWindow wrapper. | 1588 // Turn on access check on the old DOMWindow wrapper. |
| 1606 v8::Handle<v8::Object> wrapper = | 1589 v8::Handle<v8::Object> wrapper = |
| 1607 LookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global); | 1590 LookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global); |
| 1608 ASSERT(!wrapper.IsEmpty()); | 1591 ASSERT(!wrapper.IsEmpty()); |
| 1609 wrapper->TurnOnAccessCheck(); | 1592 wrapper->TurnOnAccessCheck(); |
| 1610 | 1593 |
| 1611 // Clear all timeouts. | 1594 // Clear all timeouts. |
| 1612 DOMWindow* domWindow = | 1595 DOMWindow* domWindow = |
| 1613 ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, wrapper); | 1596 ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, wrapper); |
| 1614 domWindow->clearAllTimeouts(); | 1597 domWindow->clearAllTimeouts(); |
| 1615 | 1598 |
| 1616 // disconnect all event listeners | 1599 // disconnect all event listeners |
| 1617 DisconnectEventListeners(); | 1600 DisconnectEventListeners(); |
| 1618 | 1601 |
| 1619 // Separate the context from its global object. | 1602 // Separate the context from its global object. |
| 1620 m_context->DetachGlobal(); | 1603 m_context->DetachGlobal(); |
| 1621 } | |
| 1622 | 1604 |
| 1623 // Corresponds to the context creation in initContextIfNeeded(). | 1605 m_context.Dispose(); |
| 1624 m_context.Dispose(); | 1606 m_context.Clear(); |
| 1625 m_context.Clear(); | |
| 1626 } | |
| 1627 | 1607 |
| 1628 | 1608 // Reinitialize the context so the global object points to |
| 1629 void V8Proxy::domWindowReady() | 1609 // the new DOM window. |
| 1630 { | |
| 1631 // Reinitialize context so the global object is reused by | |
| 1632 // the new context. | |
| 1633 if (!m_global.IsEmpty() && m_context.IsEmpty()) { | |
| 1634 v8::HandleScope scope; | |
| 1635 initContextIfNeeded(); | 1610 initContextIfNeeded(); |
| 1636 } | 1611 } |
| 1637 } | 1612 } |
| 1638 | 1613 |
| 1639 | 1614 |
| 1615 void V8Proxy::SetSecurityToken() { | |
| 1616 Document* document = m_frame->document(); | |
| 1617 // Setup security origin and security token | |
| 1618 if (!document) { | |
| 1619 m_context->UseDefaultSecurityToken(); | |
| 1620 return; | |
| 1621 } | |
| 1622 | |
| 1623 // Ask the document's SecurityOrigin to generate a security token. | |
| 1624 // If two tokens are equal, then the SecurityOrigins canAccess each other. | |
| 1625 // If two tokens are not equal, then we have to call canAccess. | |
| 1626 // Note: we can't use the HTTPOrigin if it was set from the DOM. | |
| 1627 SecurityOrigin* origin = document->securityOrigin(); | |
| 1628 String token; | |
| 1629 if (!origin->domainWasSetInDOM()) | |
| 1630 token = document->securityOrigin()->toString(); | |
| 1631 | |
| 1632 // An empty token means we always have to call canAccess. In this case, we | |
| 1633 // use the global object as the security token to avoid calling canAccess | |
| 1634 // when a script accesses its own objects. | |
| 1635 if (token.isEmpty()) { | |
| 1636 m_context->UseDefaultSecurityToken(); | |
| 1637 return; | |
| 1638 } | |
| 1639 | |
| 1640 CString utf8_token = token.utf8(); | |
| 1641 // NOTE: V8 does identity comparison in fast path, must use a symbol | |
| 1642 // as the security token. | |
| 1643 m_context->SetSecurityToken( | |
| 1644 v8::String::NewSymbol(utf8_token.data(), utf8_token.length())); | |
| 1645 | |
|
Mike Belshe
2008/11/13 18:13:50
extra line
Feng Qian
2008/11/13 21:30:18
Done.
| |
| 1646 } | |
| 1647 | |
| 1648 | |
| 1649 void V8Proxy::updateDocument() | |
| 1650 { | |
| 1651 if (!m_frame->document()) | |
| 1652 return; | |
| 1653 | |
| 1654 if (m_global.IsEmpty()) { | |
| 1655 ASSERT(m_context.IsEmpty()); | |
| 1656 return; | |
| 1657 } | |
| 1658 | |
| 1659 { v8::HandleScope scope; | |
|
Mike Belshe
2008/11/13 18:13:50
funky braces
Feng Qian
2008/11/13 21:30:18
Done.
| |
| 1660 SetSecurityToken(); | |
| 1661 } | |
| 1662 } | |
| 1663 | |
| 1664 | |
| 1640 // Check if the current execution context can access a target frame. | 1665 // Check if the current execution context can access a target frame. |
| 1641 // First it checks same domain policy using the lexical context | 1666 // First it checks same domain policy using the lexical context |
| 1642 // | 1667 // |
| 1643 // This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&). | 1668 // This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&). |
| 1644 bool V8Proxy::CanAccessPrivate(DOMWindow* target_window) | 1669 bool V8Proxy::CanAccessPrivate(DOMWindow* target_window) |
| 1645 { | 1670 { |
| 1646 ASSERT(target_window); | 1671 ASSERT(target_window); |
| 1647 | 1672 |
| 1648 String message; | 1673 String message; |
| 1649 | 1674 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1713 | 1738 |
| 1714 Frame* target = node->document()->frame(); | 1739 Frame* target = node->document()->frame(); |
| 1715 | 1740 |
| 1716 if (!target) | 1741 if (!target) |
| 1717 return false; | 1742 return false; |
| 1718 | 1743 |
| 1719 return CanAccessFrame(target, true); | 1744 return CanAccessFrame(target, true); |
| 1720 } | 1745 } |
| 1721 | 1746 |
| 1722 | 1747 |
| 1723 static void GenerateSecurityToken(v8::Local<v8::Context> context) | |
| 1724 { | |
| 1725 Document* document = V8Proxy::retrieveFrame(context)->document(); | |
| 1726 if (!document) { | |
| 1727 context->UseDefaultSecurityToken(); | |
| 1728 return; | |
| 1729 } | |
| 1730 | |
| 1731 // Ask the document's SecurityOrigin to generate a security token. | |
| 1732 // If two tokens are equal, then the SecurityOrigins canAccess each other. | |
| 1733 // If two tokens are not equal, then we have to call canAccess. | |
| 1734 // Note: we can't use the HTTPOrigin if it was set from the DOM. | |
| 1735 SecurityOrigin* origin = document->securityOrigin(); | |
| 1736 String token; | |
| 1737 if (!origin->domainWasSetInDOM()) | |
| 1738 token = document->securityOrigin()->toString(); | |
| 1739 | |
| 1740 // An empty token means we always have to call canAccess. In this case, we | |
| 1741 // use the global object as the security token to avoid calling canAccess | |
| 1742 // when a script accesses its own objects. | |
| 1743 if (token.isEmpty()) { | |
| 1744 context->UseDefaultSecurityToken(); | |
| 1745 return; | |
| 1746 } | |
| 1747 | |
| 1748 CString utf8_token = token.utf8(); | |
| 1749 // NOTE: V8 does identity comparison in fast path, must use a symbol | |
| 1750 // as the security token. | |
| 1751 context->SetSecurityToken( | |
| 1752 v8::String::NewSymbol(utf8_token.data(), utf8_token.length())); | |
| 1753 } | |
| 1754 | |
| 1755 | |
| 1756 // Create a new environment and setup the global object. | 1748 // Create a new environment and setup the global object. |
| 1757 // | 1749 // |
| 1758 // The global object corresponds to a DOMWindow instance. However, to | 1750 // The global object corresponds to a DOMWindow instance. However, to |
| 1759 // allow properties of the JS DOMWindow instance to be shadowed, we | 1751 // allow properties of the JS DOMWindow instance to be shadowed, we |
| 1760 // use a shadow object as the global object and use the JS DOMWindow | 1752 // use a shadow object as the global object and use the JS DOMWindow |
| 1761 // instance as the prototype for that shadow object. The JS DOMWindow | 1753 // instance as the prototype for that shadow object. The JS DOMWindow |
| 1762 // instance is undetectable from javascript code because the __proto__ | 1754 // instance is undetectable from javascript code because the __proto__ |
| 1763 // accessors skip that object. | 1755 // accessors skip that object. |
| 1764 // | 1756 // |
| 1765 // The shadow object and the DOMWindow instance are seen as one object | 1757 // The shadow object and the DOMWindow instance are seen as one object |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1865 // Setup the peer object for the DOM window. | 1857 // Setup the peer object for the DOM window. |
| 1866 dom_object_map().set(window, v8::Persistent<v8::Object>::New(window_peer)); | 1858 dom_object_map().set(window, v8::Persistent<v8::Object>::New(window_peer)); |
| 1867 // Wrap the window. | 1859 // Wrap the window. |
| 1868 SetDOMWrapper(window_peer, | 1860 SetDOMWrapper(window_peer, |
| 1869 V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), | 1861 V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), |
| 1870 window); | 1862 window); |
| 1871 // Insert the window instance as the prototype of the shadow object. | 1863 // Insert the window instance as the prototype of the shadow object. |
| 1872 v8::Handle<v8::Object> v8_global = context->Global(); | 1864 v8::Handle<v8::Object> v8_global = context->Global(); |
| 1873 v8_global->Set(v8::String::New("__proto__"), window_peer); | 1865 v8_global->Set(v8::String::New("__proto__"), window_peer); |
| 1874 | 1866 |
| 1875 // Setup security origin and security token | 1867 SetSecurityToken(); |
| 1876 GenerateSecurityToken(context); | |
| 1877 | 1868 |
| 1878 m_frame->loader()->dispatchWindowObjectAvailable(); | 1869 m_frame->loader()->dispatchWindowObjectAvailable(); |
| 1879 | 1870 |
| 1880 if (ScriptController::RecordPlaybackMode()) { | 1871 if (ScriptController::RecordPlaybackMode()) { |
| 1881 // Inject code which overrides a few common JS functions for implementing | 1872 // Inject code which overrides a few common JS functions for implementing |
| 1882 // randomness. In order to implement effective record & playback of | 1873 // randomness. In order to implement effective record & playback of |
| 1883 // websites, it is important that the URLs not change. Many popular web | 1874 // websites, it is important that the URLs not change. Many popular web |
| 1884 // based apps use randomness in URLs to unique-ify urls for proxies. | 1875 // based apps use randomness in URLs to unique-ify urls for proxies. |
| 1885 // Unfortunately, this breaks playback. | 1876 // Unfortunately, this breaks playback. |
| 1886 // To work around this, we take the two most common client-side randomness | 1877 // To work around this, we take the two most common client-side randomness |
| (...skipping 732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2619 // If instantiation failed it's important not to add the result | 2610 // If instantiation failed it's important not to add the result |
| 2620 // to the DOM node map. Instead we return an empty handle, which | 2611 // to the DOM node map. Instead we return an empty handle, which |
| 2621 // should already be handled by callers of this function in case | 2612 // should already be handled by callers of this function in case |
| 2622 // the node is NULL. | 2613 // the node is NULL. |
| 2623 return result; | 2614 return result; |
| 2624 } | 2615 } |
| 2625 | 2616 |
| 2626 dom_node_map().set(node, v8::Persistent<v8::Object>::New(result)); | 2617 dom_node_map().set(node, v8::Persistent<v8::Object>::New(result)); |
| 2627 | 2618 |
| 2628 if (is_document) { | 2619 if (is_document) { |
| 2629 Document* doc = static_cast<Document*>(node); | |
| 2630 V8Proxy* proxy = V8Proxy::retrieve(doc->frame()); | |
| 2631 if (proxy) | |
| 2632 proxy->UpdateDocumentHandle(result); | |
| 2633 | |
| 2634 if (type == V8ClassIndex::HTMLDOCUMENT) { | 2620 if (type == V8ClassIndex::HTMLDOCUMENT) { |
| 2635 // Create marker object and insert it in two internal fields. | 2621 // Create marker object and insert it in two internal fields. |
| 2636 // This is used to implement temporary shadowing of | 2622 // This is used to implement temporary shadowing of |
| 2637 // document.all. | 2623 // document.all. |
| 2638 ASSERT(result->InternalFieldCount() == | 2624 ASSERT(result->InternalFieldCount() == |
| 2639 V8Custom::kHTMLDocumentInternalFieldCount); | 2625 V8Custom::kHTMLDocumentInternalFieldCount); |
| 2640 v8::Local<v8::Object> marker = v8::Object::New(); | 2626 v8::Local<v8::Object> marker = v8::Object::New(); |
| 2641 result->SetInternalField(V8Custom::kHTMLDocumentMarkerIndex, marker); | 2627 result->SetInternalField(V8Custom::kHTMLDocumentMarkerIndex, marker); |
| 2642 result->SetInternalField(V8Custom::kHTMLDocumentShadowIndex, marker); | 2628 result->SetInternalField(V8Custom::kHTMLDocumentShadowIndex, marker); |
| 2643 } | 2629 } |
| 2644 } | 2630 } |
| 2645 | 2631 |
| 2646 return result; | 2632 return result; |
| 2647 } | 2633 } |
| 2648 | 2634 |
| 2649 | 2635 |
| 2650 void V8Proxy::UpdateDocumentHandle(v8::Local<v8::Object> handle) | |
| 2651 { | |
| 2652 // If the old handle is not empty, release it. | |
| 2653 if (!m_document.IsEmpty()) { | |
| 2654 #ifndef NDEBUG | |
| 2655 UnregisterGlobalHandle(this, m_document); | |
| 2656 #endif | |
| 2657 m_document.Dispose(); | |
| 2658 m_document.Clear(); | |
| 2659 } | |
| 2660 | |
| 2661 m_document = v8::Persistent<v8::Object>::New(handle); | |
| 2662 #ifndef NDEBUG | |
| 2663 RegisterGlobalHandle(PROXY, this, m_document); | |
| 2664 #endif | |
| 2665 } | |
| 2666 | |
| 2667 | |
| 2668 // A JS object of type EventTarget can only be five possible types: | 2636 // A JS object of type EventTarget can only be five possible types: |
| 2669 // 1) EventTargetNode; 2) XMLHttpRequest; 3) MessagePort; 4) SVGElementInstance; | 2637 // 1) EventTargetNode; 2) XMLHttpRequest; 3) MessagePort; 4) SVGElementInstance; |
| 2670 // 5) XMLHttpRequestUpload | 2638 // 5) XMLHttpRequestUpload |
| 2671 // check EventTarget.h for new type conversion methods | 2639 // check EventTarget.h for new type conversion methods |
| 2672 // also make sure to sync with V8EventListener::GetThisObject (v8_events.cpp) | 2640 // also make sure to sync with V8EventListener::GetThisObject (v8_events.cpp) |
| 2673 v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) | 2641 v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) |
| 2674 { | 2642 { |
| 2675 if (!target) | 2643 if (!target) |
| 2676 return v8::Null(); | 2644 return v8::Null(); |
| 2677 | 2645 |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2894 v8::Handle<v8::Object> global = context->Global(); | 2862 v8::Handle<v8::Object> global = context->Global(); |
| 2895 global->Set(v8::String::New(name), instance); | 2863 global->Set(v8::String::New(name), instance); |
| 2896 } | 2864 } |
| 2897 | 2865 |
| 2898 void V8Proxy::ProcessConsoleMessages() | 2866 void V8Proxy::ProcessConsoleMessages() |
| 2899 { | 2867 { |
| 2900 ConsoleMessageManager::ProcessDelayedMessages(); | 2868 ConsoleMessageManager::ProcessDelayedMessages(); |
| 2901 } | 2869 } |
| 2902 | 2870 |
| 2903 } // namespace WebCore | 2871 } // namespace WebCore |
| OLD | NEW |