1/* 2 * Copyright (C) 2011, Google Inc. All rights reserved. 3 * Copyright (C) 2012, Samsung Electronics. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 24 * DAMAGE. 25 */ 26 27#include "config.h" 28#include "NavigatorContentUtils.h" 29 30#if ENABLE(NAVIGATOR_CONTENT_UTILS) 31 32#include "Document.h" 33#include "ExceptionCode.h" 34#include "Frame.h" 35#include "Navigator.h" 36#include "Page.h" 37#include <wtf/HashSet.h> 38 39namespace WebCore { 40 41static HashSet<String>* protocolWhitelist; 42 43static void initProtocolHandlerWhitelist() 44{ 45 protocolWhitelist = new HashSet<String>; 46#if !PLATFORM(BLACKBERRY) 47 static const char* protocols[] = { 48 "irc", 49 "mailto", 50 "mms", 51 "news", 52 "nntp", 53 "sms", 54 "smsto", 55 "tel", 56 "urn", 57 "webcal", 58 }; 59 for (size_t i = 0; i < WTF_ARRAY_LENGTH(protocols); ++i) 60 protocolWhitelist->add(protocols[i]); 61#endif 62} 63 64static bool verifyCustomHandlerURL(const String& baseURL, const String& url, ExceptionCode& ec) 65{ 66 // The specification requires that it is a SYNTAX_ERR if the "%s" token is 67 // not present. 68 static const char token[] = "%s"; 69 int index = url.find(token); 70 if (-1 == index) { 71 ec = SYNTAX_ERR; 72 return false; 73 } 74 75 // It is also a SYNTAX_ERR if the custom handler URL, as created by removing 76 // the "%s" token and prepending the base url, does not resolve. 77 String newURL = url; 78 newURL.remove(index, WTF_ARRAY_LENGTH(token) - 1); 79 80 KURL base(ParsedURLString, baseURL); 81 KURL kurl(base, newURL); 82 83 if (kurl.isEmpty() || !kurl.isValid()) { 84 ec = SYNTAX_ERR; 85 return false; 86 } 87 88 return true; 89} 90 91static bool isProtocolWhitelisted(const String& scheme) 92{ 93 if (!protocolWhitelist) 94 initProtocolHandlerWhitelist(); 95 return protocolWhitelist->contains(scheme); 96} 97 98static bool verifyProtocolHandlerScheme(const String& scheme, ExceptionCode& ec) 99{ 100 if (scheme.startsWith("web+")) { 101 if (isValidProtocol(scheme)) 102 return true; 103 ec = SECURITY_ERR; 104 return false; 105 } 106 107 if (isProtocolWhitelisted(scheme)) 108 return true; 109 ec = SECURITY_ERR; 110 return false; 111} 112 113NavigatorContentUtils* NavigatorContentUtils::from(Page* page) 114{ 115 return static_cast<NavigatorContentUtils*>(RefCountedSupplement<Page, NavigatorContentUtils>::from(page, NavigatorContentUtils::supplementName())); 116} 117 118NavigatorContentUtils::~NavigatorContentUtils() 119{ 120} 121 122PassRefPtr<NavigatorContentUtils> NavigatorContentUtils::create(NavigatorContentUtilsClient* client) 123{ 124 return adoptRef(new NavigatorContentUtils(client)); 125} 126 127void NavigatorContentUtils::registerProtocolHandler(Navigator* navigator, const String& scheme, const String& url, const String& title, ExceptionCode& ec) 128{ 129 if (!navigator->frame()) 130 return; 131 132 Document* document = navigator->frame()->document(); 133 if (!document) 134 return; 135 136 String baseURL = document->baseURL().baseAsString(); 137 138 if (!verifyCustomHandlerURL(baseURL, url, ec)) 139 return; 140 141 if (!verifyProtocolHandlerScheme(scheme, ec)) 142 return; 143 144 NavigatorContentUtils::from(navigator->frame()->page())->client()->registerProtocolHandler(scheme, baseURL, url, navigator->frame()->displayStringModifiedByEncoding(title)); 145} 146 147#if ENABLE(CUSTOM_SCHEME_HANDLER) 148static String customHandlersStateString(const NavigatorContentUtilsClient::CustomHandlersState state) 149{ 150 DEFINE_STATIC_LOCAL(const String, newHandler, (ASCIILiteral("new"))); 151 DEFINE_STATIC_LOCAL(const String, registeredHandler, (ASCIILiteral("registered"))); 152 DEFINE_STATIC_LOCAL(const String, declinedHandler, (ASCIILiteral("declined"))); 153 154 switch (state) { 155 case NavigatorContentUtilsClient::CustomHandlersNew: 156 return newHandler; 157 case NavigatorContentUtilsClient::CustomHandlersRegistered: 158 return registeredHandler; 159 case NavigatorContentUtilsClient::CustomHandlersDeclined: 160 return declinedHandler; 161 } 162 163 ASSERT_NOT_REACHED(); 164 return String(); 165} 166 167String NavigatorContentUtils::isProtocolHandlerRegistered(Navigator* navigator, const String& scheme, const String& url, ExceptionCode& ec) 168{ 169 DEFINE_STATIC_LOCAL(const String, declined, ("declined")); 170 171 if (!navigator->frame()) 172 return declined; 173 174 Document* document = navigator->frame()->document(); 175 String baseURL = document->baseURL().baseAsString(); 176 177 if (!verifyCustomHandlerURL(baseURL, url, ec)) 178 return declined; 179 180 if (!verifyProtocolHandlerScheme(scheme, ec)) 181 return declined; 182 183 return customHandlersStateString(NavigatorContentUtils::from(navigator->frame()->page())->client()->isProtocolHandlerRegistered(scheme, baseURL, url)); 184} 185 186void NavigatorContentUtils::unregisterProtocolHandler(Navigator* navigator, const String& scheme, const String& url, ExceptionCode& ec) 187{ 188 if (!navigator->frame()) 189 return; 190 191 Document* document = navigator->frame()->document(); 192 String baseURL = document->baseURL().baseAsString(); 193 194 if (!verifyCustomHandlerURL(baseURL, url, ec)) 195 return; 196 197 if (!verifyProtocolHandlerScheme(scheme, ec)) 198 return; 199 200 NavigatorContentUtils::from(navigator->frame()->page())->client()->unregisterProtocolHandler(scheme, baseURL, url); 201} 202#endif 203 204const char* NavigatorContentUtils::supplementName() 205{ 206 return "NavigatorContentUtils"; 207} 208 209void provideNavigatorContentUtilsTo(Page* page, NavigatorContentUtilsClient* client) 210{ 211 RefCountedSupplement<Page, NavigatorContentUtils>::provideTo(page, NavigatorContentUtils::supplementName(), NavigatorContentUtils::create(client)); 212} 213 214} // namespace WebCore 215 216#endif // ENABLE(NAVIGATOR_CONTENT_UTILS) 217 218