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 "BackForwardList.h"
     28 #include "CString.h"
     29 #include "Document.h"
     30 #include "Frame.h"
     31 #include "HistoryItem.h"
     32 #include "KURL.h"
     33 #include "Page.h"
     34 
     35 namespace WebCore {
     36 
     37 WMLPageState::WMLPageState(Page* page)
     38     : m_page(page)
     39     , m_hasAccessControlData(false)
     40 {
     41 }
     42 
     43 WMLPageState::~WMLPageState()
     44 {
     45     m_variables.clear();
     46 }
     47 
     48 #ifndef NDEBUG
     49 // Debugging helper for use within gdb
     50 void WMLPageState::dump()
     51 {
     52     WMLVariableMap::iterator it = m_variables.begin();
     53     WMLVariableMap::iterator end = m_variables.end();
     54 
     55     fprintf(stderr, "Dumping WMLPageState (this=%p) associated with Page (page=%p)...\n", this, m_page);
     56     for (; it != end; ++it)
     57         fprintf(stderr, "\t-> name: '%s'\tvalue: '%s'\n", (*it).first.latin1().data(), (*it).second.latin1().data());
     58 }
     59 #endif
     60 
     61 void WMLPageState::reset()
     62 {
     63     // Remove all the variables
     64     m_variables.clear();
     65 
     66     // Clear the navigation history state
     67     if (BackForwardList* list = m_page ? m_page->backForwardList() : 0)
     68         list->clearWMLPageHistory();
     69 }
     70 
     71 static inline String normalizedHostName(const String& passedHost)
     72 {
     73     if (passedHost.contains("127.0.0.1")) {
     74         String host = passedHost;
     75         return host.replace("127.0.0.1", "localhost");
     76     }
     77 
     78     return passedHost;
     79 }
     80 
     81 static inline String hostFromURL(const KURL& url)
     82 {
     83     // Default to "localhost"
     84     String host = normalizedHostName(url.host());
     85     return host.isEmpty() ? "localhost" : host;
     86 }
     87 
     88 static KURL urlForHistoryItem(Frame* frame, HistoryItem* item)
     89 {
     90     // For LayoutTests we need to find the corresponding WML frame in the test document
     91     // to be able to test access-control correctly. Remember that WML is never supposed
     92     // to be embedded anywhere, so the purpose is to simulate a standalone WML document.
     93     if (frame->document()->isWMLDocument())
     94         return item->url();
     95 
     96     const HistoryItemVector& childItems = item->children();
     97     HistoryItemVector::const_iterator it = childItems.begin();
     98     const HistoryItemVector::const_iterator end = childItems.end();
     99 
    100     for (; it != end; ++it) {
    101         const RefPtr<HistoryItem> childItem = *it;
    102         Frame* childFrame = frame->tree()->child(childItem->target());
    103         if (!childFrame)
    104             continue;
    105 
    106         if (Document* childDocument = childFrame->document()) {
    107             if (childDocument->isWMLDocument())
    108                 return childItem->url();
    109         }
    110     }
    111 
    112     return item->url();
    113 }
    114 
    115 static bool tryAccessHistoryURLs(Page* page, KURL& previousURL, KURL& currentURL)
    116 {
    117     if (!page)
    118         return false;
    119 
    120     Frame* frame = page->mainFrame();
    121     if (!frame || !frame->document())
    122         return false;
    123 
    124     BackForwardList* list = page->backForwardList();
    125     if (!list)
    126         return false;
    127 
    128     HistoryItem* previousItem = list->backItem();
    129     if (!previousItem)
    130         return false;
    131 
    132     HistoryItem* currentItem = list->currentItem();
    133     if (!currentItem)
    134         return false;
    135 
    136     previousURL = urlForHistoryItem(frame, previousItem);
    137     currentURL = urlForHistoryItem(frame, currentItem);
    138 
    139     return true;
    140 }
    141 
    142 bool WMLPageState::processAccessControlData(const String& domain, const String& path)
    143 {
    144     if (m_hasAccessControlData)
    145         return false;
    146 
    147     m_hasAccessControlData = true;
    148 
    149     KURL previousURL, currentURL;
    150     if (!tryAccessHistoryURLs(m_page, previousURL, currentURL))
    151         return true;
    152 
    153     // Spec: The path attribute defaults to the value "/"
    154     m_accessPath = path.isEmpty() ? "/" : path;
    155 
    156     // Spec: The domain attribute defaults to the current decks domain.
    157     String previousHost = hostFromURL(previousURL);
    158     m_accessDomain = domain.isEmpty() ? previousHost : normalizedHostName(domain);
    159 
    160     // Spec: To simplify the development of applications that may not know the absolute path to the
    161     // current deck, the path attribute accepts relative URIs. The user agent converts the relative
    162     // path to an absolute path and then performs prefix matching against the PATH attribute.
    163     Document* document = m_page->mainFrame() ? m_page->mainFrame()->document() : 0;
    164     if (document && previousHost == m_accessDomain && !m_accessPath.startsWith("/")) {
    165         String currentPath = currentURL.path();
    166 
    167         size_t index = currentPath.reverseFind('/');
    168         if (index != WTF::notFound)
    169             m_accessPath = document->completeURL(currentPath.left(index + 1) + m_accessPath).path();
    170     }
    171 
    172     return true;
    173 }
    174 
    175 void WMLPageState::resetAccessControlData()
    176 {
    177     m_hasAccessControlData = false;
    178     m_accessDomain = String();
    179     m_accessPath = String();
    180 }
    181 
    182 bool WMLPageState::canAccessDeck() const
    183 {
    184     if (!m_hasAccessControlData)
    185         return true;
    186 
    187     KURL previousURL, currentURL;
    188     if (!tryAccessHistoryURLs(m_page, previousURL, currentURL))
    189         return true;
    190 
    191     if (equalIgnoringFragmentIdentifier(previousURL, currentURL))
    192        return true;
    193 
    194     return hostIsAllowedToAccess(hostFromURL(previousURL)) && pathIsAllowedToAccess(previousURL.path());
    195 }
    196 
    197 bool WMLPageState::hostIsAllowedToAccess(const String& host) const
    198 {
    199     // Spec: The access domain is suffix-matched against the domain name portion of the referring URI
    200     Vector<String> subdomainsAllowed;
    201     if (m_accessDomain.contains('.'))
    202         m_accessDomain.split('.', subdomainsAllowed);
    203     else
    204         subdomainsAllowed.append(m_accessDomain);
    205 
    206     Vector<String> subdomainsCheck;
    207     if (host.contains('.'))
    208         host.split('.', subdomainsCheck);
    209     else
    210         subdomainsCheck.append(host);
    211 
    212     Vector<String>::iterator itAllowed = subdomainsAllowed.end() - 1;
    213     Vector<String>::iterator beginAllowed = subdomainsAllowed.begin();
    214 
    215     Vector<String>::iterator itCheck = subdomainsCheck.end() - 1;
    216     Vector<String>::iterator beginCheck = subdomainsCheck.begin();
    217 
    218     bool hostOk = true;
    219     for (; itAllowed >= beginAllowed && itCheck >= beginCheck; ) {
    220         if (*itAllowed != *itCheck) {
    221             hostOk = false;
    222             break;
    223         }
    224 
    225         --itAllowed;
    226         --itCheck;
    227     }
    228 
    229     return hostOk;
    230 }
    231 
    232 bool WMLPageState::pathIsAllowedToAccess(const String& path) const
    233 {
    234     // Spec: The access path is prefix matched against the path portion of the referring URI
    235     Vector<String> subpathsAllowed;
    236     if (m_accessPath.contains('/'))
    237         m_accessPath.split('/', subpathsAllowed);
    238     else
    239         subpathsAllowed.append(m_accessPath);
    240 
    241     Vector<String> subpathsCheck;
    242     if (path.contains('/'))
    243         path.split('/', subpathsCheck);
    244     else
    245         subpathsCheck.append(path);
    246 
    247     Vector<String>::iterator itAllowed = subpathsAllowed.begin();
    248     Vector<String>::iterator endAllowed = subpathsAllowed.end();
    249 
    250     Vector<String>::iterator itCheck = subpathsCheck.begin();
    251     Vector<String>::iterator endCheck = subpathsCheck.end();
    252 
    253     bool pathOk = true;
    254     for (; itAllowed != endAllowed && itCheck != endCheck; ) {
    255         if (*itAllowed != *itCheck) {
    256             pathOk = false;
    257             break;
    258         }
    259 
    260         ++itAllowed;
    261         ++itCheck;
    262     }
    263 
    264     return pathOk;
    265 }
    266 
    267 }
    268 
    269 #endif
    270