Skip to content

Commit 60dba38

Browse files
WSH032pewsheen
andauthored
feat: add WebView::set_cookie and WebView::delete_cookie (#1569)
* feat: add `WebView::set_cookie` and `WebView::delete_cookie` * feat: implement for `wkwebview` * chore: changes-files * feat: implement SameSite cookie policy for wkwebview * refactor: use `&` instead of `&*` * refactor: remove `debug_assert` for `HttpOnly` * docs: add `delete_cookie` in example * chore: remove redundant samesite setting --------- Co-authored-by: Jason Tsai <[email protected]>
1 parent 27c5916 commit 60dba38

File tree

7 files changed

+364
-3
lines changed

7 files changed

+364
-3
lines changed

.changes/cookies-api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wry": "patch"
3+
---
4+
5+
Add `WebView::set_cookie` and `WebView::delete_cookie` APIs.

examples/cookies.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
2+
// SPDX-License-Identifier: Apache-2.0
3+
// SPDX-License-Identifier: MIT
4+
5+
use tao::{
6+
event::{Event, WindowEvent},
7+
event_loop::{ControlFlow, EventLoop},
8+
window::WindowBuilder,
9+
};
10+
use wry::WebViewBuilder;
11+
12+
fn main() -> wry::Result<()> {
13+
let event_loop = EventLoop::new();
14+
let window = WindowBuilder::new().build(&event_loop).unwrap();
15+
16+
let builder = WebViewBuilder::new().with_url("https://www.httpbin.org/cookies/set?foo=bar");
17+
18+
#[cfg(any(
19+
target_os = "windows",
20+
target_os = "macos",
21+
target_os = "ios",
22+
target_os = "android"
23+
))]
24+
let webview = builder.build(&window)?;
25+
#[cfg(not(any(
26+
target_os = "windows",
27+
target_os = "macos",
28+
target_os = "ios",
29+
target_os = "android"
30+
)))]
31+
let webview = {
32+
use tao::platform::unix::WindowExtUnix;
33+
use wry::WebViewBuilderExtUnix;
34+
let vbox = window.default_vbox().unwrap();
35+
builder.build_gtk(vbox)?
36+
};
37+
38+
webview.set_cookie(
39+
cookie::Cookie::build(("foo1", "bar1"))
40+
.domain("www.httpbin.org")
41+
.path("/")
42+
.secure(true)
43+
.http_only(true)
44+
.max_age(cookie::time::Duration::seconds(10))
45+
.inner(),
46+
)?;
47+
48+
let cookie_deleted = cookie::Cookie::build(("will_be_deleted", "will_be_deleted"));
49+
50+
webview.set_cookie(cookie_deleted.inner())?;
51+
println!("Setting Cookies:");
52+
for cookie in webview.cookies()? {
53+
println!("\t{cookie}");
54+
}
55+
56+
println!("After Deleting:");
57+
webview.delete_cookie(cookie_deleted.inner())?;
58+
for cookie in webview.cookies()? {
59+
println!("\t{cookie}");
60+
}
61+
62+
event_loop.run(move |event, _, control_flow| {
63+
*control_flow = ControlFlow::Wait;
64+
65+
if let Event::WindowEvent {
66+
event: WindowEvent::CloseRequested,
67+
..
68+
} = event
69+
{
70+
*control_flow = ControlFlow::Exit;
71+
}
72+
});
73+
}

src/android/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,16 @@ impl InnerWebView {
416416
rx.recv_timeout(MAIN_PIPE_TIMEOUT).map_err(Into::into)
417417
}
418418

419+
pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
420+
// Unsupported
421+
Ok(())
422+
}
423+
424+
pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
425+
// Unsupported
426+
Ok(())
427+
}
428+
419429
pub fn cookies(&self) -> Result<Vec<cookie::Cookie<'static>>> {
420430
Ok(Vec::new())
421431
}

