diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index aa7125d33..412cee154 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -737,6 +737,25 @@ typedef struct _cef_urlparts_t { cef_string_t fragment; } cef_urlparts_t; +/// +// Cookie priority values. +/// +typedef enum { + CEF_COOKIE_PRIORITY_LOW = -1, + CEF_COOKIE_PRIORITY_MEDIUM = 0, + CEF_COOKIE_PRIORITY_HIGH = 1, +} cef_cookie_priority_t; + +/// +// Cookie same site values. +/// +typedef enum { + CEF_COOKIE_SAME_SITE_UNSPECIFIED, + CEF_COOKIE_SAME_SITE_NO_RESTRICTION, + CEF_COOKIE_SAME_SITE_LAX_MODE, + CEF_COOKIE_SAME_SITE_STRICT_MODE, +} cef_cookie_same_site_t; + /// // Cookie information. /// @@ -791,6 +810,16 @@ typedef struct _cef_cookie_t { /// int has_expires; cef_time_t expires; + + /// + // Same site. + /// + cef_cookie_same_site_t same_site; + + /// + // Priority. + /// + cef_cookie_priority_t priority; } cef_cookie_t; /// diff --git a/include/internal/cef_types_wrappers.h b/include/internal/cef_types_wrappers.h index caea5c1cc..7e07755c6 100644 --- a/include/internal/cef_types_wrappers.h +++ b/include/internal/cef_types_wrappers.h @@ -851,6 +851,8 @@ struct CefCookieTraits { target->last_access = src->last_access; target->has_expires = src->has_expires; target->expires = src->expires; + target->same_site = src->same_site; + target->priority = src->priority; } }; diff --git a/libcef/browser/net_service/browser_urlrequest_impl.cc b/libcef/browser/net_service/browser_urlrequest_impl.cc index 11721c223..81a363f8b 100644 --- a/libcef/browser/net_service/browser_urlrequest_impl.cc +++ b/libcef/browser/net_service/browser_urlrequest_impl.cc @@ -31,6 +31,7 @@ #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" #include "services/network/public/cpp/simple_url_loader_stream_consumer.h" +#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h" namespace { @@ -254,6 +255,23 @@ class CefBrowserURLRequest::Context resource_request->render_frame_id = render_frame_id; + // Behave the same as a subresource load. + resource_request->fetch_request_context_type = + static_cast(blink::mojom::RequestContextType::SUBRESOURCE); + resource_request->resource_type = + static_cast(blink::mojom::ResourceType::kSubResource); + + // Set the origin to match the request. + const GURL& url = GURL(request_->GetURL().ToString()); + resource_request->request_initiator = url::Origin::Create(url); + + if (request_flags & UR_FLAG_ALLOW_STORED_CREDENTIALS) { + // Include SameSite cookies. + resource_request->attach_same_site_cookies = true; + resource_request->site_for_cookies = + net::SiteForCookies::FromOrigin(*resource_request->request_initiator); + } + // SimpleURLLoader is picky about the body contents. Try to populate them // correctly below. auto request_body = resource_request->request_body; diff --git a/libcef/browser/net_service/cookie_manager_impl.cc b/libcef/browser/net_service/cookie_manager_impl.cc index 60dcd3f81..e7f5bebf1 100644 --- a/libcef/browser/net_service/cookie_manager_impl.cc +++ b/libcef/browser/net_service/cookie_manager_impl.cc @@ -47,6 +47,9 @@ void SetCookieCallbackImpl(CefRefPtr callback, net::CanonicalCookie::CookieInclusionStatus status) { if (!callback.get()) return; + if (!status.IsInclude()) { + LOG(WARNING) << "SetCookie failed with reason: " << status.GetDebugString(); + } CEF_POST_TASK(CEF_UIT, base::Bind(&CefSetCookieCallback::OnComplete, callback.get(), status.IsInclude())); } @@ -203,6 +206,8 @@ bool CefCookieManagerImpl::VisitUrlCookies( net::CookieOptions options; if (includeHttpOnly) options.set_include_httponly(); + options.set_same_site_cookie_context( + net::CookieOptions::SameSiteCookieContext::MakeInclusive()); auto browser_context = GetBrowserContext(browser_context_getter_); if (!browser_context) @@ -239,13 +244,18 @@ bool CefCookieManagerImpl::SetCookie(const CefString& url, if (cookie.has_expires) cef_time_to_basetime(cookie.expires, expiration_time); + net::CookieSameSite same_site = + net_service::MakeCookieSameSite(cookie.same_site); + net::CookiePriority priority = + net_service::MakeCookiePriority(cookie.priority); + auto canonical_cookie = net::CanonicalCookie::CreateSanitizedCookie( gurl, name, value, domain, path, base::Time(), // Creation time. expiration_time, base::Time(), // Last access time. - cookie.secure ? true : false, cookie.httponly ? true : false, - net::CookieSameSite::UNSPECIFIED, net::COOKIE_PRIORITY_DEFAULT); + cookie.secure ? true : false, cookie.httponly ? true : false, same_site, + priority); if (!canonical_cookie) { SetCookieCallbackImpl(callback, @@ -258,6 +268,8 @@ bool CefCookieManagerImpl::SetCookie(const CefString& url, net::CookieOptions options; if (cookie.httponly) options.set_include_httponly(); + options.set_same_site_cookie_context( + net::CookieOptions::SameSiteCookieContext::MakeInclusive()); auto browser_context = GetBrowserContext(browser_context_getter_); if (!browser_context) diff --git a/libcef/common/main_delegate.cc b/libcef/common/main_delegate.cc index 37be60934..a68020efb 100644 --- a/libcef/common/main_delegate.cc +++ b/libcef/common/main_delegate.cc @@ -620,18 +620,6 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) { disable_features.push_back(network::features::kOutOfBlinkCors.name); } - // TODO: Add support for creating cookies with SameSite attribute (see issue - // #2524) - if (net::features::kSameSiteByDefaultCookies.default_state == - base::FEATURE_ENABLED_BY_DEFAULT) { - disable_features.push_back(net::features::kSameSiteByDefaultCookies.name); - } - if (net::features::kCookiesWithoutSameSiteMustBeSecure.default_state == - base::FEATURE_ENABLED_BY_DEFAULT) { - disable_features.push_back( - net::features::kCookiesWithoutSameSiteMustBeSecure.name); - } - #if defined(OS_WIN) if (features::kCalculateNativeWinOcclusion.default_state == base::FEATURE_ENABLED_BY_DEFAULT) { diff --git a/libcef/common/net_service/net_service_util.cc b/libcef/common/net_service/net_service_util.cc index 68a04a307..3f68e240a 100644 --- a/libcef/common/net_service/net_service_util.cc +++ b/libcef/common/net_service/net_service_util.cc @@ -38,6 +38,30 @@ bool GetCookieDomain(const GURL& url, result); } +cef_cookie_same_site_t MakeCefCookieSameSite(net::CookieSameSite value) { + switch (value) { + case net::CookieSameSite::UNSPECIFIED: + return CEF_COOKIE_SAME_SITE_UNSPECIFIED; + case net::CookieSameSite::NO_RESTRICTION: + return CEF_COOKIE_SAME_SITE_NO_RESTRICTION; + case net::CookieSameSite::LAX_MODE: + return CEF_COOKIE_SAME_SITE_LAX_MODE; + case net::CookieSameSite::STRICT_MODE: + return CEF_COOKIE_SAME_SITE_STRICT_MODE; + } +} + +cef_cookie_priority_t MakeCefCookiePriority(net::CookiePriority value) { + switch (value) { + case net::COOKIE_PRIORITY_LOW: + return CEF_COOKIE_PRIORITY_LOW; + case net::COOKIE_PRIORITY_MEDIUM: + return CEF_COOKIE_PRIORITY_MEDIUM; + case net::COOKIE_PRIORITY_HIGH: + return CEF_COOKIE_PRIORITY_HIGH; + } +} + } // namespace const char kHTTPLocationHeaderName[] = "Location"; @@ -177,6 +201,30 @@ net::RedirectInfo MakeRedirectInfo(const network::ResourceRequest& request, insecure_scheme_was_upgraded); } +net::CookieSameSite MakeCookieSameSite(cef_cookie_same_site_t value) { + switch (value) { + case CEF_COOKIE_SAME_SITE_UNSPECIFIED: + return net::CookieSameSite::UNSPECIFIED; + case CEF_COOKIE_SAME_SITE_NO_RESTRICTION: + return net::CookieSameSite::NO_RESTRICTION; + case CEF_COOKIE_SAME_SITE_LAX_MODE: + return net::CookieSameSite::LAX_MODE; + case CEF_COOKIE_SAME_SITE_STRICT_MODE: + return net::CookieSameSite::STRICT_MODE; + } +} + +net::CookiePriority MakeCookiePriority(cef_cookie_priority_t value) { + switch (value) { + case CEF_COOKIE_PRIORITY_LOW: + return net::COOKIE_PRIORITY_LOW; + case CEF_COOKIE_PRIORITY_MEDIUM: + return net::COOKIE_PRIORITY_MEDIUM; + case CEF_COOKIE_PRIORITY_HIGH: + return net::COOKIE_PRIORITY_HIGH; + } +} + bool MakeCefCookie(const net::CanonicalCookie& cc, CefCookie& cookie) { CefString(&cookie.name).FromString(cc.Name()); CefString(&cookie.value).FromString(cc.Value()); @@ -189,6 +237,8 @@ bool MakeCefCookie(const net::CanonicalCookie& cc, CefCookie& cookie) { cookie.has_expires = cc.IsPersistent(); if (cookie.has_expires) cef_time_from_basetime(cc.ExpiryDate(), cookie.expires); + cookie.same_site = MakeCefCookieSameSite(cc.SameSite()); + cookie.priority = MakeCefCookiePriority(cc.Priority()); return true; } @@ -225,6 +275,8 @@ bool MakeCefCookie(const GURL& url, cookie.has_expires = !cookie_expires.is_null(); if (cookie.has_expires) cef_time_from_basetime(cookie_expires, cookie.expires); + cookie.same_site = MakeCefCookieSameSite(pc.SameSite()); + cookie.priority = MakeCefCookiePriority(pc.Priority()); return true; } diff --git a/libcef/common/net_service/net_service_util.h b/libcef/common/net_service/net_service_util.h index cf748d095..83e34b307 100644 --- a/libcef/common/net_service/net_service_util.h +++ b/libcef/common/net_service/net_service_util.h @@ -11,6 +11,7 @@ #include "include/internal/cef_types_wrappers.h" #include "base/memory/scoped_refptr.h" +#include "net/cookies/cookie_constants.h" namespace net { class CanonicalCookie; @@ -70,6 +71,9 @@ bool MakeCefCookie(const GURL& url, const std::string& cookie_line, CefCookie& cookie); +net::CookieSameSite MakeCookieSameSite(cef_cookie_same_site_t value); +net::CookiePriority MakeCookiePriority(cef_cookie_priority_t value); + } // namespace net_service #endif // CEF_LIBCEF_COMMON_NET_SERVICE_NET_SERVICE_UTIL_H_ diff --git a/libcef/renderer/render_urlrequest_impl.cc b/libcef/renderer/render_urlrequest_impl.cc index c187d172a..4c5d25b03 100644 --- a/libcef/renderer/render_urlrequest_impl.cc +++ b/libcef/renderer/render_urlrequest_impl.cc @@ -132,6 +132,13 @@ class CefRenderURLRequest::Context // DCHECK'd in ResourceDispatcherHostImpl::ContinuePendingBeginRequest. resource_request->request_initiator = url::Origin::Create(url); + if (request_->GetFlags() & UR_FLAG_ALLOW_STORED_CREDENTIALS) { + // Include SameSite cookies. + resource_request->attach_same_site_cookies = true; + resource_request->site_for_cookies = + net::SiteForCookies::FromOrigin(*resource_request->request_initiator); + } + if (resource_request->request_body) { const auto& elements = *resource_request->request_body->elements(); if (elements.size() > 0) { diff --git a/tests/ceftests/cookie_unittest.cc b/tests/ceftests/cookie_unittest.cc index 1623b50f9..890286aa6 100644 --- a/tests/ceftests/cookie_unittest.cc +++ b/tests/ceftests/cookie_unittest.cc @@ -247,6 +247,8 @@ void GetCookie(CefRefPtr manager, EXPECT_EQ(cookie.expires.minute, cookie_read.expires.minute); EXPECT_EQ(cookie.expires.second, cookie_read.expires.second); EXPECT_EQ(cookie.expires.millisecond, cookie_read.expires.millisecond); + EXPECT_EQ(cookie.same_site, cookie_read.same_site); + EXPECT_EQ(cookie.priority, cookie_read.priority); } // Verify that no cookies exist. If |withUrl| is true it will only check for diff --git a/tests/ceftests/urlrequest_unittest.cc b/tests/ceftests/urlrequest_unittest.cc index 0e1cebf26..a7e8fec08 100644 --- a/tests/ceftests/urlrequest_unittest.cc +++ b/tests/ceftests/urlrequest_unittest.cc @@ -475,10 +475,7 @@ void VerifyNormalRequest(const RequestRunSettings* settings, has_send_cookie = true; } - if (settings->expect_send_cookie) - EXPECT_TRUE(has_send_cookie); - else - EXPECT_FALSE(has_send_cookie); + EXPECT_EQ(settings->expect_send_cookie, has_send_cookie); } // Populate normal response contents.