1/*
2 * Copyright (C) 2010 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26#include "config.h"
27#include "SchemeRegistry.h"
28#include <wtf/MainThread.h>
29
30namespace WebCore {
31
32static URLSchemesMap& localURLSchemes()
33{
34    DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ());
35
36    if (localSchemes.isEmpty()) {
37        localSchemes.add("file");
38#if PLATFORM(MAC)
39        localSchemes.add("applewebdata");
40#endif
41#if PLATFORM(QT)
42        localSchemes.add("qrc");
43#endif
44    }
45
46    return localSchemes;
47}
48
49static URLSchemesMap& displayIsolatedURLSchemes()
50{
51    DEFINE_STATIC_LOCAL(URLSchemesMap, displayIsolatedSchemes, ());
52    return displayIsolatedSchemes;
53}
54
55static URLSchemesMap& secureSchemes()
56{
57    DEFINE_STATIC_LOCAL(URLSchemesMap, secureSchemes, ());
58
59    if (secureSchemes.isEmpty()) {
60        secureSchemes.add("https");
61        secureSchemes.add("about");
62        secureSchemes.add("data");
63    }
64
65    return secureSchemes;
66}
67
68static URLSchemesMap& schemesWithUniqueOrigins()
69{
70    DEFINE_STATIC_LOCAL(URLSchemesMap, schemesWithUniqueOrigins, ());
71
72    if (schemesWithUniqueOrigins.isEmpty()) {
73        schemesWithUniqueOrigins.add("about");
74        schemesWithUniqueOrigins.add("javascript");
75        // This is a willful violation of HTML5.
76        // See https://bugs.webkit.org/show_bug.cgi?id=11885
77        schemesWithUniqueOrigins.add("data");
78    }
79
80    return schemesWithUniqueOrigins;
81}
82
83static URLSchemesMap& emptyDocumentSchemes()
84{
85    DEFINE_STATIC_LOCAL(URLSchemesMap, emptyDocumentSchemes, ());
86
87    if (emptyDocumentSchemes.isEmpty())
88        emptyDocumentSchemes.add("about");
89
90    return emptyDocumentSchemes;
91}
92
93static HashSet<String>& schemesForbiddenFromDomainRelaxation()
94{
95    DEFINE_STATIC_LOCAL(HashSet<String>, schemes, ());
96    return schemes;
97}
98
99static URLSchemesMap& canDisplayOnlyIfCanRequestSchemes()
100{
101    DEFINE_STATIC_LOCAL(URLSchemesMap, canDisplayOnlyIfCanRequestSchemes, ());
102
103#if ENABLE(BLOB)
104    if (canDisplayOnlyIfCanRequestSchemes.isEmpty()) {
105        canDisplayOnlyIfCanRequestSchemes.add("blob");
106#if ENABLE(FILE_SYSTEM)
107        canDisplayOnlyIfCanRequestSchemes.add("filesystem");
108#endif
109    }
110#endif // ENABLE(BLOB)
111
112    return canDisplayOnlyIfCanRequestSchemes;
113}
114
115static URLSchemesMap& notAllowingJavascriptURLsSchemes()
116{
117    DEFINE_STATIC_LOCAL(URLSchemesMap, notAllowingJavascriptURLsSchemes, ());
118    return notAllowingJavascriptURLsSchemes;
119}
120
121void SchemeRegistry::registerURLSchemeAsLocal(const String& scheme)
122{
123    localURLSchemes().add(scheme);
124}
125
126void SchemeRegistry::removeURLSchemeRegisteredAsLocal(const String& scheme)
127{
128    if (scheme == "file")
129        return;
130#if PLATFORM(MAC)
131    if (scheme == "applewebdata")
132        return;
133#endif
134    localURLSchemes().remove(scheme);
135}
136
137const URLSchemesMap& SchemeRegistry::localSchemes()
138{
139    return localURLSchemes();
140}
141
142static URLSchemesMap& schemesAllowingLocalStorageAccessInPrivateBrowsing()
143{
144    DEFINE_STATIC_LOCAL(URLSchemesMap, schemesAllowingLocalStorageAccessInPrivateBrowsing, ());
145    return schemesAllowingLocalStorageAccessInPrivateBrowsing;
146}
147
148static URLSchemesMap& schemesAllowingDatabaseAccessInPrivateBrowsing()
149{
150    DEFINE_STATIC_LOCAL(URLSchemesMap, schemesAllowingDatabaseAccessInPrivateBrowsing, ());
151    return schemesAllowingDatabaseAccessInPrivateBrowsing;
152}
153
154static URLSchemesMap& CORSEnabledSchemes()
155{
156    // FIXME: http://bugs.webkit.org/show_bug.cgi?id=77160
157    DEFINE_STATIC_LOCAL(URLSchemesMap, CORSEnabledSchemes, ());
158
159    if (CORSEnabledSchemes.isEmpty()) {
160        CORSEnabledSchemes.add("http");
161        CORSEnabledSchemes.add("https");
162    }
163
164    return CORSEnabledSchemes;
165}
166
167static URLSchemesMap& ContentSecurityPolicyBypassingSchemes()
168{
169    DEFINE_STATIC_LOCAL(URLSchemesMap, schemes, ());
170    return schemes;
171}
172
173bool SchemeRegistry::shouldTreatURLSchemeAsLocal(const String& scheme)
174{
175    if (scheme.isEmpty())
176        return false;
177    return localURLSchemes().contains(scheme);
178}
179
180void SchemeRegistry::registerURLSchemeAsNoAccess(const String& scheme)
181{
182    schemesWithUniqueOrigins().add(scheme);
183}
184
185bool SchemeRegistry::shouldTreatURLSchemeAsNoAccess(const String& scheme)
186{
187    if (scheme.isEmpty())
188        return false;
189    return schemesWithUniqueOrigins().contains(scheme);
190}
191
192void SchemeRegistry::registerURLSchemeAsDisplayIsolated(const String& scheme)
193{
194    displayIsolatedURLSchemes().add(scheme);
195}
196
197bool SchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated(const String& scheme)
198{
199    if (scheme.isEmpty())
200        return false;
201    return displayIsolatedURLSchemes().contains(scheme);
202}
203
204void SchemeRegistry::registerURLSchemeAsSecure(const String& scheme)
205{
206    secureSchemes().add(scheme);
207}
208
209bool SchemeRegistry::shouldTreatURLSchemeAsSecure(const String& scheme)
210{
211    if (scheme.isEmpty())
212        return false;
213    return secureSchemes().contains(scheme);
214}
215
216void SchemeRegistry::registerURLSchemeAsEmptyDocument(const String& scheme)
217{
218    emptyDocumentSchemes().add(scheme);
219}
220
221bool SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(const String& scheme)
222{
223    if (scheme.isEmpty())
224        return false;
225    return emptyDocumentSchemes().contains(scheme);
226}
227
228void SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const String& scheme)
229{
230    if (scheme.isEmpty())
231        return;
232
233    if (forbidden)
234        schemesForbiddenFromDomainRelaxation().add(scheme);
235    else
236        schemesForbiddenFromDomainRelaxation().remove(scheme);
237}
238
239bool SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(const String& scheme)
240{
241    if (scheme.isEmpty())
242        return false;
243    return schemesForbiddenFromDomainRelaxation().contains(scheme);
244}
245
246bool SchemeRegistry::canDisplayOnlyIfCanRequest(const String& scheme)
247{
248    if (scheme.isEmpty())
249        return false;
250    return canDisplayOnlyIfCanRequestSchemes().contains(scheme);
251}
252
253void SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest(const String& scheme)
254{
255    canDisplayOnlyIfCanRequestSchemes().add(scheme);
256}
257
258void SchemeRegistry::registerURLSchemeAsNotAllowingJavascriptURLs(const String& scheme)
259{
260    notAllowingJavascriptURLsSchemes().add(scheme);
261}
262
263bool SchemeRegistry::shouldTreatURLSchemeAsNotAllowingJavascriptURLs(const String& scheme)
264{
265    if (scheme.isEmpty())
266        return false;
267    return notAllowingJavascriptURLsSchemes().contains(scheme);
268}
269
270void SchemeRegistry::registerURLSchemeAsAllowingLocalStorageAccessInPrivateBrowsing(const String& scheme)
271{
272    schemesAllowingLocalStorageAccessInPrivateBrowsing().add(scheme);
273}
274
275bool SchemeRegistry::allowsLocalStorageAccessInPrivateBrowsing(const String& scheme)
276{
277    if (scheme.isEmpty())
278        return false;
279    return schemesAllowingLocalStorageAccessInPrivateBrowsing().contains(scheme);
280}
281
282void SchemeRegistry::registerURLSchemeAsAllowingDatabaseAccessInPrivateBrowsing(const String& scheme)
283{
284    schemesAllowingDatabaseAccessInPrivateBrowsing().add(scheme);
285}
286
287bool SchemeRegistry::allowsDatabaseAccessInPrivateBrowsing(const String& scheme)
288{
289    if (scheme.isEmpty())
290        return false;
291    return schemesAllowingDatabaseAccessInPrivateBrowsing().contains(scheme);
292}
293
294void SchemeRegistry::registerURLSchemeAsCORSEnabled(const String& scheme)
295{
296    CORSEnabledSchemes().add(scheme);
297}
298
299bool SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(const String& scheme)
300{
301    if (scheme.isEmpty())
302        return false;
303    return CORSEnabledSchemes().contains(scheme);
304}
305
306void SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme)
307{
308    ContentSecurityPolicyBypassingSchemes().add(scheme);
309}
310
311void SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const String& scheme)
312{
313    ContentSecurityPolicyBypassingSchemes().remove(scheme);
314}
315
316bool SchemeRegistry::schemeShouldBypassContentSecurityPolicy(const String& scheme)
317{
318    if (scheme.isEmpty())
319        return false;
320    return ContentSecurityPolicyBypassingSchemes().contains(scheme);
321}
322
323bool SchemeRegistry::shouldCacheResponsesFromURLSchemeIndefinitely(const String& scheme)
324{
325#if PLATFORM(MAC)
326    if (equalIgnoringCase(scheme, "applewebdata"))
327        return true;
328#endif
329    return equalIgnoringCase(scheme, "data");
330}
331
332} // namespace WebCore
333