Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / 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 "NavigatorContentUtils.h"
29
30 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
31
32 #include "Document.h"
33 #include "ExceptionCode.h"
34 #include "Frame.h"
35 #include "Navigator.h"
36 #include "Page.h"
37 #include <wtf/HashSet.h>
38 #include <wtf/NeverDestroyed.h>
39
40 namespace WebCore {
41
42 static HashSet<String>* protocolWhitelist;
43
44 static void initProtocolHandlerWhitelist()
45 {
46     protocolWhitelist = new HashSet<String>;
47     for (auto* protocol : { "bitcoin", "geo", "im", "irc", "ircs", "magnet", "mailto", "mms", "news", "nntp", "sip", "sms", "smsto", "ssh", "tel", "urn", "webcal", "wtai", "xmpp" })
48         protocolWhitelist->add(protocol);
49 }
50
51 static bool verifyCustomHandlerURL(const URL& baseURL, const String& url, ExceptionCode& ec)
52 {
53     // The specification requires that it is a SYNTAX_ERR if the "%s" token is
54     // not present.
55     static const char token[] = "%s";
56     int index = url.find(token);
57     if (-1 == index) {
58         ec = SYNTAX_ERR;
59         return false;
60     }
61
62     // It is also a SYNTAX_ERR if the custom handler URL, as created by removing
63     // the "%s" token and prepending the base url, does not resolve.
64     String newURL = url;
65     newURL.remove(index, WTF_ARRAY_LENGTH(token) - 1);
66
67     URL kurl(baseURL, newURL);
68
69     if (kurl.isEmpty() || !kurl.isValid()) {
70         ec = SYNTAX_ERR;
71         return false;
72     }
73
74     return true;
75 }
76
77 static bool isProtocolWhitelisted(const String& scheme)
78 {
79     if (!protocolWhitelist)
80         initProtocolHandlerWhitelist();
81     return protocolWhitelist->contains(scheme.convertToASCIILowercase());
82 }
83
84 static bool verifyProtocolHandlerScheme(const String& scheme, ExceptionCode& ec)
85 {
86     if (isProtocolWhitelisted(scheme))
87         return true;
88
89     if (scheme.startsWith("web+")) {
90         // The specification requires that the length of scheme is at least five characters (including 'web+' prefix).
91         if (scheme.length() >= 5 && isValidProtocol(scheme))
92             return true;
93     }
94
95     ec = SECURITY_ERR;
96     return false;
97 }
98
99 NavigatorContentUtils* NavigatorContentUtils::from(Page* page)
100 {
101     return static_cast<NavigatorContentUtils*>(Supplement<Page>::from(page, supplementName()));
102 }
103
104 NavigatorContentUtils::~NavigatorContentUtils()
105 {
106 }
107
108 void NavigatorContentUtils::registerProtocolHandler(Navigator& navigator, const String& scheme, const String& url, const String& title, ExceptionCode& ec)
109 {
110     if (!navigator.frame())
111         return;
112
113     URL baseURL = navigator.frame()->document()->baseURL();
114
115     if (!verifyCustomHandlerURL(baseURL, url, ec))
116         return;
117
118     if (!verifyProtocolHandlerScheme(scheme, ec))
119         return;
120
121     NavigatorContentUtils::from(navigator.frame()->page())->client()->registerProtocolHandler(scheme, baseURL, URL(ParsedURLString, url), navigator.frame()->displayStringModifiedByEncoding(title));
122 }
123
124 #if ENABLE(CUSTOM_SCHEME_HANDLER)
125 static String customHandlersStateString(const NavigatorContentUtilsClient::CustomHandlersState state)
126 {
127     static NeverDestroyed<String> newHandler(ASCIILiteral("new"));
128     static NeverDestroyed<String> registeredHandler(ASCIILiteral("registered"));
129     static NeverDestroyed<String> declinedHandler(ASCIILiteral("declined"));
130
131     switch (state) {
132     case NavigatorContentUtilsClient::CustomHandlersNew:
133         return newHandler;
134     case NavigatorContentUtilsClient::CustomHandlersRegistered:
135         return registeredHandler;
136     case NavigatorContentUtilsClient::CustomHandlersDeclined:
137         return declinedHandler;
138     }
139
140     ASSERT_NOT_REACHED();
141     return String();
142 }
143
144 String NavigatorContentUtils::isProtocolHandlerRegistered(Navigator& navigator, const String& scheme, const String& url, ExceptionCode& ec)
145 {
146     static NeverDestroyed<String> declined(ASCIILiteral("declined"));
147
148     if (!navigator.frame())
149         return declined;
150
151     URL baseURL = navigator.frame()->document()->baseURL();
152
153     if (!verifyCustomHandlerURL(baseURL, url, ec))
154         return declined;
155
156     if (!verifyProtocolHandlerScheme(scheme, ec))
157         return declined;
158
159     return customHandlersStateString(NavigatorContentUtils::from(navigator.frame()->page())->client()->isProtocolHandlerRegistered(scheme, baseURL, URL(ParsedURLString, url)));
160 }
161
162 void NavigatorContentUtils::unregisterProtocolHandler(Navigator& navigator, const String& scheme, const String& url, ExceptionCode& ec)
163 {
164     if (!navigator.frame())
165         return;
166
167     URL baseURL = navigator.frame()->document()->baseURL();
168
169     if (!verifyCustomHandlerURL(baseURL, url, ec))
170         return;
171
172     if (!verifyProtocolHandlerScheme(scheme, ec))
173         return;
174
175     NavigatorContentUtils::from(navigator.frame()->page())->client()->unregisterProtocolHandler(scheme, baseURL, URL(ParsedURLString, url));
176 }
177 #endif
178
179 const char* NavigatorContentUtils::supplementName()
180 {
181     return "NavigatorContentUtils";
182 }
183
184 void provideNavigatorContentUtilsTo(Page* page, std::unique_ptr<NavigatorContentUtilsClient> client)
185 {
186     NavigatorContentUtils::provideTo(page, NavigatorContentUtils::supplementName(), std::make_unique<NavigatorContentUtils>(WTFMove(client)));
187 }
188
189 } // namespace WebCore
190
191 #endif // ENABLE(NAVIGATOR_CONTENT_UTILS)
192