Skip to content

Commit 18c81ed

Browse files
feat(web): human-readable descriptions for RDCleanPath errors (#999)
More munging to give human-readable webclient-side errors for RDCleanPath general/negotiation errors, including strings for WSA and TLS and HTTP error conditions.
1 parent b91a4ee commit 18c81ed

File tree

3 files changed

+178
-6
lines changed

3 files changed

+178
-6
lines changed

crates/ironrdp-rdcleanpath/src/lib.rs

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,128 @@ pub struct RDCleanPathErr {
3030

3131
impl fmt::Display for RDCleanPathErr {
3232
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33-
write!(f, "RDCleanPath error (code {})", self.error_code)?;
33+
let error_description = match self.error_code {
34+
GENERAL_ERROR_CODE => "general error",
35+
NEGOTIATION_ERROR_CODE => "negotiation error",
36+
_ => "unknown error",
37+
};
38+
write!(f, "{error_description} (code {})", self.error_code)?;
3439

3540
if let Some(http_status_code) = self.http_status_code {
36-
write!(f, " [HTTP status = {http_status_code}]")?;
41+
let description = match http_status_code {
42+
200 => "OK",
43+
400 => "bad request",
44+
401 => "unauthorized",
45+
403 => "forbidden",
46+
404 => "not found",
47+
405 => "method not allowed",
48+
408 => "request timeout",
49+
409 => "conflict",
50+
410 => "gone",
51+
413 => "payload too large",
52+
414 => "URI too long",
53+
422 => "unprocessable entity",
54+
429 => "too many requests",
55+
500 => "internal server error",
56+
501 => "not implemented",
57+
502 => "bad gateway",
58+
503 => "service unavailable",
59+
504 => "gateway timeout",
60+
505 => "HTTP version not supported",
61+
_ => "unknown HTTP status",
62+
};
63+
write!(f, "; HTTP {http_status_code} {description}")?;
3764
}
3865

3966
if let Some(wsa_last_error) = self.wsa_last_error {
40-
write!(f, " [WSA last error = {wsa_last_error}]")?;
67+
let description = match wsa_last_error {
68+
10004 => "interrupted system call",
69+
10009 => "bad file descriptor",
70+
10013 => "permission denied",
71+
10014 => "bad address",
72+
10022 => "invalid argument",
73+
10024 => "too many open files",
74+
10035 => "resource temporarily unavailable",
75+
10036 => "operation now in progress",
76+
10037 => "operation already in progress",
77+
10038 => "socket operation on nonsocket",
78+
10039 => "destination address required",
79+
10040 => "message too long",
80+
10041 => "protocol wrong type for socket",
81+
10042 => "bad protocol option",
82+
10043 => "protocol not supported",
83+
10044 => "socket type not supported",
84+
10045 => "operation not supported",
85+
10046 => "protocol family not supported",
86+
10047 => "address family not supported by protocol family",
87+
10048 => "address already in use",
88+
10049 => "cannot assign requested address",
89+
10050 => "network is down",
90+
10051 => "network is unreachable",
91+
10052 => "network dropped connection on reset",
92+
10053 => "software caused connection abort",
93+
10054 => "connection reset by peer",
94+
10055 => "no buffer space available",
95+
10056 => "socket is already connected",
96+
10057 => "socket is not connected",
97+
10058 => "cannot send after socket shutdown",
98+
10060 => "connection timed out",
99+
10061 => "connection refused",
100+
10064 => "host is down",
101+
10065 => "no route to host",
102+
10067 => "too many processes",
103+
10091 => "network subsystem is unavailable",
104+
10092 => "Winsock version not supported",
105+
10093 => "successful WSAStartup not yet performed",
106+
10101 => "graceful shutdown in progress",
107+
10109 => "class type not found",
108+
11001 => "host not found",
109+
11002 => "nonauthoritative host not found",
110+
11003 => "this is a nonrecoverable error",
111+
11004 => "valid name, no data record of requested type",
112+
_ => "unknown WSA error",
113+
};
114+
write!(f, "; WSA {wsa_last_error} {description}")?;
41115
}
42116

43117
if let Some(tls_alert_code) = self.tls_alert_code {
44-
write!(f, " [TLS alert = {tls_alert_code}]")?;
118+
let description = match tls_alert_code {
119+
0 => "close notify",
120+
10 => "unexpected message",
121+
20 => "bad record MAC",
122+
21 => "decryption failed",
123+
22 => "record overflow",
124+
30 => "decompression failure",
125+
40 => "handshake failure",
126+
41 => "no certificate",
127+
42 => "bad certificate",
128+
43 => "unsupported certificate",
129+
44 => "certificate revoked",
130+
45 => "certificate expired",
131+
46 => "certificate unknown",
132+
47 => "illegal parameter",
133+
48 => "unknown CA",
134+
49 => "access denied",
135+
50 => "decode error",
136+
51 => "decrypt error",
137+
60 => "export restriction",
138+
70 => "protocol version",
139+
71 => "insufficient security",
140+
80 => "internal error",
141+
90 => "user canceled",
142+
100 => "no renegotiation",
143+
109 => "missing extension",
144+
110 => "unsupported extension",
145+
111 => "certificate unobtainable",
146+
112 => "unrecognized name",
147+
113 => "bad certificate status response",
148+
114 => "bad certificate hash value",
149+
115 => "unknown PSK identity",
150+
116 => "certificate required",
151+
120 => "no application protocol",
152+
_ => "unknown TLS alert",
153+
};
154+
write!(f, "; TLS alert {tls_alert_code} {description}")?;
45155
}
46156

47157
Ok(())

crates/ironrdp-testsuite-core/tests/rdcleanpath.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use ironrdp_rdcleanpath::{DetectionResult, RDCleanPathPdu, VERSION_1};
1+
use expect_test::{expect, Expect};
2+
use ironrdp_rdcleanpath::{
3+
DetectionResult, RDCleanPathErr, RDCleanPathPdu, GENERAL_ERROR_CODE, NEGOTIATION_ERROR_CODE, VERSION_1,
4+
};
25
use rstest::rstest;
36

47
fn request() -> RDCleanPathPdu {
@@ -123,3 +126,62 @@ fn detect_not_enough(#[case] payload: &[u8]) {
123126
let result = RDCleanPathPdu::detect(payload);
124127
assert_eq!(result, DetectionResult::NotEnoughBytes);
125128
}
129+
130+
#[rstest]
131+
#[case::http(
132+
RDCleanPathErr {
133+
error_code: GENERAL_ERROR_CODE,
134+
http_status_code: Some(404),
135+
wsa_last_error: None,
136+
tls_alert_code: None,
137+
},
138+
expect!["general error (code 1); HTTP 404 not found"],
139+
)]
140+
#[case::wsa(
141+
RDCleanPathErr {
142+
error_code: GENERAL_ERROR_CODE,
143+
http_status_code: None,
144+
wsa_last_error: Some(10061),
145+
tls_alert_code: None,
146+
},
147+
expect!["general error (code 1); WSA 10061 connection refused"],
148+
)]
149+
#[case::tls(
150+
RDCleanPathErr {
151+
error_code: GENERAL_ERROR_CODE,
152+
http_status_code: None,
153+
wsa_last_error: None,
154+
tls_alert_code: Some(40),
155+
},
156+
expect!["general error (code 1); TLS alert 40 handshake failure"],
157+
)]
158+
#[case::nego(
159+
RDCleanPathErr {
160+
error_code: NEGOTIATION_ERROR_CODE,
161+
http_status_code: None,
162+
wsa_last_error: None,
163+
tls_alert_code: None,
164+
},
165+
expect!["negotiation error (code 2)"],
166+
)]
167+
#[case::combined(
168+
RDCleanPathErr {
169+
error_code: GENERAL_ERROR_CODE,
170+
http_status_code: Some(502),
171+
wsa_last_error: Some(10060),
172+
tls_alert_code: Some(45),
173+
},
174+
expect!["general error (code 1); HTTP 502 bad gateway; WSA 10060 connection timed out; TLS alert 45 certificate expired"],
175+
)]
176+
#[case::unknown_codes(
177+
RDCleanPathErr {
178+
error_code: 99,
179+
http_status_code: Some(999),
180+
wsa_last_error: Some(65000),
181+
tls_alert_code: Some(255),
182+
},
183+
expect!["unknown error (code 99); HTTP 999 unknown HTTP status; WSA 65000 unknown WSA error; TLS alert 255 unknown TLS alert"],
184+
)]
185+
fn error_display(#[case] error: RDCleanPathErr, #[case] expected: Expect) {
186+
expected.assert_eq(&error.to_string());
187+
}

crates/ironrdp-web/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl IronError {
1515

1616
impl iron_remote_desktop::IronError for IronError {
1717
fn backtrace(&self) -> String {
18-
format!("{:?}", self.source)
18+
format!("{:#}", self.source)
1919
}
2020

2121
fn kind(&self) -> IronErrorKind {

0 commit comments

Comments
 (0)