From e7a02fe00fe02faeee6c20369b44004cbaad6c9e Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 1 Dec 2015 13:22:28 -0500 Subject: [PATCH] - Add CefPostData::HasExcludedElements which returns true if the underlying POST data includes elements that are not represented (issue #1761). - Add CefRequest::SetReferrer and CefRequest::GetReferrer[URL|Policy]. The Referer value will no longer be stored in the header map. - Move request-related conversion logic to CefRequestImpl and standardize the implementation. --- include/capi/cef_request_capi.h | 34 +- include/cef_request.h | 36 +- include/internal/cef_types.h | 42 ++ libcef/browser/browser_host_impl.cc | 20 +- libcef/browser/browser_urlrequest_impl.cc | 105 +--- libcef/common/request_impl.cc | 582 +++++++++++++++++----- libcef/common/request_impl.h | 49 +- libcef/renderer/browser_impl.cc | 80 +-- libcef/renderer/render_urlrequest_impl.cc | 17 +- libcef_dll/cpptoc/post_data_cpptoc.cc | 16 + libcef_dll/cpptoc/request_cpptoc.cc | 52 ++ libcef_dll/ctocpp/post_data_ctocpp.cc | 14 + libcef_dll/ctocpp/post_data_ctocpp.h | 1 + libcef_dll/ctocpp/request_ctocpp.cc | 49 ++ libcef_dll/ctocpp/request_ctocpp.h | 4 + tests/unittests/request_unittest.cc | 10 + tests/unittests/test_util.cc | 4 + tests/unittests/urlrequest_unittest.cc | 25 + 18 files changed, 793 insertions(+), 347 deletions(-) diff --git a/include/capi/cef_request_capi.h b/include/capi/cef_request_capi.h index a42c0fd7a..276044ef6 100644 --- a/include/capi/cef_request_capi.h +++ b/include/capi/cef_request_capi.h @@ -87,6 +87,27 @@ typedef struct _cef_request_t { void (CEF_CALLBACK *set_method)(struct _cef_request_t* self, const cef_string_t* method); + /// + // Set the referrer URL and policy. If non-NULL the referrer URL must be fully + // qualified with an HTTP or HTTPS scheme component. Any username, password or + // ref component will be removed. + /// + void (CEF_CALLBACK *set_referrer)(struct _cef_request_t* self, + const cef_string_t* referrer_url, cef_referrer_policy_t policy); + + /// + // Get the referrer URL. + /// + // The resulting string must be freed by calling cef_string_userfree_free(). + cef_string_userfree_t (CEF_CALLBACK *get_referrer_url)( + struct _cef_request_t* self); + + /// + // Get the referrer policy. + /// + cef_referrer_policy_t (CEF_CALLBACK *get_referrer_policy)( + struct _cef_request_t* self); + /// // Get the post data. /// @@ -100,13 +121,14 @@ typedef struct _cef_request_t { struct _cef_post_data_t* postData); /// - // Get the header values. + // Get the header values. Will not include the Referer value if any. /// void (CEF_CALLBACK *get_header_map)(struct _cef_request_t* self, cef_string_multimap_t headerMap); /// - // Set the header values. + // Set the header values. If a Referer value exists in the header map it will + // be removed and ignored. /// void (CEF_CALLBACK *set_header_map)(struct _cef_request_t* self, cef_string_multimap_t headerMap); @@ -190,6 +212,14 @@ typedef struct _cef_post_data_t { /// int (CEF_CALLBACK *is_read_only)(struct _cef_post_data_t* self); + /// + // Returns true (1) if the underlying POST data includes elements that are not + // represented by this cef_post_data_t object (for example, multi-part file + // upload data). Modifying cef_post_data_t objects with excluded elements may + // result in the request failing. + /// + int (CEF_CALLBACK *has_excluded_elements)(struct _cef_post_data_t* self); + /// // Returns the number of existing post data elements. /// diff --git a/include/cef_request.h b/include/cef_request.h index 6d13da128..a4626aa02 100644 --- a/include/cef_request.h +++ b/include/cef_request.h @@ -53,6 +53,7 @@ class CefPostDataElement; class CefRequest : public virtual CefBase { public: typedef std::multimap HeaderMap; + typedef cef_referrer_policy_t ReferrerPolicy; typedef cef_resource_type_t ResourceType; typedef cef_transition_type_t TransitionType; @@ -93,6 +94,27 @@ class CefRequest : public virtual CefBase { /*--cef()--*/ virtual void SetMethod(const CefString& method) =0; + /// + // Set the referrer URL and policy. If non-empty the referrer URL must be + // fully qualified with an HTTP or HTTPS scheme component. Any username, + // password or ref component will be removed. + /// + /*--cef()--*/ + virtual void SetReferrer(const CefString& referrer_url, + ReferrerPolicy policy) =0; + + /// + // Get the referrer URL. + /// + /*--cef()--*/ + virtual CefString GetReferrerURL() =0; + + /// + // Get the referrer policy. + /// + /*--cef(default_retval=REFERRER_POLICY_DEFAULT)--*/ + virtual ReferrerPolicy GetReferrerPolicy() =0; + /// // Get the post data. /// @@ -106,13 +128,14 @@ class CefRequest : public virtual CefBase { virtual void SetPostData(CefRefPtr postData) =0; /// - // Get the header values. + // Get the header values. Will not include the Referer value if any. /// /*--cef()--*/ virtual void GetHeaderMap(HeaderMap& headerMap) =0; /// - // Set the header values. + // Set the header values. If a Referer value exists in the header map it will + // be removed and ignored. /// /*--cef()--*/ virtual void SetHeaderMap(const HeaderMap& headerMap) =0; @@ -200,6 +223,15 @@ class CefPostData : public virtual CefBase { /*--cef()--*/ virtual bool IsReadOnly() =0; + /// + // Returns true if the underlying POST data includes elements that are not + // represented by this CefPostData object (for example, multi-part file upload + // data). Modifying CefPostData objects with excluded elements may result in + // the request failing. + /// + /*--cef()--*/ + virtual bool HasExcludedElements() = 0; + /// // Returns the number of existing post data elements. /// diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 4428973dd..1a3ede45c 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -2299,6 +2299,48 @@ typedef enum { PLUGIN_POLICY_DISABLE, } cef_plugin_policy_t; +/// +// Policy for how the Referrer HTTP header value will be sent during navigation. +// If the `--no-referrers` command-line flag is specified then the policy value +// will be ignored and the Referrer value will never be sent. +/// +typedef enum { + /// + // Always send the complete Referrer value. + /// + REFERRER_POLICY_ALWAYS, + + /// + // Use the default policy. This is REFERRER_POLICY_ORIGIN_WHEN_CROSS_ORIGIN + // when the `--reduced-referrer-granularity` command-line flag is specified + // and REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE otherwise. + // + /// + REFERRER_POLICY_DEFAULT, + + /// + // When navigating from HTTPS to HTTP do not send the Referrer value. + // Otherwise, send the complete Referrer value. + /// + REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE, + + /// + // Never send the Referrer value. + /// + REFERRER_POLICY_NEVER, + + /// + // Only send the origin component of the Referrer value. + /// + REFERRER_POLICY_ORIGIN, + + /// + // When navigating cross-origin only send the origin component of the Referrer + // value. Otherwise, send the complete Referrer value. + /// + REFERRER_POLICY_ORIGIN_WHEN_CROSS_ORIGIN, +} cef_referrer_policy_t; + #ifdef __cplusplus } #endif diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index fdb5e5900..d93f8210d 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -1713,26 +1713,10 @@ void CefBrowserHostImpl::Navigate(const CefNavigateParams& params) { void CefBrowserHostImpl::LoadRequest(int64 frame_id, CefRefPtr request) { - CefNavigateParams params(GURL(std::string(request->GetURL())), - ui::PAGE_TRANSITION_TYPED); - params.method = request->GetMethod(); + CefNavigateParams params(GURL(), ui::PAGE_TRANSITION_TYPED); params.frame_id = frame_id; - params.first_party_for_cookies = - GURL(std::string(request->GetFirstPartyForCookies())); - CefRequest::HeaderMap headerMap; - request->GetHeaderMap(headerMap); - if (!headerMap.empty()) - params.headers = HttpHeaderUtils::GenerateHeaders(headerMap); - - CefRefPtr postData = request->GetPostData(); - if (postData.get()) { - CefPostDataImpl* impl = static_cast(postData.get()); - params.upload_data = new net::UploadData(); - impl->Get(*params.upload_data.get()); - } - - params.load_flags = request->GetFlags(); + static_cast(request.get())->Get(params); Navigate(params); } diff --git a/libcef/browser/browser_urlrequest_impl.cc b/libcef/browser/browser_urlrequest_impl.cc index 6a3edcbae..afff0aa61 100644 --- a/libcef/browser/browser_urlrequest_impl.cc +++ b/libcef/browser/browser_urlrequest_impl.cc @@ -11,7 +11,6 @@ #include "libcef/browser/request_context_impl.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/url_request_user_data.h" -#include "libcef/common/http_header_utils.h" #include "libcef/common/request_impl.h" #include "libcef/common/response_impl.h" @@ -21,9 +20,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/common/url_fetcher.h" #include "net/base/io_buffer.h" -#include "net/base/load_flags.h" #include "net/base/net_errors.h" -#include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher_delegate.h" @@ -208,116 +205,24 @@ class CefBrowserURLRequest::Context net::URLFetcher::RequestType request_type) { DCHECK(CalledOnValidThread()); - fetcher_delegate_.reset( - new CefURLFetcherDelegate(this, request_->GetFlags())); + int request_flags = request_->GetFlags(); + fetcher_delegate_.reset(new CefURLFetcherDelegate(this, request_flags)); fetcher_ = net::URLFetcher::Create(url, request_type, fetcher_delegate_.get()); DCHECK(url_request_getter_.get()); fetcher_->SetRequestContext(url_request_getter_.get()); - CefRequest::HeaderMap headerMap; - request_->GetHeaderMap(headerMap); - - // Extract the Referer header value. - { - CefString referrerStr; - referrerStr.FromASCII(net::HttpRequestHeaders::kReferer); - CefRequest::HeaderMap::iterator it = headerMap.find(referrerStr); - if (it == headerMap.end()) { - fetcher_->SetReferrer(""); - } else { - fetcher_->SetReferrer(it->second); - headerMap.erase(it); - } - } - - std::string content_type; - - // Extract the Content-Type header value. - { - CefString contentTypeStr; - contentTypeStr.FromASCII(net::HttpRequestHeaders::kContentType); - CefRequest::HeaderMap::iterator it = headerMap.find(contentTypeStr); - if (it != headerMap.end()) { - content_type = it->second; - headerMap.erase(it); - } - } - - int64 upload_data_size = 0; - - CefRefPtr post_data = request_->GetPostData(); - if (post_data.get()) { - CefPostData::ElementVector elements; - post_data->GetElements(elements); - if (elements.size() == 1) { - // Default to URL encoding if not specified. - if (content_type.empty()) - content_type = "application/x-www-form-urlencoded"; - - CefPostDataElementImpl* impl = - static_cast(elements[0].get()); - - switch (elements[0]->GetType()) - case PDE_TYPE_BYTES: { - upload_data_size = impl->GetBytesCount(); - fetcher_->SetUploadData(content_type, - std::string(static_cast(impl->GetBytes()), - upload_data_size)); - break; - case PDE_TYPE_FILE: - fetcher_->SetUploadFilePath( - content_type, - base::FilePath(impl->GetFile()), - 0, kuint64max, - content::BrowserThread::GetMessageLoopProxyForThread( - content::BrowserThread::FILE).get()); - break; - case PDE_TYPE_EMPTY: - break; - } - } else if (elements.size() > 1) { - NOTIMPLEMENTED() << " multi-part form data is not supported"; - } - } - - std::string first_party_for_cookies = request_->GetFirstPartyForCookies(); - if (!first_party_for_cookies.empty()) - fetcher_->SetFirstPartyForCookies(GURL(first_party_for_cookies)); - - int cef_flags = request_->GetFlags(); - - if (cef_flags & UR_FLAG_NO_RETRY_ON_5XX) - fetcher_->SetAutomaticallyRetryOn5xx(false); - - int load_flags = 0; - - if (cef_flags & UR_FLAG_SKIP_CACHE) - load_flags |= net::LOAD_BYPASS_CACHE; - - if (!(cef_flags & UR_FLAG_ALLOW_CACHED_CREDENTIALS)) { - load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA; - load_flags |= net::LOAD_DO_NOT_SEND_COOKIES; - load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES; - } - - if (cef_flags & UR_FLAG_REPORT_UPLOAD_PROGRESS) { - upload_data_size_ = upload_data_size; - } - - fetcher_->SetLoadFlags(load_flags); - - fetcher_->SetExtraRequestHeaders( - HttpHeaderUtils::GenerateHeaders(headerMap)); + static_cast(request_.get())->Get(*fetcher_, + upload_data_size_); fetcher_->SetURLRequestUserData( CefURLRequestUserData::kUserDataKey, base::Bind(&CreateURLRequestUserData, client_)); scoped_ptr response_writer; - if (cef_flags & UR_FLAG_NO_DOWNLOAD_DATA) { + if (request_flags & UR_FLAG_NO_DOWNLOAD_DATA) { response_writer.reset(new CefURLFetcherResponseWriter(NULL, NULL)); } else { response_writer.reset( diff --git a/libcef/common/request_impl.cc b/libcef/common/request_impl.cc index 957b72878..dcd3155ff 100644 --- a/libcef/common/request_impl.cc +++ b/libcef/common/request_impl.cc @@ -5,30 +5,45 @@ #include #include +#include "libcef/common/cef_messages.h" #include "libcef/common/http_header_utils.h" #include "libcef/common/request_impl.h" -#include "libcef/common/task_runner_impl.h" #include "libcef/common/upload_data.h" +#include "libcef/browser/navigate_params.h" +#include "base/command_line.h" #include "base/logging.h" +#include "base/strings/string_util.h" +#include "base/strings/sys_string_conversions.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/browser/resource_request_info.h" +#include "content/public/common/content_switches.h" #include "content/public/common/resource_type.h" #include "net/base/elements_upload_data_stream.h" +#include "net/base/load_flags.h" #include "net/base/upload_data_stream.h" #include "net/base/upload_element_reader.h" #include "net/base/upload_bytes_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/url_fetcher.h" #include "net/url_request/url_request.h" #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLError.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "third_party/WebKit/public/web/WebSecurityPolicy.h" namespace { +const char kReferrerLowerCase[] = "referer"; +const char kContentTypeLowerCase[] = "content-type"; +const char kApplicationFormURLEncoded[] = "application/x-www-form-urlencoded"; + // A subclass of net::UploadBytesElementReader that keeps the associated // UploadElement alive until the request completes. class BytesElementReader : public net::UploadBytesElementReader { @@ -47,10 +62,8 @@ class BytesElementReader : public net::UploadBytesElementReader { }; base::TaskRunner* GetFileTaskRunner() { - scoped_refptr task_runner = - CefTaskRunnerImpl::GetTaskRunner(TID_FILE); - DCHECK(task_runner.get()); - return task_runner.get(); + return content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::FILE).get(); } // A subclass of net::UploadFileElementReader that keeps the associated @@ -74,6 +87,132 @@ class FileElementReader : public net::UploadFileElementReader { DISALLOW_COPY_AND_ASSIGN(FileElementReader); }; +// GetURLRequestReferrerPolicy() and GetURLRequestReferrer() are based on +// SetReferrerForRequest() from +// content/browser/loader/resource_dispatcher_host_impl.cc + +net::URLRequest::ReferrerPolicy GetURLRequestReferrerPolicy( + cef_referrer_policy_t policy) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + net::URLRequest::ReferrerPolicy net_referrer_policy = + net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; + switch (static_cast(policy)) { + case blink::WebReferrerPolicyAlways: + case blink::WebReferrerPolicyNever: + case blink::WebReferrerPolicyOrigin: + net_referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER; + break; + case blink::WebReferrerPolicyNoReferrerWhenDowngrade: + net_referrer_policy = + net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; + break; + case blink::WebReferrerPolicyOriginWhenCrossOrigin: + net_referrer_policy = + net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN; + break; + case blink::WebReferrerPolicyDefault: + default: + net_referrer_policy = + command_line->HasSwitch(switches::kReducedReferrerGranularity) + ? net::URLRequest:: + REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN + : net::URLRequest:: + CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; + break; + } + return net_referrer_policy; +} + +std::string GetURLRequestReferrer(const CefString& referrer_url) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!GURL(referrer_url.ToString()).is_valid() || + command_line->HasSwitch(switches::kNoReferrers)) { + return std::string(); + } + + return referrer_url; +} + +blink::WebString FilePathStringToWebString( + const base::FilePath::StringType& str) { +#if defined(OS_POSIX) + return base::WideToUTF16(base::SysNativeMBToWide(str)); +#elif defined(OS_WIN) + return base::WideToUTF16(str); +#endif +} + +// Read |headers| into |map|. +void GetHeaderMap(const net::HttpRequestHeaders& headers, + CefRequest::HeaderMap& map) { + if (headers.IsEmpty()) + return; + + net::HttpRequestHeaders::Iterator it(headers); + do { + 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())); + } while (it.GetNext()); +} + + +// Read |request| into |map|. If a Referer value is specified populate +// |referrer|. +void GetHeaderMap(const blink::WebURLRequest& request, + CefRequest::HeaderMap& map, + CefString& referrer) { + class HeaderVisitor : public blink::WebHTTPHeaderVisitor { + public: + HeaderVisitor(CefRequest::HeaderMap* map, CefString* referrer) + : map_(map), + referrer_(referrer) { + } + + void visitHeader(const blink::WebString& name, + const blink::WebString& value) override { + const base::string16& nameStr = name; + const base::string16& valueStr = value; + if (base::LowerCaseEqualsASCII(nameStr, kReferrerLowerCase)) + *referrer_ = valueStr; + else + map_->insert(std::make_pair(nameStr, valueStr)); + } + + private: + CefRequest::HeaderMap* map_; + CefString* referrer_; + }; + + HeaderVisitor visitor(&map, &referrer); + request.visitHTTPHeaderFields(&visitor); +} + +// Read |source| into |map|. +void GetHeaderMap(const CefRequest::HeaderMap& source, + CefRequest::HeaderMap& map) { + 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)); + } +} + +// Read |map| into |request|. +void SetHeaderMap(const CefRequest::HeaderMap& map, + blink::WebURLRequest& request) { + CefRequest::HeaderMap::const_iterator it = map.begin(); + for (; it != map.end(); ++it) { + request.setHTTPHeaderField(base::string16(it->first), + base::string16(it->second)); + } +} + } // namespace @@ -89,6 +228,9 @@ class FileElementReader : public net::UploadFileElementReader { return; \ } +#define SETBOOLFLAG(obj, flags, method, FLAG) \ + obj.method((flags & (FLAG)) == (FLAG)) + // CefRequest ----------------------------------------------------------------- @@ -141,6 +283,31 @@ void CefRequestImpl::SetMethod(const CefString& method) { } } +void CefRequestImpl::SetReferrer(const CefString& referrer_url, + ReferrerPolicy policy) { + base::AutoLock lock_scope(lock_); + CHECK_READONLY_RETURN_VOID(); + + // Call GetAsReferrer here for consistency since the same logic will later be + // applied by URLRequest::SetReferrer(). + const GURL& gurl = GURL(referrer_url.ToString()).GetAsReferrer(); + if (referrer_url_ != gurl.spec() || referrer_policy_ != policy) { + referrer_url_ = gurl.spec(); + referrer_policy_ = policy; + Changed(kChangedReferrer); + } +} + +CefString CefRequestImpl::GetReferrerURL() { + base::AutoLock lock_scope(lock_); + return referrer_url_; +} + +CefRequestImpl::ReferrerPolicy CefRequestImpl::GetReferrerPolicy() { + base::AutoLock lock_scope(lock_); + return referrer_policy_; +} + CefRefPtr CefRequestImpl::GetPostData() { base::AutoLock lock_scope(lock_); return postdata_; @@ -161,7 +328,7 @@ void CefRequestImpl::GetHeaderMap(HeaderMap& headerMap) { void CefRequestImpl::SetHeaderMap(const HeaderMap& headerMap) { base::AutoLock lock_scope(lock_); CHECK_READONLY_RETURN_VOID(); - headermap_ = headerMap; + ::GetHeaderMap(headerMap, headermap_); Changed(kChangedHeaderMap); } @@ -180,7 +347,7 @@ void CefRequestImpl::Set(const CefString& url, Changed(kChangedMethod); } postdata_ = postData; - headermap_ = headerMap; + ::GetHeaderMap(headerMap, headermap_); Changed(kChangedPostData | kChangedHeaderMap); } @@ -235,35 +402,46 @@ void CefRequestImpl::Set(net::URLRequest* request) { url_ = request->url().spec(); method_ = request->method(); - first_party_for_cookies_ = request->first_party_for_cookies().spec(); identifier_ = request->identifier(); - net::HttpRequestHeaders headers = request->extra_request_headers(); - // URLRequest::SetReferrer ensures that we do not send username and password // fields in the referrer. GURL referrer(request->referrer()); - // Strip Referer from request_info_.extra_headers to prevent, e.g., plugins - // from overriding headers that are controlled using other means. Otherwise a - // plugin could set a referrer although sending the referrer is inhibited. - headers.RemoveHeader(net::HttpRequestHeaders::kReferer); - - // Our consumer should have made sure that this is a safe referrer. See for + // Our consumer should have made sure that this is a safe referrer. See for // instance WebCore::FrameLoader::HideReferrer. - if (referrer.is_valid()) - headers.SetHeader(net::HttpRequestHeaders::kReferer, referrer.spec()); + if (referrer.is_valid()) { + referrer_url_ = referrer.spec(); + switch (request->referrer_policy()) { + case net::URLRequest:: + CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: + referrer_policy_ = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE; + break; + case net::URLRequest:: + REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN: + referrer_policy_ = REFERRER_POLICY_ORIGIN_WHEN_CROSS_ORIGIN; + break; + case net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN: + referrer_policy_ = REFERRER_POLICY_ORIGIN_WHEN_CROSS_ORIGIN; + break; + case net::URLRequest::NEVER_CLEAR_REFERRER: + referrer_policy_ = REFERRER_POLICY_ALWAYS; + break; + } + } - // Transfer request headers - GetHeaderMap(headers, headermap_); + // Transfer request headers. + ::GetHeaderMap(request->extra_request_headers(), headermap_); - // Transfer post data, if any + // Transfer post data, if any. const net::UploadDataStream* data = request->get_upload(); if (data) { postdata_ = CefPostData::Create(); static_cast(postdata_.get())->Set(*data); } + first_party_for_cookies_ = request->first_party_for_cookies().spec(); + const content::ResourceRequestInfo* info = content::ResourceRequestInfo::ForRequest(request); if (info) { @@ -280,25 +458,14 @@ void CefRequestImpl::Get(net::URLRequest* request, bool changed_only) const { if (ShouldSet(kChangedMethod, changed_only)) request->set_method(method_); - if (!first_party_for_cookies_.empty() && - ShouldSet(kChangedFirstPartyForCookies, changed_only)) { - request->set_first_party_for_cookies( - GURL(std::string(first_party_for_cookies_))); + if (ShouldSet(kChangedReferrer, changed_only)) { + request->SetReferrer(GetURLRequestReferrer(referrer_url_)); + request->set_referrer_policy(GetURLRequestReferrerPolicy(referrer_policy_)); } if (ShouldSet(kChangedHeaderMap, changed_only)) { - CefString referrerStr; - referrerStr.FromASCII(net::HttpRequestHeaders::kReferer); - HeaderMap headerMap = headermap_; - HeaderMap::iterator it = headerMap.find(referrerStr); - if (it == headerMap.end()) { - request->SetReferrer(std::string()); - } else { - request->SetReferrer(it->second); - headerMap.erase(it); - } net::HttpRequestHeaders headers; - headers.AddHeadersFromString(HttpHeaderUtils::GenerateHeaders(headerMap)); + headers.AddHeadersFromString(HttpHeaderUtils::GenerateHeaders(headermap_)); request->SetExtraRequestHeaders(headers); } @@ -310,6 +477,12 @@ void CefRequestImpl::Get(net::URLRequest* request, bool changed_only) const { request->set_upload(scoped_ptr()); } } + + if (!first_party_for_cookies_.empty() && + ShouldSet(kChangedFirstPartyForCookies, changed_only)) { + request->set_first_party_for_cookies( + GURL(std::string(first_party_for_cookies_))); + } } void CefRequestImpl::Set( @@ -325,10 +498,9 @@ void CefRequestImpl::Set( const content::Referrer& sanitized_referrer = content::Referrer::SanitizeForRequest(params.url(), params.referrer()); - if (!sanitized_referrer.url.is_empty()) { - headermap_.insert(std::make_pair( - CefString("Referrer"), sanitized_referrer.url.spec())); - } + referrer_url_ = sanitized_referrer.url.spec(); + referrer_policy_ = + static_cast(sanitized_referrer.policy); resource_type_ = is_main_frame ? RT_MAIN_FRAME : RT_SUB_FRAME; transition_type_ = @@ -346,13 +518,17 @@ void CefRequestImpl::Set(const blink::WebURLRequest& request) { url_ = request.url().spec().utf16(); method_ = request.httpMethod(); + ::GetHeaderMap(request, headermap_, referrer_url_); + referrer_policy_ = + static_cast(request.referrerPolicy()); + const blink::WebHTTPBody& body = request.httpBody(); if (!body.isNull()) { postdata_ = new CefPostDataImpl(); static_cast(postdata_.get())->Set(body); } - GetHeaderMap(request, headermap_); + first_party_for_cookies_ = request.firstPartyForCookies().spec().utf16(); if (request.cachePolicy() == blink::WebURLRequest::ReloadIgnoringCacheData) flags_ |= UR_FLAG_SKIP_CACHE; @@ -360,56 +536,255 @@ void CefRequestImpl::Set(const blink::WebURLRequest& request) { flags_ |= UR_FLAG_ALLOW_CACHED_CREDENTIALS; if (request.reportUploadProgress()) flags_ |= UR_FLAG_REPORT_UPLOAD_PROGRESS; - - first_party_for_cookies_ = request.firstPartyForCookies().spec().utf16(); } void CefRequestImpl::Get(blink::WebURLRequest& request, - bool changed_only) const { + int64& upload_data_size) const { request.initialize(); base::AutoLock lock_scope(lock_); - if (ShouldSet(kChangedUrl, changed_only)) { - GURL gurl = GURL(url_.ToString()); - request.setURL(blink::WebURL(gurl)); - } + request.setURL(GURL(url_.ToString())); + request.setHTTPMethod(blink::WebString::fromUTF8(method_.ToString())); - if (ShouldSet(kChangedMethod, changed_only)) { - std::string method(method_); - request.setHTTPMethod(blink::WebString::fromUTF8(method.c_str())); - } - - if (ShouldSet(kChangedPostData, changed_only)) { - blink::WebHTTPBody body; - if (postdata_.get()) { - body.initialize(); - static_cast(postdata_.get())->Get(body); - request.setHTTPBody(body); + if (!referrer_url_.empty()) { + const blink::WebString& referrer = + blink::WebSecurityPolicy::generateReferrerHeader( + static_cast(referrer_policy_), + GURL(url_.ToString()), + blink::WebString::fromUTF8(referrer_url_)); + if (!referrer.isEmpty()) { + request.setHTTPReferrer( + referrer, + static_cast(referrer_policy_)); } } - if (ShouldSet(kChangedHeaderMap, changed_only)) - SetHeaderMap(headermap_, request); + if (postdata_.get()) { + blink::WebHTTPBody body; + body.initialize(); + static_cast(postdata_.get())->Get(body); + request.setHTTPBody(body); - if (ShouldSet(kChangedFlags, changed_only)) { - request.setCachePolicy((flags_ & UR_FLAG_SKIP_CACHE) ? - blink::WebURLRequest::ReloadIgnoringCacheData : - blink::WebURLRequest::UseProtocolCachePolicy); - - #define SETBOOLFLAG(obj, flags, method, FLAG) \ - obj.method((flags & (FLAG)) == (FLAG)) - - SETBOOLFLAG(request, flags_, setAllowStoredCredentials, - UR_FLAG_ALLOW_CACHED_CREDENTIALS); - SETBOOLFLAG(request, flags_, setReportUploadProgress, - UR_FLAG_REPORT_UPLOAD_PROGRESS); + if (flags_ & UR_FLAG_REPORT_UPLOAD_PROGRESS) { + // Attempt to determine the upload data size. + CefPostData::ElementVector elements; + postdata_->GetElements(elements); + if (elements.size() == 1 && elements[0]->GetType() == PDE_TYPE_BYTES) { + CefPostDataElementImpl* impl = + static_cast(elements[0].get()); + upload_data_size = impl->GetBytesCount(); + } + } } - if (!first_party_for_cookies_.empty() && - ShouldSet(kChangedFirstPartyForCookies, changed_only)) { - GURL gurl = GURL(first_party_for_cookies_.ToString()); - request.setFirstPartyForCookies(blink::WebURL(gurl)); + ::SetHeaderMap(headermap_, request); + + if (!first_party_for_cookies_.empty()) + request.setFirstPartyForCookies(GURL(first_party_for_cookies_.ToString())); + + request.setCachePolicy((flags_ & UR_FLAG_SKIP_CACHE) ? + blink::WebURLRequest::ReloadIgnoringCacheData : + blink::WebURLRequest::UseProtocolCachePolicy); + + SETBOOLFLAG(request, flags_, setAllowStoredCredentials, + UR_FLAG_ALLOW_CACHED_CREDENTIALS); + SETBOOLFLAG(request, flags_, setReportUploadProgress, + UR_FLAG_REPORT_UPLOAD_PROGRESS); +} + +// static +void CefRequestImpl::Get(const CefMsg_LoadRequest_Params& params, + blink::WebURLRequest& request) { + request.initialize(); + + request.setURL(params.url); + if (!params.method.empty()) + request.setHTTPMethod(base::ASCIIToUTF16(params.method)); + + if (params.referrer.is_valid()) { + const blink::WebString& referrer = + blink::WebSecurityPolicy::generateReferrerHeader( + static_cast(params.referrer_policy), + params.url, + blink::WebString::fromUTF8(params.referrer.spec())); + if (!referrer.isEmpty()) { + request.setHTTPReferrer( + referrer, + static_cast(params.referrer_policy)); + } } + + if (!params.headers.empty()) { + for (net::HttpUtil::HeadersIterator i(params.headers.begin(), + params.headers.end(), "\n"); + i.GetNext(); ) { + request.addHTTPHeaderField(blink::WebString::fromUTF8(i.name()), + blink::WebString::fromUTF8(i.values())); + } + } + + if (params.upload_data.get()) { + const base::string16& method = request.httpMethod(); + if (method == base::ASCIIToUTF16("GET") || + method == base::ASCIIToUTF16("HEAD")) { + request.setHTTPMethod(base::ASCIIToUTF16("POST")); + } + + // The comparison performed by httpHeaderField() is case insensitive. + if (request.httpHeaderField(base::ASCIIToUTF16( + net::HttpRequestHeaders::kContentType)).length()== 0) { + request.setHTTPHeaderField( + base::ASCIIToUTF16(net::HttpRequestHeaders::kContentType), + base::ASCIIToUTF16(kApplicationFormURLEncoded)); + } + + blink::WebHTTPBody body; + body.initialize(); + + const ScopedVector& elements = + params.upload_data->elements(); + ScopedVector::const_iterator it = + elements.begin(); + for (; it != elements.end(); ++it) { + const net::UploadElement& element = **it; + 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.appendFile(FilePathStringToWebString(element.file_path().value())); + } else { + NOTREACHED(); + } + } + + request.setHTTPBody(body); + } + + if (params.first_party_for_cookies.is_valid()) + request.setFirstPartyForCookies(params.first_party_for_cookies); + + request.setCachePolicy((params.load_flags & UR_FLAG_SKIP_CACHE) ? + blink::WebURLRequest::ReloadIgnoringCacheData : + blink::WebURLRequest::UseProtocolCachePolicy); + + SETBOOLFLAG(request, params.load_flags, setAllowStoredCredentials, + UR_FLAG_ALLOW_CACHED_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 = GURL(url_.ToString()); + params.method = method_; + + // Referrer policy will be applied later in the request pipeline. + params.referrer.url = GURL(referrer_url_.ToString()); + params.referrer.policy = + static_cast(referrer_policy_); + + if (!headermap_.empty()) + params.headers = HttpHeaderUtils::GenerateHeaders(headermap_); + + if (postdata_) { + CefPostDataImpl* impl = static_cast(postdata_.get()); + params.upload_data = new net::UploadData(); + impl->Get(*params.upload_data.get()); + } + + params.first_party_for_cookies = GURL(first_party_for_cookies_.ToString()); + params.load_flags = flags_; +} + +void CefRequestImpl::Get(net::URLFetcher& fetcher, + int64& upload_data_size) const { + base::AutoLock lock_scope(lock_); + + if (!referrer_url_.empty()) { + fetcher.SetReferrer(GetURLRequestReferrer(referrer_url_)); + fetcher.SetReferrerPolicy(GetURLRequestReferrerPolicy(referrer_policy_)); + } + + CefRequest::HeaderMap headerMap = headermap_; + + std::string content_type; + + // Extract the Content-Type header value. + { + HeaderMap::iterator it = headerMap.begin(); + for (; it != headerMap.end(); ++it) { + if (base::LowerCaseEqualsASCII(it->first.ToString(), + kContentTypeLowerCase)) { + content_type = it->second; + headerMap.erase(it); + break; + } + } + } + + fetcher.SetExtraRequestHeaders( + HttpHeaderUtils::GenerateHeaders(headerMap)); + + if (postdata_.get()) { + CefPostData::ElementVector elements; + postdata_->GetElements(elements); + if (elements.size() == 1) { + // Default to URL encoding if not specified. + if (content_type.empty()) + content_type = kApplicationFormURLEncoded; + + CefPostDataElementImpl* impl = + static_cast(elements[0].get()); + + switch (elements[0]->GetType()) { + case PDE_TYPE_BYTES: { + const size_t size = impl->GetBytesCount(); + if (flags_ & UR_FLAG_REPORT_UPLOAD_PROGRESS) { + // Return the upload data size. + upload_data_size = size; + } + fetcher.SetUploadData( + content_type, + std::string(static_cast(impl->GetBytes()), size)); + break; + } + case PDE_TYPE_FILE: + fetcher.SetUploadFilePath( + content_type, + base::FilePath(impl->GetFile()), + 0, kuint64max, + GetFileTaskRunner()); + break; + case PDE_TYPE_EMPTY: + break; + } + } else if (elements.size() > 1) { + NOTIMPLEMENTED() << " multi-part form data is not supported"; + } + } + + if (!first_party_for_cookies_.empty()) { + fetcher.SetFirstPartyForCookies( + GURL(first_party_for_cookies_.ToString())); + } + + if (flags_ & UR_FLAG_NO_RETRY_ON_5XX) + fetcher.SetAutomaticallyRetryOn5xx(false); + + int load_flags = 0; + + if (flags_ & UR_FLAG_SKIP_CACHE) + load_flags |= net::LOAD_BYPASS_CACHE; + + if (!(flags_ & UR_FLAG_ALLOW_CACHED_CREDENTIALS)) { + load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA; + load_flags |= net::LOAD_DO_NOT_SEND_COOKIES; + load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES; + } + + fetcher.SetLoadFlags(load_flags); } void CefRequestImpl::SetReadOnly(bool read_only) { @@ -448,49 +823,6 @@ uint8 CefRequestImpl::GetChanges() const { return changes; } -// static -void CefRequestImpl::GetHeaderMap(const net::HttpRequestHeaders& headers, - HeaderMap& map) { - if (headers.IsEmpty()) - return; - - net::HttpRequestHeaders::Iterator it(headers); - do { - map.insert(std::make_pair(it.name(), it.value())); - } while (it.GetNext()); -} - - -// static -void CefRequestImpl::GetHeaderMap(const blink::WebURLRequest& request, - HeaderMap& map) { - class HeaderVisitor : public blink::WebHTTPHeaderVisitor { - public: - explicit HeaderVisitor(HeaderMap* map) : map_(map) {} - - void visitHeader(const blink::WebString& name, - const blink::WebString& value) override { - map_->insert(std::make_pair(base::string16(name), - base::string16(value))); - } - - private: - HeaderMap* map_; - }; - - HeaderVisitor visitor(&map); - request.visitHTTPHeaderFields(&visitor); -} - -// static -void CefRequestImpl::SetHeaderMap(const HeaderMap& map, - blink::WebURLRequest& request) { - HeaderMap::const_iterator it = map.begin(); - for (; it != map.end(); ++it) - request.setHTTPHeaderField(base::string16(it->first), - base::string16(it->second)); -} - void CefRequestImpl::Changed(uint8 changes) { lock_.AssertAcquired(); if (track_changes_) @@ -529,6 +861,8 @@ void CefRequestImpl::Reset() { url_.clear(); method_ = "GET"; + referrer_url_.clear(); + referrer_policy_ = REFERRER_POLICY_DEFAULT; postdata_ = NULL; headermap_.clear(); resource_type_ = RT_SUB_RESOURCE; @@ -553,6 +887,7 @@ CefRefPtr CefPostData::Create() { CefPostDataImpl::CefPostDataImpl() : read_only_(false), + has_excluded_elements_(false), track_changes_(false), has_changes_(false) { } @@ -562,6 +897,11 @@ bool CefPostDataImpl::IsReadOnly() { 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(); @@ -653,6 +993,8 @@ void CefPostDataImpl::Set(const net::UploadDataStream& data_stream) { static_cast(postelem.get())->Set(**it); if (postelem->GetType() != PDE_TYPE_EMPTY) AddElement(postelem); + else if (!has_excluded_elements_) + has_excluded_elements_ = true; } } } diff --git a/libcef/common/request_impl.h b/libcef/common/request_impl.h index 47ef9e5d8..5a53e019e 100644 --- a/libcef/common/request_impl.h +++ b/libcef/common/request_impl.h @@ -21,6 +21,7 @@ class UploadData; class UploadDataStream; class UploadElement; class UploadElementReader; +class URLFetcher; class URLRequest; }; @@ -28,6 +29,9 @@ namespace blink { class WebURLRequest; } +struct CefMsg_LoadRequest_Params; +struct CefNavigateParams; + // Implementation of CefRequest class CefRequestImpl : public CefRequest { public: @@ -35,10 +39,11 @@ class CefRequestImpl : public CefRequest { kChangedNone = 0, kChangedUrl = 1 << 0, kChangedMethod = 1 << 1, - kChangedPostData = 1 << 2, - kChangedHeaderMap = 1 << 3, - kChangedFlags = 1 << 4, - kChangedFirstPartyForCookies = 1 << 5, + kChangedReferrer = 1 << 2, + kChangedPostData = 1 << 3, + kChangedHeaderMap = 1 << 4, + kChangedFlags = 1 << 5, + kChangedFirstPartyForCookies = 1 << 6, }; CefRequestImpl(); @@ -48,6 +53,10 @@ class CefRequestImpl : public CefRequest { void SetURL(const CefString& url) override; CefString GetMethod() override; void SetMethod(const CefString& method) override; + void SetReferrer(const CefString& referrer_url, + ReferrerPolicy policy) override; + CefString GetReferrerURL() override; + ReferrerPolicy GetReferrerPolicy() override; CefRefPtr GetPostData() override; void SetPostData(CefRefPtr postData) override; void GetHeaderMap(HeaderMap& headerMap) override; @@ -74,28 +83,36 @@ class CefRequestImpl : public CefRequest { // Populate this object from the NavigationParams object. // TODO(cef): Remove the |is_main_frame| argument once NavigationParams is // reliable in reporting that value. + // Called from content_browser_client.cc NavigationOnUIThread(). void Set(const navigation_interception::NavigationParams& params, bool is_main_frame); // Populate this object from a WebURLRequest object. + // Called from CefContentRendererClient::HandleNavigation(). void Set(const blink::WebURLRequest& request); // Populate the WebURLRequest object from this object. - // If |changed_only| is true then only the changed fields will be updated. - void Get(blink::WebURLRequest& request, bool changed_only) const; + // Called from CefRenderURLRequest::Context::Start(). + void Get(blink::WebURLRequest& request, int64& upload_data_size) const; + + // Populate the WebURLRequest object based on the contents of |params|. + // Called from CefBrowserImpl::LoadRequest(). + static void Get(const CefMsg_LoadRequest_Params& params, + blink::WebURLRequest& request); + + // Populate the CefNavigateParams object from this object. + // Called from CefBrowserHostImpl::LoadRequest(). + void Get(CefNavigateParams& params) const; + + // Populate the URLFetcher object from this object. + // Called from CefBrowserURLRequest::Context::ContinueOnOriginatingThread(). + void Get(net::URLFetcher& fetcher, int64& upload_data_size) const; void SetReadOnly(bool read_only); void SetTrackChanges(bool track_changes); uint8 GetChanges() const; - static void GetHeaderMap(const net::HttpRequestHeaders& headers, - HeaderMap& map); - static void GetHeaderMap(const blink::WebURLRequest& request, - HeaderMap& map); - static void SetHeaderMap(const HeaderMap& map, - blink::WebURLRequest& request); - private: void Changed(uint8 changes); bool ShouldSet(uint8 changes, bool changed_only) const; @@ -104,6 +121,8 @@ class CefRequestImpl : public CefRequest { CefString url_; CefString method_; + CefString referrer_url_; + ReferrerPolicy referrer_policy_; CefRefPtr postdata_; HeaderMap headermap_; ResourceType resource_type_; @@ -134,6 +153,7 @@ class CefPostDataImpl : public CefPostData { CefPostDataImpl(); bool IsReadOnly() override; + bool HasExcludedElements() override; size_t GetElementCount() override; void GetElements(ElementVector& elements) override; bool RemoveElement(CefRefPtr element) override; @@ -160,6 +180,9 @@ class CefPostDataImpl : public CefPostData { // True if this object is read-only. bool read_only_; + // True if this object has excluded elements. + bool has_excluded_elements_; + // True if this object should track changes. bool track_changes_; diff --git a/libcef/renderer/browser_impl.cc b/libcef/renderer/browser_impl.cc index 99f910986..bdd087fa1 100644 --- a/libcef/renderer/browser_impl.cc +++ b/libcef/renderer/browser_impl.cc @@ -11,6 +11,7 @@ #include "libcef/common/cef_messages.h" #include "libcef/common/content_client.h" #include "libcef/common/process_message_impl.h" +#include "libcef/common/request_impl.h" #include "libcef/common/response_manager.h" #include "libcef/renderer/content_renderer_client.h" #include "libcef/renderer/dom_document_impl.h" @@ -19,14 +20,12 @@ #include "base/strings/string16.h" #include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "content/public/renderer/document_state.h" #include "content/public/renderer/navigation_state.h" #include "content/public/renderer/render_view.h" #include "content/renderer/navigation_state_impl.h" #include "content/renderer/render_view_impl.h" -#include "net/http/http_util.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLError.h" @@ -46,19 +45,6 @@ using blink::WebString; using blink::WebURL; using blink::WebView; -namespace { - -blink::WebString FilePathStringToWebString( - const base::FilePath::StringType& str) { -#if defined(OS_POSIX) - return base::WideToUTF16(base::SysNativeMBToWide(str)); -#elif defined(OS_WIN) - return base::WideToUTF16(str); -#endif -} - -} // namespace - // CefBrowserImpl static methods. // ----------------------------------------------------------------------------- @@ -305,68 +291,8 @@ void CefBrowserImpl::LoadRequest(const CefMsg_LoadRequest_Params& params) { WebFrame* web_frame = framePtr->web_frame(); - blink::WebURLRequest request(params.url); - - if (!params.method.empty()) - request.setHTTPMethod(base::ASCIIToUTF16(params.method)); - - if (params.referrer.is_valid()) { - WebString referrer = blink::WebSecurityPolicy::generateReferrerHeader( - static_cast(params.referrer_policy), - params.url, - WebString::fromUTF8(params.referrer.spec())); - if (!referrer.isEmpty()) - request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer); - } - - if (params.first_party_for_cookies.is_valid()) - request.setFirstPartyForCookies(params.first_party_for_cookies); - - if (!params.headers.empty()) { - for (net::HttpUtil::HeadersIterator i(params.headers.begin(), - params.headers.end(), "\n"); - i.GetNext(); ) { - request.addHTTPHeaderField(WebString::fromUTF8(i.name()), - WebString::fromUTF8(i.values())); - } - } - - if (params.upload_data.get()) { - base::string16 method = request.httpMethod(); - if (method == base::ASCIIToUTF16("GET") || - method == base::ASCIIToUTF16("HEAD")) { - request.setHTTPMethod(base::ASCIIToUTF16("POST")); - } - - if (request.httpHeaderField( - base::ASCIIToUTF16("Content-Type")).length() == 0) { - request.setHTTPHeaderField( - base::ASCIIToUTF16("Content-Type"), - base::ASCIIToUTF16("application/x-www-form-urlencoded")); - } - - blink::WebHTTPBody body; - body.initialize(); - - const ScopedVector& elements = - params.upload_data->elements(); - ScopedVector::const_iterator it = - elements.begin(); - for (; it != elements.end(); ++it) { - const net::UploadElement& element = **it; - 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.appendFile(FilePathStringToWebString(element.file_path().value())); - } else { - NOTREACHED(); - } - } - - request.setHTTPBody(body); - } + blink::WebURLRequest request; + CefRequestImpl::Get(params, request); web_frame->loadRequest(request); } diff --git a/libcef/renderer/render_urlrequest_impl.cc b/libcef/renderer/render_urlrequest_impl.cc index 807e9dc54..9586d2ae1 100644 --- a/libcef/renderer/render_urlrequest_impl.cc +++ b/libcef/renderer/render_urlrequest_impl.cc @@ -107,21 +107,8 @@ class CefRenderURLRequest::Context url_client_.reset(new CefWebURLLoaderClient(this, request_->GetFlags())); WebURLRequest urlRequest; - static_cast(request_.get())->Get(urlRequest, false); - - if (urlRequest.reportUploadProgress()) { - // Attempt to determine the upload data size. - CefRefPtr post_data = request_->GetPostData(); - if (post_data.get()) { - CefPostData::ElementVector elements; - post_data->GetElements(elements); - if (elements.size() == 1 && elements[0]->GetType() == PDE_TYPE_BYTES) { - CefPostDataElementImpl* impl = - static_cast(elements[0].get()); - upload_data_size_ = impl->GetBytesCount(); - } - } - } + static_cast(request_.get())->Get(urlRequest, + upload_data_size_); loader_->loadAsynchronously(urlRequest, url_client_.get()); return true; diff --git a/libcef_dll/cpptoc/post_data_cpptoc.cc b/libcef_dll/cpptoc/post_data_cpptoc.cc index 0276e3125..40397d515 100644 --- a/libcef_dll/cpptoc/post_data_cpptoc.cc +++ b/libcef_dll/cpptoc/post_data_cpptoc.cc @@ -46,6 +46,21 @@ int CEF_CALLBACK post_data_is_read_only(struct _cef_post_data_t* self) { return _retval; } +int CEF_CALLBACK post_data_has_excluded_elements( + struct _cef_post_data_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefPostDataCppToC::Get(self)->HasExcludedElements(); + + // Return type: bool + return _retval; +} + size_t CEF_CALLBACK post_data_get_element_count(struct _cef_post_data_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -153,6 +168,7 @@ void CEF_CALLBACK post_data_remove_elements(struct _cef_post_data_t* self) { CefPostDataCppToC::CefPostDataCppToC() { GetStruct()->is_read_only = post_data_is_read_only; + GetStruct()->has_excluded_elements = post_data_has_excluded_elements; GetStruct()->get_element_count = post_data_get_element_count; GetStruct()->get_elements = post_data_get_elements; GetStruct()->remove_element = post_data_remove_element; diff --git a/libcef_dll/cpptoc/request_cpptoc.cc b/libcef_dll/cpptoc/request_cpptoc.cc index f99811400..66ce9b4d4 100644 --- a/libcef_dll/cpptoc/request_cpptoc.cc +++ b/libcef_dll/cpptoc/request_cpptoc.cc @@ -110,6 +110,55 @@ void CEF_CALLBACK request_set_method(struct _cef_request_t* self, CefString(method)); } +void CEF_CALLBACK request_set_referrer(struct _cef_request_t* self, + const cef_string_t* referrer_url, cef_referrer_policy_t policy) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: referrer_url; type: string_byref_const + DCHECK(referrer_url); + if (!referrer_url) + return; + + // Execute + CefRequestCppToC::Get(self)->SetReferrer( + CefString(referrer_url), + policy); +} + +cef_string_userfree_t CEF_CALLBACK request_get_referrer_url( + struct _cef_request_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefString _retval = CefRequestCppToC::Get(self)->GetReferrerURL(); + + // Return type: string + return _retval.DetachToUserFree(); +} + +cef_referrer_policy_t CEF_CALLBACK request_get_referrer_policy( + struct _cef_request_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return REFERRER_POLICY_DEFAULT; + + // Execute + cef_referrer_policy_t _retval = CefRequestCppToC::Get( + self)->GetReferrerPolicy(); + + // Return type: simple + return _retval; +} + struct _cef_post_data_t* CEF_CALLBACK request_get_post_data( struct _cef_request_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -336,6 +385,9 @@ CefRequestCppToC::CefRequestCppToC() { GetStruct()->set_url = request_set_url; GetStruct()->get_method = request_get_method; GetStruct()->set_method = request_set_method; + GetStruct()->set_referrer = request_set_referrer; + GetStruct()->get_referrer_url = request_get_referrer_url; + GetStruct()->get_referrer_policy = request_get_referrer_policy; GetStruct()->get_post_data = request_get_post_data; GetStruct()->set_post_data = request_set_post_data; GetStruct()->get_header_map = request_get_header_map; diff --git a/libcef_dll/ctocpp/post_data_ctocpp.cc b/libcef_dll/ctocpp/post_data_ctocpp.cc index a21f9a691..2cf55e875 100644 --- a/libcef_dll/ctocpp/post_data_ctocpp.cc +++ b/libcef_dll/ctocpp/post_data_ctocpp.cc @@ -44,6 +44,20 @@ bool CefPostDataCToCpp::IsReadOnly() { return _retval?true:false; } +bool CefPostDataCToCpp::HasExcludedElements() { + cef_post_data_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, has_excluded_elements)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = _struct->has_excluded_elements(_struct); + + // Return type: bool + return _retval?true:false; +} + size_t CefPostDataCToCpp::GetElementCount() { cef_post_data_t* _struct = GetStruct(); if (CEF_MEMBER_MISSING(_struct, get_element_count)) diff --git a/libcef_dll/ctocpp/post_data_ctocpp.h b/libcef_dll/ctocpp/post_data_ctocpp.h index b8452b03d..b186dfefb 100644 --- a/libcef_dll/ctocpp/post_data_ctocpp.h +++ b/libcef_dll/ctocpp/post_data_ctocpp.h @@ -31,6 +31,7 @@ class CefPostDataCToCpp // CefPostData methods. bool IsReadOnly() OVERRIDE; + bool HasExcludedElements() OVERRIDE; size_t GetElementCount() OVERRIDE; void GetElements(ElementVector& elements) OVERRIDE; bool RemoveElement(CefRefPtr element) OVERRIDE; diff --git a/libcef_dll/ctocpp/request_ctocpp.cc b/libcef_dll/ctocpp/request_ctocpp.cc index 253b1c4dc..d9ccaffb6 100644 --- a/libcef_dll/ctocpp/request_ctocpp.cc +++ b/libcef_dll/ctocpp/request_ctocpp.cc @@ -110,6 +110,55 @@ void CefRequestCToCpp::SetMethod(const CefString& method) { method.GetStruct()); } +void CefRequestCToCpp::SetReferrer(const CefString& referrer_url, + ReferrerPolicy policy) { + cef_request_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, set_referrer)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: referrer_url; type: string_byref_const + DCHECK(!referrer_url.empty()); + if (referrer_url.empty()) + return; + + // Execute + _struct->set_referrer(_struct, + referrer_url.GetStruct(), + policy); +} + +CefString CefRequestCToCpp::GetReferrerURL() { + cef_request_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_referrer_url)) + return CefString(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_string_userfree_t _retval = _struct->get_referrer_url(_struct); + + // Return type: string + CefString _retvalStr; + _retvalStr.AttachToUserFree(_retval); + return _retvalStr; +} + +CefRequest::ReferrerPolicy CefRequestCToCpp::GetReferrerPolicy() { + cef_request_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_referrer_policy)) + return REFERRER_POLICY_DEFAULT; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_referrer_policy_t _retval = _struct->get_referrer_policy(_struct); + + // Return type: simple + return _retval; +} + CefRefPtr CefRequestCToCpp::GetPostData() { cef_request_t* _struct = GetStruct(); if (CEF_MEMBER_MISSING(_struct, get_post_data)) diff --git a/libcef_dll/ctocpp/request_ctocpp.h b/libcef_dll/ctocpp/request_ctocpp.h index 95a76aa4e..9db262e00 100644 --- a/libcef_dll/ctocpp/request_ctocpp.h +++ b/libcef_dll/ctocpp/request_ctocpp.h @@ -35,6 +35,10 @@ class CefRequestCToCpp void SetURL(const CefString& url) OVERRIDE; CefString GetMethod() OVERRIDE; void SetMethod(const CefString& method) OVERRIDE; + void SetReferrer(const CefString& referrer_url, + ReferrerPolicy policy) OVERRIDE; + CefString GetReferrerURL() OVERRIDE; + ReferrerPolicy GetReferrerPolicy() OVERRIDE; CefRefPtr GetPostData() OVERRIDE; void SetPostData(CefRefPtr postData) OVERRIDE; void GetHeaderMap(HeaderMap& headerMap) OVERRIDE; diff --git a/tests/unittests/request_unittest.cc b/tests/unittests/request_unittest.cc index 08b0e0ca7..bbbf95d03 100644 --- a/tests/unittests/request_unittest.cc +++ b/tests/unittests/request_unittest.cc @@ -89,6 +89,13 @@ TEST(RequestTest, SetGet) { request->SetMethod(method); EXPECT_EQ(method, request->GetMethod()); + // CefRequest SetReferrer + CefString referrer = "http://tests.com/referrer.html"; + CefRequest::ReferrerPolicy policy = REFERRER_POLICY_ORIGIN; + request->SetReferrer(referrer, policy); + EXPECT_EQ(referrer, request->GetReferrerURL()); + EXPECT_EQ(policy, request->GetReferrerPolicy()); + // CefRequest SetHeaderMap request->SetHeaderMap(setHeaders); request->GetHeaderMap(getHeaders); @@ -125,6 +132,9 @@ void CreateRequest(CefRefPtr& request) { request->SetURL("http://tests/run.html"); request->SetMethod("POST"); + request->SetReferrer("http://tests/main.html", + REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE); + CefRequest::HeaderMap headers; headers.insert(std::make_pair("HeaderA", "ValueA")); headers.insert(std::make_pair("HeaderB", "ValueB")); diff --git a/tests/unittests/test_util.cc b/tests/unittests/test_util.cc index 054262d75..e4cce92a9 100644 --- a/tests/unittests/test_util.cc +++ b/tests/unittests/test_util.cc @@ -80,6 +80,10 @@ void TestRequestEqual(CefRefPtr request1, EXPECT_STREQ(request1->GetMethod().ToString().c_str(), request2->GetMethod().ToString().c_str()); + EXPECT_STREQ(request1->GetReferrerURL().ToString().c_str(), + request2->GetReferrerURL().ToString().c_str()); + EXPECT_EQ(request1->GetReferrerPolicy(), request2->GetReferrerPolicy()); + CefRequest::HeaderMap headers1, headers2; request1->GetHeaderMap(headers1); request2->GetHeaderMap(headers2); diff --git a/tests/unittests/urlrequest_unittest.cc b/tests/unittests/urlrequest_unittest.cc index c77a45621..d5048e91f 100644 --- a/tests/unittests/urlrequest_unittest.cc +++ b/tests/unittests/urlrequest_unittest.cc @@ -49,6 +49,7 @@ enum RequestTestMode { REQTEST_GET_NODATA, REQTEST_GET_ALLOWCOOKIES, REQTEST_GET_REDIRECT, + REQTEST_GET_REFERRER, REQTEST_POST, REQTEST_POST_FILE, REQTEST_POST_WITHPROGRESS, @@ -583,6 +584,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe { REGISTER_TEST(REQTEST_GET_ALLOWCOOKIES, SetupGetAllowCookiesTest, GenericRunTest); REGISTER_TEST(REQTEST_GET_REDIRECT, SetupGetRedirectTest, GenericRunTest); + REGISTER_TEST(REQTEST_GET_REFERRER, SetupGetReferrerTest, GenericRunTest); REGISTER_TEST(REQTEST_POST, SetupPostTest, GenericRunTest); REGISTER_TEST(REQTEST_POST_FILE, SetupPostFileTest, GenericRunTest); REGISTER_TEST(REQTEST_POST_WITHPROGRESS, SetupPostWithProgressTest, @@ -677,6 +679,25 @@ class RequestTestRunner : public base::RefCountedThreadSafe { settings_.redirect_response->SetHeaderMap(headerMap); } + void SetupGetReferrerTest() { + settings_.request = CefRequest::Create(); + settings_.request->SetURL(MakeSchemeURL("GetTest.html")); + settings_.request->SetMethod("GET"); + + // The referrer URL must be HTTP or HTTPS. This is enforced by + // GURL::GetAsReferrer() called from URLRequest::SetReferrer(). + settings_.request->SetReferrer( + "http://tests.com/referrer.html", + REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE); + + settings_.response = CefResponse::Create(); + settings_.response->SetMimeType("text/html"); + settings_.response->SetStatus(200); + settings_.response->SetStatusText("OK"); + + settings_.response_data = "GET TEST SUCCESS"; + } + void SetupPostTest() { settings_.request = CefRequest::Create(); settings_.request->SetURL(MakeSchemeURL("PostTest.html")); @@ -1196,6 +1217,8 @@ void RegisterURLRequestCustomSchemes( REQTEST_GET_ALLOWCOOKIES, context_mode, true); \ REQ_TEST(BrowserGETRedirect##suffix, \ REQTEST_GET_REDIRECT, context_mode, true); \ + REQ_TEST(BrowserGETReferrer##suffix, \ + REQTEST_GET_REFERRER, context_mode, true); \ REQ_TEST(BrowserPOST##suffix, REQTEST_POST, context_mode, true); \ REQ_TEST(BrowserPOSTFile##suffix, REQTEST_POST_FILE, context_mode, true); \ REQ_TEST(BrowserPOSTWithProgress##suffix, \ @@ -1208,6 +1231,8 @@ void RegisterURLRequestCustomSchemes( REQTEST_GET_ALLOWCOOKIES, context_mode, false); \ REQ_TEST(RendererGETRedirect##suffix, \ REQTEST_GET_REDIRECT, context_mode, false); \ + REQ_TEST(RendererGETReferrer##suffix, \ + REQTEST_GET_REFERRER, context_mode, false); \ REQ_TEST(RendererPOST##suffix, REQTEST_POST, context_mode, false); \ REQ_TEST(RendererPOSTWithProgress##suffix, \ REQTEST_POST_WITHPROGRESS, context_mode, false); \