Files
GlobalProtect-openconnect/crates/gpapi/src/utils/mod.rs

96 lines
2.3 KiB
Rust

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://<host>:<port>`
pub fn normalize_server(server: &str) -> anyhow::Result<String> {
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<String, GpError> {
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: "<failed to read response>".to_string(),
}
})
}
async fn parse_gp_error(res: Response) -> (String, String) {
let reason = res
.headers()
.get("x-private-pan-globalprotect")
.map_or_else(|| "<none>", |v| v.to_str().unwrap_or("<invalid header>"))
.to_string();
let res = res.text().await.map_or_else(
|_| "<failed to read response>".to_string(),
|v| if v.is_empty() { "<empty>".to_string() } else { v },
);
(reason, res)
}