Skip to content

Commit 329485f

Browse files
committed
refactor: [#276] extract fn parse_torrent::decode_and_validate_torrent_file
1 parent a46d300 commit 329485f

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

src/errors.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use hyper::StatusCode;
66

77
use crate::databases::database;
88
use crate::models::torrent::MetadataError;
9+
use crate::utils::parse_torrent::MetainfoFileDataError;
910

1011
pub type ServiceResult<V> = Result<V, ServiceError>;
1112

@@ -215,6 +216,16 @@ impl From<MetadataError> for ServiceError {
215216
}
216217
}
217218

219+
impl From<MetainfoFileDataError> for ServiceError {
220+
fn from(e: MetainfoFileDataError) -> Self {
221+
eprintln!("{e}");
222+
match e {
223+
MetainfoFileDataError::InvalidBencodeData => ServiceError::InvalidTorrentFile,
224+
MetainfoFileDataError::InvalidTorrentPiecesLength => ServiceError::InvalidTorrentTitleLength,
225+
}
226+
}
227+
}
228+
218229
#[must_use]
219230
pub fn http_status_code_for_service_error(error: &ServiceError) -> StatusCode {
220231
#[allow(clippy::match_same_arms)]

src/services/torrent.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::models::torrent_file::{DbTorrent, Torrent, TorrentFile};
1717
use crate::models::torrent_tag::{TagId, TorrentTag};
1818
use crate::models::user::UserId;
1919
use crate::tracker::statistics_importer::StatisticsImporter;
20-
use crate::utils::parse_torrent;
20+
use crate::utils::parse_torrent::decode_and_validate_torrent_file;
2121
use crate::{tracker, AsCSV};
2222

2323
pub struct Index {
@@ -134,20 +134,10 @@ impl Index {
134134

135135
let metadata = self.validate_and_build_metadata(&add_torrent_req).await?;
136136

137-
// Validate and build torrent file
138-
139-
let original_info_hash = parse_torrent::calculate_info_hash(&add_torrent_req.torrent_buffer);
140-
141-
let mut torrent =
142-
parse_torrent::decode_torrent(&add_torrent_req.torrent_buffer).map_err(|_| ServiceError::InvalidTorrentFile)?;
143-
144-
// Make sure that the pieces key has a length that is a multiple of 20
145-
if let Some(pieces) = torrent.info.pieces.as_ref() {
146-
if pieces.as_ref().len() % 20 != 0 {
147-
return Err(ServiceError::InvalidTorrentPiecesLength);
148-
}
149-
}
137+
let (mut torrent, original_info_hash) = decode_and_validate_torrent_file(&add_torrent_req.torrent_buffer)?;
150138

139+
// Customize the announce URLs with the linked tracker URL
140+
// and remove others if the torrent is private.
151141
torrent.set_announce_urls(&self.configuration).await;
152142

153143
let canonical_info_hash = torrent.canonical_info_hash();

src/utils/parse_torrent.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::error;
22

3+
use derive_more::{Display, Error};
34
use serde::{self, Deserialize, Serialize};
45
use serde_bencode::value::Value;
56
use serde_bencode::{de, Error};
@@ -8,6 +9,43 @@ use sha1::{Digest, Sha1};
89
use crate::models::info_hash::InfoHash;
910
use crate::models::torrent_file::Torrent;
1011

12+
#[derive(Debug, Display, PartialEq, Eq, Error)]
13+
pub enum MetainfoFileDataError {
14+
#[display(fmt = "Torrent data could not be decoded from the bencoded format.")]
15+
InvalidBencodeData,
16+
17+
#[display(fmt = "Torrent has an invalid pieces key length. It should be a multiple of 20.")]
18+
InvalidTorrentPiecesLength,
19+
}
20+
21+
/// It decodes and validate an array of bytes containing a torrent file.
22+
///
23+
/// It returns a tuple containing the decoded torrent and the original info hash.
24+
/// The original info-hash migth not match the new one in the `Torrent` because
25+
/// the info dictionary might have been modified. For example, ignoring some
26+
/// non-standard fields.
27+
///
28+
/// # Errors
29+
///
30+
/// This function will return an error if
31+
///
32+
/// - The torrent file is not a valid bencoded file.
33+
/// - The pieces key has a length that is not a multiple of 20.
34+
pub fn decode_and_validate_torrent_file(bytes: &[u8]) -> Result<(Torrent, InfoHash), MetainfoFileDataError> {
35+
let original_info_hash = calculate_info_hash(bytes);
36+
37+
let torrent = decode_torrent(bytes).map_err(|_| MetainfoFileDataError::InvalidBencodeData)?;
38+
39+
// Make sure that the pieces key has a length that is a multiple of 20
40+
if let Some(pieces) = torrent.info.pieces.as_ref() {
41+
if pieces.as_ref().len() % 20 != 0 {
42+
return Err(MetainfoFileDataError::InvalidTorrentPiecesLength);
43+
}
44+
}
45+
46+
Ok((torrent, original_info_hash))
47+
}
48+
1149
/// Decode a Torrent from Bencoded Bytes.
1250
///
1351
/// # Errors

0 commit comments

Comments
 (0)