1 /*
2 * Copyright (C) 2000 Harri Porten (porten@kde.org)
3 * Copyright (c) 2000 Daniel Molkentin (molkentin@kde.org)
4 * Copyright (c) 2000 Stefan Schimanski (schimmi@kde.org)
5 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "config.h"
24 #include "Navigator.h"
25
26 #include "Chrome.h"
27 #include "CookieJar.h"
28 #include "ExceptionCode.h"
29 #include "Frame.h"
30 #include "FrameLoader.h"
31 #include "FrameLoaderClient.h"
32 #include "Geolocation.h"
33 #include "KURL.h"
34 #include "Language.h"
35 #include "MimeTypeArray.h"
36 #include "Page.h"
37 #include "PageGroup.h"
38 #include "PlatformString.h"
39 #include "PluginArray.h"
40 #include "PluginData.h"
41 #include "ScriptController.h"
42 #include "Settings.h"
43 #include "StorageNamespace.h"
44
45 #if PLATFORM(ANDROID)
46 #include "ApplicationInstalledCallback.h"
47 #include "Connection.h"
48 #include "PackageNotifier.h"
49 #endif
50
51 namespace WebCore {
52
Navigator(Frame * frame)53 Navigator::Navigator(Frame* frame)
54 : m_frame(frame)
55 {
56 }
57
~Navigator()58 Navigator::~Navigator()
59 {
60 disconnectFrame();
61 }
62
disconnectFrame()63 void Navigator::disconnectFrame()
64 {
65 if (m_plugins) {
66 m_plugins->disconnectFrame();
67 m_plugins = 0;
68 }
69 if (m_mimeTypes) {
70 m_mimeTypes->disconnectFrame();
71 m_mimeTypes = 0;
72 }
73 if (m_geolocation) {
74 m_geolocation->disconnectFrame();
75 m_geolocation = 0;
76 }
77 m_frame = 0;
78 }
79
80 // If this function returns true, we need to hide the substring "4." that would otherwise
81 // appear in the appVersion string. This is to avoid problems with old versions of a
82 // library called OpenCube QuickMenu, which as of this writing is still being used on
83 // sites such as nwa.com -- the library thinks Safari is Netscape 4 if we don't do this!
shouldHideFourDot(Frame * frame)84 static bool shouldHideFourDot(Frame* frame)
85 {
86 const String* sourceURL = frame->script()->sourceURL();
87 if (!sourceURL)
88 return false;
89 if (!(sourceURL->endsWith("/dqm_script.js") || sourceURL->endsWith("/dqm_loader.js") || sourceURL->endsWith("/tdqm_loader.js")))
90 return false;
91 Settings* settings = frame->settings();
92 if (!settings)
93 return false;
94 return settings->needsSiteSpecificQuirks();
95 }
96
appVersion() const97 String Navigator::appVersion() const
98 {
99 if (!m_frame)
100 return String();
101 String appVersion = NavigatorBase::appVersion();
102 if (shouldHideFourDot(m_frame))
103 appVersion.replace("4.", "4_");
104 return appVersion;
105 }
106
language() const107 String Navigator::language() const
108 {
109 return defaultLanguage();
110 }
111
userAgent() const112 String Navigator::userAgent() const
113 {
114 if (!m_frame)
115 return String();
116
117 // If the frame is already detached, FrameLoader::userAgent may malfunction, because it calls a client method
118 // that uses frame's WebView (at least, in Mac WebKit).
119 if (!m_frame->page())
120 return String();
121
122 return m_frame->loader()->userAgent(m_frame->document()->url());
123 }
124
plugins() const125 PluginArray* Navigator::plugins() const
126 {
127 if (!m_plugins)
128 m_plugins = PluginArray::create(m_frame);
129 return m_plugins.get();
130 }
131
mimeTypes() const132 MimeTypeArray* Navigator::mimeTypes() const
133 {
134 if (!m_mimeTypes)
135 m_mimeTypes = MimeTypeArray::create(m_frame);
136 return m_mimeTypes.get();
137 }
138
cookieEnabled() const139 bool Navigator::cookieEnabled() const
140 {
141 if (!m_frame)
142 return false;
143
144 if (m_frame->page() && !m_frame->page()->cookieEnabled())
145 return false;
146
147 return cookiesEnabled(m_frame->document());
148 }
149
javaEnabled() const150 bool Navigator::javaEnabled() const
151 {
152 if (!m_frame || !m_frame->settings())
153 return false;
154
155 return m_frame->settings()->isJavaEnabled();
156 }
157
geolocation() const158 Geolocation* Navigator::geolocation() const
159 {
160 if (!m_geolocation)
161 m_geolocation = Geolocation::create(m_frame);
162 return m_geolocation.get();
163 }
164
165 #if PLATFORM(ANDROID)
connection() const166 Connection* Navigator::connection() const
167 {
168 if (!m_connection)
169 m_connection = Connection::create();
170 return m_connection.get();
171 }
172 #endif
173
174 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
175
isApplicationInstalled(const String & name,PassRefPtr<ApplicationInstalledCallback> callback)176 bool Navigator::isApplicationInstalled(const String& name, PassRefPtr<ApplicationInstalledCallback> callback)
177 {
178 if (m_applicationInstalledCallback)
179 return false;
180
181 m_applicationInstalledCallback = callback;
182 m_applicationNameQuery = name;
183
184 packageNotifier().requestPackageResult();
185
186 return true;
187 }
188
onPackageResult()189 void Navigator::onPackageResult()
190 {
191 if (m_applicationInstalledCallback) {
192 m_applicationInstalledCallback->handleEvent(packageNotifier().isPackageInstalled(m_applicationNameQuery));
193 m_applicationInstalledCallback = 0;
194 }
195 }
196 #endif
197
198 #if ENABLE(DOM_STORAGE)
getStorageUpdates()199 void Navigator::getStorageUpdates()
200 {
201 if (!m_frame)
202 return;
203
204 Page* page = m_frame->page();
205 if (!page)
206 return;
207
208 StorageNamespace* localStorage = page->group().localStorage();
209 if (localStorage)
210 localStorage->unlock();
211 }
212 #endif
213
verifyCustomHandlerURL(const String & baseURL,const String & url,ExceptionCode & ec)214 static bool verifyCustomHandlerURL(const String& baseURL, const String& url, ExceptionCode& ec)
215 {
216 // The specification requires that it is a SYNTAX_ERR if the the "%s" token is not present.
217 static const char token[] = "%s";
218 int index = url.find(token);
219 if (-1 == index) {
220 ec = SYNTAX_ERR;
221 return false;
222 }
223
224 // It is also a SYNTAX_ERR if the custom handler URL, as created by removing
225 // the "%s" token and prepending the base url, does not resolve.
226 String newURL = url;
227 newURL.remove(index, sizeof(token) / sizeof(token[0]));
228
229 KURL base(ParsedURLString, baseURL);
230 KURL kurl(base, newURL);
231
232 if (kurl.isEmpty() || !kurl.isValid()) {
233 ec = SYNTAX_ERR;
234 return false;
235 }
236
237 return true;
238 }
239
verifyProtocolHandlerScheme(const String & scheme,ExceptionCode & ec)240 static bool verifyProtocolHandlerScheme(const String& scheme, ExceptionCode& ec)
241 {
242 // It is a SECURITY_ERR for these schemes to be handled by a custom handler.
243 if (equalIgnoringCase(scheme, "http") || equalIgnoringCase(scheme, "https") || equalIgnoringCase(scheme, "file")) {
244 ec = SECURITY_ERR;
245 return false;
246 }
247 return true;
248 }
249
registerProtocolHandler(const String & scheme,const String & url,const String & title,ExceptionCode & ec)250 void Navigator::registerProtocolHandler(const String& scheme, const String& url, const String& title, ExceptionCode& ec)
251 {
252 if (!verifyProtocolHandlerScheme(scheme, ec))
253 return;
254
255 if (!m_frame)
256 return;
257
258 Document* document = m_frame->document();
259 if (!document)
260 return;
261
262 String baseURL = document->baseURL().baseAsString();
263
264 if (!verifyCustomHandlerURL(baseURL, url, ec))
265 return;
266
267 if (Page* page = m_frame->page())
268 page->chrome()->registerProtocolHandler(scheme, baseURL, url, m_frame->displayStringModifiedByEncoding(title));
269 }
270
verifyProtocolHandlerMimeType(const String & type,ExceptionCode & ec)271 static bool verifyProtocolHandlerMimeType(const String& type, ExceptionCode& ec)
272 {
273 // It is a SECURITY_ERR for these mime types to be assigned to a custom
274 // handler.
275 if (equalIgnoringCase(type, "text/html") || equalIgnoringCase(type, "text/css") || equalIgnoringCase(type, "application/x-javascript")) {
276 ec = SECURITY_ERR;
277 return false;
278 }
279 return true;
280 }
281
registerContentHandler(const String & mimeType,const String & url,const String & title,ExceptionCode & ec)282 void Navigator::registerContentHandler(const String& mimeType, const String& url, const String& title, ExceptionCode& ec)
283 {
284 if (!verifyProtocolHandlerMimeType(mimeType, ec))
285 return;
286
287 if (!m_frame)
288 return;
289
290 Document* document = m_frame->document();
291 if (!document)
292 return;
293
294 String baseURL = document->baseURL().baseAsString();
295
296 if (!verifyCustomHandlerURL(baseURL, url, ec))
297 return;
298
299 if (Page* page = m_frame->page())
300 page->chrome()->registerContentHandler(mimeType, baseURL, url, m_frame->displayStringModifiedByEncoding(title));
301 }
302
303 } // namespace WebCore
304