mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-05-20 07:26:58 -04:00
96 lines
2.3 KiB
Rust
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)
|
|
}
|