From 8ae4928e4d957e07c89a79b81827727ad30972d4 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Tue, 24 Jan 2023 11:31:43 +0000 Subject: [PATCH] test(http): [#159] add test for invalid announce request params --- tests/common/fixtures.rs | 12 +++ tests/http/requests.rs | 17 +++- tests/http_tracker.rs | 188 +++++++++++++++++++++++++++++++++++++++ tests/tracker_api.rs | 12 +-- 4 files changed, 219 insertions(+), 10 deletions(-) diff --git a/tests/common/fixtures.rs b/tests/common/fixtures.rs index 78f7d381f..0ff6798f6 100644 --- a/tests/common/fixtures.rs +++ b/tests/common/fixtures.rs @@ -37,3 +37,15 @@ fn default_peer_for_testing() -> Peer { event: AnnounceEvent::Started, } } + +pub fn invalid_info_hashes() -> Vec { + [ + "0".to_string(), + "-1".to_string(), + "1.1".to_string(), + "INVALID INFOHASH".to_string(), + "9c38422213e30bff212b30c360d26f9a0213642".to_string(), // 39-char length instead of 40 + "9c38422213e30bff212b30c360d26f9a0213642&".to_string(), // Invalid char + ] + .to_vec() +} diff --git a/tests/http/requests.rs b/tests/http/requests.rs index ceff2bd77..885c48939 100644 --- a/tests/http/requests.rs +++ b/tests/http/requests.rs @@ -51,7 +51,7 @@ pub type ByteArray20 = [u8; 20]; pub type PortNumber = u16; pub enum Event { - //tarted, + //Started, //Stopped, Completed, } @@ -227,4 +227,19 @@ impl AnnounceQueryParams { self.event = None; self.compact = None; } + + pub fn set(&mut self, param_name: &str, param_value: &str) { + match param_name { + "info_hash" => self.info_hash = Some(param_value.to_string()), + "peer_addr" => self.peer_addr = Some(param_value.to_string()), + "downloaded" => self.downloaded = Some(param_value.to_string()), + "uploaded" => self.uploaded = Some(param_value.to_string()), + "peer_id" => self.peer_id = Some(param_value.to_string()), + "port" => self.port = Some(param_value.to_string()), + "left" => self.left = Some(param_value.to_string()), + "event" => self.event = Some(param_value.to_string()), + "compact" => self.compact = Some(param_value.to_string()), + &_ => panic!("Invalid param name for announce query"), + } + } } diff --git a/tests/http_tracker.rs b/tests/http_tracker.rs index 44ec6454c..a28a9efb1 100644 --- a/tests/http_tracker.rs +++ b/tests/http_tracker.rs @@ -9,6 +9,7 @@ mod http_tracker_server { mod for_all_config_modes { mod receiving_an_announce_request { + use crate::common::fixtures::invalid_info_hashes; use crate::http::asserts::{ assert_internal_server_error_response, assert_invalid_info_hash_error_response, assert_invalid_peer_id_error_response, assert_is_announce_response, @@ -81,6 +82,193 @@ mod http_tracker_server { assert_internal_server_error_response(response).await; } + + #[tokio::test] + async fn should_fail_when_the_info_hash_param_is_invalid() { + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + for invalid_value in &invalid_info_hashes() { + params.set("info_hash", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_invalid_info_hash_error_response(response).await; + } + } + + #[tokio::test] + async fn should_not_fail_when_the_peer_address_param_is_invalid() { + // AnnounceQuery does not even contain the `peer_addr` + // The peer IP is obtained in two ways: + // 1. If tracker is NOT running `on_reverse_proxy` from the remote client IP if there. + // 2. If tracker is running `on_reverse_proxy` from `X-Forwarded-For` request header is tracker is running `on_reverse_proxy`. + + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + params.peer_addr = Some("INVALID-IP-ADDRESS".to_string()); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_is_announce_response(response).await; + } + + #[tokio::test] + async fn should_fail_when_the_downloaded_param_is_invalid() { + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + let invalid_values = ["-1", "1.1", "a"]; + + for invalid_value in invalid_values { + params.set("downloaded", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_internal_server_error_response(response).await; + } + } + + #[tokio::test] + async fn should_fail_when_the_uploaded_param_is_invalid() { + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + let invalid_values = ["-1", "1.1", "a"]; + + for invalid_value in invalid_values { + params.set("uploaded", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_internal_server_error_response(response).await; + } + } + + #[tokio::test] + async fn should_fail_when_the_peer_id_param_is_invalid() { + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + let invalid_values = [ + "0", + "-1", + "1.1", + "a", + "-qB0000000000000000", // 19 bytes + "-qB000000000000000000", // 21 bytes + ]; + + for invalid_value in invalid_values { + params.set("peer_id", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_invalid_peer_id_error_response(response).await; + } + } + + #[tokio::test] + async fn should_fail_when_the_port_param_is_invalid() { + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + let invalid_values = ["-1", "1.1", "a"]; + + for invalid_value in invalid_values { + params.set("port", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_internal_server_error_response(response).await; + } + } + + #[tokio::test] + async fn should_fail_when_the_left_param_is_invalid() { + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + let invalid_values = ["-1", "1.1", "a"]; + + for invalid_value in invalid_values { + params.set("left", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_internal_server_error_response(response).await; + } + } + + #[tokio::test] + async fn should_not_fail_when_the_event_param_is_invalid() { + // All invalid values are ignored as if the `event` param was empty + + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + let invalid_values = [ + "0", + "-1", + "1.1", + "a", + "Started", // It should be lowercase + "Stopped", // It should be lowercase + "Completed", // It should be lowercase + ]; + + for invalid_value in invalid_values { + params.set("event", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_is_announce_response(response).await; + } + } + + #[tokio::test] + async fn should_not_fail_when_the_compact_param_is_invalid() { + let http_tracker_server = start_default_http_tracker().await; + + let mut params = AnnounceQueryBuilder::default().query().params(); + + let invalid_values = ["-1", "1.1", "a"]; + + for invalid_value in invalid_values { + params.set("compact", invalid_value); + + let response = Client::new(http_tracker_server.get_connection_info()) + .get(&format!("announce?{params}")) + .await; + + assert_internal_server_error_response(response).await; + } + } } mod receiving_an_scrape_request { diff --git a/tests/tracker_api.rs b/tests/tracker_api.rs index 5710db6a6..b79e8a8af 100644 --- a/tests/tracker_api.rs +++ b/tests/tracker_api.rs @@ -10,18 +10,12 @@ mod common; mod tracker_apis { + use crate::common::fixtures::invalid_info_hashes; + // When these infohashes are used in URL path params // the response is a custom response returned in the handler fn invalid_infohashes_returning_bad_request() -> Vec { - [ - "0".to_string(), - "-1".to_string(), - "1.1".to_string(), - "INVALID INFOHASH".to_string(), - "9c38422213e30bff212b30c360d26f9a0213642".to_string(), // 39-char length instead of 40 - "9c38422213e30bff212b30c360d26f9a0213642&".to_string(), // Invalid char - ] - .to_vec() + invalid_info_hashes() } // When these infohashes are used in URL path params