diff options
Diffstat (limited to 'Source/WebCore/wml/WMLPageState.cpp')
-rw-r--r-- | Source/WebCore/wml/WMLPageState.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/Source/WebCore/wml/WMLPageState.cpp b/Source/WebCore/wml/WMLPageState.cpp new file mode 100644 index 0000000..a3c6243 --- /dev/null +++ b/Source/WebCore/wml/WMLPageState.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2004-2007 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(WML) +#include "WMLPageState.h" + +#include "BackForwardController.h" +#include "BackForwardList.h" +#include "Document.h" +#include "Frame.h" +#include "HistoryItem.h" +#include "KURL.h" +#include "Page.h" +#include <wtf/text/CString.h> + +namespace WebCore { + +WMLPageState::WMLPageState(Page* page) + : m_page(page) + , m_hasAccessControlData(false) +{ +} + +WMLPageState::~WMLPageState() +{ + m_variables.clear(); +} + +#ifndef NDEBUG +// Debugging helper for use within gdb +void WMLPageState::dump() +{ + WMLVariableMap::iterator it = m_variables.begin(); + WMLVariableMap::iterator end = m_variables.end(); + + fprintf(stderr, "Dumping WMLPageState (this=%p) associated with Page (page=%p)...\n", this, m_page); + for (; it != end; ++it) + fprintf(stderr, "\t-> name: '%s'\tvalue: '%s'\n", (*it).first.latin1().data(), (*it).second.latin1().data()); +} +#endif + +void WMLPageState::reset() +{ + // Remove all the variables + m_variables.clear(); + + // Clear the navigation history state + if (m_page) + m_page->backForward()->client()->clearWMLPageHistory(); +} + +static inline String normalizedHostName(const String& passedHost) +{ + if (passedHost.contains("127.0.0.1")) { + String host = passedHost; + return host.replace("127.0.0.1", "localhost"); + } + + return passedHost; +} + +static inline String hostFromURL(const KURL& url) +{ + // Default to "localhost" + String host = normalizedHostName(url.host()); + return host.isEmpty() ? "localhost" : host; +} + +static KURL urlForHistoryItem(Frame* frame, HistoryItem* item) +{ + // For LayoutTests we need to find the corresponding WML frame in the test document + // to be able to test access-control correctly. Remember that WML is never supposed + // to be embedded anywhere, so the purpose is to simulate a standalone WML document. + if (frame->document()->isWMLDocument()) + return item->url(); + + const HistoryItemVector& childItems = item->children(); + HistoryItemVector::const_iterator it = childItems.begin(); + const HistoryItemVector::const_iterator end = childItems.end(); + + for (; it != end; ++it) { + const RefPtr<HistoryItem> childItem = *it; + Frame* childFrame = frame->tree()->child(childItem->target()); + if (!childFrame) + continue; + + if (Document* childDocument = childFrame->document()) { + if (childDocument->isWMLDocument()) + return childItem->url(); + } + } + + return item->url(); +} + +static bool tryAccessHistoryURLs(Page* page, KURL& previousURL, KURL& currentURL) +{ + if (!page) + return false; + + Frame* frame = page->mainFrame(); + if (!frame || !frame->document()) + return false; + + HistoryItem* previousItem = page->backForward()->backItem(); + if (!previousItem) + return false; + + HistoryItem* currentItem = page->backForward()->currentItem(); + if (!currentItem) + return false; + + previousURL = urlForHistoryItem(frame, previousItem); + currentURL = urlForHistoryItem(frame, currentItem); + + return true; +} + +bool WMLPageState::processAccessControlData(const String& domain, const String& path) +{ + if (m_hasAccessControlData) + return false; + + m_hasAccessControlData = true; + + KURL previousURL, currentURL; + if (!tryAccessHistoryURLs(m_page, previousURL, currentURL)) + return true; + + // Spec: The path attribute defaults to the value "/" + m_accessPath = path.isEmpty() ? "/" : path; + + // Spec: The domain attribute defaults to the current decks domain. + String previousHost = hostFromURL(previousURL); + m_accessDomain = domain.isEmpty() ? previousHost : normalizedHostName(domain); + + // Spec: To simplify the development of applications that may not know the absolute path to the + // current deck, the path attribute accepts relative URIs. The user agent converts the relative + // path to an absolute path and then performs prefix matching against the PATH attribute. + Document* document = m_page->mainFrame() ? m_page->mainFrame()->document() : 0; + if (document && previousHost == m_accessDomain && !m_accessPath.startsWith("/")) { + String currentPath = currentURL.path(); + + size_t index = currentPath.reverseFind('/'); + if (index != WTF::notFound) + m_accessPath = document->completeURL(currentPath.left(index + 1) + m_accessPath).path(); + } + + return true; +} + +void WMLPageState::resetAccessControlData() +{ + m_hasAccessControlData = false; + m_accessDomain = String(); + m_accessPath = String(); +} + +bool WMLPageState::canAccessDeck() const +{ + if (!m_hasAccessControlData) + return true; + + KURL previousURL, currentURL; + if (!tryAccessHistoryURLs(m_page, previousURL, currentURL)) + return true; + + if (equalIgnoringFragmentIdentifier(previousURL, currentURL)) + return true; + + return hostIsAllowedToAccess(hostFromURL(previousURL)) && pathIsAllowedToAccess(previousURL.path()); +} + +bool WMLPageState::hostIsAllowedToAccess(const String& host) const +{ + // Spec: The access domain is suffix-matched against the domain name portion of the referring URI + Vector<String> subdomainsAllowed; + if (m_accessDomain.contains('.')) + m_accessDomain.split('.', subdomainsAllowed); + else + subdomainsAllowed.append(m_accessDomain); + + Vector<String> subdomainsCheck; + if (host.contains('.')) + host.split('.', subdomainsCheck); + else + subdomainsCheck.append(host); + + Vector<String>::iterator itAllowed = subdomainsAllowed.end() - 1; + Vector<String>::iterator beginAllowed = subdomainsAllowed.begin(); + + Vector<String>::iterator itCheck = subdomainsCheck.end() - 1; + Vector<String>::iterator beginCheck = subdomainsCheck.begin(); + + bool hostOk = true; + for (; itAllowed >= beginAllowed && itCheck >= beginCheck; ) { + if (*itAllowed != *itCheck) { + hostOk = false; + break; + } + + --itAllowed; + --itCheck; + } + + return hostOk; +} + +bool WMLPageState::pathIsAllowedToAccess(const String& path) const +{ + // Spec: The access path is prefix matched against the path portion of the referring URI + Vector<String> subpathsAllowed; + if (m_accessPath.contains('/')) + m_accessPath.split('/', subpathsAllowed); + else + subpathsAllowed.append(m_accessPath); + + Vector<String> subpathsCheck; + if (path.contains('/')) + path.split('/', subpathsCheck); + else + subpathsCheck.append(path); + + Vector<String>::iterator itAllowed = subpathsAllowed.begin(); + Vector<String>::iterator endAllowed = subpathsAllowed.end(); + + Vector<String>::iterator itCheck = subpathsCheck.begin(); + Vector<String>::iterator endCheck = subpathsCheck.end(); + + bool pathOk = true; + for (; itAllowed != endAllowed && itCheck != endCheck; ) { + if (*itAllowed != *itCheck) { + pathOk = false; + break; + } + + ++itAllowed; + ++itCheck; + } + + return pathOk; +} + +} + +#endif |