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