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 "base/strings/string_number_conversions.h"
30 #include "net/base/net_errors.h"
31 #include "services/network/public/mojom/trust_tokens.mojom-blink-forward.h"
32 #include "third_party/blink/public/platform/platform.h"
33 #include "third_party/blink/public/platform/resource_request_blocked_reason.h"
34 #include "third_party/blink/public/platform/web_string.h"
35 #include "third_party/blink/public/platform/web_url.h"
36 #include "third_party/blink/public/platform/web_url_error.h"
37 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
38 #include "third_party/blink/renderer/platform/loader/fetch/trust_token_params_conversion.h"
39
40 namespace blink {
41
42 namespace {
43 constexpr char kThrottledErrorDescription[] =
44 "Request throttled. Visit https://dev.chromium.org/throttling for more "
45 "information.";
46 } // namespace
47
CancelledError(const KURL & url)48 ResourceError ResourceError::CancelledError(const KURL& url) {
49 return ResourceError(net::ERR_ABORTED, url, base::nullopt);
50 }
51
CancelledDueToAccessCheckError(const KURL & url,ResourceRequestBlockedReason blocked_reason)52 ResourceError ResourceError::CancelledDueToAccessCheckError(
53 const KURL& url,
54 ResourceRequestBlockedReason blocked_reason) {
55 ResourceError error = CancelledError(url);
56 error.is_access_check_ = true;
57 error.blocked_by_subresource_filter_ =
58 blocked_reason == ResourceRequestBlockedReason::kSubresourceFilter;
59 return error;
60 }
61
CancelledDueToAccessCheckError(const KURL & url,ResourceRequestBlockedReason blocked_reason,const String & localized_description)62 ResourceError ResourceError::CancelledDueToAccessCheckError(
63 const KURL& url,
64 ResourceRequestBlockedReason blocked_reason,
65 const String& localized_description) {
66 ResourceError error = CancelledDueToAccessCheckError(url, blocked_reason);
67 error.localized_description_ = localized_description;
68 return error;
69 }
70
BlockedByResponse(const KURL & url,network::mojom::BlockedByResponseReason blocked_by_response_reason)71 ResourceError ResourceError::BlockedByResponse(
72 const KURL& url,
73 network::mojom::BlockedByResponseReason blocked_by_response_reason) {
74 ResourceError error(net::ERR_BLOCKED_BY_RESPONSE, url, base::nullopt);
75 error.blocked_by_response_reason_ = blocked_by_response_reason;
76 return error;
77 }
78
CacheMissError(const KURL & url)79 ResourceError ResourceError::CacheMissError(const KURL& url) {
80 return ResourceError(net::ERR_CACHE_MISS, url, base::nullopt);
81 }
82
TimeoutError(const KURL & url)83 ResourceError ResourceError::TimeoutError(const KURL& url) {
84 return ResourceError(net::ERR_TIMED_OUT, url, base::nullopt);
85 }
86
Failure(const KURL & url)87 ResourceError ResourceError::Failure(const KURL& url) {
88 return ResourceError(net::ERR_FAILED, url, base::nullopt);
89 }
90
ResourceError(int error_code,const KURL & url,base::Optional<network::CorsErrorStatus> cors_error_status)91 ResourceError::ResourceError(
92 int error_code,
93 const KURL& url,
94 base::Optional<network::CorsErrorStatus> cors_error_status)
95 : error_code_(error_code),
96 failing_url_(url),
97 is_access_check_(cors_error_status.has_value()),
98 cors_error_status_(cors_error_status) {
99 DCHECK_NE(error_code_, 0);
100 InitializeDescription();
101 }
102
ResourceError(const KURL & url,const network::CorsErrorStatus & cors_error_status)103 ResourceError::ResourceError(const KURL& url,
104 const network::CorsErrorStatus& cors_error_status)
105 : ResourceError(net::ERR_FAILED, url, cors_error_status) {}
106
ResourceError(const WebURLError & error)107 ResourceError::ResourceError(const WebURLError& error)
108 : error_code_(error.reason()),
109 extended_error_code_(error.extended_reason()),
110 resolve_error_info_(error.resolve_error_info()),
111 failing_url_(error.url()),
112 is_access_check_(error.is_web_security_violation()),
113 has_copy_in_cache_(error.has_copy_in_cache()),
114 cors_error_status_(error.cors_error_status()),
115 blocked_by_response_reason_(error.blocked_by_response_reason()),
116 trust_token_operation_error_(error.trust_token_operation_error()) {
117 DCHECK_NE(error_code_, 0);
118 InitializeDescription();
119 }
120
operator WebURLError() const121 ResourceError::operator WebURLError() const {
122 WebURLError::HasCopyInCache has_copy_in_cache =
123 has_copy_in_cache_ ? WebURLError::HasCopyInCache::kTrue
124 : WebURLError::HasCopyInCache::kFalse;
125
126 if (cors_error_status_) {
127 DCHECK_EQ(net::ERR_FAILED, error_code_);
128 return WebURLError(*cors_error_status_, has_copy_in_cache, failing_url_);
129 }
130
131 if (trust_token_operation_error_ !=
132 network::mojom::blink::TrustTokenOperationStatus::kOk) {
133 return WebURLError(error_code_, trust_token_operation_error_, failing_url_);
134 }
135
136 return WebURLError(
137 error_code_, extended_error_code_, resolve_error_info_, has_copy_in_cache,
138 is_access_check_ ? WebURLError::IsWebSecurityViolation::kTrue
139 : WebURLError::IsWebSecurityViolation::kFalse,
140 failing_url_);
141 }
142
Compare(const ResourceError & a,const ResourceError & b)143 bool ResourceError::Compare(const ResourceError& a, const ResourceError& b) {
144 if (a.ErrorCode() != b.ErrorCode())
145 return false;
146
147 if (a.FailingURL() != b.FailingURL())
148 return false;
149
150 if (a.LocalizedDescription() != b.LocalizedDescription())
151 return false;
152
153 if (a.IsAccessCheck() != b.IsAccessCheck())
154 return false;
155
156 if (a.HasCopyInCache() != b.HasCopyInCache())
157 return false;
158
159 if (a.CorsErrorStatus() != b.CorsErrorStatus())
160 return false;
161
162 if (a.extended_error_code_ != b.extended_error_code_)
163 return false;
164
165 if (a.resolve_error_info_ != b.resolve_error_info_)
166 return false;
167
168 if (a.trust_token_operation_error_ != b.trust_token_operation_error_)
169 return false;
170
171 return true;
172 }
173
IsTimeout() const174 bool ResourceError::IsTimeout() const {
175 return error_code_ == net::ERR_TIMED_OUT;
176 }
177
IsCancellation() const178 bool ResourceError::IsCancellation() const {
179 return error_code_ == net::ERR_ABORTED;
180 }
181
IsTrustTokenCacheHit() const182 bool ResourceError::IsTrustTokenCacheHit() const {
183 return error_code_ == net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT;
184 }
185
IsUnactionableTrustTokensStatus() const186 bool ResourceError::IsUnactionableTrustTokensStatus() const {
187 return IsTrustTokenCacheHit() ||
188 (error_code_ == net::ERR_TRUST_TOKEN_OPERATION_FAILED &&
189 trust_token_operation_error_ ==
190 network::mojom::TrustTokenOperationStatus::kUnavailable);
191 }
192
IsCacheMiss() const193 bool ResourceError::IsCacheMiss() const {
194 return error_code_ == net::ERR_CACHE_MISS;
195 }
196
WasBlockedByResponse() const197 bool ResourceError::WasBlockedByResponse() const {
198 return error_code_ == net::ERR_BLOCKED_BY_RESPONSE;
199 }
200
ShouldCollapseInitiator() const201 bool ResourceError::ShouldCollapseInitiator() const {
202 return blocked_by_subresource_filter_ ||
203 GetResourceRequestBlockedReason() ==
204 ResourceRequestBlockedReason::kCollapsedByClient;
205 }
206
207 namespace {
208 blink::ResourceRequestBlockedReason
BlockedByResponseReasonToResourceRequestBlockedReason(network::mojom::BlockedByResponseReason reason)209 BlockedByResponseReasonToResourceRequestBlockedReason(
210 network::mojom::BlockedByResponseReason reason) {
211 switch (reason) {
212 case network::mojom::BlockedByResponseReason::
213 kCoepFrameResourceNeedsCoepHeader:
214 return blink::ResourceRequestBlockedReason::
215 kCoepFrameResourceNeedsCoepHeader;
216 case network::mojom::BlockedByResponseReason::
217 kCoopSandboxedIFrameCannotNavigateToCoopPage:
218 return blink::ResourceRequestBlockedReason::
219 kCoopSandboxedIFrameCannotNavigateToCoopPage;
220 case network::mojom::BlockedByResponseReason::kCorpNotSameOrigin:
221 return blink::ResourceRequestBlockedReason::kCorpNotSameOrigin;
222 case network::mojom::BlockedByResponseReason::
223 kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
224 return blink::ResourceRequestBlockedReason::
225 kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
226 case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
227 return blink::ResourceRequestBlockedReason::kCorpNotSameSite;
228 }
229 NOTREACHED();
230 return blink::ResourceRequestBlockedReason::kOther;
231 }
232 } // namespace
233
234 base::Optional<ResourceRequestBlockedReason>
GetResourceRequestBlockedReason() const235 ResourceError::GetResourceRequestBlockedReason() const {
236 if (error_code_ != net::ERR_BLOCKED_BY_CLIENT &&
237 error_code_ != net::ERR_BLOCKED_BY_RESPONSE) {
238 return base::nullopt;
239 }
240 if (blocked_by_response_reason_) {
241 return BlockedByResponseReasonToResourceRequestBlockedReason(
242 *blocked_by_response_reason_);
243 }
244 return static_cast<ResourceRequestBlockedReason>(extended_error_code_);
245 }
246
247 base::Optional<network::mojom::BlockedByResponseReason>
GetBlockedByResponseReason() const248 ResourceError::GetBlockedByResponseReason() const {
249 if (error_code_ != net::ERR_BLOCKED_BY_CLIENT &&
250 error_code_ != net::ERR_BLOCKED_BY_RESPONSE) {
251 return base::nullopt;
252 }
253 return blocked_by_response_reason_;
254 }
255
256 namespace {
DescriptionForBlockedByClientOrResponse(int error,int extended_error)257 String DescriptionForBlockedByClientOrResponse(int error, int extended_error) {
258 if (extended_error == 0)
259 return WebString::FromASCII(net::ErrorToString(error));
260 std::string detail;
261 switch (static_cast<ResourceRequestBlockedReason>(extended_error)) {
262 case ResourceRequestBlockedReason::kOther:
263 NOTREACHED(); // extended_error == 0, handled above
264 break;
265 case ResourceRequestBlockedReason::kCSP:
266 detail = "CSP";
267 break;
268 case ResourceRequestBlockedReason::kMixedContent:
269 detail = "MixedContent";
270 break;
271 case ResourceRequestBlockedReason::kOrigin:
272 detail = "Origin";
273 break;
274 case ResourceRequestBlockedReason::kInspector:
275 detail = "Inspector";
276 break;
277 case ResourceRequestBlockedReason::kSubresourceFilter:
278 detail = "SubresourceFilter";
279 break;
280 case ResourceRequestBlockedReason::kContentType:
281 detail = "ContentType";
282 break;
283 case ResourceRequestBlockedReason::kCollapsedByClient:
284 detail = "Collapsed";
285 break;
286 case ResourceRequestBlockedReason::kCoepFrameResourceNeedsCoepHeader:
287 detail = "ResponseNeedsCrossOriginEmbedderPolicy";
288 break;
289 case ResourceRequestBlockedReason::
290 kCoopSandboxedIFrameCannotNavigateToCoopPage:
291 detail = "SandboxedIFrameCannotNavigateToOriginIsolatedPage";
292 break;
293 case ResourceRequestBlockedReason::kCorpNotSameOrigin:
294 detail = "NotSameOrigin";
295 break;
296 case ResourceRequestBlockedReason::
297 kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
298 detail = "NotSameOriginAfterDefaultedToSameOriginByCoep";
299 break;
300 case ResourceRequestBlockedReason::kCorpNotSameSite:
301 detail = "NotSameSite";
302 break;
303 case ResourceRequestBlockedReason::
304 kBlockedByExtensionCrbug1128174Investigation:
305 detail = "BlockedByExtensionCrbug1128174Investigation";
306 break;
307 }
308 return WebString::FromASCII(net::ErrorToString(error) + "." + detail);
309 }
310 } // namespace
311
InitializeDescription()312 void ResourceError::InitializeDescription() {
313 if (error_code_ == net::ERR_TEMPORARILY_THROTTLED) {
314 localized_description_ = WebString::FromASCII(kThrottledErrorDescription);
315 } else if (error_code_ == net::ERR_BLOCKED_BY_CLIENT ||
316 error_code_ == net::ERR_BLOCKED_BY_RESPONSE) {
317 localized_description_ = DescriptionForBlockedByClientOrResponse(
318 error_code_, extended_error_code_);
319 } else {
320 localized_description_ = WebString::FromASCII(
321 net::ExtendedErrorToString(error_code_, extended_error_code_));
322 }
323 }
324
operator <<(std::ostream & os,const ResourceError & error)325 std::ostream& operator<<(std::ostream& os, const ResourceError& error) {
326 return os << ", ErrorCode = " << error.ErrorCode()
327 << ", FailingURL = " << error.FailingURL()
328 << ", LocalizedDescription = " << error.LocalizedDescription()
329 << ", IsCancellation = " << error.IsCancellation()
330 << ", IsAccessCheck = " << error.IsAccessCheck()
331 << ", IsTimeout = " << error.IsTimeout()
332 << ", HasCopyInCache = " << error.HasCopyInCache()
333 << ", IsCacheMiss = " << error.IsCacheMiss()
334 << ", TrustTokenOperationError = "
335 << String::FromUTF8(base::NumberToString(
336 static_cast<int32_t>(error.TrustTokenOperationError())));
337 }
338
339 } // namespace blink
340