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