@@ -12,7 +12,6 @@ use std::sync::Arc;
12
12
13
13
use bittorrent_http_tracker_protocol:: v1:: requests:: scrape:: Scrape ;
14
14
use bittorrent_http_tracker_protocol:: v1:: services:: peer_ip_resolver:: { self , ClientIpSources , PeerIpResolutionError } ;
15
- use bittorrent_primitives:: info_hash:: InfoHash ;
16
15
use bittorrent_tracker_core:: authentication:: service:: AuthenticationService ;
17
16
use bittorrent_tracker_core:: authentication:: { self , Key } ;
18
17
use bittorrent_tracker_core:: error:: { ScrapeError , TrackerCoreError , WhitelistError } ;
@@ -63,6 +62,9 @@ impl ScrapeService {
63
62
64
63
/// Handles a scrape request.
65
64
///
65
+ /// When the peer is not authenticated and the tracker is running in `private`
66
+ /// mode, the tracker returns empty stats for all the torrents.
67
+ ///
66
68
/// # Errors
67
69
///
68
70
/// This function will return an error if:
@@ -74,67 +76,43 @@ impl ScrapeService {
74
76
client_ip_sources : & ClientIpSources ,
75
77
maybe_key : Option < Key > ,
76
78
) -> Result < ScrapeData , HttpScrapeError > {
77
- // Authentication
78
- let return_fake_scrape_data = if self . core_config . private {
79
- match maybe_key {
80
- Some ( key) => match self . authentication_service . authenticate ( & key) . await {
81
- Ok ( ( ) ) => false ,
82
- Err ( _error) => true ,
83
- } ,
84
- None => true ,
85
- }
79
+ let scrape_data = if self . authentication_is_required ( ) && !self . is_authenticated ( maybe_key) . await {
80
+ ScrapeData :: zeroed ( & scrape_request. info_hashes )
86
81
} else {
87
- false
82
+ self . scrape_handler . scrape ( & scrape_request . info_hashes ) . await ?
88
83
} ;
89
84
90
- // Authorization for scrape requests is handled at the `bittorrent_tracker_core`
91
- // level for each torrent.
85
+ let remote_client_ip = self . resolve_remote_client_ip ( client_ip_sources) ?;
92
86
93
- let peer_ip = match peer_ip_resolver:: invoke ( self . core_config . net . on_reverse_proxy , client_ip_sources) {
94
- Ok ( peer_ip) => peer_ip,
95
- Err ( error) => return Err ( error. into ( ) ) ,
96
- } ;
87
+ self . send_stats_event ( & remote_client_ip) . await ;
97
88
98
- if return_fake_scrape_data {
99
- return Ok ( fake ( & self . opt_http_stats_event_sender , & scrape_request. info_hashes , & peer_ip) . await ) ;
100
- }
89
+ Ok ( scrape_data)
90
+ }
101
91
102
- let scrape_data = self . scrape_handler . scrape ( & scrape_request. info_hashes ) . await ?;
92
+ fn authentication_is_required ( & self ) -> bool {
93
+ self . core_config . private
94
+ }
103
95
104
- send_scrape_event ( & peer_ip, & self . opt_http_stats_event_sender ) . await ;
96
+ async fn is_authenticated ( & self , maybe_key : Option < Key > ) -> bool {
97
+ if let Some ( key) = maybe_key {
98
+ return self . authentication_service . authenticate ( & key) . await . is_ok ( ) ;
99
+ }
105
100
106
- Ok ( scrape_data )
101
+ false
107
102
}
108
- }
109
103
110
- /// The HTTP tracker fake `scrape` service. It returns zeroed stats.
111
- ///
112
- /// When the peer is not authenticated and the tracker is running in `private` mode,
113
- /// the tracker returns empty stats for all the torrents.
114
- ///
115
- /// > **NOTICE**: tracker statistics are not updated in this case.
116
- pub async fn fake (
117
- opt_http_stats_event_sender : & Arc < Option < Box < dyn statistics:: event:: sender:: Sender > > > ,
118
- info_hashes : & Vec < InfoHash > ,
119
- original_peer_ip : & IpAddr ,
120
- ) -> ScrapeData {
121
- send_scrape_event ( original_peer_ip, opt_http_stats_event_sender) . await ;
122
-
123
- ScrapeData :: zeroed ( info_hashes)
124
- }
104
+ /// Resolves the client's real IP address considering proxy headers.
105
+ fn resolve_remote_client_ip ( & self , client_ip_sources : & ClientIpSources ) -> Result < IpAddr , PeerIpResolutionError > {
106
+ peer_ip_resolver:: invoke ( self . core_config . net . on_reverse_proxy , client_ip_sources)
107
+ }
125
108
126
- async fn send_scrape_event (
127
- original_peer_ip : & IpAddr ,
128
- opt_http_stats_event_sender : & Arc < Option < Box < dyn statistics:: event:: sender:: Sender > > > ,
129
- ) {
130
- if let Some ( http_stats_event_sender) = opt_http_stats_event_sender. as_deref ( ) {
131
- match original_peer_ip {
132
- IpAddr :: V4 ( _) => {
133
- http_stats_event_sender. send_event ( statistics:: event:: Event :: Tcp4Scrape ) . await ;
134
- }
135
- IpAddr :: V6 ( _) => {
136
- http_stats_event_sender. send_event ( statistics:: event:: Event :: Tcp6Scrape ) . await ;
137
- }
109
+ async fn send_stats_event ( & self , original_peer_ip : & IpAddr ) {
110
+ if let Some ( http_stats_event_sender) = self . opt_http_stats_event_sender . as_deref ( ) {
111
+ let event = match original_peer_ip {
112
+ IpAddr :: V4 ( _) => statistics:: event:: Event :: Tcp4Scrape ,
113
+ IpAddr :: V6 ( _) => statistics:: event:: Event :: Tcp6Scrape ,
114
+ } ;
115
+ http_stats_event_sender. send_event ( event) . await ;
138
116
}
139
117
}
140
118
}
@@ -211,7 +189,6 @@ mod tests {
211
189
use tokio:: sync:: mpsc:: error:: SendError ;
212
190
use torrust_tracker_configuration:: Configuration ;
213
191
use torrust_tracker_primitives:: { peer, DurationSinceUnixEpoch } ;
214
- use torrust_tracker_test_helpers:: configuration;
215
192
216
193
use crate :: statistics;
217
194
use crate :: tests:: sample_info_hash;
@@ -222,10 +199,6 @@ mod tests {
222
199
authentication_service : Arc < AuthenticationService > ,
223
200
}
224
201
225
- fn initialize_services_for_public_tracker ( ) -> Container {
226
- initialize_services_with_configuration ( & configuration:: ephemeral_public ( ) )
227
- }
228
-
229
202
fn initialize_services_with_configuration ( config : & Configuration ) -> Container {
230
203
let database = initialize_database ( & config. core ) ;
231
204
let in_memory_whitelist = Arc :: new ( InMemoryWhitelist :: default ( ) ) ;
@@ -436,28 +409,34 @@ mod tests {
436
409
use std:: net:: { IpAddr , Ipv4Addr , Ipv6Addr } ;
437
410
use std:: sync:: Arc ;
438
411
412
+ use bittorrent_http_tracker_protocol:: v1:: requests:: scrape:: Scrape ;
413
+ use bittorrent_http_tracker_protocol:: v1:: services:: peer_ip_resolver:: ClientIpSources ;
439
414
use bittorrent_tracker_core:: announce_handler:: PeersWanted ;
440
415
use mockall:: predicate:: eq;
441
416
use torrust_tracker_primitives:: core:: ScrapeData ;
417
+ use torrust_tracker_test_helpers:: configuration;
442
418
443
- use crate :: services:: scrape:: fake;
444
419
use crate :: services:: scrape:: tests:: {
445
- initialize_services_for_public_tracker , sample_info_hashes, sample_peer, MockHttpStatsEventSender ,
420
+ initialize_services_with_configuration , sample_info_hashes, sample_peer, MockHttpStatsEventSender ,
446
421
} ;
422
+ use crate :: services:: scrape:: ScrapeService ;
447
423
use crate :: statistics;
448
424
use crate :: tests:: sample_info_hash;
449
425
450
426
#[ tokio:: test]
451
- async fn it_should_always_return_the_zeroed_scrape_data_for_a_torrent ( ) {
427
+ async fn it_should_return_the_zeroed_scrape_data_when_the_tracker_is_running_in_private_mode_and_the_peer_is_not_authenticated (
428
+ ) {
429
+ let config = configuration:: ephemeral_private ( ) ;
430
+
431
+ let container = initialize_services_with_configuration ( & config) ;
432
+
452
433
let ( http_stats_event_sender, _http_stats_repository) = statistics:: setup:: factory ( false ) ;
453
434
let http_stats_event_sender = Arc :: new ( http_stats_event_sender) ;
454
435
455
- let container = initialize_services_for_public_tracker ( ) ;
456
-
457
436
let info_hash = sample_info_hash ( ) ;
458
437
let info_hashes = vec ! [ info_hash] ;
459
438
460
- // Announce a new peer to force scrape data to contain not zeroed data
439
+ // Announce a new peer to force scrape data to contain non zeroed data
461
440
let mut peer = sample_peer ( ) ;
462
441
let original_peer_ip = peer. ip ( ) ;
463
442
container
@@ -466,7 +445,26 @@ mod tests {
466
445
. await
467
446
. unwrap ( ) ;
468
447
469
- let scrape_data = fake ( & http_stats_event_sender, & info_hashes, & original_peer_ip) . await ;
448
+ let scrape_request = Scrape {
449
+ info_hashes : sample_info_hashes ( ) ,
450
+ } ;
451
+
452
+ let client_ip_sources = ClientIpSources {
453
+ right_most_x_forwarded_for : None ,
454
+ connection_info_ip : Some ( original_peer_ip) ,
455
+ } ;
456
+
457
+ let scrape_service = Arc :: new ( ScrapeService :: new (
458
+ Arc :: new ( config. core ) ,
459
+ container. scrape_handler . clone ( ) ,
460
+ container. authentication_service . clone ( ) ,
461
+ http_stats_event_sender. clone ( ) ,
462
+ ) ) ;
463
+
464
+ let scrape_data = scrape_service
465
+ . handle_scrape ( & scrape_request, & client_ip_sources, None )
466
+ . await
467
+ . unwrap ( ) ;
470
468
471
469
let expected_scrape_data = ScrapeData :: zeroed ( & info_hashes) ;
472
470
@@ -475,6 +473,10 @@ mod tests {
475
473
476
474
#[ tokio:: test]
477
475
async fn it_should_send_the_tcp_4_scrape_event_when_the_peer_uses_ipv4 ( ) {
476
+ let config = configuration:: ephemeral ( ) ;
477
+
478
+ let container = initialize_services_with_configuration ( & config) ;
479
+
478
480
let mut http_stats_event_sender_mock = MockHttpStatsEventSender :: new ( ) ;
479
481
http_stats_event_sender_mock
480
482
. expect_send_event ( )
@@ -486,11 +488,34 @@ mod tests {
486
488
487
489
let peer_ip = IpAddr :: V4 ( Ipv4Addr :: new ( 126 , 0 , 0 , 1 ) ) ;
488
490
489
- fake ( & http_stats_event_sender, & sample_info_hashes ( ) , & peer_ip) . await ;
491
+ let scrape_request = Scrape {
492
+ info_hashes : sample_info_hashes ( ) ,
493
+ } ;
494
+
495
+ let client_ip_sources = ClientIpSources {
496
+ right_most_x_forwarded_for : None ,
497
+ connection_info_ip : Some ( peer_ip) ,
498
+ } ;
499
+
500
+ let scrape_service = Arc :: new ( ScrapeService :: new (
501
+ Arc :: new ( config. core ) ,
502
+ container. scrape_handler . clone ( ) ,
503
+ container. authentication_service . clone ( ) ,
504
+ http_stats_event_sender. clone ( ) ,
505
+ ) ) ;
506
+
507
+ scrape_service
508
+ . handle_scrape ( & scrape_request, & client_ip_sources, None )
509
+ . await
510
+ . unwrap ( ) ;
490
511
}
491
512
492
513
#[ tokio:: test]
493
514
async fn it_should_send_the_tcp_6_scrape_event_when_the_peer_uses_ipv6 ( ) {
515
+ let config = configuration:: ephemeral ( ) ;
516
+
517
+ let container = initialize_services_with_configuration ( & config) ;
518
+
494
519
let mut http_stats_event_sender_mock = MockHttpStatsEventSender :: new ( ) ;
495
520
http_stats_event_sender_mock
496
521
. expect_send_event ( )
@@ -502,7 +527,26 @@ mod tests {
502
527
503
528
let peer_ip = IpAddr :: V6 ( Ipv6Addr :: new ( 0x6969 , 0x6969 , 0x6969 , 0x6969 , 0x6969 , 0x6969 , 0x6969 , 0x6969 ) ) ;
504
529
505
- fake ( & http_stats_event_sender, & sample_info_hashes ( ) , & peer_ip) . await ;
530
+ let scrape_request = Scrape {
531
+ info_hashes : sample_info_hashes ( ) ,
532
+ } ;
533
+
534
+ let client_ip_sources = ClientIpSources {
535
+ right_most_x_forwarded_for : None ,
536
+ connection_info_ip : Some ( peer_ip) ,
537
+ } ;
538
+
539
+ let scrape_service = Arc :: new ( ScrapeService :: new (
540
+ Arc :: new ( config. core ) ,
541
+ container. scrape_handler . clone ( ) ,
542
+ container. authentication_service . clone ( ) ,
543
+ http_stats_event_sender. clone ( ) ,
544
+ ) ) ;
545
+
546
+ scrape_service
547
+ . handle_scrape ( & scrape_request, & client_ip_sources, None )
548
+ . await
549
+ . unwrap ( ) ;
506
550
}
507
551
}
508
552
}
0 commit comments