///|
fn CookieCompletionStore::CookieCompletionStore() -> CookieCompletionStore {
{ pending: [], }
}
///|
fn CookieCompletionStore::register(
self : CookieCompletionStore,
request_id : Int64,
) -> PendingCookieCompletion {
let completion = PendingCookieCompletion::{
request_id,
state: CookieWaiting,
changed: @async.CondVar::Cond(),
}
self.pending.push(completion)
completion
}
///|
fn CookieCompletionStore::remove(
self : CookieCompletionStore,
request_id : Int64,
) -> Unit {
for index, completion in self.pending {
if completion.request_id == request_id {
ignore(self.pending.remove(index))
return
}
}
}
///|
fn CookieCompletionStore::route_completion(
self : CookieCompletionStore,
completion : @native.NativeCookieGetCompletion?,
) -> Bool {
guard completion is Some(completion) else { return false }
for pending in self.pending {
if pending.request_id == completion.request_id {
if pending.state is CookieWaiting {
pending.state = CookieCompleted(completion.result)
pending.changed.broadcast()
}
return true
}
}
true
}
///|
async fn CookieCompletionStore::wait(
self : CookieCompletionStore,
request_id : Int64,
) -> String raise WindowSessionError {
let completion = self.register(request_id)
defer self.remove(request_id)
while completion.state is CookieWaiting {
completion.changed.wait() catch {
_ => raise Cancelled
}
}
match completion.state {
CookieCompleted(Ok(payload)) => payload
CookieCompleted(Err(error)) =>
raise window_operation_failed("complete cookie read", error)
CookieWaiting => abort("cookie completion resumed without a result")
}
}
///|
fn CookieSameSite::to_native(self : CookieSameSite) -> @native.CookieSameSite {
match self {
Unspecified => @native.CookieSameSite::Unspecified
NoRestriction => @native.CookieSameSite::NoRestriction
Lax => @native.CookieSameSite::Lax
Strict => @native.CookieSameSite::Strict
}
}
///|
fn cookie_same_site_from_native(
value : String,
) -> CookieSameSite raise CookieDecodeError {
match value {
"unspecified" => Unspecified
"no_restriction" => NoRestriction
"lax" => Lax
"strict" => Strict
other => raise CookieDecodeError("unknown cookie SameSite value: " + other)
}
}
///|
fn cookie_expiration_date(record : NativeCookieRecord) -> Double? {
if !record.has_expires {
None
} else {
match record.expires {
Some(expires) =>
// CEF stores base time as microseconds since the Windows epoch.
Some((expires - 11644473600000000.0) / 1000000.0)
None => None
}
}
}
///|
fn decode_cookies(payload : String) -> Array[Cookie] raise CookieDecodeError {
let json = @json.parse(payload) catch {
error =>
raise CookieDecodeError("invalid cookie JSON: " + error.to_string())
}
let records : Array[NativeCookieRecord] = @json.from_json(json) catch {
error =>
raise CookieDecodeError("invalid cookie payload: " + error.to_string())
}
records.map(record => {
ignore(record.creation)
ignore(record.last_access)
{
name: record.name,
value: record.value,
domain: record.domain,
path: record.path,
secure: record.secure,
http_only: record.http_only,
same_site: cookie_same_site_from_native(record.same_site),
expiration_date: cookie_expiration_date(record),
}
})
}
///|
/// Returns the window id whose request context owns this session.
pub fn SessionHandle::window_id(self : SessionHandle) -> String {
self.id
}
///|
/// Returns cookies visible to the session, optionally restricted to one URL.
pub async fn SessionHandle::get_cookies(
self : SessionHandle,
url? : String,
include_http_only? : Bool = false,
) -> Array[Cookie] raise WindowSessionError {
(self.read_cookies)(url, include_http_only)
}
///|
/// Sets a cookie in the session's cookie store.
pub fn SessionHandle::set_cookie(
self : SessionHandle,
url : String,
name : String,
value : String,
domain? : String,
path? : String,
secure? : Bool = false,
http_only? : Bool = false,
same_site? : CookieSameSite = Unspecified,
) -> Unit raise WindowSessionError {
(self.write_cookie)(
url, name, value, domain, path, secure, http_only, same_site,
)
}
///|
/// Deletes matching cookies. Omitting both filters deletes all cookies.
pub fn SessionHandle::delete_cookies(
self : SessionHandle,
url? : String,
name? : String,
) -> Unit raise WindowSessionError {
(self.remove_cookies)(url, name)
}
///|
/// Flushes pending cookie changes to disk.
pub fn SessionHandle::flush_cookies(
self : SessionHandle,
) -> Unit raise WindowSessionError {
(self.flush_cookie_store)()
}
///|
/// Clears the session's HTTP cache.
pub fn SessionHandle::clear_cache(
self : SessionHandle,
) -> Unit raise WindowSessionError {
(self.clear_http_cache)()
}