Skip to content

Add tests for the HTTP tracker #162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c26b356
feat(http): [#159] during HTTP tracker setup wait until job is running
josecelano Jan 17, 2023
3449202
test(http): [#159] HTTP tracker tests scaffolding
josecelano Jan 17, 2023
41ad07f
refactor(http): [#159] add dependencies: serde_urlencoded and serde_repr
josecelano Jan 20, 2023
1a558d2
test(http): [#159] add tests for public http tracker
josecelano Jan 20, 2023
dd38045
refactor(http): [#159] extract test builders
josecelano Jan 23, 2023
ca8fc22
test(http): [#159] add tests for public http tracker
josecelano Jan 23, 2023
7fa8ec8
test(http): add test for failing convertion of peer Id into String
josecelano Jan 23, 2023
62dbffa
test(http): [#159] add test for missing announce req params in http t…
josecelano Jan 23, 2023
8ae4928
test(http): [#159] add test for invalid announce request params
josecelano Jan 24, 2023
8e5c992
refactor(http): [#159] add dependency: serde_bytes
josecelano Jan 24, 2023
96fb56c
test(http): [#159] add test for compact announce response
josecelano Jan 24, 2023
3fce688
refactor(http): extract converter
josecelano Jan 25, 2023
85a4894
test(http): [#159] add test for default announce response format
josecelano Jan 25, 2023
080f3c4
test(http): [#159] add tests for uptadint statistics after announce r…
josecelano Jan 25, 2023
5cc2ac1
refactor(http): [#159] add dependency local-ip-address
josecelano Jan 26, 2023
452b81a
test(http): [#159] add tests for assigning IP to peers in announce re…
josecelano Jan 26, 2023
86155d6
refactor(http): improve readability
josecelano Jan 26, 2023
11492a3
test(http): [#159] add tests for announce request in whitelisted mode
josecelano Jan 26, 2023
badb791
test(http): [#159] add tests for announce request in private mode
josecelano Jan 26, 2023
e1765f3
fix: new clippy errors
josecelano Jan 27, 2023
fcd60e2
fix(http): Display impl for tracker::peer:ID
josecelano Jan 27, 2023
953a100
docs(http): [#159] add links to info about scrape requests
josecelano Jan 30, 2023
d7610ef
refactor(http): [#159] move mods to folders
josecelano Jan 30, 2023
dc304e7
test(http): [#159] scaffolding to test scrape responses in http tracker
josecelano Jan 30, 2023
2754189
refactor(http): [#159] rename struct in announce responses to follow …
josecelano Jan 30, 2023
c89a1f3
fix(http): [#159] minor text fixes
josecelano Jan 30, 2023
7ee588a
refactor(test): [#159] refactor tests for scrape request
josecelano Jan 31, 2023
c24d744
refactor(test): [#159] refactor tests for announce request
josecelano Jan 31, 2023
c46e417
test(http): [#159] add more tests for scrape request
josecelano Feb 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 45 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ uuid = { version = "1", features = ["v4"] }
axum = "0.6.1"
axum-server = { version = "0.4.4", features = ["tls-rustls"] }


[dev-dependencies]
mockall = "0.11"
reqwest = { version = "0.11.13", features = ["json"] }
serde_urlencoded = "0.7.1"
serde_repr = "0.1.10"
serde_bytes = "0.11.8"
local-ip-address = "0.5.1"
8 changes: 7 additions & 1 deletion cSpell.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"Avicora",
"Azureus",
"bencode",
"bencoded",
"binascii",
"Bitflu",
"bools",
Expand Down Expand Up @@ -39,6 +40,7 @@
"nanos",
"nextest",
"nocapture",
"numwant",
"oneshot",
"ostr",
"Pando",
Expand All @@ -62,12 +64,16 @@
"Torrentstorm",
"torrust",
"torrustracker",
"trackerid",
"typenum",
"Unamed",
"untuple",
"uroot",
"Vagaa",
"Vuze",
"Xtorrent",
"Xunlei"
"Xunlei",
"xxxxxxxxxxxxxxxxxxxxd",
"yyyyyyyyyyyyyyyyyyyyd"
]
}
5 changes: 1 addition & 4 deletions src/apis/middlewares/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ pub async fn auth<B>(
where
B: Send,
{
let token = match params.token {
None => return AuthError::Unauthorized.into_response(),
Some(token) => token,
};
let Some(token) = params.token else { return AuthError::Unauthorized.into_response() };

if !authenticate(&token, &config.http_api) {
return AuthError::TokenNotValid.into_response();
Expand Down
2 changes: 1 addition & 1 deletion src/apis/resources/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct Id {
impl From<tracker::peer::Id> for Id {
fn from(peer_id: tracker::peer::Id) -> Self {
Id {
id: peer_id.get_id(),
id: peer_id.to_hex_string(),
client: peer_id.get_client_name().map(std::string::ToString::to_string),
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/apis/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ pub fn ok_response() -> Response {
#[must_use]
pub fn invalid_info_hash_param_response(info_hash: &str) -> Response {
bad_request_response(&format!(
"Invalid URL: invalid infohash param: string \"{}\", expected a 40 character long string",
info_hash
"Invalid URL: invalid infohash param: string \"{info_hash}\", expected a 40 character long string"
))
}

Expand Down
20 changes: 16 additions & 4 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,27 +84,39 @@ pub enum Error {
}

/// This configuration is used for testing. It generates random config values so they do not collide
/// if you run more than one tracker at the same time.
/// if you run more than one tracker at the same time.
///
/// # Panics
///
/// Will panic if it can't convert the temp file path to string
#[must_use]
pub fn ephemeral_configuration() -> Configuration {
// todo: disable services that are not needed.
// For example: a test for the UDP tracker should disable the API and HTTP tracker.

let mut config = Configuration {
log_level: Some("off".to_owned()),
log_level: Some("off".to_owned()), // Change to `debug` for tests debugging
..Default::default()
};

// Ephemeral socket addresses
// Ephemeral socket address for API
let api_port = random_port();
config.http_api.enabled = true;
config.http_api.bind_address = format!("127.0.0.1:{}", &api_port);

// Ephemeral socket address for UDP tracker
let upd_port = random_port();
config.udp_trackers[0].enabled = true;
config.udp_trackers[0].bind_address = format!("127.0.0.1:{}", &upd_port);

// Ephemeral socket address for HTTP tracker
let http_port = random_port();
config.http_trackers[0].enabled = true;
config.http_trackers[0].bind_address = format!("127.0.0.1:{}", &http_port);

// Ephemeral sqlite database
let temp_directory = env::temp_dir();
let temp_file = temp_directory.join(format!("data_{}_{}.db", &api_port, &upd_port));
let temp_file = temp_directory.join(format!("data_{}_{}_{}.db", &api_port, &upd_port, &http_port));
config.db_path = temp_file.to_str().unwrap().to_owned();

config
Expand Down
11 changes: 11 additions & 0 deletions src/http/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
//! Tracker HTTP/HTTPS Protocol:
//!
//! Original specification in BEP 3 (section "Trackers"):
//!
//! <https://www.bittorrent.org/beps/bep_0003.html>
//!
//! Other resources:
//!
//! - <https://wiki.theory.org/BitTorrentSpecification#Tracker_HTTP.2FHTTPS_Protocol>
//! - <https://wiki.theory.org/BitTorrent_Tracker_Protocol>
//!
pub mod error;
pub mod filters;
pub mod handlers;
Expand Down
7 changes: 3 additions & 4 deletions src/http/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ use std::collections::HashMap;
use std::io::Write;
use std::net::IpAddr;

use serde;
use serde::Serialize;
use serde::{self, Deserialize, Serialize};

use crate::protocol::info_hash::InfoHash;

#[derive(Serialize)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Peer {
pub peer_id: String,
pub ip: IpAddr,
pub port: u16,
}

#[derive(Serialize)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Announce {
pub interval: u32,
#[serde(rename = "min interval")]
Expand Down
58 changes: 46 additions & 12 deletions src/jobs/http_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,69 @@ use std::net::SocketAddr;
use std::sync::Arc;

use log::{info, warn};
use tokio::sync::oneshot;
use tokio::task::JoinHandle;

use crate::config::HttpTracker;
use crate::http::server::Http;
use crate::tracker;

#[derive(Debug)]
pub struct ServerJobStarted();

/// # Panics
///
/// It would panic if the `config::HttpTracker` struct would contain an inappropriate values.
#[must_use]
pub fn start_job(config: &HttpTracker, tracker: Arc<tracker::Tracker>) -> JoinHandle<()> {
let bind_addr = config.bind_address.parse::<SocketAddr>().unwrap();
pub async fn start_job(config: &HttpTracker, tracker: Arc<tracker::Tracker>) -> JoinHandle<()> {
let bind_addr = config
.bind_address
.parse::<SocketAddr>()
.expect("HTTP tracker server bind_address invalid.");
let ssl_enabled = config.ssl_enabled;
let ssl_cert_path = config.ssl_cert_path.clone();
let ssl_key_path = config.ssl_key_path.clone();

tokio::spawn(async move {
let (tx, rx) = oneshot::channel::<ServerJobStarted>();

// Run the HTTP tracker server
let join_handle = tokio::spawn(async move {
let http_tracker = Http::new(tracker);

if !ssl_enabled {
info!("Starting HTTP server on: http://{}", bind_addr);
http_tracker.start(bind_addr).await;
info!("Starting HTTP tracker server on: http://{}", bind_addr);

let handle = http_tracker.start(bind_addr);

tx.send(ServerJobStarted())
.expect("HTTP tracker server should not be dropped");

handle.await;

info!("HTTP tracker server on http://{} stopped", bind_addr);
} else if ssl_enabled && ssl_cert_path.is_some() && ssl_key_path.is_some() {
info!("Starting HTTPS server on: https://{} (TLS)", bind_addr);
http_tracker
.start_tls(bind_addr, ssl_cert_path.unwrap(), ssl_key_path.unwrap())
.await;
info!("Starting HTTPS server on: https://{}", bind_addr);

let handle = http_tracker.start_tls(bind_addr, ssl_cert_path.unwrap(), ssl_key_path.unwrap());

tx.send(ServerJobStarted())
.expect("HTTP tracker server should not be dropped");

handle.await;

info!("HTTP tracker server on https://{} stopped", bind_addr);
} else {
warn!("Could not start HTTP tracker on: {}, missing SSL Cert or Key!", bind_addr);
warn!(
"Could not start HTTPS tracker server on: {}, missing SSL Cert or Key!",
bind_addr
);
}
})
});

// Wait until the HTTPS tracker server job is running
match rx.await {
Ok(_msg) => info!("HTTP tracker server started"),
Err(e) => panic!("HTTP tracker server was dropped: {e}"),
}

join_handle
}
8 changes: 8 additions & 0 deletions src/protocol/info_hash.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct InfoHash(pub [u8; 20]);

impl InfoHash {
/// For readability, when accessing the bytes array
#[must_use]
pub fn bytes(&self) -> [u8; 20] {
self.0
}
}

impl std::fmt::Display for InfoHash {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut chars = [0u8; 40];
Expand Down
2 changes: 1 addition & 1 deletion src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub async fn setup(config: &Configuration, tracker: Arc<tracker::Tracker>) -> Ve
if !http_tracker_config.enabled {
continue;
}
jobs.push(http_tracker::start_job(http_tracker_config, tracker.clone()));
jobs.push(http_tracker::start_job(http_tracker_config, tracker.clone()).await);
}

// Start HTTP API
Expand Down
Loading