// 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 #include #include #include #include #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 "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_handle.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 kCacheControlDirectiveNoCache[] = "no-cache"; const char kCacheControlDirectiveNoStore[] = "no-store"; const char kCacheControlDirectiveOnlyIfCached[] = "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::EqualsCaseInsensitiveASCII( it->first.ToString(), net::HttpRequestHeaders::kCacheControl)) { line = it->second; break; } } } int flags = 0; if (!line.empty()) { HttpHeaderUtils::MakeASCIILower(&line); std::vector pieces = base::SplitStringPiece( line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); for (const auto& piece : pieces) { if (base::EqualsCaseInsensitiveASCII(piece, kCacheControlDirectiveNoCache)) { flags |= UR_FLAG_SKIP_CACHE; } else if (base::EqualsCaseInsensitiveASCII( piece, kCacheControlDirectiveOnlyIfCached)) { flags |= UR_FLAG_ONLY_FROM_CACHE; } else if (base::EqualsCaseInsensitiveASCII( piece, kCacheControlDirectiveNoStore)) { 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::EqualsCaseInsensitiveASCII(name, net::HttpRequestHeaders::kReferer)) { 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::EqualsCaseInsensitiveASCII(name.ToString(), net::HttpRequestHeaders::kReferer)) { map.insert(std::make_pair(name, it->second)); } } } } // namespace #define CHECK_READONLY_RETURN(val) \ if (read_only_) { \ DCHECK(false) << "object is read only"; \ return val; \ } #define CHECK_READONLY_RETURN_VOID() \ if (read_only_) { \ DCHECK(false) << "object is read only"; \ return; \ } // CefRequest ----------------------------------------------------------------- // static CefRefPtr CefRequest::Create() { CefRefPtr request(new CefRequestImpl()); return request; } // CefRequestImpl ------------------------------------------------------------- CefRequestImpl::CefRequestImpl() { // Verify that our enum matches Chromium's values. static_assert(static_cast(REFERRER_POLICY_LAST_VALUE) == static_cast(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 CefRequestImpl::GetPostData() { base::AutoLock lock_scope(lock_); return postdata_; } void CefRequestImpl::SetPostData(CefRefPtr 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(); const std::string& nameStr = name; // Do not include Referer in the header map. if (base::EqualsCaseInsensitiveASCII(nameStr, net::HttpRequestHeaders::kReferer)) { 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(), nameStr)) { 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 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_t CefRequestImpl::GetIdentifier() { base::AutoLock lock_scope(lock_); return identifier_; } void CefRequestImpl::Set(const network::ResourceRequest* request, uint64_t 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(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(postdata_.get())->Set(*request->request_body); } site_for_cookies_ = request->site_for_cookies; resource_type_ = static_cast(request->resource_type); transition_type_ = static_cast(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(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(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( 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(content::NavigationHandle* navigation_handle) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); Reset(); url_ = navigation_handle->GetURL(); method_ = navigation_handle->IsPost() ? "POST" : "GET"; const auto& sanitized_referrer = content::Referrer::SanitizeForRequest( navigation_handle->GetURL(), navigation_handle->GetReferrer()); referrer_url_ = sanitized_referrer->url; referrer_policy_ = BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer->policy); resource_type_ = navigation_handle->IsInMainFrame() ? RT_MAIN_FRAME : RT_SUB_FRAME; transition_type_ = static_cast( navigation_handle->GetPageTransition()); } // 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)); request.SetCredentialsMode( (params->load_flags & UR_FLAG_ALLOW_STORED_CREDENTIALS) ? network::mojom::CredentialsMode::kInclude : network::mojom::CredentialsMode::kOmit); request.SetReportUploadProgress(params->load_flags & 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(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(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(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(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; } DCHECK(false); 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; } DCHECK(false); 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(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::Create() { CefRefPtr 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 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 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 postelem; for (const auto& element : *body.elements()) { postelem = CefPostDataElement::Create(); static_cast(postelem.get())->Set(element); AddElement(postelem); } } scoped_refptr CefPostDataImpl::GetBody() const { base::AutoLock lock_scope(lock_); scoped_refptr body = new network::ResourceRequestBody(); for (const auto& element : elements_) { static_cast(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(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(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(it->get())->HasChanges()) { return true; } } return false; } void CefPostDataImpl::Changed() { lock_.AssertAcquired(); if (track_changes_ && !has_changes_) { has_changes_ = true; } } // CefPostDataElement --------------------------------------------------------- // static CefRefPtr CefPostDataElement::Create() { CefRefPtr 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(); 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(); 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(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::max(), base::Time()); } else { DCHECK(false); } } 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_)); }