Home | History | Annotate | Download | only in wml
      1 /*
      2  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      3  * Copyright (C) 2004-2007 Apple Inc. All rights reserved.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  *
     20  */
     21 
     22 #include "config.h"
     23 
     24 #if ENABLE(WML)
     25 #include "WMLPageState.h"
     26 
     27 #include "BackForwardController.h"
     28 #include "BackForwardList.h"
     29 #include "Document.h"
     30 #include "Frame.h"
     31 #include "HistoryItem.h"
     32 #include "KURL.h"
     33 #include "Page.h"
     34 #include <wtf/text/CString.h>
     35 
     36 namespace WebCore {
     37 
     38 WMLPageState::WMLPageState(Page* page)
     39     : m_page(page)
     40     , m_hasAccessControlData(false)
     41 {
     42 }
     43 
     44 WMLPageState::~WMLPageState()
     45 {
     46     m_variables.clear();
     47 }
     48 
     49 #ifndef NDEBUG
     50 // Debugging helper for use within gdb
     51 void WMLPageState::dump()
     52 {
     53     WMLVariableMap::iterator it = m_variables.begin();
     54     WMLVariableMap::iterator end = m_variables.end();
     55 
     56     fprintf(stderr, "Dumping WMLPageState (this=%p) associated with Page (page=%p)...\n", this, m_page);
     57     for (; it != end; ++it)
     58         fprintf(stderr, "\t-> name: '%s'\tvalue: '%s'\n", (*it).first.latin1().data(), (*it).second.latin1().data());
     59 }
     60 #endif
     61 
     62 void WMLPageState::reset()
     63 {
     64     // Remove all the variables
     65     m_variables.clear();
     66 
     67     // Clear the navigation history state
     68     if (m_page)
     69         m_page->backForward()->client()->clearWMLPageHistory();
     70 }
     71 
     72 static inline String normalizedHostName(const String& passedHost)
     73 {
     74     if (passedHost.contains("127.0.0.1")) {
     75         String host = passedHost;
     76         return host.replace("127.0.0.1", "localhost");
     77     }
     78 
     79     return passedHost;
     80 }
     81 
     82 static inline String hostFromURL(const KURL& url)
     83 {
     84     // Default to "localhost"
     85     String host = normalizedHostName(url.host());
     86     return host.isEmpty() ? "localhost" : host;
     87 }
     88 
     89 static KURL urlForHistoryItem(Frame* frame, HistoryItem* item)
     90 {
     91     // For LayoutTests we need to find the corresponding WML frame in the test document
     92     // to be able to test access-control correctly. Remember that WML is never supposed
     93     // to be embedded anywhere, so the purpose is to simulate a standalone WML document.
     94     if (frame->document()->isWMLDocument())
     95         return item->url();
     96 
     97     const HistoryItemVector& childItems = item->children();
     98     HistoryItemVector::const_iterator it = childItems.begin();
     99     const HistoryItemVector::const_iterator end = childItems.end();
    100 
    101     for (; it != end; ++it) {
    102         const RefPtr<HistoryItem> childItem = *it;
    103         Frame* childFrame = frame->tree()->child(childItem->target());
    104         if (!childFrame)
    105             continue;
    106 
    107         if (Document* childDocument = childFrame->document()) {
    108             if (childDocument->isWMLDocument())
    109                 return childItem->url();
    110         }
    111     }
    112 
    113     return item->url();
    114 }
    115 
    116 static bool tryAccessHistoryURLs(Page* page, KURL& previousURL, KURL& currentURL)
    117 {
    118     if (!page)
    119         return false;
    120 
    121     Frame* frame = page->mainFrame();
    122     if (!frame || !frame->document())
    123         return false;
    124 
    125     HistoryItem* previousItem = page->backForward()->backItem();
    126     if (!previousItem)
    127         return false;
    128 
    129     HistoryItem* currentItem = page->backForward()->currentItem();
    130     if (!currentItem)
    131         return false;
    132 
    133     previousURL = urlForHistoryItem(frame, previousItem);
    134     currentURL = urlForHistoryItem(frame, currentItem);
    135 
    136     return true;
    137 }
    138 
    139 bool WMLPageState::processAccessControlData(const String& domain, const String& path)
    140 {
    141     if (m_hasAccessControlData)
    142         return false;
    143 
    144     m_hasAccessControlData = true;
    145 
    146     KURL previousURL, currentURL;
    147     if (!tryAccessHistoryURLs(m_page, previousURL, currentURL))
    148         return true;
    149 
    150     // Spec: The path attribute defaults to the value "/"
    151     m_accessPath = path.isEmpty() ? "/" : path;
    152 
    153     // Spec: The domain attribute defaults to the current decks domain.
    154     String previousHost = hostFromURL(previousURL);
    155     m_accessDomain = domain.isEmpty() ? previousHost : normalizedHostName(domain);
    156 
    157     // Spec: To simplify the development of applications that may not know the absolute path to the
    158     // current deck, the path attribute accepts relative URIs. The user agent converts the relative
    159     // path to an absolute path and then performs prefix matching against the PATH attribute.
    160     Document* document = m_page->mainFrame() ? m_page->mainFrame()->document() : 0;
    161     if (document && previousHost == m_accessDomain && !m_accessPath.startsWith("/")) {
    162         String currentPath = currentURL.path();
    163 
    164         size_t index = currentPath.reverseFind('/');
    165         if (index != WTF::notFound)
    166             m_accessPath = document->completeURL(currentPath.left(index + 1) + m_accessPath).path();
    167     }
    168 
    169     return true;
    170 }
    171 
    172 void WMLPageState::resetAccessControlData()
    173 {
    174     m_hasAccessControlData = false;
    175     m_accessDomain = String();
    176     m_accessPath = String();
    177 }
    178 
    179 bool WMLPageState::canAccessDeck() const
    180 {
    181     if (!m_hasAccessControlData)
    182         return true;
    183 
    184     KURL previousURL, currentURL;
    185     if (!tryAccessHistoryURLs(m_page, previousURL, currentURL))
    186         return true;
    187 
    188     if (equalIgnoringFragmentIdentifier(previousURL, currentURL))
    189        return true;
    190 
    191     return hostIsAllowedToAccess(hostFromURL(previousURL)) && pathIsAllowedToAccess(previousURL.path());
    192 }
    193 
    194 bool WMLPageState::hostIsAllowedToAccess(const String& host) const
    195 {
    196     // Spec: The access domain is suffix-matched against the domain name portion of the referring URI
    197     Vector<String> subdomainsAllowed;
    198     if (m_accessDomain.contains('.'))
    199         m_accessDomain.split('.', subdomainsAllowed);
    200     else
    201         subdomainsAllowed.append(m_accessDomain);
    202 
    203     Vector<String> subdomainsCheck;
    204     if (host.contains('.'))
    205         host.split('.', subdomainsCheck);
    206     else
    207         subdomainsCheck.append(host);
    208 
    209     Vector<String>::iterator itAllowed = subdomainsAllowed.end() - 1;
    210     Vector<String>::iterator beginAllowed = subdomainsAllowed.begin();
    211 
    212     Vector<String>::iterator itCheck = subdomainsCheck.end() - 1;
    213     Vector<String>::iterator beginCheck = subdomainsCheck.begin();
    214 
    215     bool hostOk = true;
    216     for (; itAllowed >= beginAllowed && itCheck >= beginCheck; ) {
    217         if (*itAllowed != *itCheck) {
    218             hostOk = false;
    219             break;
    220         }
    221 
    222         --itAllowed;
    223         --itCheck;
    224     }
    225 
    226     return hostOk;
    227 }
    228 
    229 bool WMLPageState::pathIsAllowedToAccess(const String& path) const
    230 {
    231     // Spec: The access path is prefix matched against the path portion of the referring URI
    232     Vector<String> subpathsAllowed;
    233     if (m_accessPath.contains('/'))
    234         m_accessPath.split('/', subpathsAllowed);
    235     else
    236         subpathsAllowed.append(m_accessPath);
    237 
    238     Vector<String> subpathsCheck;
    239     if (path.contains('/'))
    240         path.split('/', subpathsCheck);
    241     else
    242         subpathsCheck.append(path);
    243 
    244     Vector<String>::iterator itAllowed = subpathsAllowed.begin();
    245     Vector<String>::iterator endAllowed = subpathsAllowed.end();
    246 
    247     Vector<String>::iterator itCheck = subpathsCheck.begin();
    248     Vector<String>::iterator endCheck = subpathsCheck.end();
    249 
    250     bool pathOk = true;
    251     for (; itAllowed != endAllowed && itCheck != endCheck; ) {
    252         if (*itAllowed != *itCheck) {
    253             pathOk = false;
    254             break;
    255         }
    256 
    257         ++itAllowed;
    258         ++itCheck;
    259     }
    260 
    261     return pathOk;
    262 }
    263 
    264 }
    265 
    266 #endif
    267