Home | History | Annotate | Download | only in navigatorcontentutils
      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 "modules/navigatorcontentutils/NavigatorContentUtils.h"
     29 
     30 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
     31 
     32 #include "bindings/v8/ExceptionState.h"
     33 #include "core/dom/Document.h"
     34 #include "core/dom/ExceptionCode.h"
     35 #include "core/page/Frame.h"
     36 #include "core/page/Navigator.h"
     37 #include "core/page/Page.h"
     38 #include "wtf/HashSet.h"
     39 
     40 namespace WebCore {
     41 
     42 static HashSet<String>* protocolWhitelist;
     43 
     44 static void initProtocolHandlerWhitelist()
     45 {
     46     protocolWhitelist = new HashSet<String>;
     47     static const char* protocols[] = {
     48         "bitcoin",
     49         "geo",
     50         "im",
     51         "irc",
     52         "ircs",
     53         "magnet",
     54         "mailto",
     55         "mms",
     56         "news",
     57         "nntp",
     58         "sip",
     59         "sms",
     60         "smsto",
     61         "ssh",
     62         "tel",
     63         "urn",
     64         "webcal",
     65         "webtai",
     66         "xmpp",
     67     };
     68     for (size_t i = 0; i < WTF_ARRAY_LENGTH(protocols); ++i)
     69         protocolWhitelist->add(protocols[i]);
     70 }
     71 
     72 static bool verifyCustomHandlerURL(const String& baseURL, const String& url, ExceptionState& es)
     73 {
     74     // The specification requires that it is a SyntaxError if the "%s" token is
     75     // not present.
     76     static const char token[] = "%s";
     77     int index = url.find(token);
     78     if (-1 == index) {
     79         es.throwDOMException(SyntaxError);
     80         return false;
     81     }
     82 
     83     // It is also a SyntaxError if the custom handler URL, as created by removing
     84     // the "%s" token and prepending the base url, does not resolve.
     85     String newURL = url;
     86     newURL.remove(index, WTF_ARRAY_LENGTH(token) - 1);
     87 
     88     KURL base(ParsedURLString, baseURL);
     89     KURL kurl(base, newURL);
     90 
     91     if (kurl.isEmpty() || !kurl.isValid()) {
     92         es.throwDOMException(SyntaxError);
     93         return false;
     94     }
     95 
     96     return true;
     97 }
     98 
     99 static bool isProtocolWhitelisted(const String& scheme)
    100 {
    101     if (!protocolWhitelist)
    102         initProtocolHandlerWhitelist();
    103     return protocolWhitelist->contains(scheme);
    104 }
    105 
    106 static bool verifyProtocolHandlerScheme(const String& scheme, ExceptionState& es)
    107 {
    108     if (scheme.startsWith("web+")) {
    109         if (isValidProtocol(scheme))
    110             return true;
    111         es.throwDOMException(SecurityError);
    112         return false;
    113     }
    114 
    115     if (isProtocolWhitelisted(scheme))
    116         return true;
    117     es.throwDOMException(SecurityError);
    118     return false;
    119 }
    120 
    121 NavigatorContentUtils* NavigatorContentUtils::from(Page* page)
    122 {
    123     return static_cast<NavigatorContentUtils*>(RefCountedSupplement<Page, NavigatorContentUtils>::from(page, NavigatorContentUtils::supplementName()));
    124 }
    125 
    126 NavigatorContentUtils::~NavigatorContentUtils()
    127 {
    128 }
    129 
    130 PassRefPtr<NavigatorContentUtils> NavigatorContentUtils::create(NavigatorContentUtilsClient* client)
    131 {
    132     return adoptRef(new NavigatorContentUtils(client));
    133 }
    134 
    135 void NavigatorContentUtils::registerProtocolHandler(Navigator* navigator, const String& scheme, const String& url, const String& title, ExceptionState& es)
    136 {
    137     if (!navigator->frame())
    138         return;
    139 
    140     Document* document = navigator->frame()->document();
    141     if (!document)
    142         return;
    143 
    144     String baseURL = document->baseURL().baseAsString();
    145 
    146     if (!verifyCustomHandlerURL(baseURL, url, es))
    147         return;
    148 
    149     if (!verifyProtocolHandlerScheme(scheme, es))
    150         return;
    151 
    152     NavigatorContentUtils::from(navigator->frame()->page())->client()->registerProtocolHandler(scheme, baseURL, url, navigator->frame()->displayStringModifiedByEncoding(title));
    153 }
    154 
    155 #if ENABLE(CUSTOM_SCHEME_HANDLER)
    156 static String customHandlersStateString(const NavigatorContentUtilsClient::CustomHandlersState state)
    157 {
    158     DEFINE_STATIC_LOCAL(const String, newHandler, ("new"));
    159     DEFINE_STATIC_LOCAL(const String, registeredHandler, ("registered"));
    160     DEFINE_STATIC_LOCAL(const String, declinedHandler, ("declined"));
    161 
    162     switch (state) {
    163     case NavigatorContentUtilsClient::CustomHandlersNew:
    164         return newHandler;
    165     case NavigatorContentUtilsClient::CustomHandlersRegistered:
    166         return registeredHandler;
    167     case NavigatorContentUtilsClient::CustomHandlersDeclined:
    168         return declinedHandler;
    169     }
    170 
    171     ASSERT_NOT_REACHED();
    172     return String();
    173 }
    174 
    175 String NavigatorContentUtils::isProtocolHandlerRegistered(Navigator* navigator, const String& scheme, const String& url, ExceptionState& es)
    176 {
    177     DEFINE_STATIC_LOCAL(const String, declined, ("declined"));
    178 
    179     if (!navigator->frame())
    180         return declined;
    181 
    182     Document* document = navigator->frame()->document();
    183     String baseURL = document->baseURL().baseAsString();
    184 
    185     if (!verifyCustomHandlerURL(baseURL, url, es))
    186         return declined;
    187 
    188     if (!verifyProtocolHandlerScheme(scheme, es))
    189         return declined;
    190 
    191     return customHandlersStateString(NavigatorContentUtils::from(navigator->frame()->page())->client()->isProtocolHandlerRegistered(scheme, baseURL, url));
    192 }
    193 
    194 void NavigatorContentUtils::unregisterProtocolHandler(Navigator* navigator, const String& scheme, const String& url, ExceptionState& es)
    195 {
    196     if (!navigator->frame())
    197         return;
    198 
    199     Document* document = navigator->frame()->document();
    200     String baseURL = document->baseURL().baseAsString();
    201 
    202     if (!verifyCustomHandlerURL(baseURL, url, es))
    203         return;
    204 
    205     if (!verifyProtocolHandlerScheme(scheme, es))
    206         return;
    207 
    208     NavigatorContentUtils::from(navigator->frame()->page())->client()->unregisterProtocolHandler(scheme, baseURL, url);
    209 }
    210 #endif
    211 
    212 const char* NavigatorContentUtils::supplementName()
    213 {
    214     return "NavigatorContentUtils";
    215 }
    216 
    217 void provideNavigatorContentUtilsTo(Page* page, NavigatorContentUtilsClient* client)
    218 {
    219     RefCountedSupplement<Page, NavigatorContentUtils>::provideTo(page, NavigatorContentUtils::supplementName(), NavigatorContentUtils::create(client));
    220 }
    221 
    222 } // namespace WebCore
    223 
    224 #endif // ENABLE(NAVIGATOR_CONTENT_UTILS)
    225 
    226