@@ -11,7 +11,7 @@ use std::fs::{self, File};
1111use std:: io:: { BufRead , BufReader , Read , Write } ;
1212use std:: net:: { SocketAddr , TcpListener , TcpStream } ;
1313use std:: path:: PathBuf ;
14- use std:: thread;
14+ use std:: thread:: { self , JoinHandle } ;
1515use tar:: { Builder , Header } ;
1616use url:: Url ;
1717
@@ -61,6 +61,8 @@ pub struct RegistryBuilder {
6161 alternative : Option < String > ,
6262 /// If set, the authorization token for the registry.
6363 token : Option < String > ,
64+ /// If set, the registry requires authorization for all operations.
65+ auth_required : bool ,
6466 /// If set, serves the index over http.
6567 http_index : bool ,
6668 /// If set, serves the API over http.
@@ -76,7 +78,7 @@ pub struct RegistryBuilder {
7678}
7779
7880pub struct TestRegistry {
79- _server : Option < HttpServerHandle > ,
81+ server : Option < HttpServerHandle > ,
8082 index_url : Url ,
8183 path : PathBuf ,
8284 api_url : Url ,
@@ -98,6 +100,17 @@ impl TestRegistry {
98100 . as_deref ( )
99101 . expect ( "registry was not configured with a token" )
100102 }
103+
104+ /// Shutdown the server thread and wait for it to stop.
105+ /// `Drop` automatically stops the server, but this additionally
106+ /// waits for the thread to stop.
107+ pub fn join ( self ) {
108+ if let Some ( mut server) = self . server {
109+ server. stop ( ) ;
110+ let handle = server. handle . take ( ) . unwrap ( ) ;
111+ handle. join ( ) . unwrap ( ) ;
112+ }
113+ }
101114}
102115
103116impl RegistryBuilder {
@@ -106,6 +119,7 @@ impl RegistryBuilder {
106119 RegistryBuilder {
107120 alternative : None ,
108121 token : None ,
122+ auth_required : false ,
109123 http_api : false ,
110124 http_index : false ,
111125 api : true ,
@@ -160,6 +174,14 @@ impl RegistryBuilder {
160174 self
161175 }
162176
177+ /// Sets this registry to require the authentication token for
178+ /// all operations.
179+ #[ must_use]
180+ pub fn auth_required ( mut self ) -> Self {
181+ self . auth_required = true ;
182+ self
183+ }
184+
163185 /// Operate the index over http
164186 #[ must_use]
165187 pub fn http_index ( mut self ) -> Self {
@@ -207,6 +229,7 @@ impl RegistryBuilder {
207229 registry_path. clone ( ) ,
208230 dl_path,
209231 token. clone ( ) ,
232+ self . auth_required ,
210233 self . custom_responders ,
211234 ) ;
212235 let index_url = if self . http_index {
@@ -226,7 +249,7 @@ impl RegistryBuilder {
226249 let registry = TestRegistry {
227250 api_url,
228251 index_url,
229- _server : server,
252+ server,
230253 dl_url,
231254 path : registry_path,
232255 token,
@@ -293,6 +316,11 @@ impl RegistryBuilder {
293316 }
294317 }
295318
319+ let auth = if self . auth_required {
320+ r#","auth-required":true"#
321+ } else {
322+ ""
323+ } ;
296324 let api = if self . api {
297325 format ! ( r#","api":"{}""# , registry. api_url)
298326 } else {
@@ -302,7 +330,7 @@ impl RegistryBuilder {
302330 repo ( & registry. path )
303331 . file (
304332 "config.json" ,
305- & format ! ( r#"{{"dl":"{}"{api}}}"# , registry. dl_url) ,
333+ & format ! ( r#"{{"dl":"{}"{api}{auth} }}"# , registry. dl_url) ,
306334 )
307335 . build ( ) ;
308336 fs:: create_dir_all ( api_path. join ( "api/v1/crates" ) ) . unwrap ( ) ;
@@ -442,6 +470,7 @@ pub fn alt_init() -> TestRegistry {
442470
443471pub struct HttpServerHandle {
444472 addr : SocketAddr ,
473+ handle : Option < JoinHandle < ( ) > > ,
445474}
446475
447476impl HttpServerHandle {
@@ -456,10 +485,8 @@ impl HttpServerHandle {
456485 pub fn dl_url ( & self ) -> Url {
457486 Url :: parse ( & format ! ( "http://{}/dl" , self . addr. to_string( ) ) ) . unwrap ( )
458487 }
459- }
460488
461- impl Drop for HttpServerHandle {
462- fn drop ( & mut self ) {
489+ fn stop ( & self ) {
463490 if let Ok ( mut stream) = TcpStream :: connect ( self . addr ) {
464491 // shutdown the server
465492 let _ = stream. write_all ( b"stop" ) ;
@@ -468,6 +495,12 @@ impl Drop for HttpServerHandle {
468495 }
469496}
470497
498+ impl Drop for HttpServerHandle {
499+ fn drop ( & mut self ) {
500+ self . stop ( ) ;
501+ }
502+ }
503+
471504/// Request to the test http server
472505#[ derive( Clone ) ]
473506pub struct Request {
@@ -504,6 +537,7 @@ pub struct HttpServer {
504537 registry_path : PathBuf ,
505538 dl_path : PathBuf ,
506539 token : Option < String > ,
540+ auth_required : bool ,
507541 custom_responders : HashMap < & ' static str , Box < dyn Send + Fn ( & Request , & HttpServer ) -> Response > > ,
508542}
509543
@@ -512,6 +546,7 @@ impl HttpServer {
512546 registry_path : PathBuf ,
513547 dl_path : PathBuf ,
514548 token : Option < String > ,
549+ auth_required : bool ,
515550 api_responders : HashMap <
516551 & ' static str ,
517552 Box < dyn Send + Fn ( & Request , & HttpServer ) -> Response > ,
@@ -524,10 +559,11 @@ impl HttpServer {
524559 registry_path,
525560 dl_path,
526561 token,
562+ auth_required,
527563 custom_responders : api_responders,
528564 } ;
529- thread:: spawn ( move || server. start ( ) ) ;
530- HttpServerHandle { addr }
565+ let handle = Some ( thread:: spawn ( move || server. start ( ) ) ) ;
566+ HttpServerHandle { addr, handle }
531567 }
532568
533569 fn start ( & self ) {
@@ -615,7 +651,7 @@ impl HttpServer {
615651 /// Route the request
616652 fn route ( & self , req : & Request ) -> Response {
617653 let authorized = |mutatation : bool | {
618- if mutatation {
654+ if mutatation || self . auth_required {
619655 self . token == req. authorization
620656 } else {
621657 assert ! ( req. authorization. is_none( ) , "unexpected token" ) ;
@@ -676,7 +712,9 @@ impl HttpServer {
676712 pub fn unauthorized ( & self , _req : & Request ) -> Response {
677713 Response {
678714 code : 401 ,
679- headers : vec ! [ ] ,
715+ headers : vec ! [
716+ r#"WWW-Authenticate: Cargo login_url="https://test-registry-login/me""# . to_string( ) ,
717+ ] ,
680718 body : b"Unauthorized message from server." . to_vec ( ) ,
681719 }
682720 }
0 commit comments