src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,24 @@ impl WebView {
18351835
self.webview.cookies()
18361836
}
18371837

1838+
/// Set a cookie for the webview.
1839+
///
1840+
/// ## Platform-specific
1841+
///
1842+
/// - **Android**: Not supported.
1843+
pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
1844+
self.webview.set_cookie(cookie)
1845+
}
1846+
1847+
/// Delete a cookie for the webview.
1848+
///
1849+
/// ## Platform-specific
1850+
///
1851+
/// - **Android**: Not supported.
1852+
pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
1853+
self.webview.delete_cookie(cookie)
1854+
}
1855+
18381856
/// Open the web inspector which is usually called dev tool.
18391857
///
18401858
/// ## Platform-specific

src/webkitgtk/mod.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,41 @@ impl InnerWebView {
899899
cookie_builder.build()
900900
}
901901

902+
fn cookie_into_soup_cookie(cookie: &cookie::Cookie<'_>) -> soup::Cookie {
903+
let mut soup_cookie = soup::Cookie::new(
904+
cookie.name(),
905+
cookie.value(),
906+
cookie.domain().unwrap_or(""),
907+
cookie.path().unwrap_or(""),
908+
cookie
909+
.max_age()
910+
.map(|d| d.whole_seconds() as i32)
911+
.unwrap_or(-1),
912+
);
913+
914+
if let Some(dt) = cookie.expires_datetime() {
915+
soup_cookie.set_expires(&glib::DateTime::from_unix_utc(dt.unix_timestamp()).unwrap());
916+
}
917+
918+
if let Some(http_only) = cookie.http_only() {
919+
soup_cookie.set_http_only(http_only);
920+
}
921+
922+
if let Some(same_site) = cookie.same_site() {
923+
soup_cookie.set_same_site_policy(match same_site {
924+
cookie::SameSite::Lax => soup::SameSitePolicy::Lax,
925+
cookie::SameSite::Strict => soup::SameSitePolicy::Strict,
926+
cookie::SameSite::None => soup::SameSitePolicy::None,
927+
});
928+
}
929+
930+
if let Some(secure) = cookie.secure() {
931+
soup_cookie.set_secure(secure);
932+
}
933+
934+
soup_cookie
935+
}
936+
902937
pub fn cookies_for_url(&self, url: &str) -> Result<Vec<cookie::Cookie<'static>>> {
903938
let (tx, rx) = std::sync::mpsc::channel();
904939
self
@@ -953,6 +988,50 @@ impl InnerWebView {
953988
}
954989
}
955990

991+
pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
992+
let (tx, rx) = std::sync::mpsc::channel();
993+
self
994+
.webview
995+
.website_data_manager()
996+
.and_then(|manager| manager.cookie_manager())
997+
.map(|cookies_manager| {
998+
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
999+
cookies_manager.add_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
1000+
let _ = tx.send(ret);
1001+
});
1002+
});
1003+
1004+
loop {
1005+
gtk::main_iteration();
1006+
1007+
if let Ok(response) = rx.try_recv() {
1008+
return response.map_err(Into::into);
1009+
}
1010+
}
1011+
}
1012+
1013+
pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
1014+
let (tx, rx) = std::sync::mpsc::channel();
1015+
self
1016+
.webview
1017+
.website_data_manager()
1018+
.and_then(|manager| manager.cookie_manager())
1019+
.map(|cookies_manager| {
1020+
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
1021+
cookies_manager.delete_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
1022+
let _ = tx.send(ret);
1023+
});
1024+
});
1025+
1026+
loop {
1027+
gtk::main_iteration();
1028+
1029+
if let Ok(response) = rx.try_recv() {
1030+
return response.map_err(Into::into);
1031+
}
1032+
}
1033+
}
1034+
9561035
pub fn reparent<W>(&self, container: &W) -> Result<()>
9571036
where
9581037
W: gtk::prelude::IsA<gtk::Container>,

