2 * Copyright (C) 2011, Google Inc. All rights reserved.
3 * Copyright (C) 2012, Samsung Electronics. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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
28 #include "modules/navigatorcontentutils/NavigatorContentUtils.h"
30 #include "bindings/v8/ExceptionState.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/ExceptionCode.h"
33 #include "core/frame/LocalFrame.h"
34 #include "core/frame/Navigator.h"
35 #include "core/page/Page.h"
36 #include "wtf/HashSet.h"
40 static HashSet<String>* protocolWhitelist;
42 static void initProtocolHandlerWhitelist()
44 protocolWhitelist = new HashSet<String>;
45 static const char* const protocols[] = {
66 for (size_t i = 0; i < WTF_ARRAY_LENGTH(protocols); ++i)
67 protocolWhitelist->add(protocols[i]);
70 static bool verifyCustomHandlerURL(const KURL& baseURL, const String& url, ExceptionState& exceptionState)
72 // The specification requires that it is a SyntaxError if the "%s" token is
74 static const char token[] = "%s";
75 int index = url.find(token);
77 exceptionState.throwDOMException(SyntaxError, "The url provided ('" + url + "') does not contain '%s'.");
81 // It is also a SyntaxError if the custom handler URL, as created by removing
82 // the "%s" token and prepending the base url, does not resolve.
84 newURL.remove(index, WTF_ARRAY_LENGTH(token) - 1);
86 KURL kurl(baseURL, newURL);
88 if (kurl.isEmpty() || !kurl.isValid()) {
89 exceptionState.throwDOMException(SyntaxError, "The custom handler URL created by removing '%s' and prepending '" + baseURL.string() + "' is invalid.");
96 static bool isProtocolWhitelisted(const String& scheme)
98 if (!protocolWhitelist)
99 initProtocolHandlerWhitelist();
100 return protocolWhitelist->contains(scheme);
103 static bool verifyProtocolHandlerScheme(const String& scheme, const String& method, ExceptionState& exceptionState)
105 if (scheme.startsWith("web+")) {
106 // The specification requires that the length of scheme is at least five characteres (including 'web+' prefix).
107 if (scheme.length() >= 5 && isValidProtocol(scheme))
109 if (!isValidProtocol(scheme))
110 exceptionState.throwSecurityError("The scheme '" + scheme + "' is not a valid protocol.");
112 exceptionState.throwSecurityError("The scheme '" + scheme + "' is less than five characters long.");
116 if (isProtocolWhitelisted(scheme))
118 exceptionState.throwSecurityError("The scheme '" + scheme + "' doesn't belong to the protocol whitelist. Please prefix non-whitelisted schemes with the string 'web+'.");
122 NavigatorContentUtils* NavigatorContentUtils::from(Page& page)
124 return static_cast<NavigatorContentUtils*>(WillBeHeapSupplement<Page>::from(page, supplementName()));
127 NavigatorContentUtils::~NavigatorContentUtils()
131 PassOwnPtrWillBeRawPtr<NavigatorContentUtils> NavigatorContentUtils::create(PassOwnPtr<NavigatorContentUtilsClient> client)
133 return adoptPtrWillBeNoop(new NavigatorContentUtils(client));
136 void NavigatorContentUtils::registerProtocolHandler(Navigator& navigator, const String& scheme, const String& url, const String& title, ExceptionState& exceptionState)
138 if (!navigator.frame())
141 ASSERT(navigator.frame()->document());
142 KURL baseURL = navigator.frame()->document()->baseURL();
144 if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
147 if (!verifyProtocolHandlerScheme(scheme, "registerProtocolHandler", exceptionState))
150 ASSERT(navigator.frame()->page());
151 NavigatorContentUtils::from(*navigator.frame()->page())->client()->registerProtocolHandler(scheme, baseURL, KURL(ParsedURLString, url), title);
154 static String customHandlersStateString(const NavigatorContentUtilsClient::CustomHandlersState state)
156 DEFINE_STATIC_LOCAL(const String, newHandler, ("new"));
157 DEFINE_STATIC_LOCAL(const String, registeredHandler, ("registered"));
158 DEFINE_STATIC_LOCAL(const String, declinedHandler, ("declined"));
161 case NavigatorContentUtilsClient::CustomHandlersNew:
163 case NavigatorContentUtilsClient::CustomHandlersRegistered:
164 return registeredHandler;
165 case NavigatorContentUtilsClient::CustomHandlersDeclined:
166 return declinedHandler;
169 ASSERT_NOT_REACHED();
173 String NavigatorContentUtils::isProtocolHandlerRegistered(Navigator& navigator, const String& scheme, const String& url, ExceptionState& exceptionState)
175 DEFINE_STATIC_LOCAL(const String, declined, ("declined"));
177 if (!navigator.frame())
180 Document* document = navigator.frame()->document();
182 if (document->activeDOMObjectsAreStopped())
185 KURL baseURL = document->baseURL();
187 if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
190 if (!verifyProtocolHandlerScheme(scheme, "isProtocolHandlerRegistered", exceptionState))
193 ASSERT(navigator.frame()->page());
194 return customHandlersStateString(NavigatorContentUtils::from(*navigator.frame()->page())->client()->isProtocolHandlerRegistered(scheme, baseURL, KURL(ParsedURLString, url)));
197 void NavigatorContentUtils::unregisterProtocolHandler(Navigator& navigator, const String& scheme, const String& url, ExceptionState& exceptionState)
199 if (!navigator.frame())
202 ASSERT(navigator.frame()->document());
203 KURL baseURL = navigator.frame()->document()->baseURL();
205 if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
208 if (!verifyProtocolHandlerScheme(scheme, "unregisterProtocolHandler", exceptionState))
211 ASSERT(navigator.frame()->page());
212 NavigatorContentUtils::from(*navigator.frame()->page())->client()->unregisterProtocolHandler(scheme, baseURL, KURL(ParsedURLString, url));
215 const char* NavigatorContentUtils::supplementName()
217 return "NavigatorContentUtils";
220 void provideNavigatorContentUtilsTo(Page& page, PassOwnPtr<NavigatorContentUtilsClient> client)
222 NavigatorContentUtils::provideTo(page, NavigatorContentUtils::supplementName(), NavigatorContentUtils::create(client));
225 } // namespace WebCore