|
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 "Document.h" |
|
29 #include "Frame.h" |
|
30 #include "HistoryItem.h" |
|
31 #include "KURL.h" |
|
32 #include "Page.h" |
|
33 #include <wtf/text/CString.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 |