Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/cookies-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": "patch"
---

Add `WebView::set_cookie` and `WebView::delete_cookie` APIs.
73 changes: 73 additions & 0 deletions examples/cookies.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use tao::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use wry::WebViewBuilder;

fn main() -> wry::Result<()> {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();

let builder = WebViewBuilder::new().with_url("https://www.httpbin.org/cookies/set?foo=bar");

#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
))]
let webview = builder.build(&window)?;
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
)))]
let webview = {
use tao::platform::unix::WindowExtUnix;
use wry::WebViewBuilderExtUnix;
let vbox = window.default_vbox().unwrap();
builder.build_gtk(vbox)?
};

webview.set_cookie(
cookie::Cookie::build(("foo1", "bar1"))
.domain("www.httpbin.org")
.path("/")
.secure(true)
.http_only(true)
.max_age(cookie::time::Duration::seconds(10))
.inner(),
)?;

let cookie_deleted = cookie::Cookie::build(("will_be_deleted", "will_be_deleted"));

webview.set_cookie(cookie_deleted.inner())?;
println!("Setting Cookies:");
for cookie in webview.cookies()? {
println!("\t{cookie}");
}

println!("After Deleting:");
webview.delete_cookie(cookie_deleted.inner())?;
for cookie in webview.cookies()? {
println!("\t{cookie}");
}

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

if let Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} = event
{
*control_flow = ControlFlow::Exit;
}
});
}
10 changes: 10 additions & 0 deletions src/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,16 @@ impl InnerWebView {
rx.recv_timeout(MAIN_PIPE_TIMEOUT).map_err(Into::into)
}

pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
// Unsupported
Ok(())
}

pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
// Unsupported
Ok(())
}

pub fn cookies(&self) -> Result<Vec<cookie::Cookie<'static>>> {
Ok(Vec::new())
}
Expand Down
18 changes: 18 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1835,6 +1835,24 @@ impl WebView {
self.webview.cookies()
}

/// Set a cookie for the webview.
///
/// ## Platform-specific
///
/// - **Android**: Not supported.
pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
self.webview.set_cookie(cookie)
}

/// Delete a cookie for the webview.
///
/// ## Platform-specific
///
/// - **Android**: Not supported.
pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
self.webview.delete_cookie(cookie)
}

/// Open the web inspector which is usually called dev tool.
///
/// ## Platform-specific
Expand Down
79 changes: 79 additions & 0 deletions src/webkitgtk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,41 @@ impl InnerWebView {
cookie_builder.build()
}

fn cookie_into_soup_cookie(cookie: &cookie::Cookie<'_>) -> soup::Cookie {
let mut soup_cookie = soup::Cookie::new(
cookie.name(),
cookie.value(),
cookie.domain().unwrap_or(""),
cookie.path().unwrap_or(""),
cookie
.max_age()
.map(|d| d.whole_seconds() as i32)
.unwrap_or(-1),
);

if let Some(dt) = cookie.expires_datetime() {
soup_cookie.set_expires(&glib::DateTime::from_unix_utc(dt.unix_timestamp()).unwrap());
}

if let Some(http_only) = cookie.http_only() {
soup_cookie.set_http_only(http_only);
}

if let Some(same_site) = cookie.same_site() {
soup_cookie.set_same_site_policy(match same_site {
cookie::SameSite::Lax => soup::SameSitePolicy::Lax,
cookie::SameSite::Strict => soup::SameSitePolicy::Strict,
cookie::SameSite::None => soup::SameSitePolicy::None,
});
}

if let Some(secure) = cookie.secure() {
soup_cookie.set_secure(secure);
}

soup_cookie
}

pub fn cookies_for_url(&self, url: &str) -> Result<Vec<cookie::Cookie<'static>>> {
let (tx, rx) = std::sync::mpsc::channel();
self
Expand Down Expand Up @@ -953,6 +988,50 @@ impl InnerWebView {
}
}

pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
let (tx, rx) = std::sync::mpsc::channel();
self
.webview
.website_data_manager()
.and_then(|manager| manager.cookie_manager())
.map(|cookies_manager| {
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
cookies_manager.add_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
let _ = tx.send(ret);
});
});

loop {
gtk::main_iteration();

if let Ok(response) = rx.try_recv() {
return response.map_err(Into::into);
}
}
}

pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
let (tx, rx) = std::sync::mpsc::channel();
self
.webview
.website_data_manager()
.and_then(|manager| manager.cookie_manager())
.map(|cookies_manager| {
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
cookies_manager.delete_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
let _ = tx.send(ret);
});
});

loop {
gtk::main_iteration();

if let Ok(response) = rx.try_recv() {
return response.map_err(Into::into);
}
}
}

pub fn reparent<W>(&self, container: &W) -> Result<()>
where
W: gtk::prelude::IsA<gtk::Container>,
Expand Down
71 changes: 71 additions & 0 deletions src/webview2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,57 @@ impl InnerWebView {
Ok(cookie_builder.build())
}

unsafe fn cookie_into_win32(
cookie_manager: &ICoreWebView2CookieManager,
cookie: &cookie::Cookie<'_>,
) -> windows::core::Result<ICoreWebView2Cookie> {
let name = HSTRING::from(cookie.name());
let value = HSTRING::from(cookie.value());
let domain = match cookie.domain() {
Some(domain) => HSTRING::from(domain),
None => HSTRING::new(),
};
let path = match cookie.path() {
Some(path) => HSTRING::from(path),
None => HSTRING::new(),
};

let win32_cookie = cookie_manager.CreateCookie(&name, &value, &domain, &path)?;

let expires = if let Some(max_age) = cookie.max_age() {
let expires_ = cookie::time::OffsetDateTime::now_utc()
.saturating_add(max_age)
.unix_timestamp();
Some(expires_)
} else if let Some(dt) = cookie.expires_datetime() {
Some(dt.unix_timestamp())
} else {
None
};
if let Some(expires) = expires {
win32_cookie.SetExpires(expires as f64)?;
}

if let Some(http_only) = cookie.http_only() {
win32_cookie.SetIsHttpOnly(http_only)?;
}

if let Some(same_site) = cookie.same_site() {
let same_site = match same_site {
cookie::SameSite::Lax => COREWEBVIEW2_COOKIE_SAME_SITE_KIND_LAX,
cookie::SameSite::Strict => COREWEBVIEW2_COOKIE_SAME_SITE_KIND_STRICT,
cookie::SameSite::None => COREWEBVIEW2_COOKIE_SAME_SITE_KIND_NONE,
};
win32_cookie.SetSameSite(same_site)?;
}

if let Some(secure) = cookie.secure() {
win32_cookie.SetIsSecure(secure)?;
}

Ok(win32_cookie)
}

pub fn cookies_for_url(&self, url: &str) -> Result<Vec<cookie::Cookie<'static>>> {
let uri = HSTRING::from(url);
self.cookies_inner(PCWSTR::from_raw(uri.as_ptr()))
Expand Down Expand Up @@ -1519,6 +1570,26 @@ impl InnerWebView {
webview2_com::wait_with_pump(rx).map_err(Into::into)
}

pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
let webview = self.webview.cast::<ICoreWebView2_2>()?;
unsafe {
let cookie_manager = webview.CookieManager()?;
let cookie = Self::cookie_into_win32(&cookie_manager, cookie)?;
cookie_manager.AddOrUpdateCookie(&cookie)?;
}
Ok(())
}

pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
let webview = self.webview.cast::<ICoreWebView2_2>()?;
unsafe {
let cookie_manager = webview.CookieManager()?;
let cookie = Self::cookie_into_win32(&cookie_manager, cookie)?;
cookie_manager.DeleteCookie(&cookie)?;
}
Ok(())
}

pub fn reparent(&self, parent: isize) -> Result<()> {
let parent = HWND(parent as _);

Expand Down
Loading
Loading