This source file includes following definitions.
- initProtocolHandlerWhitelist
- verifyCustomHandlerURL
- isProtocolWhitelisted
- verifyProtocolHandlerScheme
- from
- create
- registerProtocolHandler
- customHandlersStateString
- isProtocolHandlerRegistered
- unregisterProtocolHandler
- supplementName
- provideNavigatorContentUtilsTo
#include "config.h"
#include "modules/navigatorcontentutils/NavigatorContentUtils.h"
#include "bindings/v8/ExceptionState.h"
#include "core/dom/Document.h"
#include "core/dom/ExceptionCode.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Navigator.h"
#include "core/page/Page.h"
#include "wtf/HashSet.h"
namespace WebCore {
static HashSet<String>* protocolWhitelist;
static void initProtocolHandlerWhitelist()
{
protocolWhitelist = new HashSet<String>;
static const char* const protocols[] = {
"bitcoin",
"geo",
"im",
"irc",
"ircs",
"magnet",
"mailto",
"mms",
"news",
"nntp",
"sip",
"sms",
"smsto",
"ssh",
"tel",
"urn",
"webcal",
"wtai",
"xmpp",
};
for (size_t i = 0; i < WTF_ARRAY_LENGTH(protocols); ++i)
protocolWhitelist->add(protocols[i]);
}
static bool verifyCustomHandlerURL(const KURL& baseURL, const String& url, ExceptionState& exceptionState)
{
static const char token[] = "%s";
int index = url.find(token);
if (-1 == index) {
exceptionState.throwDOMException(SyntaxError, "The url provided ('" + url + "') does not contain '%s'.");
return false;
}
String newURL = url;
newURL.remove(index, WTF_ARRAY_LENGTH(token) - 1);
KURL kurl(baseURL, newURL);
if (kurl.isEmpty() || !kurl.isValid()) {
exceptionState.throwDOMException(SyntaxError, "The custom handler URL created by removing '%s' and prepending '" + baseURL.string() + "' is invalid.");
return false;
}
return true;
}
static bool isProtocolWhitelisted(const String& scheme)
{
if (!protocolWhitelist)
initProtocolHandlerWhitelist();
return protocolWhitelist->contains(scheme);
}
static bool verifyProtocolHandlerScheme(const String& scheme, const String& method, ExceptionState& exceptionState)
{
if (scheme.startsWith("web+")) {
if (scheme.length() >= 5 && isValidProtocol(scheme))
return true;
if (!isValidProtocol(scheme))
exceptionState.throwSecurityError("The scheme '" + scheme + "' is not a valid protocol.");
else
exceptionState.throwSecurityError("The scheme '" + scheme + "' is less than five characters long.");
return false;
}
if (isProtocolWhitelisted(scheme))
return true;
exceptionState.throwSecurityError("The scheme '" + scheme + "' doesn't belong to the protocol whitelist. Please prefix non-whitelisted schemes with the string 'web+'.");
return false;
}
NavigatorContentUtils* NavigatorContentUtils::from(Page& page)
{
return static_cast<NavigatorContentUtils*>(RefCountedSupplement<Page, NavigatorContentUtils>::from(page, NavigatorContentUtils::supplementName()));
}
NavigatorContentUtils::~NavigatorContentUtils()
{
}
PassRefPtr<NavigatorContentUtils> NavigatorContentUtils::create(PassOwnPtr<NavigatorContentUtilsClient> client)
{
return adoptRef(new NavigatorContentUtils(client));
}
void NavigatorContentUtils::registerProtocolHandler(Navigator& navigator, const String& scheme, const String& url, const String& title, ExceptionState& exceptionState)
{
if (!navigator.frame())
return;
Document* document = navigator.frame()->document();
if (!document)
return;
KURL baseURL = document->baseURL();
if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
return;
if (!verifyProtocolHandlerScheme(scheme, "registerProtocolHandler", exceptionState))
return;
ASSERT(navigator.frame()->page());
NavigatorContentUtils::from(*navigator.frame()->page())->client()->registerProtocolHandler(scheme, baseURL, KURL(ParsedURLString, url), title);
}
static String customHandlersStateString(const NavigatorContentUtilsClient::CustomHandlersState state)
{
DEFINE_STATIC_LOCAL(const String, newHandler, ("new"));
DEFINE_STATIC_LOCAL(const String, registeredHandler, ("registered"));
DEFINE_STATIC_LOCAL(const String, declinedHandler, ("declined"));
switch (state) {
case NavigatorContentUtilsClient::CustomHandlersNew:
return newHandler;
case NavigatorContentUtilsClient::CustomHandlersRegistered:
return registeredHandler;
case NavigatorContentUtilsClient::CustomHandlersDeclined:
return declinedHandler;
}
ASSERT_NOT_REACHED();
return String();
}
String NavigatorContentUtils::isProtocolHandlerRegistered(Navigator& navigator, const String& scheme, const String& url, ExceptionState& exceptionState)
{
DEFINE_STATIC_LOCAL(const String, declined, ("declined"));
if (!navigator.frame())
return declined;
Document* document = navigator.frame()->document();
KURL baseURL = document->baseURL();
if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
return declined;
if (!verifyProtocolHandlerScheme(scheme, "isProtocolHandlerRegistered", exceptionState))
return declined;
ASSERT(navigator.frame()->page());
return customHandlersStateString(NavigatorContentUtils::from(*navigator.frame()->page())->client()->isProtocolHandlerRegistered(scheme, baseURL, KURL(ParsedURLString, url)));
}
void NavigatorContentUtils::unregisterProtocolHandler(Navigator& navigator, const String& scheme, const String& url, ExceptionState& exceptionState)
{
if (!navigator.frame())
return;
Document* document = navigator.frame()->document();
KURL baseURL = document->baseURL();
if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
return;
if (!verifyProtocolHandlerScheme(scheme, "unregisterProtocolHandler", exceptionState))
return;
ASSERT(navigator.frame()->page());
NavigatorContentUtils::from(*navigator.frame()->page())->client()->unregisterProtocolHandler(scheme, baseURL, KURL(ParsedURLString, url));
}
const char* NavigatorContentUtils::supplementName()
{
return "NavigatorContentUtils";
}
void provideNavigatorContentUtilsTo(Page& page, PassOwnPtr<NavigatorContentUtilsClient> client)
{
RefCountedSupplement<Page, NavigatorContentUtils>::provideTo(page, NavigatorContentUtils::supplementName(), NavigatorContentUtils::create(client));
}
}