mirror of
https://github.com/element-hq/synapse
synced 2024-10-01 02:52:40 +00:00
92 lines
2.8 KiB
Rust
92 lines
2.8 KiB
Rust
|
/*
|
||
|
* This file is licensed under the Affero General Public License (AGPL) version 3.
|
||
|
*
|
||
|
* Copyright (C) 2024 New Vector, Ltd
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Affero General Public License as
|
||
|
* published by the Free Software Foundation, either version 3 of the
|
||
|
* License, or (at your option) any later version.
|
||
|
*
|
||
|
* See the GNU Affero General Public License for more details:
|
||
|
* <https://www.gnu.org/licenses/agpl-3.0.html>.
|
||
|
*/
|
||
|
|
||
|
use std::time::{Duration, SystemTime};
|
||
|
|
||
|
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
|
||
|
use bytes::Bytes;
|
||
|
use headers::{ContentLength, ContentType, ETag, Expires, LastModified};
|
||
|
use mime::Mime;
|
||
|
use sha2::{Digest, Sha256};
|
||
|
|
||
|
/// A single session, containing data, metadata, and expiry information.
|
||
|
pub struct Session {
|
||
|
hash: [u8; 32],
|
||
|
data: Bytes,
|
||
|
content_type: Mime,
|
||
|
last_modified: SystemTime,
|
||
|
expires: SystemTime,
|
||
|
}
|
||
|
|
||
|
impl Session {
|
||
|
/// Create a new session with the given data, content type, and time-to-live.
|
||
|
pub fn new(data: Bytes, content_type: Mime, now: SystemTime, ttl: Duration) -> Self {
|
||
|
let hash = Sha256::digest(&data).into();
|
||
|
Self {
|
||
|
hash,
|
||
|
data,
|
||
|
content_type,
|
||
|
expires: now + ttl,
|
||
|
last_modified: now,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Returns true if the session has expired at the given time.
|
||
|
pub fn expired(&self, now: SystemTime) -> bool {
|
||
|
self.expires <= now
|
||
|
}
|
||
|
|
||
|
/// Update the session with new data, content type, and last modified time.
|
||
|
pub fn update(&mut self, data: Bytes, content_type: Mime, now: SystemTime) {
|
||
|
self.hash = Sha256::digest(&data).into();
|
||
|
self.data = data;
|
||
|
self.content_type = content_type;
|
||
|
self.last_modified = now;
|
||
|
}
|
||
|
|
||
|
/// Returns the Content-Type header of the session.
|
||
|
pub fn content_type(&self) -> ContentType {
|
||
|
self.content_type.clone().into()
|
||
|
}
|
||
|
|
||
|
/// Returns the Content-Length header of the session.
|
||
|
pub fn content_length(&self) -> ContentLength {
|
||
|
ContentLength(self.data.len() as _)
|
||
|
}
|
||
|
|
||
|
/// Returns the ETag header of the session.
|
||
|
pub fn etag(&self) -> ETag {
|
||
|
let encoded = URL_SAFE_NO_PAD.encode(self.hash);
|
||
|
// SAFETY: Base64 encoding is URL-safe, so ETag-safe
|
||
|
format!("\"{encoded}\"")
|
||
|
.parse()
|
||
|
.expect("base64-encoded hash should be URL-safe")
|
||
|
}
|
||
|
|
||
|
/// Returns the Last-Modified header of the session.
|
||
|
pub fn last_modified(&self) -> LastModified {
|
||
|
self.last_modified.into()
|
||
|
}
|
||
|
|
||
|
/// Returns the Expires header of the session.
|
||
|
pub fn expires(&self) -> Expires {
|
||
|
self.expires.into()
|
||
|
}
|
||
|
|
||
|
/// Returns the current data stored in the session.
|
||
|
pub fn data(&self) -> Bytes {
|
||
|
self.data.clone()
|
||
|
}
|
||
|
}
|