1 /* 2 * Copyright (C) 2000 Harri Porten (porten (at) kde.org) 3 * Copyright (c) 2000 Daniel Molkentin (molkentin (at) kde.org) 4 * Copyright (c) 2000 Stefan Schimanski (schimmi (at) 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 53 Navigator::Navigator(Frame* frame) 54 : m_frame(frame) 55 { 56 } 57 58 Navigator::~Navigator() 59 { 60 disconnectFrame(); 61 } 62 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! 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 97 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 107 String Navigator::language() const 108 { 109 return defaultLanguage(); 110 } 111 112 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 125 PluginArray* Navigator::plugins() const 126 { 127 if (!m_plugins) 128 m_plugins = PluginArray::create(m_frame); 129 return m_plugins.get(); 130 } 131 132 MimeTypeArray* Navigator::mimeTypes() const 133 { 134 if (!m_mimeTypes) 135 m_mimeTypes = MimeTypeArray::create(m_frame); 136 return m_mimeTypes.get(); 137 } 138 139 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 150 bool Navigator::javaEnabled() const 151 { 152 if (!m_frame || !m_frame->settings()) 153 return false; 154 155 return m_frame->settings()->isJavaEnabled(); 156 } 157 158 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) 166 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 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 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) 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 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 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 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 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 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