| Index: Source/WebCore/dom/Document.cpp
 | 
| ===================================================================
 | 
| --- Source/WebCore/dom/Document.cpp	(revision 112895)
 | 
| +++ Source/WebCore/dom/Document.cpp	(working copy)
 | 
| @@ -339,6 +339,34 @@
 | 
|  #endif
 | 
|  }
 | 
|  
 | 
| +static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
 | 
| +{
 | 
| +    // targetFrame can be 0 when we're trying to navigate a top-level frame
 | 
| +    // that has a 0 opener.
 | 
| +    if (!targetFrame)
 | 
| +        return false;
 | 
| +
 | 
| +    const bool isLocalActiveOrigin = activeSecurityOrigin->isLocal();
 | 
| +    for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
 | 
| +        Document* ancestorDocument = ancestorFrame->document();
 | 
| +        // FIXME: Should be an ASSERT? Frames should alway have documents.
 | 
| +        if (!ancestorDocument)
 | 
| +            return true;
 | 
| +
 | 
| +        const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
 | 
| +        if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
 | 
| +            return true;
 | 
| +        
 | 
| +        // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
 | 
| +        // FIXME: It's a bit strange to special-case local origins here. Should we be doing
 | 
| +        // something more general instead?
 | 
| +        if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal())
 | 
| +            return true;
 | 
| +    }
 | 
| +
 | 
| +    return false;
 | 
| +}
 | 
| +
 | 
|  static HashSet<Document*>* documentsThatNeedStyleRecalc = 0;
 | 
|  
 | 
|  class DocumentWeakReference : public ThreadSafeRefCounted<DocumentWeakReference> {
 | 
| @@ -2534,6 +2562,61 @@
 | 
|      frame()->script()->disableEval();
 | 
|  }
 | 
|  
 | 
| +bool Document::canNavigate(Frame* targetFrame)
 | 
| +{
 | 
| +    // The navigation change is safe if the active document is:
 | 
| +    //   - in the same security origin as the target or one of the target's
 | 
| +    //     ancestors.
 | 
| +    //
 | 
| +    // Or the target frame is:
 | 
| +    //   - a top-level frame in the frame hierarchy and the active frame can
 | 
| +    //     navigate the target frame's opener per above or it is the opener of
 | 
| +    //     the target frame.
 | 
| +
 | 
| +    if (!m_frame)
 | 
| +        return false;
 | 
| +
 | 
| +    // FIXME: Do we actually ever call this function without a targetFrame?
 | 
| +    if (!targetFrame)
 | 
| +        return true;
 | 
| +
 | 
| +    // Performance optimization.
 | 
| +    // FIXME: Delete this code. It seems very unlikely that this affects performance.
 | 
| +    if (m_frame == targetFrame)
 | 
| +        return true;
 | 
| +
 | 
| +    // Let a document navigate window.top so that it can framebust.
 | 
| +    if (!isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree()->top())
 | 
| +        return true;
 | 
| +
 | 
| +    // A sandboxed frame can only navigate itself and its descendants.
 | 
| +    if (isSandboxed(SandboxNavigation) && !targetFrame->tree()->isDescendantOf(m_frame))
 | 
| +        return false;
 | 
| +
 | 
| +    // Let a frame navigate its opener if the opener is a top-level window.
 | 
| +    if (!targetFrame->tree()->parent() && m_frame->loader()->opener() == targetFrame)
 | 
| +        return true;
 | 
| +
 | 
| +    // For top-level windows, check the opener.
 | 
| +    // FIXME: Can this check be combined with the previous check?
 | 
| +    if (!targetFrame->tree()->parent() && canAccessAncestor(securityOrigin(), targetFrame->loader()->opener()))
 | 
| +        return true;
 | 
| +
 | 
| +    // In general, check the frame's ancestors.
 | 
| +    if (canAccessAncestor(securityOrigin(), targetFrame))
 | 
| +        return true;
 | 
| +
 | 
| +    Document* targetDocument = targetFrame->document();
 | 
| +    // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
 | 
| +    String message = "Unsafe JavaScript attempt to initiate a navigation change for frame with URL " +
 | 
| +                     targetDocument->url().string() + " from frame with URL " + url().string() + ".\n";
 | 
| +
 | 
| +    // FIXME: should we print to the console of the activeFrame as well?
 | 
| +    targetFrame->domWindow()->printErrorMessage(message);
 | 
| +
 | 
| +    return false;
 | 
| +}
 | 
| +
 | 
|  CSSStyleSheet* Document::pageUserSheet()
 | 
|  {
 | 
|      if (m_pageUserSheet)
 | 
| 
 |