mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			1192 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1192 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2008-2009 The Chromium Embedded Framework Authors. All rights
 | |
| // reserved. Use of this source code is governed by a BSD-style license that
 | |
| // can be found in the LICENSE file.
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <limits>
 | |
| #include <string>
 | |
| #include <utility>
 | |
| #include <vector>
 | |
| 
 | |
| #include "libcef/common/net/http_header_utils.h"
 | |
| #include "libcef/common/net_service/net_service_util.h"
 | |
| #include "libcef/common/request_impl.h"
 | |
| 
 | |
| #include "base/command_line.h"
 | |
| #include "base/logging.h"
 | |
| #include "base/strings/string_split.h"
 | |
| #include "base/strings/string_util.h"
 | |
| #include "base/strings/utf_string_conversions.h"
 | |
| #include "components/navigation_interception/navigation_params.h"
 | |
| #include "content/public/browser/browser_thread.h"
 | |
| #include "content/public/common/content_switches.h"
 | |
| #include "net/base/elements_upload_data_stream.h"
 | |
| #include "net/base/load_flags.h"
 | |
| #include "net/base/upload_bytes_element_reader.h"
 | |
| #include "net/base/upload_data_stream.h"
 | |
| #include "net/base/upload_element_reader.h"
 | |
| #include "net/base/upload_file_element_reader.h"
 | |
| #include "net/http/http_request_headers.h"
 | |
| #include "net/http/http_util.h"
 | |
| #include "net/url_request/redirect_info.h"
 | |
| #include "net/url_request/referrer_policy.h"
 | |
| #include "services/network/public/cpp/data_element.h"
 | |
| #include "services/network/public/cpp/network_switches.h"
 | |
| #include "services/network/public/cpp/resource_request.h"
 | |
| #include "services/network/public/cpp/resource_request_body.h"
 | |
| #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
 | |
| #include "third_party/blink/public/platform/web_http_body.h"
 | |
| #include "third_party/blink/public/platform/web_security_origin.h"
 | |
| #include "third_party/blink/public/platform/web_string.h"
 | |
| #include "third_party/blink/public/platform/web_url.h"
 | |
| #include "third_party/blink/public/platform/web_url_error.h"
 | |
| #include "third_party/blink/public/platform/web_url_request.h"
 | |
| #include "third_party/blink/public/platform/web_url_request_util.h"
 | |
| #include "third_party/blink/public/web/web_security_policy.h"
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| const char kReferrerLowerCase[] = "referer";
 | |
| const char kCacheControlLowerCase[] = "cache-control";
 | |
| const char kCacheControlDirectiveNoCacheLowerCase[] = "no-cache";
 | |
| const char kCacheControlDirectiveNoStoreLowerCase[] = "no-store";
 | |
| const char kCacheControlDirectiveOnlyIfCachedLowerCase[] = "only-if-cached";
 | |
| 
 | |
| // Mask of values that configure the cache policy.
 | |
| const int kURCachePolicyMask =
 | |
|     (UR_FLAG_SKIP_CACHE | UR_FLAG_ONLY_FROM_CACHE | UR_FLAG_DISABLE_CACHE);
 | |
| 
 | |
| // Returns the cef_urlrequest_flags_t policy specified by the Cache-Control
 | |
| // request header directives, if any. The directives are case-insensitive and
 | |
| // some have an optional argument. Multiple directives are comma-separated.
 | |
| // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
 | |
| // for details.
 | |
