| // 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/browser/navigate_params.h" |
| #include "libcef/common/cef_messages.h" |
| #include "libcef/common/net/http_header_utils.h" |
| #include "libcef/common/net/upload_data.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_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/post_task.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 "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/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); |
| |
| // A subclass of net::UploadBytesElementReader that keeps the associated |
| // UploadElement alive until the request completes. |
| class BytesElementReader : public net::UploadBytesElementReader { |
| public: |
| explicit BytesElementReader(std::unique_ptr<net::UploadElement> element) |
| : net::UploadBytesElementReader(element->bytes(), |
| element->bytes_length()), |
| element_(std::move(element)) { |
| DCHECK_EQ(net::UploadElement::TYPE_BYTES, element_->type()); |
| } |
| |
| private: |
| std::unique_ptr<net::UploadElement> element_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BytesElementReader); |
| }; |
| |
| scoped_refptr<base::SequencedTaskRunner> GetFileTaskRunner() { |
| return base::CreateSequencedTaskRunner( |
| {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE}); |
| } |
| |
| // A subclass of net::UploadFileElementReader that keeps the associated |
| // UploadElement alive until the request completes. |
| class FileElementReader : public net::UploadFileElementReader { |
| public: |
| explicit FileElementReader(std::unique_ptr<net::UploadElement> element) |
| : net::UploadFileElementReader( |
| GetFileTaskRunner().get(), |
| element->file_path(), |
| element->file_range_offset(), |
| element->file_range_length(), |
| element->expected_file_modification_time()), |
| element_(std::move(element)) { |
| DCHECK_EQ(net::UploadElement::TYPE_FILE, element_->type()); |
| } |
| |
| private: |
| scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| std::unique_ptr<net::UploadElement> element_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FileElementReader); |
| }; |
| |
| // 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; |
| } |
| |
| blink::WebString FilePathStringToWebString( |
| const base::FilePath::StringType& str) { |
| #if defined(OS_POSIX) |
| return blink::WebString::FromUTF8(str); |
| #elif defined(OS_WIN) |
| return blink::WebString::FromUTF16(str); |
| #endif |
| } |
| |
| // 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)); |
| } |
| } |
| |
| // Type used in UploadDataStream. |
| typedef std::vector<std::unique_ptr<net::UploadElementReader>> |
| UploadElementReaders; |
| |
| } // 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::URLRequest::MAX_REFERRER_POLICY), |
| "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::URLRequest::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)) { |
| net_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA | |
| net::LOAD_DO_NOT_SEND_COOKIES | |
| net::LOAD_DO_NOT_SAVE_COOKIES; |
| } |
| |
| 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 CefMsg_LoadRequest_Params& 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.is_valid()) { |
| const blink::WebString& referrer = |
| blink::WebSecurityPolicy::GenerateReferrerHeader( |
| NetReferrerPolicyToBlinkReferrerPolicy( |
| static_cast<cef_referrer_policy_t>(params.referrer_policy)), |
| params.url, blink::WebString::FromUTF8(params.referrer.spec())); |
| if (!referrer.IsEmpty()) { |
| request.SetReferrerString(referrer); |
| request.SetReferrerPolicy(NetReferrerPolicyToBlinkReferrerPolicy( |
| static_cast<cef_referrer_policy_t>(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.get()) { |
| const base::string16& method = request.HttpMethod().Utf16(); |
| if (method == base::ASCIIToUTF16("GET") || |
| method == base::ASCIIToUTF16("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)); |
| } |
| |
| blink::WebHTTPBody body; |
| body.Initialize(); |
| |
| for (const auto& element : params.upload_data->elements()) { |
| if (element->type() == net::UploadElement::TYPE_BYTES) { |
| blink::WebData data; |
| data.Assign(element->bytes(), element->bytes_length()); |
| body.AppendData(data); |
| } else if (element->type() == net::UploadElement::TYPE_FILE) { |
| body.AppendFileRange( |
| FilePathStringToWebString(element->file_path().value()), |
| element->file_range_offset(), element->file_range_length(), |
| element->expected_file_modification_time()); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| request.SetHttpBody(body); |
| } |
| |
| 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(CefNavigateParams& 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.url = referrer_url_; |
| params.referrer.policy = |
| NetReferrerPolicyToBlinkReferrerPolicy(referrer_policy_); |
| |
| if (!headermap_.empty()) |
| params.headers = HttpHeaderUtils::GenerateHeaders(headermap_); |
| |
| if (postdata_) { |
| CefPostDataImpl* impl = static_cast<CefPostDataImpl*>(postdata_.get()); |
| params.upload_data = new net::UploadData(); |
| impl->Get(*params.upload_data.get()); |
| } |
| |
| 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::Set(const net::UploadData& data) { |
| { |
| base::AutoLock lock_scope(lock_); |
| CHECK_READONLY_RETURN_VOID(); |
| } |
| |
| CefRefPtr<CefPostDataElement> postelem; |
| |
| for (const auto& element : data.elements()) { |
| postelem = CefPostDataElement::Create(); |
| static_cast<CefPostDataElementImpl*>(postelem.get())->Set(*element); |
| AddElement(postelem); |
| } |
| } |
| |
| void CefPostDataImpl::Set(const net::UploadDataStream& data_stream) { |
| { |
| base::AutoLock lock_scope(lock_); |
| CHECK_READONLY_RETURN_VOID(); |
| } |
| |
| CefRefPtr<CefPostDataElement> postelem; |
| |
| const UploadElementReaders* elements = data_stream.GetElementReaders(); |
| if (elements) { |
| UploadElementReaders::const_iterator it = elements->begin(); |
| for (; it != elements->end(); ++it) { |
| postelem = CefPostDataElement::Create(); |
| static_cast<CefPostDataElementImpl*>(postelem.get())->Set(**it); |
| if (postelem->GetType() != PDE_TYPE_EMPTY) |
| AddElement(postelem); |
| else if (!has_excluded_elements_) |
| has_excluded_elements_ = true; |
| } |
| } |
| } |
| |
| void CefPostDataImpl::Get(net::UploadData& data) const { |
| base::AutoLock lock_scope(lock_); |
| |
| net::UploadData::ElementsVector data_elements; |
| for (const auto& element : elements_) { |
| std::unique_ptr<net::UploadElement> data_element = |
| std::make_unique<net::UploadElement>(); |
| static_cast<CefPostDataElementImpl*>(element.get()) |
| ->Get(*data_element.get()); |
| data_elements.push_back(std::move(data_element)); |
| } |
| data.swap_elements(&data_elements); |
| } |
| |
| std::unique_ptr<net::UploadDataStream> CefPostDataImpl::Get() const { |
| base::AutoLock lock_scope(lock_); |
| |
| UploadElementReaders element_readers; |
| for (const auto& element : elements_) { |
| element_readers.push_back( |
| static_cast<CefPostDataElementImpl*>(element.get())->Get()); |
| } |
| |
| return std::make_unique<net::ElementsUploadDataStream>( |
| std::move(element_readers), 0); |
| } |
| |
| 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::mojom::DataElementType::kBytes) { |
| SetToBytes(element.length(), element.bytes()); |
| } else if (element.type() == network::mojom::DataElementType::kFile) { |
| SetToFile(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::Set(const net::UploadElement& element) { |
| { |
| base::AutoLock lock_scope(lock_); |
| CHECK_READONLY_RETURN_VOID(); |
| } |
| |
| if (element.type() == net::UploadElement::TYPE_BYTES) { |
| SetToBytes(element.bytes_length(), element.bytes()); |
| } else if (element.type() == net::UploadElement::TYPE_FILE) { |
| SetToFile(element.file_path().value()); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| void CefPostDataElementImpl::Set( |
| const net::UploadElementReader& element_reader) { |
| { |
| base::AutoLock lock_scope(lock_); |
| CHECK_READONLY_RETURN_VOID(); |
| } |
| |
| const net::UploadBytesElementReader* bytes_reader = |
| element_reader.AsBytesReader(); |
| if (bytes_reader) { |
| SetToBytes(bytes_reader->length(), bytes_reader->bytes()); |
| return; |
| } |
| |
| const net::UploadFileElementReader* file_reader = |
| element_reader.AsFileReader(); |
| if (file_reader) { |
| SetToFile(file_reader->path().value()); |
| return; |
| } |
| |
| // Chunked uploads cannot currently be represented. |
| SetToEmpty(); |
| } |
| |
| void CefPostDataElementImpl::Get(net::UploadElement& element) const { |
| base::AutoLock lock_scope(lock_); |
| |
| if (type_ == PDE_TYPE_BYTES) { |
| element.SetToBytes(static_cast<char*>(data_.bytes.bytes), data_.bytes.size); |
| } else if (type_ == PDE_TYPE_FILE) { |
| base::FilePath path = base::FilePath(CefString(&data_.filename)); |
| element.SetToFilePath(path); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| std::unique_ptr<net::UploadElementReader> CefPostDataElementImpl::Get() const { |
| base::AutoLock lock_scope(lock_); |
| |
| if (type_ == PDE_TYPE_BYTES) { |
| net::UploadElement* element = new net::UploadElement(); |
| element->SetToBytes(static_cast<char*>(data_.bytes.bytes), |
| data_.bytes.size); |
| return std::make_unique<BytesElementReader>(base::WrapUnique(element)); |
| } else if (type_ == PDE_TYPE_FILE) { |
| net::UploadElement* element = new net::UploadElement(); |
| base::FilePath path = base::FilePath(CefString(&data_.filename)); |
| element->SetToFilePath(path); |
| return std::make_unique<FileElementReader>(base::WrapUnique(element)); |
| } else { |
| NOTREACHED(); |
| return nullptr; |
| } |
| } |
| |
| 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_)); |
| } |