src/webview2/mod.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,57 @@ impl InnerWebView {
14691469
Ok(cookie_builder.build())
14701470
}
14711471

1472+
unsafe fn cookie_into_win32(
1473+
cookie_manager: &ICoreWebView2CookieManager,
1474+
cookie: &cookie::Cookie<'_>,
1475+
) -> windows::core::Result<ICoreWebView2Cookie> {
1476+
let name = HSTRING::from(cookie.name());
1477+
let value = HSTRING::from(cookie.value());
1478+
let domain = match cookie.domain() {
1479+
Some(domain) => HSTRING::from(domain),
1480+
None => HSTRING::new(),
1481+
};
1482+
let path = match cookie.path() {
1483+
Some(path) => HSTRING::from(path),
1484+
None => HSTRING::new(),
1485+
};
1486+
1487+
let win32_cookie = cookie_manager.CreateCookie(&name, &value, &domain, &path)?;
1488+
1489+
let expires = if let Some(max_age) = cookie.max_age() {
1490+
let expires_ = cookie::time::OffsetDateTime::now_utc()
1491+
.saturating_add(max_age)
1492+
.unix_timestamp();
1493+
Some(expires_)
1494+
} else if let Some(dt) = cookie.expires_datetime() {
1495+
Some(dt.unix_timestamp())
1496+
} else {
1497+
None
1498+
};
1499+
if let Some(expires) = expires {
1500+
win32_cookie.SetExpires(expires as f64)?;
1501+
}
1502+
1503+
if let Some(http_only) = cookie.http_only() {
1504+
win32_cookie.SetIsHttpOnly(http_only)?;
1505+
}
1506+
1507+
if let Some(same_site) = cookie.same_site() {
1508+
let same_site = match same_site {
1509+
cookie::SameSite::Lax => COREWEBVIEW2_COOKIE_SAME_SITE_KIND_LAX,
1510+
cookie::SameSite::Strict => COREWEBVIEW2_COOKIE_SAME_SITE_KIND_STRICT,
1511+
cookie::SameSite::None => COREWEBVIEW2_COOKIE_SAME_SITE_KIND_NONE,
1512+
};
1513+
win32_cookie.SetSameSite(same_site)?;
1514+
}
1515+
1516+
if let Some(secure) = cookie.secure() {
1517+
win32_cookie.SetIsSecure(secure)?;
1518+
}
1519+
1520+
Ok(win32_cookie)
1521+
}
1522+
14721523
pub fn cookies_for_url(&self, url: &str) -> Result<Vec<cookie::Cookie<'static>>> {
14731524
let uri = HSTRING::from(url);
14741525
self.cookies_inner(PCWSTR::from_raw(uri.as_ptr()))
@@ -1519,6 +1570,26 @@ impl InnerWebView {
15191570
webview2_com::wait_with_pump(rx).map_err(Into::into)
15201571
}
15211572

1573+
pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
1574+
let webview = self.webview.cast::<ICoreWebView2_2>()?;
1575+
unsafe {
1576+
let cookie_manager = webview.CookieManager()?;
1577+
let cookie = Self::cookie_into_win32(&cookie_manager, cookie)?;
1578+
cookie_manager.AddOrUpdateCookie(&cookie)?;
1579+
}
1580+
Ok(())
1581+
}
1582+
1583+
pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
1584+
let webview = self.webview.cast::<ICoreWebView2_2>()?;
1585+
unsafe {
1586+
let cookie_manager = webview.CookieManager()?;
1587+
let cookie = Self::cookie_into_win32(&cookie_manager, cookie)?;
1588+
cookie_manager.DeleteCookie(&cookie)?;
1589+
}
1590+
Ok(())
1591+
}
1592+
15221593
pub fn reparent(&self, parent: isize) -> Result<()> {
15231594
let parent = HWND(parent as _);
15241595

0 commit comments

Comments
 (0)