1 /*
2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2009 Google Inc. 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
7 * are met:
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 COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
28
29 #include "net/base/net_errors.h"
30 #include "third_party/blink/public/platform/platform.h"
31 #include "third_party/blink/public/platform/resource_request_blocked_reason.h"
32 #include "third_party/blink/public/platform/web_string.h"
33 #include "third_party/blink/public/platform/web_url.h"
34 #include "third_party/blink/public/platform/web_url_error.h"
35 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
36
37 namespace blink {
38
39 namespace {
40 constexpr char kThrottledErrorDescription[] =
41 "Request throttled. Visit https://dev.chromium.org/throttling for more "
42 "information.";
43 } // namespace
44
CancelledError(const KURL & url)45 ResourceError ResourceError::CancelledError(const KURL& url) {
46 return ResourceError(net::ERR_ABORTED, url, base::nullopt);
47 }
48
CancelledDueToAccessCheckError(const KURL & url,ResourceRequestBlockedReason blocked_reason)49 ResourceError ResourceError::CancelledDueToAccessCheckError(
50 const KURL& url,
51 ResourceRequestBlockedReason blocked_reason) {
52 ResourceError error = CancelledError(url);
53 error.is_access_check_ = true;
54 error.blocked_by_subresource_filter_ =
55 blocked_reason == ResourceRequestBlockedReason::kSubresourceFilter;
56 return error;
57 }
58
CancelledDueToAccessCheckError(const KURL & url,ResourceRequestBlockedReason blocked_reason,const String & localized_description)59 ResourceError ResourceError::CancelledDueToAccessCheckError(
60 const KURL& url,
61 ResourceRequestBlockedReason blocked_reason,
62 const String& localized_description) {
63 ResourceError error = CancelledDueToAccessCheckError(url, blocked_reason);
64 error.localized_description_ = localized_description;
65 return error;
66 }
67
CacheMissError(const KURL & url)68 ResourceError ResourceError::CacheMissError(const KURL& url) {
69 return ResourceError(net::ERR_CACHE_MISS, url, base::nullopt);
70 }
71
TimeoutError(const KURL & url)72 ResourceError ResourceError::TimeoutError(const KURL& url) {
73 return ResourceError(net::ERR_TIMED_OUT, url, base::nullopt);
74 }
75
Failure(const KURL & url)76 ResourceError ResourceError::Failure(const KURL& url) {
77 return ResourceError(net::ERR_FAILED, url, base::nullopt);
78 }
79
ResourceError(int error_code,const KURL & url,base::Optional<network::CorsErrorStatus> cors_error_status)80 ResourceError::ResourceError(
81 int error_code,
82 const KURL& url,
83 base::Optional<network::CorsErrorStatus> cors_error_status)
84 : error_code_(error_code),
85 failing_url_(url),
86 is_access_check_(cors_error_status.has_value()),
87 cors_error_status_(cors_error_status) {
88 DCHECK_NE(error_code_, 0);
89 InitializeDescription();
90 }
91
ResourceError(const KURL & url,const network::CorsErrorStatus & cors_error_status)92 ResourceError::ResourceError(const KURL& url,
93 const network::CorsErrorStatus& cors_error_status)
94 : ResourceError(net::ERR_FAILED, url, cors_error_status) {}
95
ResourceError(const WebURLError & error)96 ResourceError::ResourceError(const WebURLError& error)
97 : error_code_(error.reason()),
98 extended_error_code_(error.extended_reason()),
99 resolve_error_info_(error.resolve_error_info()),
100 failing_url_(error.url()),
101 is_access_check_(error.is_web_security_violation()),
102 has_copy_in_cache_(error.has_copy_in_cache()),
103 cors_error_status_(error.cors_error_status()),
104 blocked_by_response_reason_(error.blocked_by_response_reason()) {
105 DCHECK_NE(error_code_, 0);
106 InitializeDescription();
107 }
108
Copy() const109 ResourceError ResourceError::Copy() const {
110 ResourceError error_copy(error_code_, failing_url_.Copy(),
111 cors_error_status_);
112 error_copy.extended_error_code_ = extended_error_code_;
113 error_copy.resolve_error_info_ = resolve_error_info_;
114 error_copy.has_copy_in_cache_ = has_copy_in_cache_;
115 error_copy.localized_description_ = localized_description_.IsolatedCopy();
116 error_copy.is_access_check_ = is_access_check_;
117 return error_copy;
118 }
119
operator WebURLError() const120 ResourceError::operator WebURLError() const {
121 WebURLError::HasCopyInCache has_copy_in_cache =
122 has_copy_in_cache_ ? WebURLError::HasCopyInCache::kTrue
123 : WebURLError::HasCopyInCache::kFalse;
124
125 if (cors_error_status_) {
126 DCHECK_EQ(net::ERR_FAILED, error_code_);
127 return WebURLError(*cors_error_status_, has_copy_in_cache, failing_url_);
128 }
129
130 return WebURLError(
131 error_code_, extended_error_code_, resolve_error_info_, has_copy_in_cache,
132 is_access_check_ ? WebURLError::IsWebSecurityViolation::kTrue
133 : WebURLError::IsWebSecurityViolation::kFalse,
134 failing_url_);
135 }
136
Compare(const ResourceError & a,const ResourceError & b)137 bool ResourceError::Compare(const ResourceError& a, const ResourceError& b) {
138 if (a.ErrorCode() != b.ErrorCode())
139 return false;
140
141 if (a.FailingURL() != b.FailingURL())
142 return false;
143
144 if (a.LocalizedDescription() != b.LocalizedDescription())
145 return false;
146
147 if (a.IsAccessCheck() != b.IsAccessCheck())
148 return false;
149
150 if (a.HasCopyInCache() != b.HasCopyInCache())
151 return false;
152
153 if (a.CorsErrorStatus() != b.CorsErrorStatus())
154 return false;
155
156 if (a.extended_error_code_ != b.extended_error_code_)
157 return false;
158
159 if (a.resolve_error_info_ != b.resolve_error_info_)
160 return false;
161
162 return true;
163 }
164
IsTimeout() const165 bool ResourceError::IsTimeout() const {
166 return error_code_ == net::ERR_TIMED_OUT;
167 }
168
IsCancellation() const169 bool ResourceError::IsCancellation() const {
170 return error_code_ == net::ERR_ABORTED;
171 }
172
IsCacheMiss() const173 bool ResourceError::IsCacheMiss() const {
174 return error_code_ == net::ERR_CACHE_MISS;
175 }
176
WasBlockedByResponse() const177 bool ResourceError::WasBlockedByResponse() const {
178 return error_code_ == net::ERR_BLOCKED_BY_RESPONSE;
179 }
180
ShouldCollapseInitiator() const181 bool ResourceError::ShouldCollapseInitiator() const {
182 return blocked_by_subresource_filter_ ||
183 GetResourceRequestBlockedReason() ==
184 ResourceRequestBlockedReason::kCollapsedByClient;
185 }
186
187 namespace {
188
189 blink::ResourceRequestBlockedReason
BlockedByResponseReasonToResourceRequestBlockedReason(network::BlockedByResponseReason reason)190 BlockedByResponseReasonToResourceRequestBlockedReason(
191 network::BlockedByResponseReason reason) {
192 switch (reason) {
193 case network::BlockedByResponseReason::kCoepFrameResourceNeedsCoepHeader:
194 return blink::ResourceRequestBlockedReason::
195 kCoepFrameResourceNeedsCoepHeader;
196 case network::BlockedByResponseReason::
197 kCoopSandboxedIFrameCannotNavigateToCoopPage:
198 return blink::ResourceRequestBlockedReason::
199 kCoopSandboxedIFrameCannotNavigateToCoopPage;
200 case network::BlockedByResponseReason::kCorpNotSameOrigin:
201 return blink::ResourceRequestBlockedReason::kCorpNotSameOrigin;
202 case network::BlockedByResponseReason::
203 kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
204 return blink::ResourceRequestBlockedReason::
205 kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
206 break;
207 case network::BlockedByResponseReason::kCorpNotSameSite:
208 return blink::ResourceRequestBlockedReason::kCorpNotSameSite;
209 break;
210 }
211 NOTREACHED();
212 return blink::ResourceRequestBlockedReason::kOther;
213 }
214
215 } // namespace
216 base::Optional<ResourceRequestBlockedReason>
GetResourceRequestBlockedReason() const217 ResourceError::GetResourceRequestBlockedReason() const {
218 if (error_code_ != net::ERR_BLOCKED_BY_CLIENT &&
219 error_code_ != net::ERR_BLOCKED_BY_RESPONSE) {
220 return base::nullopt;
221 }
222 if (blocked_by_response_reason_) {
223 return BlockedByResponseReasonToResourceRequestBlockedReason(
224 *blocked_by_response_reason_);
225 }
226 return static_cast<ResourceRequestBlockedReason>(extended_error_code_);
227 }
228
229 namespace {
DescriptionForBlockedByClientOrResponse(int error,int extended_error)230 String DescriptionForBlockedByClientOrResponse(int error, int extended_error) {
231 if (extended_error == 0)
232 return WebString::FromASCII(net::ErrorToString(error));
233 std::string detail;
234 switch (static_cast<ResourceRequestBlockedReason>(extended_error)) {
235 case ResourceRequestBlockedReason::kOther:
236 NOTREACHED(); // extended_error == 0, handled above
237 break;
238 case ResourceRequestBlockedReason::kCSP:
239 detail = "CSP";
240 break;
241 case ResourceRequestBlockedReason::kMixedContent:
242 detail = "MixedContent";
243 break;
244 case ResourceRequestBlockedReason::kOrigin:
245 detail = "Origin";
246 break;
247 case ResourceRequestBlockedReason::kInspector:
248 detail = "Inspector";
249 break;
250 case ResourceRequestBlockedReason::kSubresourceFilter:
251 detail = "SubresourceFilter";
252 break;
253 case ResourceRequestBlockedReason::kContentType:
254 detail = "ContentType";
255 break;
256 case ResourceRequestBlockedReason::kCollapsedByClient:
257 detail = "Collapsed";
258 break;
259 case ResourceRequestBlockedReason::kCoepFrameResourceNeedsCoepHeader:
260 detail = "ResponseNeedsCrossOriginEmbedderPolicy";
261 break;
262 case ResourceRequestBlockedReason::
263 kCoopSandboxedIFrameCannotNavigateToCoopPage:
264 detail = "SandboxedIFrameCannotNavigateToOriginIsolatedPage";
265 break;
266 case ResourceRequestBlockedReason::kCorpNotSameOrigin:
267 detail = "NotSameOrigin";
268 break;
269 case ResourceRequestBlockedReason::
270 kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
271 detail = "NotSameOriginAfterDefaultedToSameOriginByCoep";
272 break;
273 case ResourceRequestBlockedReason::kCorpNotSameSite:
274 detail = "NotSameSite";
275 break;
276 }
277 return WebString::FromASCII(net::ErrorToString(error) + "." + detail);
278 }
279 } // namespace
280
InitializeDescription()281 void ResourceError::InitializeDescription() {
282 if (error_code_ == net::ERR_TEMPORARILY_THROTTLED) {
283 localized_description_ = WebString::FromASCII(kThrottledErrorDescription);
284 } else if (error_code_ == net::ERR_BLOCKED_BY_CLIENT ||
285 error_code_ == net::ERR_BLOCKED_BY_RESPONSE) {
286 localized_description_ = DescriptionForBlockedByClientOrResponse(
287 error_code_, extended_error_code_);
288 } else {
289 localized_description_ = WebString::FromASCII(
290 net::ExtendedErrorToString(error_code_, extended_error_code_));
291 }
292 }
293
operator <<(std::ostream & os,const ResourceError & error)294 std::ostream& operator<<(std::ostream& os, const ResourceError& error) {
295 return os << ", ErrorCode = " << error.ErrorCode()
296 << ", FailingURL = " << error.FailingURL()
297 << ", LocalizedDescription = " << error.LocalizedDescription()
298 << ", IsCancellation = " << error.IsCancellation()
299 << ", IsAccessCheck = " << error.IsAccessCheck()
300 << ", IsTimeout = " << error.IsTimeout()
301 << ", HasCopyInCache = " << error.HasCopyInCache()
302 << ", IsCacheMiss = " << error.IsCacheMiss();
303 }
304
305 } // namespace blink
306