Skip to content

Commit 08a712d

Browse files
committed
dev: located error for http
1 parent 662123b commit 08a712d

File tree

4 files changed

+97
-60
lines changed

4 files changed

+97
-60
lines changed

src/http/error.rs

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,40 @@
1+
use std::panic::Location;
2+
13
use thiserror::Error;
24
use warp::reject::Reject;
35

6+
use crate::located_error::LocatedError;
7+
48
#[derive(Error, Debug)]
59
pub enum Error {
6-
#[error("internal server error")]
7-
InternalServer,
8-
9-
#[error("info_hash is either missing or invalid")]
10-
InvalidInfo,
11-
12-
#[error("peer_id is either missing or invalid")]
13-
InvalidPeerId,
14-
15-
#[error("could not find remote address")]
16-
AddressNotFound,
17-
18-
#[error("torrent has no peers")]
19-
NoPeersFound,
20-
21-
#[error("torrent not on whitelist")]
22-
TorrentNotWhitelisted,
23-
24-
#[error("peer not authenticated")]
25-
PeerNotAuthenticated,
26-
27-
#[error("invalid authentication key")]
28-
PeerKeyNotValid,
29-
30-
#[error("exceeded info_hash limit")]
31-
ExceededInfoHashLimit,
10+
#[error("tracker server error: {source}")]
11+
TrackerError {
12+
source: LocatedError<'static, dyn std::error::Error + Send + Sync>,
13+
},
14+
15+
#[error("internal server error: {message}, {location}")]
16+
InternalServer {
17+
location: &'static Location<'static>,
18+
message: String,
19+
},
20+
21+
#[error("no valid infohashes found, {location}")]
22+
EmptyInfoHash { location: &'static Location<'static> },
23+
24+
#[error("peer_id is either missing or invalid, {location}")]
25+
InvalidPeerId { location: &'static Location<'static> },
26+
27+
#[error("could not find remote address: {message}, {location}")]
28+
AddressNotFound {
29+
location: &'static Location<'static>,
30+
message: String,
31+
},
32+
33+
#[error("too many infohashes: {message}, {location}")]
34+
TwoManyInfoHashes {
35+
location: &'static Location<'static>,
36+
message: String,
37+
},
3238
}
3339

3440
impl Reject for Error {}

src/http/filters.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::convert::Infallible;
22
use std::net::{IpAddr, SocketAddr};
3+
use std::panic::Location;
34
use std::str::FromStr;
45
use std::sync::Arc;
56

@@ -87,9 +88,14 @@ fn info_hashes(raw_query: &String) -> WebResult<Vec<InfoHash>> {
8788
}
8889

