pub(crate) mod xml; pub mod base64; pub mod checksum; pub mod crypto; pub mod endpoint; pub mod env_file; pub mod lock_file; pub mod openssl; pub mod redact; pub mod request; #[cfg(feature = "tauri")] pub mod window; mod shutdown_signal; use log::warn; pub use shutdown_signal::shutdown_signal; use reqwest::{Response, StatusCode, Url}; use thiserror::Error; /// Normalize the server URL to the format `https://:` pub fn normalize_server(server: &str) -> anyhow::Result { let server = if server.starts_with("https://") || server.starts_with("http://") { server.to_string() } else { format!("https://{}", server) }; let normalized_url = Url::parse(&server)?; let scheme = normalized_url.scheme(); let host = normalized_url .host_str() .ok_or(anyhow::anyhow!("Invalid server URL: missing host"))?; let port: String = normalized_url.port().map_or("".into(), |port| format!(":{}", port)); let normalized_url = format!("{}://{}{}", scheme, host, port); Ok(normalized_url) } pub fn remove_url_scheme(s: &str) -> String { s.replace("http://", "").replace("https://", "") } #[derive(Error, Debug)] #[error("GP response error: reason={reason}, status={status}, body={body}")] pub(crate) struct GpError { pub status: StatusCode, pub reason: String, body: String, } impl GpError { pub fn is_status_error(&self) -> bool { self.status.is_client_error() || self.status.is_server_error() } } pub(crate) async fn parse_gp_response(res: Response) -> anyhow::Result { let status = res.status(); if status.is_client_error() || status.is_server_error() { let (reason, body) = parse_gp_error(res).await; return Err(GpError { status, reason, body }); } res.text().await.map_err(|err| { warn!("Failed to read response: {}", err); GpError { status, reason: "failed to read response".to_string(), body: "".to_string(), } }) } async fn parse_gp_error(res: Response) -> (String, String) { let reason = res .headers() .get("x-private-pan-globalprotect") .map_or_else(|| "", |v| v.to_str().unwrap_or("")) .to_string(); let res = res.text().await.map_or_else( |_| "".to_string(), |v| if v.is_empty() { "".to_string() } else { v }, ); (reason, res) }