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