General Upgrade, NEW: WebServers, Better Docs
Some checks failed
CI / checks (push) Failing after 2m23s
Some checks failed
CI / checks (push) Failing after 2m23s
This commit is contained in:
parent
5f11d476b6
commit
3afc75b45d
120 changed files with 10032 additions and 4886 deletions
2
common/Cargo.lock
generated
2
common/Cargo.lock
generated
|
|
@ -4,7 +4,7 @@ version = 4
|
|||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
quinn = { version = "0.11.9", default-features = false, features = [
|
||||
"rustls-aws-lc-rs",
|
||||
"rustls",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "mtp-common"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ mod tests {
|
|||
* wrappers) is available. On WASM only the transport-independent subset is
|
||||
* compiled. */
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[derive(Debug, Error, Clone)]
|
||||
pub enum CommunicationError {
|
||||
#[error("Use after Closed")]
|
||||
|
|
@ -66,6 +65,7 @@ pub enum CommunicationError {
|
|||
ConnectionLost,
|
||||
|
||||
#[error("QUIC error: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Quinn(#[from] quinn::ConnectionError),
|
||||
|
||||
#[error("ParseCommunicationValue error")]
|
||||
|
|
@ -84,24 +84,29 @@ pub enum CommunicationError {
|
|||
ParseError(String),
|
||||
|
||||
#[error("Connection error: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
ConnectionError(#[from] wtransport::error::ConnectionError),
|
||||
|
||||
#[error("Connecting error: {0}")]
|
||||
ConnectingError(String),
|
||||
|
||||
#[error("ReadToEnd error: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
ReadToEndError(#[from] quinn::ReadToEndError),
|
||||
|
||||
#[error("Write error: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
WriteError(#[from] quinn::WriteError),
|
||||
|
||||
#[error("Closed error: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
ClosedError(#[from] quinn::ClosedStream),
|
||||
|
||||
#[error("Message too large")]
|
||||
MessageTooLarge,
|
||||
|
||||
#[error("ReadExactError: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
ReadExactError(#[from] quinn::ReadExactError),
|
||||
|
||||
#[error("Stream Closed")]
|
||||
|
|
@ -111,9 +116,11 @@ pub enum CommunicationError {
|
|||
StreamError,
|
||||
|
||||
#[error("Stream Error: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
StreamWriteError(#[from] wtransport::error::StreamWriteError),
|
||||
|
||||
#[error("Read Exact Error: {0}")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
StreamReadExactError(#[from] wtransport::error::StreamReadExactError),
|
||||
|
||||
#[error("Crypto Provider Install Error")]
|
||||
|
|
@ -126,61 +133,8 @@ pub enum CommunicationError {
|
|||
Other(String),
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[derive(Debug, Error, Clone)]
|
||||
pub enum CommunicationError {
|
||||
#[error("Use after Closed")]
|
||||
UseAfterClosed,
|
||||
|
||||
#[error("Connection closed by local shutdown")]
|
||||
ClosedLocally,
|
||||
|
||||
#[error("Connection closed by peer")]
|
||||
ClosedByPeer,
|
||||
|
||||
#[error("Connection terminated unexpectedly")]
|
||||
ConnectionLost,
|
||||
|
||||
#[error("ParseCommunicationValue error")]
|
||||
ParseCommunicationValue,
|
||||
|
||||
#[error("Encode error")]
|
||||
Encode,
|
||||
|
||||
#[error("Parse Certificate error")]
|
||||
CertificateParseFailed,
|
||||
|
||||
#[error("Loading Certificate error")]
|
||||
CertificateLoadFailed,
|
||||
|
||||
#[error("Parse error: {0}")]
|
||||
ParseError(String),
|
||||
|
||||
#[error("Connecting error: {0}")]
|
||||
ConnectingError(String),
|
||||
|
||||
#[error("Message too large")]
|
||||
MessageTooLarge,
|
||||
|
||||
#[error("Stream Closed")]
|
||||
StreamClosed,
|
||||
|
||||
#[error("Stream Error")]
|
||||
StreamError,
|
||||
|
||||
#[error("Crypto Provider Install Error")]
|
||||
CryptoProviderInstallFailed,
|
||||
|
||||
#[error("Authentication failed: {0}")]
|
||||
AuthenticationFailed(String),
|
||||
|
||||
#[error("Other: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
// ---- manual PartialEq (quinn / wtransport types don't impl PartialEq) ----
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl PartialEq for CommunicationError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
|
|
@ -188,22 +142,30 @@ impl PartialEq for CommunicationError {
|
|||
(Self::ClosedLocally, Self::ClosedLocally) => true,
|
||||
(Self::ClosedByPeer, Self::ClosedByPeer) => true,
|
||||
(Self::ConnectionLost, Self::ConnectionLost) => true,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::Quinn(_), Self::Quinn(_)) => true,
|
||||
(Self::ParseCommunicationValue, Self::ParseCommunicationValue) => true,
|
||||
(Self::Encode, Self::Encode) => true,
|
||||
(Self::CertificateParseFailed, Self::CertificateParseFailed) => true,
|
||||
(Self::CertificateLoadFailed, Self::CertificateLoadFailed) => true,
|
||||
(Self::ParseError(a), Self::ParseError(b)) => a == b,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::ConnectionError(_), Self::ConnectionError(_)) => true,
|
||||
(Self::ConnectingError(a), Self::ConnectingError(b)) => a == b,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::ReadToEndError(_), Self::ReadToEndError(_)) => true,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::WriteError(_), Self::WriteError(_)) => true,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::ClosedError(_), Self::ClosedError(_)) => true,
|
||||
(Self::MessageTooLarge, Self::MessageTooLarge) => true,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::ReadExactError(_), Self::ReadExactError(_)) => true,
|
||||
(Self::StreamClosed, Self::StreamClosed) => true,
|
||||
(Self::StreamError, Self::StreamError) => true,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::StreamWriteError(_), Self::StreamWriteError(_)) => true,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
(Self::StreamReadExactError(_), Self::StreamReadExactError(_)) => true,
|
||||
(Self::CryptoProviderInstallFailed, Self::CryptoProviderInstallFailed) => true,
|
||||
(Self::AuthenticationFailed(a), Self::AuthenticationFailed(b)) => a == b,
|
||||
|
|
@ -213,35 +175,6 @@ impl PartialEq for CommunicationError {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
impl PartialEq for CommunicationError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::UseAfterClosed, Self::UseAfterClosed) => true,
|
||||
(Self::ClosedLocally, Self::ClosedLocally) => true,
|
||||
(Self::ClosedByPeer, Self::ClosedByPeer) => true,
|
||||
(Self::ConnectionLost, Self::ConnectionLost) => true,
|
||||
(Self::ParseCommunicationValue, Self::ParseCommunicationValue) => true,
|
||||
(Self::Encode, Self::Encode) => true,
|
||||
(Self::CertificateParseFailed, Self::CertificateParseFailed) => true,
|
||||
(Self::CertificateLoadFailed, Self::CertificateLoadFailed) => true,
|
||||
(Self::ParseError(a), Self::ParseError(b)) => a == b,
|
||||
(Self::ConnectingError(a), Self::ConnectingError(b)) => a == b,
|
||||
(Self::MessageTooLarge, Self::MessageTooLarge) => true,
|
||||
(Self::StreamClosed, Self::StreamClosed) => true,
|
||||
(Self::StreamError, Self::StreamError) => true,
|
||||
(Self::CryptoProviderInstallFailed, Self::CryptoProviderInstallFailed) => true,
|
||||
(Self::AuthenticationFailed(a), Self::AuthenticationFailed(b)) => a == b,
|
||||
(Self::Other(a), Self::Other(b)) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl Eq for CommunicationError {}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
impl Eq for CommunicationError {}
|
||||
|
||||
/* ================================ PipeError ================================ */
|
||||
|
|
@ -283,6 +216,53 @@ impl From<CommunicationError> for PipeError {
|
|||
}
|
||||
}
|
||||
|
||||
/* ===================== Handshake Outcome Types ===================== */
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RejectionReason {
|
||||
BadVersion { supported_versions: Vec<String> },
|
||||
AuthenticationFailed { detail: String },
|
||||
RateLimited,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RejectionReason {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
RejectionReason::BadVersion { supported_versions } => {
|
||||
write!(
|
||||
f,
|
||||
"unsupported protocol version; supported: {}",
|
||||
supported_versions.join(", ")
|
||||
)
|
||||
}
|
||||
RejectionReason::AuthenticationFailed { detail } => {
|
||||
write!(f, "authentication failed: {detail}")
|
||||
}
|
||||
RejectionReason::RateLimited => write!(f, "rate limited"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum HandshakeOutcome {
|
||||
Accepted { version: String, assigned_id: u64 },
|
||||
Rejected { reason: RejectionReason },
|
||||
}
|
||||
|
||||
impl std::fmt::Display for HandshakeOutcome {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
HandshakeOutcome::Accepted {
|
||||
version,
|
||||
assigned_id,
|
||||
} => {
|
||||
write!(f, "accepted (version={version}, id={assigned_id})")
|
||||
}
|
||||
HandshakeOutcome::Rejected { reason } => write!(f, "rejected: {reason}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================ TESTS ================================ */
|
||||
#[cfg(test)]
|
||||
mod communication_error_tests {
|
||||
|
|
@ -381,3 +361,81 @@ mod pipe_error_tests {
|
|||
assert_eq!(pe, PipeError::IoError("Stream Error".into()));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== HandshakeOutcome TESTS ==================== */
|
||||
#[cfg(test)]
|
||||
mod handshake_outcome_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_accepted_display() {
|
||||
let outcome = HandshakeOutcome::Accepted {
|
||||
version: "1.0".into(),
|
||||
assigned_id: 42,
|
||||
};
|
||||
assert_eq!(format!("{outcome}"), "accepted (version=1.0, id=42)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejected_bad_version_display() {
|
||||
let outcome = HandshakeOutcome::Rejected {
|
||||
reason: RejectionReason::BadVersion {
|
||||
supported_versions: vec!["1.0".into(), "2.0".into()],
|
||||
},
|
||||
};
|
||||
let msg = format!("{outcome}");
|
||||
assert!(msg.contains("1.0"));
|
||||
assert!(msg.contains("2.0"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejected_auth_failed_display() {
|
||||
let outcome = HandshakeOutcome::Rejected {
|
||||
reason: RejectionReason::AuthenticationFailed {
|
||||
detail: "invalid signature".into(),
|
||||
},
|
||||
};
|
||||
assert!(format!("{outcome}").contains("invalid signature"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejected_rate_limited_display() {
|
||||
let outcome = HandshakeOutcome::Rejected {
|
||||
reason: RejectionReason::RateLimited,
|
||||
};
|
||||
assert_eq!(format!("{outcome}"), "rejected: rate limited");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejection_reason_display() {
|
||||
assert!(
|
||||
format!(
|
||||
"{}",
|
||||
RejectionReason::BadVersion {
|
||||
supported_versions: vec!["1.0".into()]
|
||||
}
|
||||
)
|
||||
.contains("1.0")
|
||||
);
|
||||
assert!(
|
||||
format!(
|
||||
"{}",
|
||||
RejectionReason::AuthenticationFailed {
|
||||
detail: "bad".into()
|
||||
}
|
||||
)
|
||||
.contains("bad")
|
||||
);
|
||||
assert_eq!(format!("{}", RejectionReason::RateLimited), "rate limited");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_handshake_outcome_clone_eq() {
|
||||
let a = HandshakeOutcome::Accepted {
|
||||
version: "1.0".into(),
|
||||
assigned_id: 1,
|
||||
};
|
||||
let b = a.clone();
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue