1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/public/common/url_utils.h"
6 
7 #include <set>
8 #include <string>
9 
10 #include "base/containers/flat_set.h"
11 #include "base/feature_list.h"
12 #include "base/logging.h"
13 #include "base/no_destructor.h"
14 #include "base/strings/string_piece.h"
15 #include "build/build_config.h"
16 #include "content/common/url_schemes.h"
17 #include "content/public/common/content_features.h"
18 #include "content/public/common/url_constants.h"
19 #include "net/net_buildflags.h"
20 #include "url/gurl.h"
21 #include "url/url_util.h"
22 
23 namespace content {
24 
HasWebUIScheme(const GURL & url)25 bool HasWebUIScheme(const GURL& url) {
26   return url.SchemeIs(kChromeDevToolsScheme) ||
27          url.SchemeIs(kChromeUIScheme);
28 }
29 
IsSavableURL(const GURL & url)30 bool IsSavableURL(const GURL& url) {
31   for (auto& scheme : GetSavableSchemes()) {
32     if (url.SchemeIs(scheme))
33       return true;
34   }
35   return false;
36 }
37 
IsURLHandledByNetworkStack(const GURL & url)38 bool IsURLHandledByNetworkStack(const GURL& url) {
39   // Javascript URLs, srcdoc, schemes that don't load data should not send a
40   // request to the network stack.
41   if (url.SchemeIs(url::kJavaScriptScheme) || url.is_empty() ||
42       url.IsAboutSrcdoc()) {
43     return false;
44   }
45 
46   for (const auto& scheme : url::GetEmptyDocumentSchemes()) {
47     if (url.SchemeIs(scheme))
48       return false;
49   }
50 
51   // Renderer debug URLs (e.g. chrome://kill) are handled in the renderer
52   // process directly and should not be sent to the network stack.
53   if (IsRendererDebugURL(url))
54     return false;
55 
56   // For you information, even though a "data:" url doesn't generate actual
57   // network requests, it is handled by the network stack and so must return
58   // true. The reason is that a few "data:" urls can't be handled locally. For
59   // instance:
60   // - the ones that result in downloads.
61   // - the ones that are invalid. An error page must be served instead.
62   // - the ones that have an unsupported MIME type.
63   // - the ones that target the top-level frame on Android.
64 
65   return true;
66 }
67 
IsURLHandledByNetworkService(const GURL & url)68 bool IsURLHandledByNetworkService(const GURL& url) {
69   if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsWSOrWSS())
70     return true;
71 #if !BUILDFLAG(DISABLE_FTP_SUPPORT)
72   if (url.SchemeIs(url::kFtpScheme) &&
73       base::FeatureList::IsEnabled(features::kFtpProtocol))
74     return true;
75 #endif
76   return false;
77 }
78 
IsRendererDebugURL(const GURL & url)79 bool IsRendererDebugURL(const GURL& url) {
80   if (!url.is_valid())
81     return false;
82 
83   if (url.SchemeIs(url::kJavaScriptScheme))
84     return true;
85 
86   if (!url.SchemeIs(kChromeUIScheme))
87     return false;
88 
89   if (url == kChromeUICheckCrashURL || url == kChromeUIBadCastCrashURL ||
90       url == kChromeUICrashURL || url == kChromeUIDumpURL ||
91       url == kChromeUIKillURL || url == kChromeUIHangURL ||
92       url == kChromeUIShorthangURL || url == kChromeUIMemoryExhaustURL) {
93     return true;
94   }
95 
96 #if defined(ADDRESS_SANITIZER)
97   if (url == kChromeUICrashHeapOverflowURL ||
98       url == kChromeUICrashHeapUnderflowURL ||
99       url == kChromeUICrashUseAfterFreeURL) {
100     return true;
101   }
102 #endif
103 
104 #if defined(OS_WIN)
105   if (url == kChromeUIHeapCorruptionCrashURL)
106     return true;
107 #endif
108 
109 #if DCHECK_IS_ON()
110   if (url == kChromeUICrashDcheckURL)
111     return true;
112 #endif
113 
114 #if defined(OS_WIN) && defined(ADDRESS_SANITIZER)
115   if (url == kChromeUICrashCorruptHeapBlockURL ||
116       url == kChromeUICrashCorruptHeapURL) {
117     return true;
118   }
119 #endif
120 
121   return false;
122 }
123 
IsSafeRedirectTarget(const GURL & from_url,const GURL & to_url)124 bool IsSafeRedirectTarget(const GURL& from_url, const GURL& to_url) {
125   static const base::NoDestructor<base::flat_set<base::StringPiece>>
126       kUnsafeSchemes(base::flat_set<base::StringPiece>({
127         url::kAboutScheme,
128             url::kBlobScheme,
129             url::kJavaScriptScheme,
130 #if !defined(CHROMECAST_BUILD)
131             url::kDataScheme,
132 #endif
133 #if defined(OS_ANDROID)
134             url::kContentScheme,
135 #endif
136       }));
137 #if defined(TOOLKIT_QT)
138   if (from_url.IsCustom())
139     return true;
140 #endif
141   if (HasWebUIScheme(to_url))
142     return false;
143   if (kUnsafeSchemes->contains(to_url.scheme_piece()))
144     return false;
145   for (const auto& local_scheme : url::GetLocalSchemes()) {
146     if (to_url.SchemeIs(local_scheme)) {
147       return from_url.SchemeIs(local_scheme);
148     }
149   }
150   if (to_url.SchemeIsFileSystem())
151     return from_url.SchemeIsFileSystem();
152   return true;
153 }
154 
155 }  // namespace content
156