• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WMLPageState(Page * page)38 WMLPageState::WMLPageState(Page* page)
39     : m_page(page)
40     , m_hasAccessControlData(false)
41 {
42 }
43 
~WMLPageState()44 WMLPageState::~WMLPageState()
45 {
46     m_variables.clear();
47 }
48 
49 #ifndef NDEBUG
50 // Debugging helper for use within gdb
dump()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 
reset()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 
normalizedHostName(const String & passedHost)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 
hostFromURL(const KURL & url)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 
urlForHistoryItem(Frame * frame,HistoryItem * item)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 
tryAccessHistoryURLs(Page * page,KURL & previousURL,KURL & currentURL)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 
processAccessControlData(const String & domain,const String & path)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 
resetAccessControlData()172 void WMLPageState::resetAccessControlData()
173 {
174     m_hasAccessControlData = false;
175     m_accessDomain = String();
176     m_accessPath = String();
177 }
178 
canAccessDeck() const179 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 
hostIsAllowedToAccess(const String & host) const194 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 
pathIsAllowedToAccess(const String & path) const229 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