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