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
27#include "config.h"
28#include "platform/weborigin/SchemeRegistry.h"
29
30#include "wtf/MainThread.h"
31#include "wtf/text/StringBuilder.h"
32
33namespace blink {
34
35static URLSchemesMap& localURLSchemes()
36{
37    DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ());
38
39    if (localSchemes.isEmpty())
40        localSchemes.add("file");
41
42    return localSchemes;
43}
44
45static URLSchemesMap& displayIsolatedURLSchemes()
46{
47    DEFINE_STATIC_LOCAL(URLSchemesMap, displayIsolatedSchemes, ());
48    return displayIsolatedSchemes;
49}
50
51static URLSchemesMap& secureSchemes()
52{
53    DEFINE_STATIC_LOCAL(URLSchemesMap, secureSchemes, ());
54
55    if (secureSchemes.isEmpty()) {
56        secureSchemes.add("https");
57        secureSchemes.add("about");
58        secureSchemes.add("data");
59        secureSchemes.add("wss");
60    }
61
62    return secureSchemes;
63}
64
65static URLSchemesMap& schemesWithUniqueOrigins()
66{
67    DEFINE_STATIC_LOCAL(URLSchemesMap, schemesWithUniqueOrigins, ());
68
69    if (schemesWithUniqueOrigins.isEmpty()) {
70        schemesWithUniqueOrigins.add("about");
71        schemesWithUniqueOrigins.add("javascript");
72        // This is a willful violation of HTML5.
73        // See https://bugs.webkit.org/show_bug.cgi?id=11885
74        schemesWithUniqueOrigins.add("data");
75    }
76
77    return schemesWithUniqueOrigins;
78}
79
80static URLSchemesMap& emptyDocumentSchemes()
81{
82    DEFINE_STATIC_LOCAL(URLSchemesMap, emptyDocumentSchemes, ());
83
84    if (emptyDocumentSchemes.isEmpty())
85        emptyDocumentSchemes.add("about");
86
87    return emptyDocumentSchemes;
88}
89
90static HashSet<String>& schemesForbiddenFromDomainRelaxation()
91{
92    DEFINE_STATIC_LOCAL(HashSet<String>, schemes, ());
93    return schemes;
94}
95
96static URLSchemesMap& canDisplayOnlyIfCanRequestSchemes()
97{
98    DEFINE_STATIC_LOCAL(URLSchemesMap, canDisplayOnlyIfCanRequestSchemes, ());
99
100    if (canDisplayOnlyIfCanRequestSchemes.isEmpty()) {
101        canDisplayOnlyIfCanRequestSchemes.add("blob");
102        canDisplayOnlyIfCanRequestSchemes.add("filesystem");
103    }
104
105    return canDisplayOnlyIfCanRequestSchemes;
106}
107
108static URLSchemesMap& notAllowingJavascriptURLsSchemes()
109{
110    DEFINE_STATIC_LOCAL(URLSchemesMap, notAllowingJavascriptURLsSchemes, ());
111    return notAllowingJavascriptURLsSchemes;
112}
113
114void SchemeRegistry::registerURLSchemeAsLocal(const String& scheme)
115{
116    localURLSchemes().add(scheme);
117}
118
119void SchemeRegistry::removeURLSchemeRegisteredAsLocal(const String& scheme)
120{
121    if (scheme == "file")
122        return;
123    localURLSchemes().remove(scheme);
124}
125
126const URLSchemesMap& SchemeRegistry::localSchemes()
127{
128    return localURLSchemes();
129}
130
131static URLSchemesMap& CORSEnabledSchemes()
132{
133    // FIXME: http://bugs.webkit.org/show_bug.cgi?id=77160
134    DEFINE_STATIC_LOCAL(URLSchemesMap, CORSEnabledSchemes, ());
135
136    if (CORSEnabledSchemes.isEmpty()) {
137        CORSEnabledSchemes.add("http");
138        CORSEnabledSchemes.add("https");
139        CORSEnabledSchemes.add("data");
140    }
141
142    return CORSEnabledSchemes;
143}
144
145static URLSchemesMap& LegacySchemes()
146{
147    DEFINE_STATIC_LOCAL(URLSchemesMap, LegacySchemes, ());
148
149    if (LegacySchemes.isEmpty()) {
150        LegacySchemes.add("ftp");
151        LegacySchemes.add("gopher");
152    }
153
154    return LegacySchemes;
155}
156
157static URLSchemesMap& ContentSecurityPolicyBypassingSchemes()
158{
159    DEFINE_STATIC_LOCAL(URLSchemesMap, schemes, ());
160    return schemes;
161}
162
163bool SchemeRegistry::shouldTreatURLSchemeAsLocal(const String& scheme)
164{
165    if (scheme.isEmpty())
166        return false;
167    return localURLSchemes().contains(scheme);
168}
169
170void SchemeRegistry::registerURLSchemeAsNoAccess(const String& scheme)
171{
172    schemesWithUniqueOrigins().add(scheme);
173}
174
175bool SchemeRegistry::shouldTreatURLSchemeAsNoAccess(const String& scheme)
176{
177    if (scheme.isEmpty())
178        return false;
179    return schemesWithUniqueOrigins().contains(scheme);
180}
181
182void SchemeRegistry::registerURLSchemeAsDisplayIsolated(const String& scheme)
183{
184    displayIsolatedURLSchemes().add(scheme);
185}
186
187bool SchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated(const String& scheme)
188{
189    if (scheme.isEmpty())
190        return false;
191    return displayIsolatedURLSchemes().contains(scheme);
192}
193
194void SchemeRegistry::registerURLSchemeAsSecure(const String& scheme)
195{
196    secureSchemes().add(scheme);
197}
198
199bool SchemeRegistry::shouldTreatURLSchemeAsSecure(const String& scheme)
200{
201    if (scheme.isEmpty())
202        return false;
203    return secureSchemes().contains(scheme);
204}
205
206void SchemeRegistry::registerURLSchemeAsEmptyDocument(const String& scheme)
207{
208    emptyDocumentSchemes().add(scheme);
209}
210
211bool SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(const String& scheme)
212{
213    if (scheme.isEmpty())
214        return false;
215    return emptyDocumentSchemes().contains(scheme);
216}
217
218void SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const String& scheme)
219{
220    if (scheme.isEmpty())
221        return;
222
223    if (forbidden)
224        schemesForbiddenFromDomainRelaxation().add(scheme);
225    else
226        schemesForbiddenFromDomainRelaxation().remove(scheme);
227}
228
229bool SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(const String& scheme)
230{
231    if (scheme.isEmpty())
232        return false;
233    return schemesForbiddenFromDomainRelaxation().contains(scheme);
234}
235
236bool SchemeRegistry::canDisplayOnlyIfCanRequest(const String& scheme)
237{
238    if (scheme.isEmpty())
239        return false;
240    return canDisplayOnlyIfCanRequestSchemes().contains(scheme);
241}
242
243void SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest(const String& scheme)
244{
245    canDisplayOnlyIfCanRequestSchemes().add(scheme);
246}
247
248void SchemeRegistry::registerURLSchemeAsNotAllowingJavascriptURLs(const String& scheme)
249{
250    notAllowingJavascriptURLsSchemes().add(scheme);
251}
252
253bool SchemeRegistry::shouldTreatURLSchemeAsNotAllowingJavascriptURLs(const String& scheme)
254{
255    if (scheme.isEmpty())
256        return false;
257    return notAllowingJavascriptURLsSchemes().contains(scheme);
258}
259
260void SchemeRegistry::registerURLSchemeAsCORSEnabled(const String& scheme)
261{
262    CORSEnabledSchemes().add(scheme);
263}
264
265bool SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(const String& scheme)
266{
267    if (scheme.isEmpty())
268        return false;
269    return CORSEnabledSchemes().contains(scheme);
270}
271
272String SchemeRegistry::listOfCORSEnabledURLSchemes()
273{
274    StringBuilder builder;
275    const URLSchemesMap& corsEnabledSchemes = CORSEnabledSchemes();
276
277    bool addSeparator = false;
278    for (URLSchemesMap::const_iterator it = corsEnabledSchemes.begin(); it != corsEnabledSchemes.end(); ++it) {
279        if (addSeparator)
280            builder.appendLiteral(", ");
281        else
282            addSeparator = true;
283
284        builder.append(*it);
285    }
286    return builder.toString();
287}
288
289void SchemeRegistry::registerURLSchemeAsLegacy(const String& scheme)
290{
291    LegacySchemes().add(scheme);
292}
293
294bool SchemeRegistry::shouldTreatURLSchemeAsLegacy(const String& scheme)
295{
296    if (scheme.isEmpty())
297        return false;
298    return LegacySchemes().contains(scheme);
299}
300
301void SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme)
302{
303    ContentSecurityPolicyBypassingSchemes().add(scheme);
304}
305
306void SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const String& scheme)
307{
308    ContentSecurityPolicyBypassingSchemes().remove(scheme);
309}
310
311bool SchemeRegistry::schemeShouldBypassContentSecurityPolicy(const String& scheme)
312{
313    if (scheme.isEmpty())
314        return false;
315    return ContentSecurityPolicyBypassingSchemes().contains(scheme);
316}
317
318} // namespace blink
319