NavigatorContentUtils.cpp [plain text]
#include "config.h"
#include "NavigatorContentUtils.h"
#if ENABLE(NAVIGATOR_CONTENT_UTILS)
#include "Document.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "Navigator.h"
#include "Page.h"
#include <wtf/HashSet.h>
#include <wtf/NeverDestroyed.h>
namespace WebCore {
static HashSet<String>* protocolWhitelist;
static void initProtocolHandlerWhitelist()
{
protocolWhitelist = new HashSet<String>;
for (auto* protocol : { "bitcoin", "geo", "im", "irc", "ircs", "magnet", "mailto", "mms", "news", "nntp", "sip", "sms", "smsto", "ssh", "tel", "urn", "webcal", "wtai", "xmpp" })
protocolWhitelist->add(protocol);
}
static bool verifyCustomHandlerURL(const URL& baseURL, const String& url, ExceptionCode& ec)
{
static const char token[] = "%s";
int index = url.find(token);
if (-1 == index) {
ec = SYNTAX_ERR;
return false;
}
String newURL = url;
newURL.remove(index, WTF_ARRAY_LENGTH(token) - 1);
URL kurl(baseURL, newURL);
if (kurl.isEmpty() || !kurl.isValid()) {
ec = SYNTAX_ERR;
return false;
}
return true;
}
static bool isProtocolWhitelisted(const String& scheme)
{
if (!protocolWhitelist)
initProtocolHandlerWhitelist();
return protocolWhitelist->contains(scheme.convertToASCIILowercase());
}
static bool verifyProtocolHandlerScheme(const String& scheme, ExceptionCode& ec)
{
if (isProtocolWhitelisted(scheme))
return true;
if (scheme.startsWith("web+")) {
if (scheme.length() >= 5 && isValidProtocol(scheme))
return true;
}
ec = SECURITY_ERR;
return false;
}
NavigatorContentUtils* NavigatorContentUtils::from(Page* page)
{
return static_cast<NavigatorContentUtils*>(Supplement<Page>::from(page, supplementName()));
}
NavigatorContentUtils::~NavigatorContentUtils()
{
}
void NavigatorContentUtils::registerProtocolHandler(Navigator* navigator, const String& scheme, const String& url, const String& title, ExceptionCode& ec)
{
if (!navigator->frame())
return;
URL baseURL = navigator->frame()->document()->baseURL();
if (!verifyCustomHandlerURL(baseURL, url, ec))
return;
if (!verifyProtocolHandlerScheme(scheme, ec))
return;
NavigatorContentUtils::from(navigator->frame()->page())->client()->registerProtocolHandler(scheme, baseURL, URL(ParsedURLString, url), navigator->frame()->displayStringModifiedByEncoding(title));
}
#if ENABLE(CUSTOM_SCHEME_HANDLER)
static String customHandlersStateString(const NavigatorContentUtilsClient::CustomHandlersState state)
{
static NeverDestroyed<String> newHandler(ASCIILiteral("new"));
static NeverDestroyed<String> registeredHandler(ASCIILiteral("registered"));
static NeverDestroyed<String> declinedHandler(ASCIILiteral("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, ExceptionCode& ec)
{
static NeverDestroyed<String> declined(ASCIILiteral("declined"));
if (!navigator->frame())
return declined;
URL baseURL = navigator->frame()->document()->baseURL();
if (!verifyCustomHandlerURL(baseURL, url, ec))
return declined;
if (!verifyProtocolHandlerScheme(scheme, ec))
return declined;
return customHandlersStateString(NavigatorContentUtils::from(navigator->frame()->page())->client()->isProtocolHandlerRegistered(scheme, baseURL, URL(ParsedURLString, url)));
}
void NavigatorContentUtils::unregisterProtocolHandler(Navigator* navigator, const String& scheme, const String& url, ExceptionCode& ec)
{
if (!navigator->frame())
return;
URL baseURL = navigator->frame()->document()->baseURL();
if (!verifyCustomHandlerURL(baseURL, url, ec))
return;
if (!verifyProtocolHandlerScheme(scheme, ec))
return;
NavigatorContentUtils::from(navigator->frame()->page())->client()->unregisterProtocolHandler(scheme, baseURL, URL(ParsedURLString, url));
}
#endif
const char* NavigatorContentUtils::supplementName()
{
return "NavigatorContentUtils";
}
void provideNavigatorContentUtilsTo(Page* page, std::unique_ptr<NavigatorContentUtilsClient> client)
{
NavigatorContentUtils::provideTo(page, NavigatorContentUtils::supplementName(), std::make_unique<NavigatorContentUtils>(WTF::move(client)));
}
}
#endif // ENABLE(NAVIGATOR_CONTENT_UTILS)