mirror of
https://github.com/YGGverse/ggemini.git
synced 2026-03-31 17:15:31 +00:00
implement session update on certificate change in runtime
This commit is contained in:
parent
f4cb0c3bcc
commit
c4c173f6cf
3 changed files with 113 additions and 36 deletions
120
src/client.rs
120
src/client.rs
|
|
@ -4,13 +4,17 @@
|
||||||
pub mod connection;
|
pub mod connection;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
|
pub mod session;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub use connection::Connection;
|
pub use connection::Connection;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use response::Response;
|
pub use response::Response;
|
||||||
|
pub use session::Session;
|
||||||
|
|
||||||
use gio::{
|
use gio::{
|
||||||
prelude::{IOStreamExt, OutputStreamExt, SocketClientExt, TlsConnectionExt},
|
prelude::{IOStreamExt, OutputStreamExt, SocketClientExt, TlsCertificateExt, TlsConnectionExt},
|
||||||
Cancellable, SocketClient, SocketClientEvent, SocketProtocol, TlsCertificate,
|
Cancellable, SocketClient, SocketClientEvent, SocketProtocol, TlsCertificate,
|
||||||
TlsClientConnection,
|
TlsClientConnection,
|
||||||
};
|
};
|
||||||
|
|
@ -19,6 +23,7 @@ use glib::{object::Cast, Bytes, Priority, Uri};
|
||||||
pub const DEFAULT_TIMEOUT: u32 = 10;
|
pub const DEFAULT_TIMEOUT: u32 = 10;
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
|
session: Rc<Session>,
|
||||||
pub socket: SocketClient,
|
pub socket: SocketClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,15 +54,18 @@ impl Client {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
Self { socket }
|
Self {
|
||||||
|
session: Rc::new(Session::new()),
|
||||||
|
socket,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
|
||||||
/// Make async request to given [Uri](https://docs.gtk.org/glib/struct.Uri.html),
|
/// Make new async request to given [Uri](https://docs.gtk.org/glib/struct.Uri.html),
|
||||||
/// callback with new `Response`on success or `Error` on failure.
|
/// callback with new `Response`on success or `Error` on failure.
|
||||||
/// * creates new [SocketConnection](https://docs.gtk.org/gio/class.SocketConnection.html)
|
/// * call this method ignore default session resumption by Glib TLS backend,
|
||||||
/// * session management by Glib TLS Backend
|
/// implement certificate change ability in application runtime
|
||||||
pub fn request_async(
|
pub fn request_async(
|
||||||
&self,
|
&self,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
|
|
@ -70,51 +78,95 @@ impl Client {
|
||||||
// * guest sessions will not work without!
|
// * guest sessions will not work without!
|
||||||
self.socket.set_tls(certificate.is_none());
|
self.socket.set_tls(certificate.is_none());
|
||||||
|
|
||||||
match crate::gio::network_address::from_uri(&uri, crate::DEFAULT_PORT) {
|
// Update previous session available for this request
|
||||||
Ok(network_address) => {
|
match self.update_session(&uri, certificate.as_ref()) {
|
||||||
self.socket.connect_async(
|
Ok(()) => match crate::gio::network_address::from_uri(&uri, crate::DEFAULT_PORT) {
|
||||||
|
Ok(network_address) => self.socket.connect_async(
|
||||||
&network_address.clone(),
|
&network_address.clone(),
|
||||||
match cancellable {
|
match cancellable {
|
||||||
Some(ref cancellable) => Some(cancellable.clone()),
|
Some(ref cancellable) => Some(cancellable.clone()),
|
||||||
None => None::<Cancellable>,
|
None => None::<Cancellable>,
|
||||||
}
|
}
|
||||||
.as_ref(),
|
.as_ref(),
|
||||||
move |result| match result {
|
{
|
||||||
Ok(connection) => {
|
let session = self.session.clone();
|
||||||
match Connection::new_wrap(
|
move |result| match result {
|
||||||
connection,
|
Ok(connection) => {
|
||||||
certificate,
|
match Connection::new_wrap(
|
||||||
Some(network_address),
|
connection,
|
||||||
) {
|
certificate,
|
||||||
Ok(result) => request_async(
|
Some(network_address),
|
||||||
result,
|
) {
|
||||||
uri.to_string(),
|
Ok(connection) => {
|
||||||
match priority {
|
// Wrap connection to shared reference clone semantics
|
||||||
Some(priority) => Some(priority),
|
let connection = Rc::new(connection);
|
||||||
None => Some(Priority::DEFAULT),
|
|
||||||
},
|
// Update session record
|
||||||
match cancellable {
|
session.update(uri.to_string(), connection.clone());
|
||||||
Some(ref cancellable) => Some(cancellable.clone()),
|
|
||||||
None => None::<Cancellable>,
|
// Begin new request
|
||||||
},
|
request_async(
|
||||||
move |result| callback(result),
|
connection,
|
||||||
),
|
uri.to_string(),
|
||||||
Err(reason) => callback(Err(Error::Connection(reason))),
|
match priority {
|
||||||
|
Some(priority) => Some(priority),
|
||||||
|
None => Some(Priority::DEFAULT),
|
||||||
|
},
|
||||||
|
match cancellable {
|
||||||
|
Some(ref cancellable) => Some(cancellable.clone()),
|
||||||
|
None => None::<Cancellable>,
|
||||||
|
},
|
||||||
|
move |result| callback(result),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Err(reason) => callback(Err(Error::Connection(reason))),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Err(reason) => callback(Err(Error::Connect(reason))),
|
||||||
}
|
}
|
||||||
Err(reason) => callback(Err(Error::Connect(reason))),
|
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
|
Err(reason) => callback(Err(Error::NetworkAddress(reason))),
|
||||||
|
},
|
||||||
|
Err(reason) => callback(Err(reason)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update existing session for given request
|
||||||
|
pub fn update_session(
|
||||||
|
&self,
|
||||||
|
uri: &Uri,
|
||||||
|
certificate: Option<&TlsCertificate>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if let Some(connection) = self.session.get(&uri.to_string()) {
|
||||||
|
// Check connection contain TLS authorization
|
||||||
|
if let Some(ref tls_client_connection) = connection.tls_client_connection {
|
||||||
|
if let Some(new) = certificate {
|
||||||
|
// Get previous certificate
|
||||||
|
if let Some(ref old) = tls_client_connection.certificate() {
|
||||||
|
if !new.is_same(old) {
|
||||||
|
// Prevent session resumption
|
||||||
|
// Glib backend restore session in runtime with old certificate
|
||||||
|
// @TODO keep in mind, until better solution found for TLS 1.3
|
||||||
|
println!("{:?}", tls_client_connection.handshake(Cancellable::NONE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(reason) => callback(Err(Error::NetworkAddress(reason))),
|
|
||||||
};
|
// Close connection if active yet
|
||||||
|
if let Err(reason) = connection.close(Cancellable::NONE) {
|
||||||
|
return Err(Error::Connection(reason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make new request for constructed `Connection`
|
/// Make new request for constructed `Connection`
|
||||||
/// * callback with new `Response`on success or `Error` on failure
|
/// * callback with new `Response`on success or `Error` on failure
|
||||||
pub fn request_async(
|
pub fn request_async(
|
||||||
connection: Connection,
|
connection: Rc<Connection>,
|
||||||
query: String,
|
query: String,
|
||||||
priority: Option<Priority>,
|
priority: Option<Priority>,
|
||||||
cancellable: Option<Cancellable>,
|
cancellable: Option<Cancellable>,
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,10 @@ pub use meta::Meta;
|
||||||
use super::Connection;
|
use super::Connection;
|
||||||
use gio::Cancellable;
|
use gio::Cancellable;
|
||||||
use glib::Priority;
|
use glib::Priority;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
pub connection: Connection,
|
pub connection: Rc<Connection>,
|
||||||
pub meta: Meta,
|
pub meta: Meta,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,7 +21,7 @@ impl Response {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
pub fn from_request_async(
|
pub fn from_request_async(
|
||||||
connection: Connection,
|
connection: Rc<Connection>,
|
||||||
priority: Option<Priority>,
|
priority: Option<Priority>,
|
||||||
cancellable: Option<Cancellable>,
|
cancellable: Option<Cancellable>,
|
||||||
callback: impl FnOnce(Result<Self, Error>) + 'static,
|
callback: impl FnOnce(Result<Self, Error>) + 'static,
|
||||||
|
|
|
||||||
24
src/client/session.rs
Normal file
24
src/client/session.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
use super::Connection;
|
||||||
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
|
/// Request sessions holder for `Client` object
|
||||||
|
/// * useful to keep connections open and / or validate TLS certificate updates in runtime
|
||||||
|
pub struct Session {
|
||||||
|
index: RefCell<HashMap<String, Rc<Connection>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Session {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
index: RefCell::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, request: &str) -> Option<Rc<Connection>> {
|
||||||
|
self.index.borrow().get(request).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&self, request: String, connection: Rc<Connection>) -> Option<Rc<Connection>> {
|
||||||
|
self.index.borrow_mut().insert(request, connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue