-
Notifications
You must be signed in to change notification settings - Fork 431
feat(http): persist cookies on disk #1978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
7ef9a00
24f1e76
e4eed02
514afdb
8f5b6ca
f2fcf2b
10ce353
dbf5695
5881ee3
39bc197
ea860c4
356b7ec
c74db78
b3cec50
e76347b
be11ca8
3d8ce8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"http": "patch" | ||
"http-js": "patch" | ||
--- | ||
|
||
Persist cookies to disk and load it on next app start. | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,25 +14,68 @@ pub use error::{Error, Result}; | |
|
||
mod commands; | ||
mod error; | ||
#[cfg(feature = "cookies")] | ||
mod reqwest_cookie_store; | ||
mod scope; | ||
|
||
pub(crate) struct Http { | ||
#[cfg(feature = "cookies")] | ||
cookies_jar: std::sync::Arc<reqwest::cookie::Jar>, | ||
cookies_jar_path: std::path::PathBuf, | ||
#[cfg(feature = "cookies")] | ||
cookies_jar: std::sync::Arc<crate::reqwest_cookie_store::CookieStoreMutex>, | ||
} | ||
|
||
pub fn init<R: Runtime>() -> TauriPlugin<R> { | ||
Builder::<R>::new("http") | ||
.setup(|app, _| { | ||
#[cfg(feature = "cookies")] | ||
let (cookies_jar_path, cookies_jar) = { | ||
use crate::reqwest_cookie_store::*; | ||
use std::fs::File; | ||
use std::io::BufReader; | ||
use std::sync::Arc; | ||
|
||
let cache_dir = app.path().app_cache_dir()?; | ||
std::fs::create_dir_all(&cache_dir)?; | ||
|
||
let path = cache_dir.join("Cookies"); | ||
|
||
let file = File::options() | ||
.create(true) | ||
.append(true) | ||
.read(true) | ||
.open(&path)?; | ||
|
||
let reader = BufReader::new(file); | ||
let store = CookieStoreMutex::load(reader).map_err(|e| e.to_string())?; | ||
|
||
(path, Arc::new(store)) | ||
}; | ||
|
||
let state = Http { | ||
#[cfg(feature = "cookies")] | ||
cookies_jar: std::sync::Arc::new(reqwest::cookie::Jar::default()), | ||
cookies_jar_path, | ||
#[cfg(feature = "cookies")] | ||
cookies_jar, | ||
}; | ||
|
||
app.manage(state); | ||
|
||
Ok(()) | ||
}) | ||
.on_event(|app, event| { | ||
#[cfg(feature = "cookies")] | ||
if let tauri::RunEvent::Exit = event { | ||
use std::fs::File; | ||
use std::io::BufWriter; | ||
|
||
let state = app.state::<Http>(); | ||
|
||
if let Ok(file) = File::create(&state.cookies_jar_path) { | ||
let mut writer = BufWriter::new(file); | ||
let _ = state.cookies_jar.save(&mut writer); | ||
} | ||
} | ||
}) | ||
.invoke_handler(tauri::generate_handler![ | ||
commands::fetch, | ||
commands::fetch_cancel, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// taken from https://github.com/pfernie/reqwest_cookie_store/blob/2ec4afabcd55e24d3afe3f0626ee6dc97bed938d/src/lib.rs | ||
amrbashir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
use std::sync::{Mutex, MutexGuard, PoisonError}; | ||
|
||
use cookie_store::{CookieStore, RawCookie, RawCookieParseError}; | ||
use reqwest::header::HeaderValue; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
fn set_cookies( | ||
cookie_store: &mut CookieStore, | ||
cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, | ||
url: &url::Url, | ||
) { | ||
let cookies = cookie_headers.filter_map(|val| { | ||
std::str::from_utf8(val.as_bytes()) | ||
.map_err(RawCookieParseError::from) | ||
.and_then(RawCookie::parse) | ||
.map(|c| c.into_owned()) | ||
.ok() | ||
}); | ||
cookie_store.store_response_cookies(cookies, url); | ||
} | ||
|
||
fn cookies(cookie_store: &CookieStore, url: &url::Url) -> Option<HeaderValue> { | ||
let s = cookie_store | ||
.get_request_values(url) | ||
.map(|(name, value)| format!("{}={}", name, value)) | ||
.collect::<Vec<_>>() | ||
.join("; "); | ||
|
||
if s.is_empty() { | ||
return None; | ||
} | ||
|
||
HeaderValue::from_maybe_shared(bytes::Bytes::from(s)).ok() | ||
} | ||
|
||
/// A [`cookie_store::CookieStore`] wrapped internally by a [`std::sync::Mutex`], suitable for use in | ||
/// async/concurrent contexts. | ||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct CookieStoreMutex(Mutex<CookieStore>); | ||
|
||
impl Default for CookieStoreMutex { | ||
/// Create a new, empty [`CookieStoreMutex`] | ||
fn default() -> Self { | ||
CookieStoreMutex::new(CookieStore::default()) | ||
} | ||
} | ||
|
||
impl CookieStoreMutex { | ||
/// Create a new [`CookieStoreMutex`] from an existing [`cookie_store::CookieStore`]. | ||
pub const fn new(cookie_store: CookieStore) -> CookieStoreMutex { | ||
CookieStoreMutex(Mutex::new(cookie_store)) | ||
} | ||
|
||
/// Lock and get a handle to the contained [`cookie_store::CookieStore`]. | ||
pub fn lock( | ||
&self, | ||
) -> Result<MutexGuard<'_, CookieStore>, PoisonError<MutexGuard<'_, CookieStore>>> { | ||
self.0.lock() | ||
} | ||
|
||
pub fn load<R: std::io::BufRead>(reader: R) -> cookie_store::Result<CookieStoreMutex> { | ||
cookie_store::serde::load(reader, |c| serde_json::from_str(c)).map(CookieStoreMutex::new) | ||
} | ||
|
||
pub fn save<W: std::io::Write>(&self, writer: &mut W) -> cookie_store::Result<()> { | ||
let store = self.lock().expect("poisoned cookie jar mutex"); | ||
cookie_store::serde::save(&store, writer, serde_json::to_string) | ||
} | ||
} | ||
|
||
impl reqwest::cookie::CookieStore for CookieStoreMutex { | ||
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, url: &url::Url) { | ||
let mut store = self.0.lock().unwrap(); | ||
set_cookies(&mut store, cookie_headers, url); | ||
} | ||
|
||
fn cookies(&self, url: &url::Url) -> Option<HeaderValue> { | ||
let store = self.0.lock().unwrap(); | ||
cookies(&store, url) | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.