• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2008-2009 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include <algorithm>
6 #include <limits>
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include "libcef/common/net/http_header_utils.h"
12 #include "libcef/common/net_service/net_service_util.h"
13 #include "libcef/common/request_impl.h"
14 
15 #include "base/command_line.h"
16 #include "base/logging.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "components/navigation_interception/navigation_params.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/common/content_switches.h"
23 #include "net/base/elements_upload_data_stream.h"
24 #include "net/base/load_flags.h"
25 #include "net/base/upload_bytes_element_reader.h"
26 #include "net/base/upload_data_stream.h"
27 #include "net/base/upload_element_reader.h"
28 #include "net/base/upload_file_element_reader.h"
29 #include "net/http/http_request_headers.h"
30 #include "net/http/http_util.h"
31 #include "net/url_request/redirect_info.h"
32 #include "net/url_request/referrer_policy.h"
33 #include "services/network/public/cpp/data_element.h"
34 #include "services/network/public/cpp/network_switches.h"
35 #include "services/network/public/cpp/resource_request.h"
36 #include "services/network/public/cpp/resource_request_body.h"
37 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
38 #include "third_party/blink/public/platform/web_http_body.h"
39 #include "third_party/blink/public/platform/web_security_origin.h"
40 #include "third_party/blink/public/platform/web_string.h"
41 #include "third_party/blink/public/platform/web_url.h"
42 #include "third_party/blink/public/platform/web_url_error.h"
43 #include "third_party/blink/public/platform/web_url_request.h"
44 #include "third_party/blink/public/platform/web_url_request_util.h"
45 #include "third_party/blink/public/web/web_security_policy.h"
46 
47 namespace {
48 
49 const char kReferrerLowerCase[] = "referer";
50 const char kCacheControlLowerCase[] = "cache-control";
51 const char kCacheControlDirectiveNoCacheLowerCase[] = "no-cache";
52 const char kCacheControlDirectiveNoStoreLowerCase[] = "no-store";
53 const char kCacheControlDirectiveOnlyIfCachedLowerCase[] = "only-if-cached";
54 
55 // Mask of values that configure the cache policy.
56 const int kURCachePolicyMask =
57     (UR_FLAG_SKIP_CACHE | UR_FLAG_ONLY_FROM_CACHE | UR_FLAG_DISABLE_CACHE);
58 
59 // Returns the cef_urlrequest_flags_t policy specified by the Cache-Control
60 // request header directives, if any. The directives are case-insensitive and
61 // some have an optional argument. Multiple directives are comma-separated.
62 // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
63 // for details.
GetCacheControlHeaderPolicy(CefRequest::HeaderMap headerMap)64 int GetCacheControlHeaderPolicy(CefRequest::HeaderMap headerMap) {
65   std::string line;
66 
67   // Extract the Cache-Control header line.
68   {
69     CefRequest::HeaderMap::const_iterator it = headerMap.begin();
70     for (; it != headerMap.end(); ++it) {
71       if (base::LowerCaseEqualsASCII(it->first.ToString(),
72                                      kCacheControlLowerCase)) {
73         line = it->second;
74         break;
75       }
76     }
77   }
78 
79   int flags = 0;
80 
81   if (!line.empty()) {
82     HttpHeaderUtils::MakeASCIILower(&line);
83 
84     std::vector<base::StringPiece> pieces = base::SplitStringPiece(
85         line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
86     for (const auto& piece : pieces) {
87       if (base::LowerCaseEqualsASCII(piece,
88                                      kCacheControlDirectiveNoCacheLowerCase)) {
89         flags |= UR_FLAG_SKIP_CACHE;
90       } else if (base::LowerCaseEqualsASCII(
91                      piece, kCacheControlDirectiveOnlyIfCachedLowerCase)) {
92         flags |= UR_FLAG_ONLY_FROM_CACHE;
93       } else if (base::LowerCaseEqualsASCII(
94                      piece, kCacheControlDirectiveNoStoreLowerCase)) {
95         flags |= UR_FLAG_DISABLE_CACHE;
96       }
97     }
98   }
99 
100   return flags;
101 }
102 
103 // Convert cef_urlrequest_flags_t to blink::WebCachePolicy.
GetFetchCacheMode(int ur_flags)104 blink::mojom::FetchCacheMode GetFetchCacheMode(int ur_flags) {
105   const bool skip_cache{!!(ur_flags & UR_FLAG_SKIP_CACHE)};
106   const bool only_from_cache{!!(ur_flags & UR_FLAG_ONLY_FROM_CACHE)};
107   const bool disable_cache{!!(ur_flags & UR_FLAG_DISABLE_CACHE)};
108   if (only_from_cache && (skip_cache || disable_cache)) {
109     // The request will always fail because only_from_cache and
110     // skip_cache/disable_cache are mutually exclusive.
111     return blink::mojom::FetchCacheMode::kUnspecifiedForceCacheMiss;
112   } else if (disable_cache) {
113     // This additionally implies the skip_cache behavior.
114     return blink::mojom::FetchCacheMode::kNoStore;
115   } else if (skip_cache) {
116     return blink::mojom::FetchCacheMode::kBypassCache;
117   } else if (only_from_cache) {
118     return blink::mojom::FetchCacheMode::kOnlyIfCached;
119   }
120   return blink::mojom::FetchCacheMode::kDefault;
121 }
122 
123 // Read |headers| into |map|.
GetHeaderMap(const net::HttpRequestHeaders & headers,CefRequest::HeaderMap & map)124 void GetHeaderMap(const net::HttpRequestHeaders& headers,
125                   CefRequest::HeaderMap& map) {
126   map.clear();
127 
128   if (headers.IsEmpty())
129     return;
130 
131   net::HttpRequestHeaders::Iterator it(headers);
132   while (it.GetNext()) {
133     const std::string& name = it.name();
134 
135     // Do not include Referer in the header map.
136     if (!base::LowerCaseEqualsASCII(name, kReferrerLowerCase))
137       map.insert(std::make_pair(name, it.value()));
138   };
139 }
140 
141 // Read |source| into |map|.
GetHeaderMap(const CefRequest::HeaderMap & source,CefRequest::HeaderMap & map)142 void GetHeaderMap(const CefRequest::HeaderMap& source,
143                   CefRequest::HeaderMap& map) {
144   map.clear();
145 
146   CefRequest::HeaderMap::const_iterator it = source.begin();
147   for (; it != source.end(); ++it) {
148     const CefString& name = it->first;
149 
150     // Do not include Referer in the header map.
151     if (!base::LowerCaseEqualsASCII(name.ToString(), kReferrerLowerCase))
152       map.insert(std::make_pair(name, it->second));
153   }
154 }
155 
156 }  // namespace
157 
158 #define CHECK_READONLY_RETURN(val)         \
159   if (read_only_) {                        \
160     NOTREACHED() << "object is read only"; \
161     return val;                            \
162   }
163 
164 #define CHECK_READONLY_RETURN_VOID()       \
165   if (read_only_) {                        \
166     NOTREACHED() << "object is read only"; \
167     return;                                \
168   }
169 
170 #define SETBOOLFLAG(obj, flags, method, FLAG) \
171   obj.method((flags & (FLAG)) == (FLAG))
172 
173 // CefRequest -----------------------------------------------------------------
174 
175 // static
Create()176 CefRefPtr<CefRequest> CefRequest::Create() {
177   CefRefPtr<CefRequest> request(new CefRequestImpl());
178   return request;
179 }
180 
181 // CefRequestImpl -------------------------------------------------------------
182 
CefRequestImpl()183 CefRequestImpl::CefRequestImpl() {
184   // Verify that our enum matches Chromium's values.
185   static_assert(static_cast<int>(REFERRER_POLICY_LAST_VALUE) ==
186                     static_cast<int>(net::ReferrerPolicy::MAX),
187                 "enum mismatch");
188 
189   base::AutoLock lock_scope(lock_);
190   Reset();
191 }
192 
IsReadOnly()193 bool CefRequestImpl::IsReadOnly() {
194   base::AutoLock lock_scope(lock_);
195   return read_only_;
196 }
197 
GetURL()198 CefString CefRequestImpl::GetURL() {
199   base::AutoLock lock_scope(lock_);
200   return url_.spec();
201 }
202 
SetURL(const CefString & url)203 void CefRequestImpl::SetURL(const CefString& url) {
204   base::AutoLock lock_scope(lock_);
205   CHECK_READONLY_RETURN_VOID();
206   const GURL& new_url = GURL(url.ToString());
207   if (url_ != new_url) {
208     Changed(kChangedUrl);
209     url_ = new_url;
210   }
211 }
212 
GetMethod()213 CefString CefRequestImpl::GetMethod() {
214   base::AutoLock lock_scope(lock_);
215   return method_;
216 }
217 
SetMethod(const CefString & method)218 void CefRequestImpl::SetMethod(const CefString& method) {
219   base::AutoLock lock_scope(lock_);
220   CHECK_READONLY_RETURN_VOID();
221   const std::string& new_method = method;
222   if (method_ != new_method) {
223     Changed(kChangedMethod);
224     method_ = new_method;
225   }
226 }
227 
SetReferrer(const CefString & referrer_url,ReferrerPolicy policy)228 void CefRequestImpl::SetReferrer(const CefString& referrer_url,
229                                  ReferrerPolicy policy) {
230   base::AutoLock lock_scope(lock_);
231   CHECK_READONLY_RETURN_VOID();
232 
233   const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
234       url_, content::Referrer(GURL(referrer_url.ToString()),
235                               NetReferrerPolicyToBlinkReferrerPolicy(policy)));
236   const auto sanitized_policy =
237       BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
238 
239   if (referrer_url_ != sanitized_referrer.url ||
240       referrer_policy_ != sanitized_policy) {
241     Changed(kChangedReferrer);
242     referrer_url_ = sanitized_referrer.url;
243     referrer_policy_ = sanitized_policy;
244   }
245 }
246 
GetReferrerURL()247 CefString CefRequestImpl::GetReferrerURL() {
248   base::AutoLock lock_scope(lock_);
249   return referrer_url_.spec();
250 }
251 
GetReferrerPolicy()252 CefRequestImpl::ReferrerPolicy CefRequestImpl::GetReferrerPolicy() {
253   base::AutoLock lock_scope(lock_);
254   return referrer_policy_;
255 }
256 
GetPostData()257 CefRefPtr<CefPostData> CefRequestImpl::GetPostData() {
258   base::AutoLock lock_scope(lock_);
259   return postdata_;
260 }
261 
SetPostData(CefRefPtr<CefPostData> postData)262 void CefRequestImpl::SetPostData(CefRefPtr<CefPostData> postData) {
263   base::AutoLock lock_scope(lock_);
264   CHECK_READONLY_RETURN_VOID();
265   Changed(kChangedPostData);
266   postdata_ = postData;
267 }
268 
GetHeaderMap(HeaderMap & headerMap)269 void CefRequestImpl::GetHeaderMap(HeaderMap& headerMap) {
270   base::AutoLock lock_scope(lock_);
271   headerMap = headermap_;
272 }
273 
SetHeaderMap(const HeaderMap & headerMap)274 void CefRequestImpl::SetHeaderMap(const HeaderMap& headerMap) {
275   base::AutoLock lock_scope(lock_);
276   CHECK_READONLY_RETURN_VOID();
277   Changed(kChangedHeaderMap);
278   ::GetHeaderMap(headerMap, headermap_);
279 }
280 
GetHeaderByName(const CefString & name)281 CefString CefRequestImpl::GetHeaderByName(const CefString& name) {
282   base::AutoLock lock_scope(lock_);
283 
284   std::string nameLower = name;
285   HttpHeaderUtils::MakeASCIILower(&nameLower);
286 
287   auto it = HttpHeaderUtils::FindHeaderInMap(nameLower, headermap_);
288   if (it != headermap_.end())
289     return it->second;
290 
291   return CefString();
292 }
293 
SetHeaderByName(const CefString & name,const CefString & value,bool overwrite)294 void CefRequestImpl::SetHeaderByName(const CefString& name,
295                                      const CefString& value,
296                                      bool overwrite) {
297   base::AutoLock lock_scope(lock_);
298   CHECK_READONLY_RETURN_VOID();
299 
300   std::string nameLower = name;
301   HttpHeaderUtils::MakeASCIILower(&nameLower);
302 
303   // Do not include Referer in the header map.
304   if (nameLower == kReferrerLowerCase)
305     return;
306 
307   Changed(kChangedHeaderMap);
308 
309   // There may be multiple values, so remove any first.
310   for (auto it = headermap_.begin(); it != headermap_.end();) {
311     if (base::EqualsCaseInsensitiveASCII(it->first.ToString(), nameLower)) {
312       if (!overwrite)
313         return;
314       it = headermap_.erase(it);
315     } else {
316       ++it;
317     }
318   }
319 
320   headermap_.insert(std::make_pair(name, value));
321 }
322 
Set(const CefString & url,const CefString & method,CefRefPtr<CefPostData> postData,const HeaderMap & headerMap)323 void CefRequestImpl::Set(const CefString& url,
324                          const CefString& method,
325                          CefRefPtr<CefPostData> postData,
326                          const HeaderMap& headerMap) {
327   base::AutoLock lock_scope(lock_);
328   CHECK_READONLY_RETURN_VOID();
329   const GURL& new_url = GURL(url.ToString());
330   if (url_ != new_url) {
331     Changed(kChangedUrl);
332     url_ = new_url;
333   }
334   const std::string& new_method = method;
335   if (method_ != new_method) {
336     Changed(kChangedMethod);
337     method_ = new_method;
338   }
339   if (postdata_ != postData) {
340     Changed(kChangedPostData);
341     postdata_ = postData;
342   }
343   Changed(kChangedHeaderMap);
344   ::GetHeaderMap(headerMap, headermap_);
345 }
346 
GetFlags()347 int CefRequestImpl::GetFlags() {
348   base::AutoLock lock_scope(lock_);
349   return flags_;
350 }
351 
SetFlags(int flags)352 void CefRequestImpl::SetFlags(int flags) {
353   base::AutoLock lock_scope(lock_);
354   CHECK_READONLY_RETURN_VOID();
355   if (flags_ != flags) {
356     Changed(kChangedFlags);
357     flags_ = flags;
358   }
359 }
360 
GetFirstPartyForCookies()361 CefString CefRequestImpl::GetFirstPartyForCookies() {
362   base::AutoLock lock_scope(lock_);
363   return site_for_cookies_.RepresentativeUrl().spec();
364 }
365 
SetFirstPartyForCookies(const CefString & url)366 void CefRequestImpl::SetFirstPartyForCookies(const CefString& url) {
367   base::AutoLock lock_scope(lock_);
368   CHECK_READONLY_RETURN_VOID();
369   auto new_site = net::SiteForCookies::FromUrl(GURL(url.ToString()));
370   if (!new_site.IsEquivalent(site_for_cookies_)) {
371     Changed(kChangedSiteForCookies);
372     site_for_cookies_ = new_site;
373   }
374 }
375 
GetResourceType()376 CefRequestImpl::ResourceType CefRequestImpl::GetResourceType() {
377   base::AutoLock lock_scope(lock_);
378   return resource_type_;
379 }
380 
GetTransitionType()381 CefRequestImpl::TransitionType CefRequestImpl::GetTransitionType() {
382   base::AutoLock lock_scope(lock_);
383   return transition_type_;
384 }
385 
GetIdentifier()386 uint64 CefRequestImpl::GetIdentifier() {
387   base::AutoLock lock_scope(lock_);
388   return identifier_;
389 }
390 
Set(const network::ResourceRequest * request,uint64 identifier)391 void CefRequestImpl::Set(const network::ResourceRequest* request,
392                          uint64 identifier) {
393   base::AutoLock lock_scope(lock_);
394   CHECK_READONLY_RETURN_VOID();
395 
396   Reset();
397 
398   url_ = request->url;
399   method_ = request->method;
400   identifier_ = identifier;
401 
402   if (request->referrer.is_valid()) {
403     const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
404         request->url,
405         content::Referrer(
406             request->referrer,
407             NetReferrerPolicyToBlinkReferrerPolicy(
408                 static_cast<cef_referrer_policy_t>(request->referrer_policy))));
409     referrer_url_ = sanitized_referrer.url;
410     referrer_policy_ =
411         BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
412   }
413 
414   // Transfer request headers.
415   ::GetHeaderMap(request->headers, headermap_);
416 
417   // Transfer post data, if any.
418   if (request->request_body) {
419     postdata_ = CefPostData::Create();
420     static_cast<CefPostDataImpl*>(postdata_.get())->Set(*request->request_body);
421   }
422 
423   site_for_cookies_ = request->site_for_cookies;
424 
425   resource_type_ = static_cast<cef_resource_type_t>(request->resource_type);
426   transition_type_ =
427       static_cast<cef_transition_type_t>(request->transition_type);
428 }
429 
Get(network::ResourceRequest * request,bool changed_only) const430 void CefRequestImpl::Get(network::ResourceRequest* request,
431                          bool changed_only) const {
432   base::AutoLock lock_scope(lock_);
433 
434   if (ShouldSet(kChangedUrl, changed_only))
435     request->url = url_;
436 
437   if (ShouldSet(kChangedMethod, changed_only))
438     request->method = method_;
439 
440   if (ShouldSet(kChangedReferrer, changed_only)) {
441     request->referrer = referrer_url_;
442     request->referrer_policy =
443         static_cast<net::ReferrerPolicy>(referrer_policy_);
444   }
445 
446   if (ShouldSet(kChangedHeaderMap, changed_only)) {
447     net::HttpRequestHeaders headers;
448     headers.AddHeadersFromString(HttpHeaderUtils::GenerateHeaders(headermap_));
449     request->headers.Swap(&headers);
450   }
451 
452   if (ShouldSet(kChangedPostData, changed_only)) {
453     if (postdata_.get()) {
454       request->request_body =
455           static_cast<CefPostDataImpl*>(postdata_.get())->GetBody();
456     } else if (request->request_body) {
457       request->request_body = nullptr;
458     }
459   }
460 
461   if (!site_for_cookies_.IsNull() &&
462       ShouldSet(kChangedSiteForCookies, changed_only)) {
463     request->site_for_cookies = site_for_cookies_;
464   }
465 
466   if (ShouldSet(kChangedFlags, changed_only)) {
467     int flags = flags_;
468     if (!(flags & kURCachePolicyMask)) {
469       // Only consider the Cache-Control directives when a cache policy is not
470       // explicitly set on the request.
471       flags |= GetCacheControlHeaderPolicy(headermap_);
472     }
473 
474     int net_flags = 0;
475 
476     if (flags & UR_FLAG_SKIP_CACHE) {
477       net_flags |= net::LOAD_BYPASS_CACHE;
478     }
479     if (flags & UR_FLAG_ONLY_FROM_CACHE) {
480       net_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION;
481     }
482     if (flags & UR_FLAG_DISABLE_CACHE) {
483       net_flags |= net::LOAD_DISABLE_CACHE;
484     }
485 
486     if (!(flags & UR_FLAG_ALLOW_STORED_CREDENTIALS)) {
487       // This will disable all credentials including cookies, auth tokens, etc.
488       request->credentials_mode = network::mojom::CredentialsMode::kOmit;
489     }
490 
491     request->load_flags = net_flags;
492   }
493 }
494 
Set(const net::RedirectInfo & redirect_info)495 void CefRequestImpl::Set(const net::RedirectInfo& redirect_info) {
496   base::AutoLock lock_scope(lock_);
497   CHECK_READONLY_RETURN_VOID();
498 
499   url_ = redirect_info.new_url;
500   method_ = redirect_info.new_method;
501   site_for_cookies_ = redirect_info.new_site_for_cookies;
502 
503   const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
504       redirect_info.new_url,
505       content::Referrer(GURL(redirect_info.new_referrer),
506                         NetReferrerPolicyToBlinkReferrerPolicy(
507                             static_cast<cef_referrer_policy_t>(
508                                 redirect_info.new_referrer_policy))));
509   referrer_url_ = sanitized_referrer.url;
510   referrer_policy_ =
511       BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
512 }
513 
Set(const net::HttpRequestHeaders & headers)514 void CefRequestImpl::Set(const net::HttpRequestHeaders& headers) {
515   base::AutoLock lock_scope(lock_);
516   CHECK_READONLY_RETURN_VOID();
517 
518   ::GetHeaderMap(headers, headermap_);
519 }
520 
Set(const navigation_interception::NavigationParams & params,bool is_main_frame)521 void CefRequestImpl::Set(
522     const navigation_interception::NavigationParams& params,
523     bool is_main_frame) {
524   base::AutoLock lock_scope(lock_);
525   CHECK_READONLY_RETURN_VOID();
526 
527   Reset();
528 
529   url_ = params.url();
530   method_ = params.is_post() ? "POST" : "GET";
531 
532   const auto& sanitized_referrer =
533       content::Referrer::SanitizeForRequest(params.url(), params.referrer());
534   referrer_url_ = sanitized_referrer.url;
535   referrer_policy_ =
536       BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
537 
538   resource_type_ = is_main_frame ? RT_MAIN_FRAME : RT_SUB_FRAME;
539   transition_type_ =
540       static_cast<cef_transition_type_t>(params.transition_type());
541 }
542 
543 // static
Get(const cef::mojom::RequestParamsPtr & params,blink::WebURLRequest & request)544 void CefRequestImpl::Get(const cef::mojom::RequestParamsPtr& params,
545                          blink::WebURLRequest& request) {
546   request.SetUrl(params->url);
547   request.SetRequestorOrigin(blink::WebSecurityOrigin::Create(params->url));
548   if (!params->method.empty())
549     request.SetHttpMethod(blink::WebString::FromASCII(params->method));
550 
551   if (params->referrer && params->referrer->url.is_valid()) {
552     const blink::WebString& referrer =
553         blink::WebSecurityPolicy::GenerateReferrerHeader(
554             params->referrer->policy, params->url,
555             blink::WebString::FromUTF8(params->referrer->url.spec()));
556     if (!referrer.IsEmpty()) {
557       request.SetReferrerString(referrer);
558       request.SetReferrerPolicy(params->referrer->policy);
559     }
560   }
561 
562   CefRequest::HeaderMap headerMap;
563   if (!params->headers.empty()) {
564     for (net::HttpUtil::HeadersIterator i(params->headers.begin(),
565                                           params->headers.end(), "\n\r");
566          i.GetNext();) {
567       request.AddHttpHeaderField(blink::WebString::FromUTF8(i.name()),
568                                  blink::WebString::FromUTF8(i.values()));
569       headerMap.insert(std::make_pair(i.name(), i.values()));
570     }
571   }
572 
573   if (params->upload_data) {
574     const std::u16string& method = request.HttpMethod().Utf16();
575     if (method == u"GET" || method == u"HEAD") {
576       request.SetHttpMethod(blink::WebString::FromASCII("POST"));
577     }
578 
579     // The comparison performed by httpHeaderField() is case insensitive.
580     if (request
581             .HttpHeaderField(blink::WebString::FromASCII(
582                 net::HttpRequestHeaders::kContentType))
583             .length() == 0) {
584       request.SetHttpHeaderField(
585           blink::WebString::FromASCII(net::HttpRequestHeaders::kContentType),
586           blink::WebString::FromASCII(
587               net_service::kContentTypeApplicationFormURLEncoded));
588     }
589 
590     request.SetHttpBody(
591         blink::GetWebHTTPBodyForRequestBody(*params->upload_data));
592   }
593 
594   if (!params->site_for_cookies.IsNull())
595     request.SetSiteForCookies(params->site_for_cookies);
596 
597   int flags = params->load_flags;
598   if (!(flags & kURCachePolicyMask)) {
599     // Only consider the Cache-Control directives when a cache policy is not
600     // explicitly set on the request.
601     flags |= GetCacheControlHeaderPolicy(headerMap);
602   }
603   request.SetCacheMode(GetFetchCacheMode(flags));
604 
605   SETBOOLFLAG(request, params->load_flags, SetAllowStoredCredentials,
606               UR_FLAG_ALLOW_STORED_CREDENTIALS);
607   SETBOOLFLAG(request, params->load_flags, SetReportUploadProgress,
608               UR_FLAG_REPORT_UPLOAD_PROGRESS);
609 }
610 
Get(cef::mojom::RequestParamsPtr & params) const611 void CefRequestImpl::Get(cef::mojom::RequestParamsPtr& params) const {
612   base::AutoLock lock_scope(lock_);
613 
614   params->url = url_;
615   params->method = method_;
616 
617   // Referrer policy will be applied later in the request pipeline.
618   params->referrer = blink::mojom::Referrer::New(
619       referrer_url_, NetReferrerPolicyToBlinkReferrerPolicy(referrer_policy_));
620 
621   if (!headermap_.empty())
622     params->headers = HttpHeaderUtils::GenerateHeaders(headermap_);
623 
624   if (postdata_) {
625     CefPostDataImpl* impl = static_cast<CefPostDataImpl*>(postdata_.get());
626     params->upload_data = impl->GetBody();
627   }
628 
629   params->site_for_cookies = site_for_cookies_;
630   params->load_flags = flags_;
631 }
632 
SetReadOnly(bool read_only)633 void CefRequestImpl::SetReadOnly(bool read_only) {
634   base::AutoLock lock_scope(lock_);
635   if (read_only_ == read_only)
636     return;
637 
638   read_only_ = read_only;
639 
640   if (postdata_.get())
641     static_cast<CefPostDataImpl*>(postdata_.get())->SetReadOnly(read_only);
642 }
643 
SetTrackChanges(bool track_changes,bool backup_on_change)644 void CefRequestImpl::SetTrackChanges(bool track_changes,
645                                      bool backup_on_change) {
646   base::AutoLock lock_scope(lock_);
647   if (track_changes_ == track_changes)
648     return;
649 
650   if (!track_changes && backup_on_change_)
651     backup_.reset();
652 
653   track_changes_ = track_changes;
654   backup_on_change_ = track_changes ? backup_on_change : false;
655   changes_ = kChangedNone;
656 
657   if (postdata_.get()) {
658     static_cast<CefPostDataImpl*>(postdata_.get())
659         ->SetTrackChanges(track_changes);
660   }
661 }
662 
RevertChanges()663 void CefRequestImpl::RevertChanges() {
664   base::AutoLock lock_scope(lock_);
665   DCHECK(!read_only_);
666   DCHECK(track_changes_);
667   DCHECK(backup_on_change_);
668   if (!backup_)
669     return;
670 
671   // Restore the original values if a backup exists.
672   if (backup_->backups_ & kChangedUrl)
673     url_ = backup_->url_;
674   if (backup_->backups_ & kChangedMethod)
675     method_ = backup_->method_;
676   if (backup_->backups_ & kChangedReferrer) {
677     referrer_url_ = backup_->referrer_url_;
678     referrer_policy_ = backup_->referrer_policy_;
679   }
680   if (backup_->backups_ & kChangedPostData)
681     postdata_ = backup_->postdata_;
682   if (backup_->backups_ & kChangedHeaderMap) {
683     DCHECK(backup_->headermap_);
684     headermap_.swap(*backup_->headermap_);
685   }
686   if (backup_->backups_ & kChangedFlags)
687     flags_ = backup_->flags_;
688   if (backup_->backups_ & kChangedSiteForCookies)
689     site_for_cookies_ = backup_->site_for_cookies_;
690 
691   backup_.reset();
692 }
693 
DiscardChanges()694 void CefRequestImpl::DiscardChanges() {
695   base::AutoLock lock_scope(lock_);
696   DCHECK(track_changes_);
697   DCHECK(backup_on_change_);
698   backup_.reset();
699 }
700 
GetChanges() const701 uint8_t CefRequestImpl::GetChanges() const {
702   base::AutoLock lock_scope(lock_);
703 
704   uint8_t changes = changes_;
705   if (postdata_.get() &&
706       static_cast<CefPostDataImpl*>(postdata_.get())->HasChanges()) {
707     changes |= kChangedPostData;
708   }
709   return changes;
710 }
711 
712 // From content/child/web_url_loader_impl.cc
713 // static
714 network::mojom::ReferrerPolicy
NetReferrerPolicyToBlinkReferrerPolicy(cef_referrer_policy_t net_policy)715 CefRequestImpl::NetReferrerPolicyToBlinkReferrerPolicy(
716     cef_referrer_policy_t net_policy) {
717   switch (net_policy) {
718     case REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
719       return network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
720     case REFERRER_POLICY_REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
721       return network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin;
722     case REFERRER_POLICY_ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
723       return network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin;
724     case REFERRER_POLICY_NEVER_CLEAR_REFERRER:
725       return network::mojom::ReferrerPolicy::kAlways;
726     case REFERRER_POLICY_ORIGIN:
727       return network::mojom::ReferrerPolicy::kOrigin;
728     case REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN:
729       return network::mojom::ReferrerPolicy::kSameOrigin;
730     case REFERRER_POLICY_ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
731       return network::mojom::ReferrerPolicy::kStrictOrigin;
732     case REFERRER_POLICY_NO_REFERRER:
733       return network::mojom::ReferrerPolicy::kNever;
734   }
735   NOTREACHED();
736   return network::mojom::ReferrerPolicy::kDefault;
737 }
738 
739 // static
BlinkReferrerPolicyToNetReferrerPolicy(network::mojom::ReferrerPolicy blink_policy)740 cef_referrer_policy_t CefRequestImpl::BlinkReferrerPolicyToNetReferrerPolicy(
741     network::mojom::ReferrerPolicy blink_policy) {
742   switch (blink_policy) {
743     case network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade:
744       return REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
745     case network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin:
746       return REFERRER_POLICY_REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN;
747     case network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin:
748       return REFERRER_POLICY_ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
749     case network::mojom::ReferrerPolicy::kAlways:
750       return REFERRER_POLICY_NEVER_CLEAR_REFERRER;
751     case network::mojom::ReferrerPolicy::kOrigin:
752       return REFERRER_POLICY_ORIGIN;
753     case network::mojom::ReferrerPolicy::kSameOrigin:
754       return REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN;
755     case network::mojom::ReferrerPolicy::kStrictOrigin:
756       return REFERRER_POLICY_ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
757     case network::mojom::ReferrerPolicy::kNever:
758       return REFERRER_POLICY_NO_REFERRER;
759     case network::mojom::ReferrerPolicy::kDefault:
760       return REFERRER_POLICY_DEFAULT;
761   }
762   NOTREACHED();
763   return REFERRER_POLICY_DEFAULT;
764 }
765 
Changed(uint8_t changes)766 void CefRequestImpl::Changed(uint8_t changes) {
767   lock_.AssertAcquired();
768   if (!track_changes_)
769     return;
770 
771   if (backup_on_change_) {
772     if (!backup_)
773       backup_.reset(new Backup());
774 
775     // Set the backup values if not already set.
776     if ((changes & kChangedUrl) && !(backup_->backups_ & kChangedUrl)) {
777       backup_->url_ = url_;
778       backup_->backups_ |= kChangedUrl;
779     }
780     if ((changes & kChangedMethod) && !(backup_->backups_ & kChangedMethod)) {
781       backup_->method_ = method_;
782       backup_->backups_ |= kChangedMethod;
783     }
784     if ((changes & kChangedReferrer) &&
785         !(backup_->backups_ & kChangedReferrer)) {
786       backup_->referrer_url_ = referrer_url_;
787       backup_->referrer_policy_ = referrer_policy_;
788       backup_->backups_ |= kChangedReferrer;
789     }
790     if ((changes & kChangedPostData) &&
791         !(backup_->backups_ & kChangedPostData)) {
792       backup_->postdata_ = postdata_;
793       backup_->backups_ |= kChangedPostData;
794     }
795     if ((changes & kChangedHeaderMap) &&
796         !(backup_->backups_ & kChangedHeaderMap)) {
797       backup_->headermap_.reset(new HeaderMap());
798       if (!headermap_.empty()) {
799         backup_->headermap_->insert(headermap_.begin(), headermap_.end());
800       }
801       backup_->backups_ |= kChangedHeaderMap;
802     }
803     if ((changes & kChangedFlags) && !(backup_->backups_ & kChangedFlags)) {
804       backup_->flags_ = flags_;
805       backup_->backups_ |= kChangedFlags;
806     }
807     if ((changes & kChangedSiteForCookies) &&
808         !(backup_->backups_ & kChangedSiteForCookies)) {
809       backup_->site_for_cookies_ = site_for_cookies_;
810       backup_->backups_ |= kChangedSiteForCookies;
811     }
812   }
813 
814   changes_ |= changes;
815 }
816 
ShouldSet(uint8_t changes,bool changed_only) const817 bool CefRequestImpl::ShouldSet(uint8_t changes, bool changed_only) const {
818   lock_.AssertAcquired();
819 
820   // Always change if changes are not being tracked.
821   if (!track_changes_)
822     return true;
823 
824   // Always change if changed-only was not requested.
825   if (!changed_only)
826     return true;
827 
828   // Change if the |changes| bit flag has been set.
829   if ((changes_ & changes) == changes)
830     return true;
831 
832   if ((changes & kChangedPostData) == kChangedPostData) {
833     // Change if the post data object was modified directly.
834     if (postdata_.get() &&
835         static_cast<CefPostDataImpl*>(postdata_.get())->HasChanges()) {
836       return true;
837     }
838   }
839 
840   return false;
841 }
842 
Reset()843 void CefRequestImpl::Reset() {
844   lock_.AssertAcquired();
845   DCHECK(!read_only_);
846 
847   url_ = GURL();
848   method_ = "GET";
849   referrer_url_ = GURL();
850   referrer_policy_ = REFERRER_POLICY_DEFAULT;
851   postdata_ = nullptr;
852   headermap_.clear();
853   resource_type_ = RT_SUB_RESOURCE;
854   transition_type_ = TT_EXPLICIT;
855   identifier_ = 0U;
856   flags_ = UR_FLAG_NONE;
857   site_for_cookies_ = net::SiteForCookies();
858 
859   changes_ = kChangedNone;
860 }
861 
862 // CefPostData ----------------------------------------------------------------
863 
864 // static
Create()865 CefRefPtr<CefPostData> CefPostData::Create() {
866   CefRefPtr<CefPostData> postdata(new CefPostDataImpl());
867   return postdata;
868 }
869 
870 // CefPostDataImpl ------------------------------------------------------------
871 
CefPostDataImpl()872 CefPostDataImpl::CefPostDataImpl()
873     : read_only_(false),
874       has_excluded_elements_(false),
875       track_changes_(false),
876       has_changes_(false) {}
877 
IsReadOnly()878 bool CefPostDataImpl::IsReadOnly() {
879   base::AutoLock lock_scope(lock_);
880   return read_only_;
881 }
882 
HasExcludedElements()883 bool CefPostDataImpl::HasExcludedElements() {
884   base::AutoLock lock_scope(lock_);
885   return has_excluded_elements_;
886 }
887 
GetElementCount()888 size_t CefPostDataImpl::GetElementCount() {
889   base::AutoLock lock_scope(lock_);
890   return elements_.size();
891 }
892 
GetElements(ElementVector & elements)893 void CefPostDataImpl::GetElements(ElementVector& elements) {
894   base::AutoLock lock_scope(lock_);
895   elements = elements_;
896 }
897 
RemoveElement(CefRefPtr<CefPostDataElement> element)898 bool CefPostDataImpl::RemoveElement(CefRefPtr<CefPostDataElement> element) {
899   base::AutoLock lock_scope(lock_);
900   CHECK_READONLY_RETURN(false);
901 
902   ElementVector::iterator it = elements_.begin();
903   for (; it != elements_.end(); ++it) {
904     if (it->get() == element.get()) {
905       elements_.erase(it);
906       Changed();
907       return true;
908     }
909   }
910 
911   return false;
912 }
913 
AddElement(CefRefPtr<CefPostDataElement> element)914 bool CefPostDataImpl::AddElement(CefRefPtr<CefPostDataElement> element) {
915   bool found = false;
916 
917   base::AutoLock lock_scope(lock_);
918   CHECK_READONLY_RETURN(false);
919 
920   // check that the element isn't already in the list before adding
921   ElementVector::const_iterator it = elements_.begin();
922   for (; it != elements_.end(); ++it) {
923     if (it->get() == element.get()) {
924       found = true;
925       break;
926     }
927   }
928 
929   if (!found) {
930     elements_.push_back(element);
931     Changed();
932   }
933 
934   return !found;
935 }
936 
RemoveElements()937 void CefPostDataImpl::RemoveElements() {
938   base::AutoLock lock_scope(lock_);
939   CHECK_READONLY_RETURN_VOID();
940   elements_.clear();
941   Changed();
942 }
943 
Set(const network::ResourceRequestBody & body)944 void CefPostDataImpl::Set(const network::ResourceRequestBody& body) {
945   {
946     base::AutoLock lock_scope(lock_);
947     CHECK_READONLY_RETURN_VOID();
948   }
949 
950   CefRefPtr<CefPostDataElement> postelem;
951 
952   for (const auto& element : *body.elements()) {
953     postelem = CefPostDataElement::Create();
954     static_cast<CefPostDataElementImpl*>(postelem.get())->Set(element);
955     AddElement(postelem);
956   }
957 }
958 
GetBody() const959 scoped_refptr<network::ResourceRequestBody> CefPostDataImpl::GetBody() const {
960   base::AutoLock lock_scope(lock_);
961 
962   scoped_refptr<network::ResourceRequestBody> body =
963       new network::ResourceRequestBody();
964   for (const auto& element : elements_) {
965     static_cast<CefPostDataElementImpl*>(element.get())->Get(*body);
966   }
967   return body;
968 }
969 
SetReadOnly(bool read_only)970 void CefPostDataImpl::SetReadOnly(bool read_only) {
971   base::AutoLock lock_scope(lock_);
972   if (read_only_ == read_only)
973     return;
974 
975   read_only_ = read_only;
976 
977   ElementVector::const_iterator it = elements_.begin();
978   for (; it != elements_.end(); ++it) {
979     static_cast<CefPostDataElementImpl*>(it->get())->SetReadOnly(read_only);
980   }
981 }
982 
SetTrackChanges(bool track_changes)983 void CefPostDataImpl::SetTrackChanges(bool track_changes) {
984   base::AutoLock lock_scope(lock_);
985   if (track_changes_ == track_changes)
986     return;
987 
988   track_changes_ = track_changes;
989   has_changes_ = false;
990 
991   ElementVector::const_iterator it = elements_.begin();
992   for (; it != elements_.end(); ++it) {
993     static_cast<CefPostDataElementImpl*>(it->get())->SetTrackChanges(
994         track_changes);
995   }
996 }
997 
HasChanges() const998 bool CefPostDataImpl::HasChanges() const {
999   base::AutoLock lock_scope(lock_);
1000   if (has_changes_)
1001     return true;
1002 
1003   ElementVector::const_iterator it = elements_.begin();
1004   for (; it != elements_.end(); ++it) {
1005     if (static_cast<CefPostDataElementImpl*>(it->get())->HasChanges())
1006       return true;
1007   }
1008 
1009   return false;
1010 }
1011 
Changed()1012 void CefPostDataImpl::Changed() {
1013   lock_.AssertAcquired();
1014   if (track_changes_ && !has_changes_)
1015     has_changes_ = true;
1016 }
1017 
1018 // CefPostDataElement ---------------------------------------------------------
1019 
1020 // static
Create()1021 CefRefPtr<CefPostDataElement> CefPostDataElement::Create() {
1022   CefRefPtr<CefPostDataElement> element(new CefPostDataElementImpl());
1023   return element;
1024 }
1025 
1026 // CefPostDataElementImpl -----------------------------------------------------
1027 
CefPostDataElementImpl()1028 CefPostDataElementImpl::CefPostDataElementImpl()
1029     : type_(PDE_TYPE_EMPTY),
1030       read_only_(false),
1031       track_changes_(false),
1032       has_changes_(false) {
1033   memset(&data_, 0, sizeof(data_));
1034 }
1035 
~CefPostDataElementImpl()1036 CefPostDataElementImpl::~CefPostDataElementImpl() {
1037   Cleanup();
1038 }
1039 
IsReadOnly()1040 bool CefPostDataElementImpl::IsReadOnly() {
1041   base::AutoLock lock_scope(lock_);
1042   return read_only_;
1043 }
1044 
SetToEmpty()1045 void CefPostDataElementImpl::SetToEmpty() {
1046   base::AutoLock lock_scope(lock_);
1047   CHECK_READONLY_RETURN_VOID();
1048 
1049   Cleanup();
1050   Changed();
1051 }
1052 
SetToFile(const CefString & fileName)1053 void CefPostDataElementImpl::SetToFile(const CefString& fileName) {
1054   base::AutoLock lock_scope(lock_);
1055   CHECK_READONLY_RETURN_VOID();
1056 
1057   // Clear any data currently in the element
1058   Cleanup();
1059 
1060   // Assign the new data
1061   type_ = PDE_TYPE_FILE;
1062   cef_string_copy(fileName.c_str(), fileName.length(), &data_.filename);
1063 
1064   Changed();
1065 }
1066 
SetToBytes(size_t size,const void * bytes)1067 void CefPostDataElementImpl::SetToBytes(size_t size, const void* bytes) {
1068   base::AutoLock lock_scope(lock_);
1069   CHECK_READONLY_RETURN_VOID();
1070 
1071   // Clear any data currently in the element
1072   Cleanup();
1073 
1074   // Assign the new data
1075   void* data = malloc(size);
1076   DCHECK(data != nullptr);
1077   if (data == nullptr)
1078     return;
1079 
1080   memcpy(data, bytes, size);
1081 
1082   type_ = PDE_TYPE_BYTES;
1083   data_.bytes.bytes = data;
1084   data_.bytes.size = size;
1085 
1086   Changed();
1087 }
1088 
GetType()1089 CefPostDataElement::Type CefPostDataElementImpl::GetType() {
1090   base::AutoLock lock_scope(lock_);
1091   return type_;
1092 }
1093 
GetFile()1094 CefString CefPostDataElementImpl::GetFile() {
1095   base::AutoLock lock_scope(lock_);
1096   DCHECK(type_ == PDE_TYPE_FILE);
1097   CefString filename;
1098   if (type_ == PDE_TYPE_FILE)
1099     filename.FromString(data_.filename.str, data_.filename.length, false);
1100   return filename;
1101 }
1102 
GetBytesCount()1103 size_t CefPostDataElementImpl::GetBytesCount() {
1104   base::AutoLock lock_scope(lock_);
1105   DCHECK(type_ == PDE_TYPE_BYTES);
1106   size_t size = 0;
1107   if (type_ == PDE_TYPE_BYTES)
1108     size = data_.bytes.size;
1109   return size;
1110 }
1111 
GetBytes(size_t size,void * bytes)1112 size_t CefPostDataElementImpl::GetBytes(size_t size, void* bytes) {
1113   base::AutoLock lock_scope(lock_);
1114   DCHECK(type_ == PDE_TYPE_BYTES);
1115   size_t rv = 0;
1116   if (type_ == PDE_TYPE_BYTES) {
1117     rv = (size < data_.bytes.size ? size : data_.bytes.size);
1118     memcpy(bytes, data_.bytes.bytes, rv);
1119   }
1120   return rv;
1121 }
1122 
Set(const network::DataElement & element)1123 void CefPostDataElementImpl::Set(const network::DataElement& element) {
1124   {
1125     base::AutoLock lock_scope(lock_);
1126     CHECK_READONLY_RETURN_VOID();
1127   }
1128 
1129   if (element.type() == network::DataElement::Tag::kBytes) {
1130     const auto& bytes_element = element.As<network::DataElementBytes>();
1131     const auto& bytes = bytes_element.bytes();
1132     SetToBytes(bytes.size(), bytes.data());
1133   } else if (element.type() == network::DataElement::Tag::kFile) {
1134     const auto& file_element = element.As<network::DataElementFile>();
1135     SetToFile(file_element.path().value());
1136   }
1137 }
1138 
Get(network::ResourceRequestBody & body) const1139 void CefPostDataElementImpl::Get(network::ResourceRequestBody& body) const {
1140   base::AutoLock lock_scope(lock_);
1141 
1142   if (type_ == PDE_TYPE_BYTES) {
1143     body.AppendBytes(static_cast<char*>(data_.bytes.bytes), data_.bytes.size);
1144   } else if (type_ == PDE_TYPE_FILE) {
1145     base::FilePath path = base::FilePath(CefString(&data_.filename));
1146     body.AppendFileRange(path, 0, std::numeric_limits<uint64_t>::max(),
1147                          base::Time());
1148   } else {
1149     NOTREACHED();
1150   }
1151 }
1152 
SetReadOnly(bool read_only)1153 void CefPostDataElementImpl::SetReadOnly(bool read_only) {
1154   base::AutoLock lock_scope(lock_);
1155   if (read_only_ == read_only)
1156     return;
1157 
1158   read_only_ = read_only;
1159 }
1160 
SetTrackChanges(bool track_changes)1161 void CefPostDataElementImpl::SetTrackChanges(bool track_changes) {
1162   base::AutoLock lock_scope(lock_);
1163   if (track_changes_ == track_changes)
1164     return;
1165 
1166   track_changes_ = track_changes;
1167   has_changes_ = false;
1168 }
1169 
HasChanges() const1170 bool CefPostDataElementImpl::HasChanges() const {
1171   base::AutoLock lock_scope(lock_);
1172   return has_changes_;
1173 }
1174 
Changed()1175 void CefPostDataElementImpl::Changed() {
1176   lock_.AssertAcquired();
1177   if (track_changes_ && !has_changes_)
1178     has_changes_ = true;
1179 }
1180 
Cleanup()1181 void CefPostDataElementImpl::Cleanup() {
1182   if (type_ == PDE_TYPE_EMPTY)
1183     return;
1184 
1185   if (type_ == PDE_TYPE_BYTES)
1186     free(data_.bytes.bytes);
1187   else if (type_ == PDE_TYPE_FILE)
1188     cef_string_clear(&data_.filename);
1189   type_ = PDE_TYPE_EMPTY;
1190   memset(&data_, 0, sizeof(data_));
1191 }
1192