Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / navigatorcontentutils / NavigatorContentUtils.cpp
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 #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"
37
38 namespace WebCore {
39
40 static HashSet<String>* protocolWhitelist;
41
42 static void initProtocolHandlerWhitelist()
43 {
44     protocolWhitelist = new HashSet<String>;
45     static const char* const protocols[] = {
46         "bitcoin",
47         "geo",
48         "im",
49         "irc",
50         "ircs",
51         "magnet",
52         "mailto",
53         "mms",
54         "news",
55         "nntp",
56         "sip",
57         "sms",
58         "smsto",
59         "ssh",
60         "tel",
61         "urn",
62         "webcal",
63         "wtai",
64         "xmpp",
65     };
66     for (size_t i = 0; i < WTF_ARRAY_LENGTH(protocols); ++i)
67         protocolWhitelist->add(protocols[i]);
68 }
69
70 static bool verifyCustomHandlerURL(const KURL& baseURL, const String& url, ExceptionState& exceptionState)
71 {
72     // The specification requires that it is a SyntaxError if the "%s" token is
73     // not present.
74     static const char token[] = "%s";
75     int index = url.find(token);
76     if (-1 == index) {
77         exceptionState.throwDOMException(SyntaxError, "The url provided ('" + url + "') does not contain '%s'.");
78         return false;
79     }
80
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.
83     String newURL = url;
84     newURL.remove(index, WTF_ARRAY_LENGTH(token) - 1);
85
86     KURL kurl(baseURL, newURL);
87
88     if (kurl.isEmpty() || !kurl.isValid()) {
89         exceptionState.throwDOMException(SyntaxError, "The custom handler URL created by removing '%s' and prepending '" + baseURL.string() + "' is invalid.");
90         return false;
91     }
92
93     return true;
94 }
95
96 static bool isProtocolWhitelisted(const String& scheme)
97 {
98     if (!protocolWhitelist)
99         initProtocolHandlerWhitelist();
100     return protocolWhitelist->contains(scheme);
101 }
102
103 static bool verifyProtocolHandlerScheme(const String& scheme, const String& method, ExceptionState& exceptionState)
104 {
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))
108             return true;
109         if (!isValidProtocol(scheme))
110             exceptionState.throwSecurityError("The scheme '" + scheme + "' is not a valid protocol.");
111         else
112             exceptionState.throwSecurityError("The scheme '" + scheme + "' is less than five characters long.");
113         return false;
114     }
115
116     if (isProtocolWhitelisted(scheme))
117         return true;
118     exceptionState.throwSecurityError("The scheme '" + scheme + "' doesn't belong to the protocol whitelist. Please prefix non-whitelisted schemes with the string 'web+'.");
119     return false;
120 }
121
122 NavigatorContentUtils* NavigatorContentUtils::from(Page& page)
123 {
124     return static_cast<NavigatorContentUtils*>(WillBeHeapSupplement<Page>::from(page, supplementName()));
125 }
126
127 NavigatorContentUtils::~NavigatorContentUtils()
128 {
129 }
130
131 PassOwnPtrWillBeRawPtr<NavigatorContentUtils> NavigatorContentUtils::create(PassOwnPtr<NavigatorContentUtilsClient> client)
132 {
133     return adoptPtrWillBeNoop(new NavigatorContentUtils(client));
134 }
135
136 void NavigatorContentUtils::registerProtocolHandler(Navigator& navigator, const String& scheme, const String& url, const String& title, ExceptionState& exceptionState)
137 {
138     if (!navigator.frame())
139         return;
140
141     ASSERT(navigator.frame()->document());
142     KURL baseURL = navigator.frame()->document()->baseURL();
143
144     if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
145         return;
146
147     if (!verifyProtocolHandlerScheme(scheme, "registerProtocolHandler", exceptionState))
148         return;
149
150     ASSERT(navigator.frame()->page());
151     NavigatorContentUtils::from(*navigator.frame()->page())->client()->registerProtocolHandler(scheme, baseURL, KURL(ParsedURLString, url), title);
152 }
153
154 static String customHandlersStateString(const NavigatorContentUtilsClient::CustomHandlersState state)
155 {
156     DEFINE_STATIC_LOCAL(const String, newHandler, ("new"));
157     DEFINE_STATIC_LOCAL(const String, registeredHandler, ("registered"));
158     DEFINE_STATIC_LOCAL(const String, declinedHandler, ("declined"));
159
160     switch (state) {
161     case NavigatorContentUtilsClient::CustomHandlersNew:
162         return newHandler;
163     case NavigatorContentUtilsClient::CustomHandlersRegistered:
164         return registeredHandler;
165     case NavigatorContentUtilsClient::CustomHandlersDeclined:
166         return declinedHandler;
167     }
168
169     ASSERT_NOT_REACHED();
170     return String();
171 }
172
173 String NavigatorContentUtils::isProtocolHandlerRegistered(Navigator& navigator, const String& scheme, const String& url, ExceptionState& exceptionState)
174 {
175     DEFINE_STATIC_LOCAL(const String, declined, ("declined"));
176
177     if (!navigator.frame())
178         return declined;
179
180     Document* document = navigator.frame()->document();
181     ASSERT(document);
182     if (document->activeDOMObjectsAreStopped())
183         return declined;
184
185     KURL baseURL = document->baseURL();
186
187     if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
188         return declined;
189
190     if (!verifyProtocolHandlerScheme(scheme, "isProtocolHandlerRegistered", exceptionState))
191         return declined;
192
193     ASSERT(navigator.frame()->page());
194     return customHandlersStateString(NavigatorContentUtils::from(*navigator.frame()->page())->client()->isProtocolHandlerRegistered(scheme, baseURL, KURL(ParsedURLString, url)));
195 }
196
197 void NavigatorContentUtils::unregisterProtocolHandler(Navigator& navigator, const String& scheme, const String& url, ExceptionState& exceptionState)
198 {
199     if (!navigator.frame())
200         return;
201
202     ASSERT(navigator.frame()->document());
203     KURL baseURL = navigator.frame()->document()->baseURL();
204
205     if (!verifyCustomHandlerURL(baseURL, url, exceptionState))
206         return;
207
208     if (!verifyProtocolHandlerScheme(scheme, "unregisterProtocolHandler", exceptionState))
209         return;
210
211     ASSERT(navigator.frame()->page());
212     NavigatorContentUtils::from(*navigator.frame()->page())->client()->unregisterProtocolHandler(scheme, baseURL, KURL(ParsedURLString, url));
213 }
214
215 const char* NavigatorContentUtils::supplementName()
216 {
217     return "NavigatorContentUtils";
218 }
219
220 void provideNavigatorContentUtilsTo(Page& page, PassOwnPtr<NavigatorContentUtilsClient> client)
221 {
222     NavigatorContentUtils::provideTo(page, NavigatorContentUtils::supplementName(), NavigatorContentUtils::create(client));
223 }
224
225 } // namespace WebCore