8990
if info_hashes.len() > MAX_SCRAPE_TORRENTS as usize {
90-
Err(reject::custom(Error::ExceededInfoHashLimit))
91+
Err(reject::custom(Error::TwoManyInfoHashes {
92+
location: Location::caller(),
93+
message: format! {"found: {}, but limit is: {}",info_hashes.len(), MAX_SCRAPE_TORRENTS},
94+
}))
9195
} else if info_hashes.is_empty() {
92-
Err(reject::custom(Error::InvalidInfo))
96+
Err(reject::custom(Error::EmptyInfoHash {
97+
location: Location::caller(),
98+
}))
9399
} else {
94100
Ok(info_hashes)
95101
}
@@ -114,7 +120,9 @@ fn peer_id(raw_query: &String) -> WebResult<peer::Id> {
114120

115121
// peer_id must be 20 bytes
116122
if peer_id_bytes.len() != 20 {
117-
return Err(reject::custom(Error::InvalidPeerId));
123+
return Err(reject::custom(Error::InvalidPeerId {
124+
location: Location::caller(),
125+
}));
118126
}
119127

120128
// clone peer_id_bytes into fixed length array
@@ -128,18 +136,26 @@ fn peer_id(raw_query: &String) -> WebResult<peer::Id> {
128136

129137
match peer_id {
130138
Some(id) => Ok(id),
131-
None => Err(reject::custom(Error::InvalidPeerId)),
139+
None => Err(reject::custom(Error::InvalidPeerId {
140+
location: Location::caller(),
141+
})),
132142
}
133143
}
134144

135145
/// Get `PeerAddress` from `RemoteAddress` or Forwarded
136146
fn peer_addr((on_reverse_proxy, remote_addr, x_forwarded_for): (bool, Option<SocketAddr>, Option<String>)) -> WebResult<IpAddr> {
137147
if !on_reverse_proxy && remote_addr.is_none() {
138-
return Err(reject::custom(Error::AddressNotFound));
148+
return Err(reject::custom(Error::AddressNotFound {
149+
location: Location::caller(),
150+
message: "neither on have remote address or on a reverse proxy".to_string(),
151+
}));
139152
}
140153

141154
if on_reverse_proxy && x_forwarded_for.is_none() {
142-
return Err(reject::custom(Error::AddressNotFound));
155+
return Err(reject::custom(Error::AddressNotFound {
156+
location: Location::caller(),
157+
message: "must have a x-forwarded-for when using a reverse proxy".to_string(),
158+
}));
143159
}
144160

145161
if on_reverse_proxy {
@@ -151,7 +167,14 @@ fn peer_addr((on_reverse_proxy, remote_addr, x_forwarded_for): (bool, Option<Soc
151167
// set client ip to last forwarded ip
152168
let x_forwarded_ip = *x_forwarded_ips.last().unwrap();
153169

154-
IpAddr::from_str(x_forwarded_ip).map_err(|_| reject::custom(Error::AddressNotFound))
170+
IpAddr::from_str(x_forwarded_ip).map_err(|e| {
171+
reject::custom(Error::AddressNotFound {
172+
location: Location::caller(),
173+
message: format!(
174+
"on remote proxy and unable to parse the last x-forwarded-ip: `{e}`, from `{x_forwarded_for_raw}`"
175+
),
176+
})
177+
})
155178
} else {
156179
Ok(remote_addr.unwrap().ip())
157180
}

src/http/handlers.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::collections::HashMap;
22
use std::convert::Infallible;
33
use std::net::IpAddr;
4+
use std::panic::Location;
45
use std::sync::Arc;
56

67
use log::debug;
@@ -16,17 +17,18 @@ use crate::tracker::{self, auth, peer, statistics, torrent};
1617
///
1718
/// # Errors
1819
///
19-
/// Will return `ServerError` that wraps the `Error` if unable to `authenticate_request`.
20+
/// Will return `ServerError` that wraps the `tracker::error::Error` if unable to `authenticate_request`.
2021
pub async fn authenticate(
2122
info_hash: &InfoHash,
2223
auth_key: &Option<auth::Key>,
2324
tracker: Arc<tracker::Tracker>,
2425
) -> Result<(), Error> {
25-
tracker.authenticate_request(info_hash, auth_key).await.map_err(|e| match e {
26-
tracker::error::Error::TorrentNotWhitelisted { info_hash, location } => Error::TorrentNotWhitelisted,
27-
tracker::error::Error::PeerNotAuthenticated { location } => Error::PeerNotAuthenticated,
28-
tracker::error::Error::PeerKeyNotValid { key, source } => Error::PeerKeyNotValid,
29-
})
26+
tracker
27+
.authenticate_request(info_hash, auth_key)
28+
.await
29+
.map_err(|e| Error::TrackerError {
30+
source: (Arc::new(e) as Arc<dyn std::error::Error + Send + Sync>).into(),
31+
})
3032
}
3133

3234
/// Handle announce request
@@ -39,9 +41,7 @@ pub async fn handle_announce(
3941
auth_key: Option<auth::Key>,
4042
tracker: Arc<tracker::Tracker>,
4143
) -> WebResult<impl Reply> {
42-
authenticate(&announce_request.info_hash, &auth_key, tracker.clone())
43-
.await
44-
.map_err(reject::custom)?;
44+
authenticate(&announce_request.info_hash, &auth_key, tracker.clone()).await?;
4545

4646
debug!("{:?}", announce_request);
4747

@@ -158,7 +158,10 @@ fn send_announce_response(
158158
if let Some(1) = announce_request.compact {
159159
match res.write_compact() {
160160
Ok(body) => Ok(Response::new(body)),
161-
Err(_) => Err(reject::custom(Error::InternalServer)),
161+
Err(e) => Err(reject::custom(Error::InternalServer {
162+
message: e.to_string(),
163+
location: Location::caller(),
164+
})),
162165
}
163166
} else {
164167
Ok(Response::new(res.write().into()))
@@ -171,7 +174,10 @@ fn send_scrape_response(files: HashMap<InfoHash, response::ScrapeEntry>) -> WebR
171174

172175
match res.write() {
173176
Ok(body) => Ok(Response::new(body)),
174-
Err(_) => Err(reject::custom(Error::InternalServer)),
177+
Err(e) => Err(reject::custom(Error::InternalServer {
178+
message: e.to_string(),
179+
location: Location::caller(),
180+
})),
175181
}
176182
}
177183

@@ -181,15 +187,21 @@ fn send_scrape_response(files: HashMap<InfoHash, response::ScrapeEntry>) -> WebR
181187
///
182188
/// Will not return a error, `Infallible`, but instead convert the `ServerError` into a `Response`.
183189
pub fn send_error(r: &Rejection) -> std::result::Result<impl Reply, Infallible> {
184-
let body = if let Some(server_error) = r.find::<Error>() {
185-
debug!("{:?}", server_error);
190+
let warp_reject_error = r.find::<Error>();
191+
192+
let body = if let Some(error) = warp_reject_error {
193+
debug!("{:?}", error);
186194
response::Error {
187-
failure_reason: server_error.to_string(),
195+
failure_reason: error.to_string(),
188196
}
189197
.write()
190198
} else {
191199
response::Error {
192-
failure_reason: Error::InternalServer.to_string(),
200+
failure_reason: Error::InternalServer {
201+
message: "Undefined".to_string(),
202+
location: Location::caller(),
203+
}
204+
.to_string(),
193205
}
194206
.write()
195207
};

tests/http/asserts.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub async fn assert_invalid_info_hash_error_response(response: Response) {
9191

9292
assert_error_bencoded(
9393
&response.text().await.unwrap(),
94-
"info_hash is either missing or invalid",
94+
"no valid infohashes found",
9595
Location::caller(),
9696
);
9797
}
@@ -109,25 +109,21 @@ pub async fn assert_invalid_peer_id_error_response(response: Response) {
109109
pub async fn assert_torrent_not_in_whitelist_error_response(response: Response) {
110110
assert_eq!(response.status(), 200);
111111

112-
assert_error_bencoded(
113-
&response.text().await.unwrap(),
114-
"torrent not on whitelist",
115-
Location::caller(),
116-
);
112+
assert_error_bencoded(&response.text().await.unwrap(), "is not whitelisted", Location::caller());
117113
}
118114

119115
pub async fn assert_peer_not_authenticated_error_response(response: Response) {
120116
assert_eq!(response.status(), 200);
121117

122-
assert_error_bencoded(&response.text().await.unwrap(), "peer not authenticated", Location::caller());
118+
assert_error_bencoded(
119+
&response.text().await.unwrap(),
120+
"The peer is not authenticated",
121+
Location::caller(),
122+
);
123123
}
124124

125125
pub async fn assert_invalid_authentication_key_error_response(response: Response) {
126126
assert_eq!(response.status(), 200);
127127

128-
assert_error_bencoded(
129-
&response.text().await.unwrap(),
130-
"invalid authentication key",
131-
Location::caller(),
132-
);
128+
assert_error_bencoded(&response.text().await.unwrap(), "is not valid", Location::caller());
133129
}

0 commit comments

Comments
 (0)