forked from torrust/torrust-tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror.rs
More file actions
131 lines (115 loc) · 3.94 KB
/
error.rs
File metadata and controls
131 lines (115 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! `Error` response for the HTTP tracker.
//!
//! Data structures and logic to build the error responses.
//!
//! From the [BEP 03. The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html):
//!
//! _"Tracker responses are bencoded dictionaries. If a tracker response has a
//! key failure reason, then that maps to a human readable string which explains
//! why the query failed, and no other keys are required."_
//!
//! > **NOTICE**: error responses are bencoded and always have a `200 OK` status
//! > code. The official `BitTorrent` specification does not specify the status
//! > code.
use serde::Serialize;
use crate::v1::auth;
use crate::v1::services::peer_ip_resolver::PeerIpResolutionError;
/// `Error` response for the HTTP tracker.
#[derive(Serialize, Debug, PartialEq)]
pub struct Error {
/// Human readable string which explains why the request failed.
#[serde(rename = "failure reason")]
pub failure_reason: String,
}
impl Error {
/// Returns the bencoded representation of the `Error` struct.
///
/// ```rust
/// use bittorrent_http_tracker_protocol::v1::responses::error::Error;
///
/// let err = Error {
/// failure_reason: "error message".to_owned(),
/// };
///
/// // cspell:disable-next-line
/// assert_eq!(err.write(), "d14:failure reason13:error messagee");
/// ```
///
/// # Panics
///
/// It would panic if the `Error` struct contained an inappropriate field
/// type.
#[must_use]
pub fn write(&self) -> String {
serde_bencode::to_string(&self).unwrap()
}
}
impl From<auth::Error> for Error {
fn from(err: auth::Error) -> Self {
Self {
failure_reason: format!("Tracker authentication error: {err}"),
}
}
}
impl From<PeerIpResolutionError> for Error {
fn from(err: PeerIpResolutionError) -> Self {
Self {
failure_reason: format!("Error resolving peer IP: {err}"),
}
}
}
impl From<bittorrent_tracker_core::error::AnnounceError> for Error {
fn from(err: bittorrent_tracker_core::error::AnnounceError) -> Self {
Error {
failure_reason: format!("Tracker announce error: {err}"),
}
}
}
impl From<bittorrent_tracker_core::error::ScrapeError> for Error {
fn from(err: bittorrent_tracker_core::error::ScrapeError) -> Self {
Error {
failure_reason: format!("Tracker scrape error: {err}"),
}
}
}
impl From<bittorrent_tracker_core::error::WhitelistError> for Error {
fn from(err: bittorrent_tracker_core::error::WhitelistError) -> Self {
Error {
failure_reason: format!("Tracker whitelist error: {err}"),
}
}
}
impl From<bittorrent_tracker_core::authentication::Error> for Error {
fn from(err: bittorrent_tracker_core::authentication::Error) -> Self {
Error {
failure_reason: format!("Tracker authentication error: {err}"),
}
}
}
#[cfg(test)]
mod tests {
use std::panic::Location;
use super::Error;
use crate::v1::responses;
use crate::v1::services::peer_ip_resolver::PeerIpResolutionError;
#[test]
fn http_tracker_errors_can_be_bencoded() {
let err = Error {
failure_reason: "error message".to_owned(),
};
assert_eq!(err.write(), "d14:failure reason13:error messagee"); // cspell:disable-line
}
fn assert_error_response(error: &responses::error::Error, error_message: &str) {
assert!(
error.failure_reason.contains(error_message),
"Error response does not contain message: '{error_message}'. Error: {error:?}"
);
}
#[test]
fn it_should_map_a_peer_ip_resolution_error_into_an_error_response() {
let response = responses::error::Error::from(PeerIpResolutionError::MissingRightMostXForwardedForIp {
location: Location::caller(),
});
assert_error_response(&response, "Error resolving peer IP");
}
}