| /* |
| * 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 |