1use poem::error::ResponseError;
2use poem::http::StatusCode;
3use std::io;
4use std::net::IpAddr;
5use std::ops::Range;
6
7use thiserror::Error;
8use tokio::runtime::TryCurrentError;
9use tokio::sync::mpsc;
10use tokio::task::JoinError;
11
12use crate::server::ServerControl;
13
14#[derive(Error, Debug)]
16pub enum ConfigError {
17 #[error("Invalid server config (expected {expected}, found {found})")]
19 InvalidServerConfig { expected: String, found: String },
20 #[error("Cannot bind to {addr} on any port from {}-{}", port_range.start, port_range.end - 1)]
22 CannotBindAddress {
23 addr: IpAddr,
24 port_range: Range<u16>,
25 },
26}
27
28#[derive(Error, Debug)]
30pub enum ServerError {
31 #[error("Tokio must be running")]
33 AsyncRuntimeRequired(#[from] TryCurrentError),
34 #[error("Internal runtime error")]
35 InternalRuntimeError(#[from] JoinError),
36 #[error("Error signaling server")]
38 InternalCommError(#[from] mpsc::error::SendError<ServerControl>),
39 #[error("Internal server error")]
41 InternalServerError(#[from] io::Error),
42 #[error("No authorization code received")]
44 NoResult,
45}
46
47impl ResponseError for ServerError {
48 fn status(&self) -> StatusCode {
49 use ServerError::*;
50 match self {
51 NoResult => StatusCode::BAD_REQUEST,
52 _ => StatusCode::INTERNAL_SERVER_ERROR,
53 }
54 }
55}
56
57#[derive(Error, Debug)]
59pub enum AuthError {
60 #[error("Invalid CSRF token (state parameter)")]
62 CsrfMismatch,
63 #[error("No authorization code or PKCE verifier present")]
66 InvalidAuthState,
67}
68
69#[cfg(test)]
70mod tests {
71 mod config_error {
72 use crate::ConfigError;
73
74 #[test]
75 fn invalid_server_config() {
76 let error = ConfigError::InvalidServerConfig {
77 expected: "blah".to_owned(),
78 found: "foobar".to_owned(),
79 };
80 assert!(
81 format!("{error}").contains("Invalid server config (expected blah, found foobar)")
82 );
83 }
84
85 #[test]
86 fn cannot_bind_address() {
87 let error = ConfigError::CannotBindAddress {
88 addr: [127, 0, 0, 1].into(),
89 port_range: 5678..6789,
90 };
91 assert!(
92 format!("{error}").contains("Cannot bind to 127.0.0.1 on any port from 5678-6788")
93 )
94 }
95 }
96
97 mod server_error {
98 use crate::ServerError;
99 use poem::error::ResponseError;
100 use poem::http::StatusCode;
101 use std::io;
102 use std::io::ErrorKind;
103
104 #[test]
105 fn no_result_response_error_trait() {
106 let response = ServerError::NoResult.as_response();
107 assert_eq!(response.status(), StatusCode::BAD_REQUEST);
108 }
109
110 #[test]
111 fn internal_server_error_response_error_trait() {
112 let io_error = io::Error::from(ErrorKind::AddrInUse);
113 let response = ServerError::InternalServerError(io_error).as_response();
114 assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
115 }
116 }
117
118 mod auth_error {
119 use crate::AuthError;
120
121 #[test]
122 fn csrf_mismatch() {
123 assert!(format!("{}", AuthError::CsrfMismatch)
124 .contains("Invalid CSRF token (state parameter)"));
125 }
126
127 #[test]
128 fn invalid_auth_state() {
129 assert!(format!("{}", AuthError::InvalidAuthState)
130 .contains("No authorization code or PKCE verifier present"));
131 }
132 }
133}