| int GetCacheControlHeaderPolicy(CefRequest::HeaderMap headerMap) {
 | |
|   std::string line;
 | |
| 
 | |
|   // Extract the Cache-Control header line.
 | |
|   {
 | |
|     CefRequest::HeaderMap::const_iterator it = headerMap.begin();
 | |
|     for (; it != headerMap.end(); ++it) {
 | |
|       if (base::LowerCaseEqualsASCII(it->first.ToString(),
 | |
|                                      kCacheControlLowerCase)) {
 | |
|         line = it->second;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   int flags = 0;
 | |
| 
 | |
|   if (!line.empty()) {
 | |
|     HttpHeaderUtils::MakeASCIILower(&line);
 | |
| 
 | |
|     std::vector<base::StringPiece> pieces = base::SplitStringPiece(
 | |
|         line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 | |
|     for (const auto& piece : pieces) {
 | |
|       if (base::LowerCaseEqualsASCII(piece,
 | |
|                                      kCacheControlDirectiveNoCacheLowerCase)) {
 | |
|         flags |= UR_FLAG_SKIP_CACHE;
 | |
|       } else if (base::LowerCaseEqualsASCII(
 | |
|                      piece, kCacheControlDirectiveOnlyIfCachedLowerCase)) {
 | |
|         flags |= UR_FLAG_ONLY_FROM_CACHE;
 | |
|       } else if (base::LowerCaseEqualsASCII(
 | |
|                      piece, kCacheControlDirectiveNoStoreLowerCase)) {
 | |
|         flags |= UR_FLAG_DISABLE_CACHE;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return flags;
 | |
| }
 | |
| 
 | |
| // Convert cef_urlrequest_flags_t to blink::WebCachePolicy.
 | |
| blink::mojom::FetchCacheMode GetFetchCacheMode(int ur_flags) {
 | |
|   const bool skip_cache{!!(ur_flags & UR_FLAG_SKIP_CACHE)};
 | |
|   const bool only_from_cache{!!(ur_flags & UR_FLAG_ONLY_FROM_CACHE)};
 | |
|   const bool disable_cache{!!(ur_flags & UR_FLAG_DISABLE_CACHE)};
 | |
|   if (only_from_cache && (skip_cache || disable_cache)) {
 | |
|     // The request will always fail because only_from_cache and
 | |
|     // skip_cache/disable_cache are mutually exclusive.
 | |
|     return blink::mojom::FetchCacheMode::kUnspecifiedForceCacheMiss;
 | |
|   } else if (disable_cache) {
 | |
|     // This additionally implies the skip_cache behavior.
 | |
|     return blink::mojom::FetchCacheMode::kNoStore;
 | |
|   } else if (skip_cache) {
 | |
|     return blink::mojom::FetchCacheMode::kBypassCache;
 | |
|   } else if (only_from_cache) {
 | |
|     return blink::mojom::FetchCacheMode::kOnlyIfCached;
 | |
|   }
 | |
|   return blink::mojom::FetchCacheMode::kDefault;
 | |
| }
 | |
| 
 | |
| // Read |headers| into |map|.
 | |
| void GetHeaderMap(const net::HttpRequestHeaders& headers,
 | |
|                   CefRequest::HeaderMap& map) {
 | |
|   map.clear();
 | |
| 
 | |
|   if (headers.IsEmpty())
 | |
|     return;
 | |
| 
 | |
|   net::HttpRequestHeaders::Iterator it(headers);
 | |
|   while (it.GetNext()) {
 | |
|     const std::string& name = it.name();
 | |
| 
 | |
|     // Do not include Referer in the header map.
 | |
|     if (!base::LowerCaseEqualsASCII(name, kReferrerLowerCase))
 | |
|       map.insert(std::make_pair(name, it.value()));
 | |
|   };
 | |
| }
 | |
| 
 | |
| // Read |source| into |map|.
 | |
| void GetHeaderMap(const CefRequest::HeaderMap& source,
 | |
|                   CefRequest::HeaderMap& map) {
 | |
|   map.clear();
 | |
| 
 | |
|   CefRequest::HeaderMap::const_iterator it = source.begin();
 | |
|   for (; it != source.end(); ++it) {
 | |
|     const CefString& name = it->first;
 | |
| 
 | |
|     // Do not include Referer in the header map.
 | |
|     if (!base::LowerCaseEqualsASCII(name.ToString(), kReferrerLowerCase))
 | |
|       map.insert(std::make_pair(name, it->second));
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| #define CHECK_READONLY_RETURN(val)         \
 | |
|   if (read_only_) {                        \
 | |
|     NOTREACHED() << "object is read only"; \
 | |
|     return val;                            \
 | |
|   }
 | |
| 
 | |
| #define CHECK_READONLY_RETURN_VOID()       \
 | |
|   if (read_only_) {                        \
 | |
|     NOTREACHED() << "object is read only"; \
 | |
|     return;                                \
 | |
|   }
 | |
| 
 | |
| #define SETBOOLFLAG(obj, flags, method, FLAG) \
 | |
|   obj.method((flags & (FLAG)) == (FLAG))
 | |
| 
 | |
| // CefRequest -----------------------------------------------------------------
 | |
| 
 | |
| // static
 | |
| CefRefPtr<CefRequest> CefRequest::Create() {
 | |
|   CefRefPtr<CefRequest> request(new CefRequestImpl());
 | |
|   return request;
 | |
| }
 | |
| 
 | |
| // CefRequestImpl -------------------------------------------------------------
 | |
| 
 | |
| CefRequestImpl::CefRequestImpl() {
 | |
|   // Verify that our enum matches Chromium's values.
 | |
|   static_assert(static_cast<int>(REFERRER_POLICY_LAST_VALUE) ==
 | |
|                     static_cast<int>(net::ReferrerPolicy::MAX),
 | |
|                 "enum mismatch");
 | |
| 
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   Reset();
 | |
| }
 | |
| 
 | |
| bool CefRequestImpl::IsReadOnly() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return read_only_;
 | |
| }
 | |
| 
 | |
| CefString CefRequestImpl::GetURL() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return url_.spec();
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetURL(const CefString& url) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   const GURL& new_url = GURL(url.ToString());
 | |
|   if (url_ != new_url) {
 | |
|     Changed(kChangedUrl);
 | |
|     url_ = new_url;
 | |
|   }
 | |
| }
 | |
| 
 | |
| CefString CefRequestImpl::GetMethod() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return method_;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetMethod(const CefString& method) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   const std::string& new_method = method;
 | |
|   if (method_ != new_method) {
 | |
|     Changed(kChangedMethod);
 | |
|     method_ = new_method;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetReferrer(const CefString& referrer_url,
 | |
|                                  ReferrerPolicy policy) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
 | |
|       url_, content::Referrer(GURL(referrer_url.ToString()),
 | |
|                               NetReferrerPolicyToBlinkReferrerPolicy(policy)));
 | |
|   const auto sanitized_policy =
 | |
|       BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
 | |
| 
 | |
|   if (referrer_url_ != sanitized_referrer.url ||
 | |
|       referrer_policy_ != sanitized_policy) {
 | |
|     Changed(kChangedReferrer);
 | |
|     referrer_url_ = sanitized_referrer.url;
 | |
|     referrer_policy_ = sanitized_policy;
 | |
|   }
 | |
| }
 | |
| 
 | |
| CefString CefRequestImpl::GetReferrerURL() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return referrer_url_.spec();
 | |
| }
 | |
| 
 | |
| CefRequestImpl::ReferrerPolicy CefRequestImpl::GetReferrerPolicy() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return referrer_policy_;
 | |
| }
 | |
| 
 | |
| CefRefPtr<CefPostData> CefRequestImpl::GetPostData() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return postdata_;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetPostData(CefRefPtr<CefPostData> postData) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   Changed(kChangedPostData);
 | |
|   postdata_ = postData;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::GetHeaderMap(HeaderMap& headerMap) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   headerMap = headermap_;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetHeaderMap(const HeaderMap& headerMap) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   Changed(kChangedHeaderMap);
 | |
|   ::GetHeaderMap(headerMap, headermap_);
 | |
| }
 | |
| 
 | |
| CefString CefRequestImpl::GetHeaderByName(const CefString& name) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|   std::string nameLower = name;
 | |
|   HttpHeaderUtils::MakeASCIILower(&nameLower);
 | |
| 
 | |
|   auto it = HttpHeaderUtils::FindHeaderInMap(nameLower, headermap_);
 | |
|   if (it != headermap_.end())
 | |
|     return it->second;
 | |
| 
 | |
|   return CefString();
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetHeaderByName(const CefString& name,
 | |
|                                      const CefString& value,
 | |
|                                      bool overwrite) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   std::string nameLower = name;
 | |
|   HttpHeaderUtils::MakeASCIILower(&nameLower);
 | |
| 
 | |
|   // Do not include Referer in the header map.
 | |
|   if (nameLower == kReferrerLowerCase)
 | |
|     return;
 | |
| 
 | |
|   Changed(kChangedHeaderMap);
 | |
| 
 | |
|   // There may be multiple values, so remove any first.
 | |
|   for (auto it = headermap_.begin(); it != headermap_.end();) {
 | |
|     if (base::EqualsCaseInsensitiveASCII(it->first.ToString(), nameLower)) {
 | |
|       if (!overwrite)
 | |
|         return;
 | |
|       it = headermap_.erase(it);
 | |
|     } else {
 | |
|       ++it;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   headermap_.insert(std::make_pair(name, value));
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Set(const CefString& url,
 | |
|                          const CefString& method,
 | |
|                          CefRefPtr<CefPostData> postData,
 | |
|                          const HeaderMap& headerMap) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   const GURL& new_url = GURL(url.ToString());
 | |
|   if (url_ != new_url) {
 | |
|     Changed(kChangedUrl);
 | |
|     url_ = new_url;
 | |
|   }
 | |
|   const std::string& new_method = method;
 | |
|   if (method_ != new_method) {
 | |
|     Changed(kChangedMethod);
 | |
|     method_ = new_method;
 | |
|   }
 | |
|   if (postdata_ != postData) {
 | |
|     Changed(kChangedPostData);
 | |
|     postdata_ = postData;
 | |
|   }
 | |
|   Changed(kChangedHeaderMap);
 | |
|   ::GetHeaderMap(headerMap, headermap_);
 | |
| }
 | |
| 
 | |
| int CefRequestImpl::GetFlags() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return flags_;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetFlags(int flags) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   if (flags_ != flags) {
 | |
|     Changed(kChangedFlags);
 | |
|     flags_ = flags;
 | |
|   }
 | |
| }
 | |
| 
 | |
| CefString CefRequestImpl::GetFirstPartyForCookies() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return site_for_cookies_.RepresentativeUrl().spec();
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetFirstPartyForCookies(const CefString& url) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   auto new_site = net::SiteForCookies::FromUrl(GURL(url.ToString()));
 | |
|   if (!new_site.IsEquivalent(site_for_cookies_)) {
 | |
|     Changed(kChangedSiteForCookies);
 | |
|     site_for_cookies_ = new_site;
 | |
|   }
 | |
| }
 | |
| 
 | |
| CefRequestImpl::ResourceType CefRequestImpl::GetResourceType() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return resource_type_;
 | |
| }
 | |
| 
 | |
| CefRequestImpl::TransitionType CefRequestImpl::GetTransitionType() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return transition_type_;
 | |
| }
 | |
