#include "config.h"
#if ENABLE(WML)
#include "WMLPageState.h"
#include "BackForwardList.h"
#include "CString.h"
#include "Document.h"
#include "Frame.h"
#include "HistoryItem.h"
#include "KURL.h"
#include "Page.h"
namespace WebCore {
WMLPageState::WMLPageState(Page* page)
: m_page(page)
, m_hasAccessControlData(false)
{
}
WMLPageState::~WMLPageState()
{
m_variables.clear();
}
#ifndef NDEBUG
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()
{
m_variables.clear();
if (BackForwardList* list = m_page ? m_page->backForwardList() : 0)
list->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)
{
String host = normalizedHostName(url.host());
return host.isEmpty() ? "localhost" : host;
}
static KURL urlForHistoryItem(Frame* frame, HistoryItem* item)
{
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;
BackForwardList* list = page->backForwardList();
if (!list)
return false;
HistoryItem* previousItem = list->backItem();
if (!previousItem)
return false;
HistoryItem* currentItem = list->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;
m_accessPath = path.isEmpty() ? "/" : path;
String previousHost = hostFromURL(previousURL);
m_accessDomain = domain.isEmpty() ? previousHost : normalizedHostName(domain);
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
{
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
{
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