| 
 | |
| uint64 CefRequestImpl::GetIdentifier() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return identifier_;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Set(const network::ResourceRequest* request,
 | |
|                          uint64 identifier) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   Reset();
 | |
| 
 | |
|   url_ = request->url;
 | |
|   method_ = request->method;
 | |
|   identifier_ = identifier;
 | |
| 
 | |
|   if (request->referrer.is_valid()) {
 | |
|     const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
 | |
|         request->url,
 | |
|         content::Referrer(
 | |
|             request->referrer,
 | |
|             NetReferrerPolicyToBlinkReferrerPolicy(
 | |
|                 static_cast<cef_referrer_policy_t>(request->referrer_policy))));
 | |
|     referrer_url_ = sanitized_referrer.url;
 | |
|     referrer_policy_ =
 | |
|         BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
 | |
|   }
 | |
| 
 | |
|   // Transfer request headers.
 | |
|   ::GetHeaderMap(request->headers, headermap_);
 | |
| 
 | |
|   // Transfer post data, if any.
 | |
|   if (request->request_body) {
 | |
|     postdata_ = CefPostData::Create();
 | |
|     static_cast<CefPostDataImpl*>(postdata_.get())->Set(*request->request_body);
 | |
|   }
 | |
| 
 | |
|   site_for_cookies_ = request->site_for_cookies;
 | |
| 
 | |
|   resource_type_ = static_cast<cef_resource_type_t>(request->resource_type);
 | |
|   transition_type_ =
 | |
|       static_cast<cef_transition_type_t>(request->transition_type);
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Get(network::ResourceRequest* request,
 | |
|                          bool changed_only) const {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|   if (ShouldSet(kChangedUrl, changed_only))
 | |
|     request->url = url_;
 | |
| 
 | |
|   if (ShouldSet(kChangedMethod, changed_only))
 | |
|     request->method = method_;
 | |
| 
 | |
|   if (ShouldSet(kChangedReferrer, changed_only)) {
 | |
|     request->referrer = referrer_url_;
 | |
|     request->referrer_policy =
 | |
|         static_cast<net::ReferrerPolicy>(referrer_policy_);
 | |
|   }
 | |
| 
 | |
|   if (ShouldSet(kChangedHeaderMap, changed_only)) {
 | |
|     net::HttpRequestHeaders headers;
 | |
|     headers.AddHeadersFromString(HttpHeaderUtils::GenerateHeaders(headermap_));
 | |
|     request->headers.Swap(&headers);
 | |
|   }
 | |
| 
 | |
|   if (ShouldSet(kChangedPostData, changed_only)) {
 | |
|     if (postdata_.get()) {
 | |
|       request->request_body =
 | |
|           static_cast<CefPostDataImpl*>(postdata_.get())->GetBody();
 | |
|     } else if (request->request_body) {
 | |
|       request->request_body = nullptr;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!site_for_cookies_.IsNull() &&
 | |
|       ShouldSet(kChangedSiteForCookies, changed_only)) {
 | |
|     request->site_for_cookies = site_for_cookies_;
 | |
|   }
 | |
| 
 | |
|   if (ShouldSet(kChangedFlags, changed_only)) {
 | |
|     int flags = flags_;
 | |
|     if (!(flags & kURCachePolicyMask)) {
 | |
|       // Only consider the Cache-Control directives when a cache policy is not
 | |
|       // explicitly set on the request.
 | |
|       flags |= GetCacheControlHeaderPolicy(headermap_);
 | |
|     }
 | |
| 
 | |
|     int net_flags = 0;
 | |
| 
 | |
|     if (flags & UR_FLAG_SKIP_CACHE) {
 | |
|       net_flags |= net::LOAD_BYPASS_CACHE;
 | |
|     }
 | |
|     if (flags & UR_FLAG_ONLY_FROM_CACHE) {
 | |
|       net_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION;
 | |
|     }
 | |
|     if (flags & UR_FLAG_DISABLE_CACHE) {
 | |
|       net_flags |= net::LOAD_DISABLE_CACHE;
 | |
|     }
 | |
| 
 | |
|     if (!(flags & UR_FLAG_ALLOW_STORED_CREDENTIALS)) {
 | |
|       // This will disable all credentials including cookies, auth tokens, etc.
 | |
|       request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 | |
|     }
 | |
| 
 | |
|     request->load_flags = net_flags;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Set(const net::RedirectInfo& redirect_info) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   url_ = redirect_info.new_url;
 | |
|   method_ = redirect_info.new_method;
 | |
|   site_for_cookies_ = redirect_info.new_site_for_cookies;
 | |
| 
 | |
|   const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
 | |
|       redirect_info.new_url,
 | |
|       content::Referrer(GURL(redirect_info.new_referrer),
 | |
|                         NetReferrerPolicyToBlinkReferrerPolicy(
 | |
|                             static_cast<cef_referrer_policy_t>(
 | |
|                                 redirect_info.new_referrer_policy))));
 | |
|   referrer_url_ = sanitized_referrer.url;
 | |
|   referrer_policy_ =
 | |
|       BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Set(const net::HttpRequestHeaders& headers) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   ::GetHeaderMap(headers, headermap_);
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Set(
 | |
|     const navigation_interception::NavigationParams& params,
 | |
|     bool is_main_frame) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   Reset();
 | |
| 
 | |
|   url_ = params.url();
 | |
|   method_ = params.is_post() ? "POST" : "GET";
 | |
| 
 | |
|   const auto& sanitized_referrer =
 | |
|       content::Referrer::SanitizeForRequest(params.url(), params.referrer());
 | |
|   referrer_url_ = sanitized_referrer.url;
 | |
|   referrer_policy_ =
 | |
|       BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
 | |
| 
 | |
|   resource_type_ = is_main_frame ? RT_MAIN_FRAME : RT_SUB_FRAME;
 | |
|   transition_type_ =
 | |
|       static_cast<cef_transition_type_t>(params.transition_type());
 | |
| }
 | |
| 
 | |
| // static
 | |
| void CefRequestImpl::Get(const cef::mojom::RequestParamsPtr& params,
 | |
|                          blink::WebURLRequest& request) {
 | |
|   request.SetUrl(params->url);
 | |
|   request.SetRequestorOrigin(blink::WebSecurityOrigin::Create(params->url));
 | |
|   if (!params->method.empty())
 | |
|     request.SetHttpMethod(blink::WebString::FromASCII(params->method));
 | |
| 
 | |
|   if (params->referrer && params->referrer->url.is_valid()) {
 | |
|     const blink::WebString& referrer =
 | |
|         blink::WebSecurityPolicy::GenerateReferrerHeader(
 | |
|             params->referrer->policy, params->url,
 | |
|             blink::WebString::FromUTF8(params->referrer->url.spec()));
 | |
|     if (!referrer.IsEmpty()) {
 | |
|       request.SetReferrerString(referrer);
 | |
|       request.SetReferrerPolicy(params->referrer->policy);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   CefRequest::HeaderMap headerMap;
 | |
|   if (!params->headers.empty()) {
 | |
|     for (net::HttpUtil::HeadersIterator i(params->headers.begin(),
 | |
|                                           params->headers.end(), "\n\r");
 | |
|          i.GetNext();) {
 | |
|       request.AddHttpHeaderField(blink::WebString::FromUTF8(i.name()),
 | |
|                                  blink::WebString::FromUTF8(i.values()));
 | |
|       headerMap.insert(std::make_pair(i.name(), i.values()));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (params->upload_data) {
 | |
|     const std::u16string& method = request.HttpMethod().Utf16();
 | |
|     if (method == u"GET" || method == u"HEAD") {
 | |
|       request.SetHttpMethod(blink::WebString::FromASCII("POST"));
 | |
|     }
 | |
| 
 | |
|     // The comparison performed by httpHeaderField() is case insensitive.
 | |
|     if (request
 | |
|             .HttpHeaderField(blink::WebString::FromASCII(
 | |
|                 net::HttpRequestHeaders::kContentType))
 | |
|             .length() == 0) {
 | |
|       request.SetHttpHeaderField(
 | |
|           blink::WebString::FromASCII(net::HttpRequestHeaders::kContentType),
 | |
|           blink::WebString::FromASCII(
 | |
|               net_service::kContentTypeApplicationFormURLEncoded));
 | |
|     }
 | |
| 
 | |
|     request.SetHttpBody(
 | |
|         blink::GetWebHTTPBodyForRequestBody(*params->upload_data));
 | |
|   }
 | |
| 
 | |
|   if (!params->site_for_cookies.IsNull())
 | |
|     request.SetSiteForCookies(params->site_for_cookies);
 | |
| 
 | |
|   int flags = params->load_flags;
 | |
|   if (!(flags & kURCachePolicyMask)) {
 | |
|     // Only consider the Cache-Control directives when a cache policy is not
 | |
|     // explicitly set on the request.
 | |
|     flags |= GetCacheControlHeaderPolicy(headerMap);
 | |
|   }
 | |
|   request.SetCacheMode(GetFetchCacheMode(flags));
 | |
| 
 | |
|   SETBOOLFLAG(request, params->load_flags, SetAllowStoredCredentials,
 | |
|               UR_FLAG_ALLOW_STORED_CREDENTIALS);
 | |
|   SETBOOLFLAG(request, params->load_flags, SetReportUploadProgress,
 | |
|               UR_FLAG_REPORT_UPLOAD_PROGRESS);
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Get(cef::mojom::RequestParamsPtr& params) const {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|   params->url = url_;
 | |
|   params->method = method_;
 | |
| 
 | |
|   // Referrer policy will be applied later in the request pipeline.
 | |
|   params->referrer = blink::mojom::Referrer::New(
 | |
|       referrer_url_, NetReferrerPolicyToBlinkReferrerPolicy(referrer_policy_));
 | |
| 
 | |
|   if (!headermap_.empty())
 | |
|     params->headers = HttpHeaderUtils::GenerateHeaders(headermap_);
 | |
| 
 | |
|   if (postdata_) {
 | |
|     CefPostDataImpl* impl = static_cast<CefPostDataImpl*>(postdata_.get());
 | |
|     params->upload_data = impl->GetBody();
 | |
|   }
 | |
| 
 | |
|   params->site_for_cookies = site_for_cookies_;
 | |
|   params->load_flags = flags_;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetReadOnly(bool read_only) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   if (read_only_ == read_only)
 | |
|     return;
 | |
| 
 | |
|   read_only_ = read_only;
 | |
| 
 | |
|   if (postdata_.get())
 | |
|     static_cast<CefPostDataImpl*>(postdata_.get())->SetReadOnly(read_only);
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::SetTrackChanges(bool track_changes,
 | |
|                                      bool backup_on_change) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   if (track_changes_ == track_changes)
 | |
|     return;
 | |
| 
 | |
|   if (!track_changes && backup_on_change_)
 | |
|     backup_.reset();
 | |
| 
 | |
|   track_changes_ = track_changes;
 | |
|   backup_on_change_ = track_changes ? backup_on_change : false;
 | |
|   changes_ = kChangedNone;
 | |
| 
 | |
|   if (postdata_.get()) {
 | |
|     static_cast<CefPostDataImpl*>(postdata_.get())
 | |
|         ->SetTrackChanges(track_changes);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::RevertChanges() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   DCHECK(!read_only_);
 | |
|   DCHECK(track_changes_);
 | |
|   DCHECK(backup_on_change_);
 | |
|   if (!backup_)
 | |
|     return;
 | |
| 
 | |
|   // Restore the original values if a backup exists.
 | |
|   if (backup_->backups_ & kChangedUrl)
 | |
|     url_ = backup_->url_;
 | |
|   if (backup_->backups_ & kChangedMethod)
 | |
|     method_ = backup_->method_;
 | |
|   if (backup_->backups_ & kChangedReferrer) {
 | |
|     referrer_url_ = backup_->referrer_url_;
 | |
|     referrer_policy_ = backup_->referrer_policy_;
 | |
|   }
 | |
|   if (backup_->backups_ & kChangedPostData)
 | |
|     postdata_ = backup_->postdata_;
 | |
|   if (backup_->backups_ & kChangedHeaderMap) {
 | |
|     DCHECK(backup_->headermap_);
 | |
|     headermap_.swap(*backup_->headermap_);
 | |
|   }
 | |
|   if (backup_->backups_ & kChangedFlags)
 | |
|     flags_ = backup_->flags_;
 | |
|   if (backup_->backups_ & kChangedSiteForCookies)
 | |
|     site_for_cookies_ = backup_->site_for_cookies_;
 | |
| 
 | |
|   backup_.reset();
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::DiscardChanges() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   DCHECK(track_changes_);
 | |
|   DCHECK(backup_on_change_);
 | |
|   backup_.reset();
 | |
| }
 | |
| 
 | |
| uint8_t CefRequestImpl::GetChanges() const {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|   uint8_t changes = changes_;
 | |
|   if (postdata_.get() &&
 | |
|       static_cast<CefPostDataImpl*>(postdata_.get())->HasChanges()) {
 | |
|     changes |= kChangedPostData;
 | |
|   }
 | |
|   return changes;
 | |
| }
 | |
| 
 | |
| // From content/child/web_url_loader_impl.cc
 | |
| // static
 | |
| network::mojom::ReferrerPolicy
 | |
| CefRequestImpl::NetReferrerPolicyToBlinkReferrerPolicy(
 | |
|     cef_referrer_policy_t net_policy) {
 | |
|   switch (net_policy) {
 | |
|     case REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
 | |
|       return network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
 | |
|     case REFERRER_POLICY_REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
 | |
|       return network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin;
 | |
|     case REFERRER_POLICY_ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
 | |
|       return network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin;
 | |
|     case REFERRER_POLICY_NEVER_CLEAR_REFERRER:
 | |
|       return network::mojom::ReferrerPolicy::kAlways;
 | |
|     case REFERRER_POLICY_ORIGIN:
 | |
|       return network::mojom::ReferrerPolicy::kOrigin;
 | |
|     case REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN:
 | |
|       return network::mojom::ReferrerPolicy::kSameOrigin;
 | |
|     case REFERRER_POLICY_ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
 | |
|       return network::mojom::ReferrerPolicy::kStrictOrigin;
 | |
|     case REFERRER_POLICY_NO_REFERRER:
 | |
|       return network::mojom::ReferrerPolicy::kNever;
 | |
|   }
 | |
|   NOTREACHED();
 | |
|   return network::mojom::ReferrerPolicy::kDefault;
 | |
| }
 | |
| 
 | |
| // static
 | |
| cef_referrer_policy_t CefRequestImpl::BlinkReferrerPolicyToNetReferrerPolicy(
 | |
|     network::mojom::ReferrerPolicy blink_policy) {
 | |
|   switch (blink_policy) {
 | |
|     case network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade:
 | |
|       return REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
 | |
|     case network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin:
 | |
|       return REFERRER_POLICY_REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN;
 | |
|     case network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin:
 | |
|       return REFERRER_POLICY_ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
 | |
|     case network::mojom::ReferrerPolicy::kAlways:
 | |
|       return REFERRER_POLICY_NEVER_CLEAR_REFERRER;
 | |
|     case network::mojom::ReferrerPolicy::kOrigin:
 | |
|       return REFERRER_POLICY_ORIGIN;
 | |
|     case network::mojom::ReferrerPolicy::kSameOrigin:
 | |
|       return REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN;
 | |
|     case network::mojom::ReferrerPolicy::kStrictOrigin:
 | |
|       return REFERRER_POLICY_ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
 | |
|     case network::mojom::ReferrerPolicy::kNever:
 | |
|       return REFERRER_POLICY_NO_REFERRER;
 | |
|     case network::mojom::ReferrerPolicy::kDefault:
 | |
|       return REFERRER_POLICY_DEFAULT;
 | |
|   }
 | |
|   NOTREACHED();
 | |
|   return REFERRER_POLICY_DEFAULT;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Changed(uint8_t changes) {
 | |
|   lock_.AssertAcquired();
 | |
|   if (!track_changes_)
 | |
|     return;
 | |
| 
 | |
|   if (backup_on_change_) {
 | |
|     if (!backup_)
 | |
|       backup_.reset(new Backup());
 | |
| 
 | |
|     // Set the backup values if not already set.
 | |
|     if ((changes & kChangedUrl) && !(backup_->backups_ & kChangedUrl)) {
 | |
|       backup_->url_ = url_;
 | |
|       backup_->backups_ |= kChangedUrl;
 | |
|     }
 | |
|     if ((changes & kChangedMethod) && !(backup_->backups_ & kChangedMethod)) {
 | |
|       backup_->method_ = method_;
 | |
|       backup_->backups_ |= kChangedMethod;
 | |
|     }
 | |
|     if ((changes & kChangedReferrer) &&
 | |
|         !(backup_->backups_ & kChangedReferrer)) {
 | |
|       backup_->referrer_url_ = referrer_url_;
 | |
|       backup_->referrer_policy_ = referrer_policy_;
 | |
|       backup_->backups_ |= kChangedReferrer;
 | |
|     }
 | |
|     if ((changes & kChangedPostData) &&
 | |
|         !(backup_->backups_ & kChangedPostData)) {
 | |
|       backup_->postdata_ = postdata_;
 | |
|       backup_->backups_ |= kChangedPostData;
 | |
|     }
 | |
|     if ((changes & kChangedHeaderMap) &&
 | |
|         !(backup_->backups_ & kChangedHeaderMap)) {
 | |
|       backup_->headermap_.reset(new HeaderMap());
 | |
|       if (!headermap_.empty()) {
 | |
|         backup_->headermap_->insert(headermap_.begin(), headermap_.end());
 | |
|       }
 | |
|       backup_->backups_ |= kChangedHeaderMap;
 | |
|     }
 | |
|     if ((changes & kChangedFlags) && !(backup_->backups_ & kChangedFlags)) {
 | |
|       backup_->flags_ = flags_;
 | |
|       backup_->backups_ |= kChangedFlags;
 | |
|     }
 | |
|     if ((changes & kChangedSiteForCookies) &&
 | |
|         !(backup_->backups_ & kChangedSiteForCookies)) {
 | |
|       backup_->site_for_cookies_ = site_for_cookies_;
 | |
|       backup_->backups_ |= kChangedSiteForCookies;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   changes_ |= changes;
 | |
| }
 | |
| 
 | |
| bool CefRequestImpl::ShouldSet(uint8_t changes, bool changed_only) const {
 | |
|   lock_.AssertAcquired();
 | |
| 
 | |
|   // Always change if changes are not being tracked.
 | |
|   if (!track_changes_)
 | |
|     return true;
 | |
| 
 | |
|   // Always change if changed-only was not requested.
 | |
|   if (!changed_only)
 | |
|     return true;
 | |
| 
 | |
|   // Change if the |changes| bit flag has been set.
 | |
|   if ((changes_ & changes) == changes)
 | |
|     return true;
 | |
| 
 | |
|   if ((changes & kChangedPostData) == kChangedPostData) {
 | |
|     // Change if the post data object was modified directly.
 | |
|     if (postdata_.get() &&
 | |
|         static_cast<CefPostDataImpl*>(postdata_.get())->HasChanges()) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void CefRequestImpl::Reset() {
 | |
|   lock_.AssertAcquired();
 | |
|   DCHECK(!read_only_);
 | |
| 
 | |
|   url_ = GURL();
 | |
|   method_ = "GET";
 | |
|   referrer_url_ = GURL();
 | |
|   referrer_policy_ = REFERRER_POLICY_DEFAULT;
 | |
|   postdata_ = nullptr;
 | |
|   headermap_.clear();
 | |
|   resource_type_ = RT_SUB_RESOURCE;
 | |
|   transition_type_ = TT_EXPLICIT;
 | |
|   identifier_ = 0U;
 | |
|   flags_ = UR_FLAG_NONE;
 | |
|   site_for_cookies_ = net::SiteForCookies();
 | |
| 
 | |
|   changes_ = kChangedNone;
 | |
| }
 | |
| 
 | |
| // CefPostData ----------------------------------------------------------------
 | |
| 
 | |
| // static
 | |
| CefRefPtr<CefPostData> CefPostData::Create() {
 | |
|   CefRefPtr<CefPostData> postdata(new CefPostDataImpl());
 | |
|   return postdata;
 | |
| }
 | |
| 
 | |
| // CefPostDataImpl ------------------------------------------------------------
 | |
| 
 | |
| CefPostDataImpl::CefPostDataImpl()
 | |
|     : read_only_(false),
 | |
|       has_excluded_elements_(false),
 | |
|       track_changes_(false),
 | |
|       has_changes_(false) {}
 | |
| 
 | |
| bool CefPostDataImpl::IsReadOnly() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return read_only_;
 | |
| }
 | |
| 
 | |
| bool CefPostDataImpl::HasExcludedElements() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return has_excluded_elements_;
 | |
| }
 | |
| 
 | |
| size_t CefPostDataImpl::GetElementCount() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return elements_.size();
 | |
| }
 | |
| 
 | |
| void CefPostDataImpl::GetElements(ElementVector& elements) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   elements = elements_;
 | |
| }
 | |
| 
 | |
| bool CefPostDataImpl::RemoveElement(CefRefPtr<CefPostDataElement> element) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN(false);
 | |
| 
 | |
|   ElementVector::iterator it = elements_.begin();
 | |
|   for (; it != elements_.end(); ++it) {
 | |
|     if (it->get() == element.get()) {
 | |
|       elements_.erase(it);
 | |
|       Changed();
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool CefPostDataImpl::AddElement(CefRefPtr<CefPostDataElement> element) {
 | |
|   bool found = false;
 | |
| 
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN(false);
 | |
| 
 | |
|   // check that the element isn't already in the list before adding
 | |
|   ElementVector::const_iterator it = elements_.begin();
 | |
|   for (; it != elements_.end(); ++it) {
 | |
|     if (it->get() == element.get()) {
 | |
|       found = true;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!found) {
 | |
|     elements_.push_back(element);
 | |
|     Changed();
 | |
|   }
 | |
| 
 | |
|   return !found;
 | |
| }
 | |
| 
 | |
| void CefPostDataImpl::RemoveElements() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
|   elements_.clear();
 | |
|   Changed();
 | |
| }
 | |
| 
 | |
| void CefPostDataImpl::Set(const network::ResourceRequestBody& body) {
 | |
|   {
 | |
|     base::AutoLock lock_scope(lock_);
 | |
|     CHECK_READONLY_RETURN_VOID();
 | |
|   }
 | |
| 
 | |
|   CefRefPtr<CefPostDataElement> postelem;
 | |
| 
 | |
|   for (const auto& element : *body.elements()) {
 | |
|     postelem = CefPostDataElement::Create();
 | |
|     static_cast<CefPostDataElementImpl*>(postelem.get())->Set(element);
 | |
|     AddElement(postelem);
 | |
|   }
 | |
| }
 | |
| 
 | |
| scoped_refptr<network::ResourceRequestBody> CefPostDataImpl::GetBody() const {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|   scoped_refptr<network::ResourceRequestBody> body =
 | |
|       new network::ResourceRequestBody();
 | |
|   for (const auto& element : elements_) {
 | |
|     static_cast<CefPostDataElementImpl*>(element.get())->Get(*body);
 | |
|   }
 | |
|   return body;
 | |
| }
 | |
| 
 | |
| void CefPostDataImpl::SetReadOnly(bool read_only) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   if (read_only_ == read_only)
 | |
|     return;
 | |
| 
 | |
|   read_only_ = read_only;
 | |
| 
 | |
|   ElementVector::const_iterator it = elements_.begin();
 | |
|   for (; it != elements_.end(); ++it) {
 | |
|     static_cast<CefPostDataElementImpl*>(it->get())->SetReadOnly(read_only);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefPostDataImpl::SetTrackChanges(bool track_changes) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   if (track_changes_ == track_changes)
 | |
|     return;
 | |
| 
 | |
|   track_changes_ = track_changes;
 | |
|   has_changes_ = false;
 | |
| 
 | |
|   ElementVector::const_iterator it = elements_.begin();
 | |
|   for (; it != elements_.end(); ++it) {
 | |
|     static_cast<CefPostDataElementImpl*>(it->get())->SetTrackChanges(
 | |
|         track_changes);
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool CefPostDataImpl::HasChanges() const {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   if (has_changes_)
 | |
|     return true;
 | |
| 
 | |
|   ElementVector::const_iterator it = elements_.begin();
 | |
|   for (; it != elements_.end(); ++it) {
 | |
|     if (static_cast<CefPostDataElementImpl*>(it->get())->HasChanges())
 | |
|       return true;
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void CefPostDataImpl::Changed() {
 | |
|   lock_.AssertAcquired();
 | |
|   if (track_changes_ && !has_changes_)
 | |
|     has_changes_ = true;
 | |
| }
 | |
| 
 | |
| // CefPostDataElement ---------------------------------------------------------
 | |
| 
 | |
| // static
 | |
| CefRefPtr<CefPostDataElement> CefPostDataElement::Create() {
 | |
|   CefRefPtr<CefPostDataElement> element(new CefPostDataElementImpl());
 | |
|   return element;
 | |
| }
 | |
| 
 | |
| // CefPostDataElementImpl -----------------------------------------------------
 | |
| 
 | |
| CefPostDataElementImpl::CefPostDataElementImpl()
 | |
|     : type_(PDE_TYPE_EMPTY),
 | |
|       read_only_(false),
 | |
|       track_changes_(false),
 | |
|       has_changes_(false) {
 | |
|   memset(&data_, 0, sizeof(data_));
 | |
| }
 | |
| 
 | |
| CefPostDataElementImpl::~CefPostDataElementImpl() {
 | |
|   Cleanup();
 | |
| }
 | |
| 
 | |
| bool CefPostDataElementImpl::IsReadOnly() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return read_only_;
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::SetToEmpty() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   Cleanup();
 | |
|   Changed();
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::SetToFile(const CefString& fileName) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   // Clear any data currently in the element
 | |
|   Cleanup();
 | |
| 
 | |
|   // Assign the new data
 | |
|   type_ = PDE_TYPE_FILE;
 | |
|   cef_string_copy(fileName.c_str(), fileName.length(), &data_.filename);
 | |
| 
 | |
|   Changed();
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::SetToBytes(size_t size, const void* bytes) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   CHECK_READONLY_RETURN_VOID();
 | |
| 
 | |
|   // Clear any data currently in the element
 | |
|   Cleanup();
 | |
| 
 | |
|   // Assign the new data
 | |
|   void* data = malloc(size);
 | |
|   DCHECK(data != nullptr);
 | |
|   if (data == nullptr)
 | |
|     return;
 | |
| 
 | |
|   memcpy(data, bytes, size);
 | |
| 
 | |
|   type_ = PDE_TYPE_BYTES;
 | |
|   data_.bytes.bytes = data;
 | |
|   data_.bytes.size = size;
 | |
| 
 | |
|   Changed();
 | |
| }
 | |
| 
 | |
| CefPostDataElement::Type CefPostDataElementImpl::GetType() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return type_;
 | |
| }
 | |
| 
 | |
| CefString CefPostDataElementImpl::GetFile() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   DCHECK(type_ == PDE_TYPE_FILE);
 | |
|   CefString filename;
 | |
|   if (type_ == PDE_TYPE_FILE)
 | |
|     filename.FromString(data_.filename.str, data_.filename.length, false);
 | |
|   return filename;
 | |
| }
 | |
| 
 | |
| size_t CefPostDataElementImpl::GetBytesCount() {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   DCHECK(type_ == PDE_TYPE_BYTES);
 | |
|   size_t size = 0;
 | |
|   if (type_ == PDE_TYPE_BYTES)
 | |
|     size = data_.bytes.size;
 | |
|   return size;
 | |
| }
 | |
| 
 | |
| size_t CefPostDataElementImpl::GetBytes(size_t size, void* bytes) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   DCHECK(type_ == PDE_TYPE_BYTES);
 | |
|   size_t rv = 0;
 | |
|   if (type_ == PDE_TYPE_BYTES) {
 | |
|     rv = (size < data_.bytes.size ? size : data_.bytes.size);
 | |
|     memcpy(bytes, data_.bytes.bytes, rv);
 | |
|   }
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::Set(const network::DataElement& element) {
 | |
|   {
 | |
|     base::AutoLock lock_scope(lock_);
 | |
|     CHECK_READONLY_RETURN_VOID();
 | |
|   }
 | |
| 
 | |
|   if (element.type() == network::DataElement::Tag::kBytes) {
 | |
|     const auto& bytes_element = element.As<network::DataElementBytes>();
 | |
|     const auto& bytes = bytes_element.bytes();
 | |
|     SetToBytes(bytes.size(), bytes.data());
 | |
|   } else if (element.type() == network::DataElement::Tag::kFile) {
 | |
|     const auto& file_element = element.As<network::DataElementFile>();
 | |
|     SetToFile(file_element.path().value());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::Get(network::ResourceRequestBody& body) const {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|   if (type_ == PDE_TYPE_BYTES) {
 | |
|     body.AppendBytes(static_cast<char*>(data_.bytes.bytes), data_.bytes.size);
 | |
|   } else if (type_ == PDE_TYPE_FILE) {
 | |
|     base::FilePath path = base::FilePath(CefString(&data_.filename));
 | |
|     body.AppendFileRange(path, 0, std::numeric_limits<uint64_t>::max(),
 | |
|                          base::Time());
 | |
|   } else {
 | |
|     NOTREACHED();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::SetReadOnly(bool read_only) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   if (read_only_ == read_only)
 | |
|     return;
 | |
| 
 | |
|   read_only_ = read_only;
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::SetTrackChanges(bool track_changes) {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   if (track_changes_ == track_changes)
 | |
|     return;
 | |
| 
 | |
|   track_changes_ = track_changes;
 | |
|   has_changes_ = false;
 | |
| }
 | |
| 
 | |
| bool CefPostDataElementImpl::HasChanges() const {
 | |
|   base::AutoLock lock_scope(lock_);
 | |
|   return has_changes_;
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::Changed() {
 | |
|   lock_.AssertAcquired();
 | |
|   if (track_changes_ && !has_changes_)
 | |
|     has_changes_ = true;
 | |
| }
 | |
| 
 | |
| void CefPostDataElementImpl::Cleanup() {
 | |
|   if (type_ == PDE_TYPE_EMPTY)
 | |
|     return;
 | |
| 
 | |
|   if (type_ == PDE_TYPE_BYTES)
 | |
|     free(data_.bytes.bytes);
 | |
|   else if (type_ == PDE_TYPE_FILE)
 | |
|     cef_string_clear(&data_.filename);
 | |
|   type_ = PDE_TYPE_EMPTY;
 | |
|   memset(&data_, 0, sizeof(data_));
 | |
| }
 |