@@ -21,72 +21,85 @@ pub enum AuthConfigError {
2121 ParseError ( #[ from] netrc:: Error ) ,
2222}
2323
24- #[ derive( Debug , Eq ) ]
24+ #[ derive( Debug , PartialEq , Eq ) ]
2525pub struct AuthUrl {
2626 schema : Option < String > ,
27- host_and_path : String ,
28- }
29-
30- impl AuthUrl {
31- fn drop_suffix ( & self ) -> & str {
32- let mut res = self . host_and_path . as_str ( ) ;
33-
34- while let Some ( x) = res. strip_suffix ( '/' ) {
35- res = x;
36- }
37-
38- res
39- }
27+ host : String ,
28+ port : Option < u16 > ,
29+ path : Option < String > ,
4030}
4131
4232impl From < & str > for AuthUrl {
4333 fn from ( value : & str ) -> Self {
44- if let Ok ( url) = Url :: parse ( value) {
45- AuthUrl {
46- schema : Some ( url. scheme ( ) . to_string ( ) ) ,
47- host_and_path : {
48- let mut s = String :: new ( ) ;
49- if let Some ( host) = url. host_str ( ) {
50- s. push_str ( host) ;
51- }
52- s. push_str ( url. path ( ) ) ;
53- s
54- } ,
55- }
56- } else {
57- AuthUrl {
58- schema : None ,
59- host_and_path : value. to_string ( ) ,
34+ // extract schema
35+ let ( schema, host_port_path) = value. split_once ( "://" ) . unzip ( ) ;
36+ let host_port_path = host_port_path. unwrap_or ( value) ;
37+
38+ // extract path
39+ let ( host_port, mut path) = host_port_path. split_once ( "/" ) . unzip ( ) ;
40+ let host_port = host_port. unwrap_or ( host_port_path) ;
41+
42+ // extract port
43+ let ( host, port) = host_port. split_once ( ":" ) . unzip ( ) ;
44+ let host = host. unwrap_or ( host_port) ;
45+ let ( host, port) = port
46+ . and_then ( |port| port. parse :: < u16 > ( ) . ok ( ) )
47+ . map ( |port| ( host, Some ( port) ) )
48+ . unwrap_or ( ( host_port, None ) ) ;
49+
50+ // strip suffix
51+ if let Some ( path) = & mut path {
52+ while let Some ( x) = path. strip_suffix ( '/' ) {
53+ * path = x;
6054 }
6155 }
56+
57+ Self {
58+ schema : schema. map ( |schema| schema. to_string ( ) ) ,
59+ host : host. to_string ( ) ,
60+ port,
61+ path : path. map ( |path| path. to_string ( ) ) ,
62+ }
6263 }
6364}
6465
6566impl From < & Url > for AuthUrl {
6667 fn from ( value : & Url ) -> Self {
67- let mut host_and_path = String :: new ( ) ;
68- let schema = value. scheme ( ) . to_string ( ) ;
69-
70- if let Some ( host) = value. host_str ( ) {
71- host_and_path. push_str ( host) ;
68+ let mut path = value. path ( ) ;
69+ while let Some ( x) = path. strip_suffix ( '/' ) {
70+ path = x;
7271 }
7372
74- host_and_path. push_str ( value. path ( ) ) ;
75-
7673 AuthUrl {
77- schema : Some ( schema) ,
78- host_and_path,
74+ schema : Some ( value. scheme ( ) . to_string ( ) ) ,
75+ host : value
76+ . host ( )
77+ . map ( |host| host. to_string ( ) )
78+ . unwrap_or_default ( ) ,
79+ port : value. port_or_known_default ( ) ,
80+ path : Some ( path. to_string ( ) ) ,
7981 }
8082 }
8183}
8284
83- impl PartialEq for AuthUrl {
84- fn eq ( & self , other : & Self ) -> bool {
85- if let Some ( ( a, b) ) = self . schema . as_ref ( ) . zip ( other. schema . as_ref ( ) ) {
86- return a == b && self . drop_suffix ( ) == other. drop_suffix ( ) ;
85+ impl AuthUrl {
86+ fn test ( & self , other : & Self ) -> bool {
87+ if let Some ( a) = & other. schema {
88+ if let Some ( b) = & self . schema {
89+ if a != b {
90+ return false ;
91+ }
92+ } else if a != "https" && a != "tor+https" {
93+ return false ;
94+ }
8795 }
88-
89- self . drop_suffix ( ) == other. drop_suffix ( )
96+ if self . port . is_some ( ) && other. port . is_some ( ) && self . port != other. port {
97+ return false ;
98+ }
99+ if self . path . is_some ( ) && other. path . is_some ( ) && self . path != other. path {
100+ return false ;
101+ }
102+ self . host == other. host
90103 }
91104}
92105
@@ -139,7 +152,91 @@ impl AuthConfig {
139152 pub fn find ( & self , url : & str ) -> Option < & Authenticator > {
140153 self . 0
141154 . iter ( )
142- . find ( |x| AuthUrl :: from ( url) == x . 0 )
155+ . find ( |( x , _ ) | x . test ( & AuthUrl :: from ( url) ) )
143156 . map ( |x| & x. 1 )
144157 }
145158}
159+
160+ #[ cfg( test) ]
161+ mod test {
162+ use crate :: * ;
163+
164+ #[ test]
165+ fn test_auth_parse ( ) {
166+ assert_eq ! (
167+ AuthUrl :: from( "localhost" ) ,
168+ AuthUrl {
169+ schema: None ,
170+ host: "localhost" . to_string( ) ,
171+ port: None ,
172+ path: None
173+ }
174+ ) ;
175+ assert_eq ! (
176+ AuthUrl :: from( "localhost:1234" ) ,
177+ AuthUrl {
178+ schema: None ,
179+ host: "localhost" . to_string( ) ,
180+ port: Some ( 1234 ) ,
181+ path: None
182+ }
183+ ) ;
184+ assert_eq ! (
185+ AuthUrl :: from( "ftp://localhost" ) ,
186+ AuthUrl {
187+ schema: Some ( "ftp" . to_string( ) ) ,
188+ host: "localhost" . to_string( ) ,
189+ port: None ,
190+ path: None
191+ }
192+ ) ;
193+ assert_eq ! (
194+ AuthUrl :: from( "ftp://localhost:123/something" ) ,
195+ AuthUrl {
196+ schema: Some ( "ftp" . to_string( ) ) ,
197+ host: "localhost" . to_string( ) ,
198+ port: Some ( 123 ) ,
199+ path: Some ( "something" . to_string( ) )
200+ }
201+ ) ;
202+ assert_eq ! (
203+ AuthUrl :: from( "ftp://localhost:123/something///" ) ,
204+ AuthUrl {
205+ schema: Some ( "ftp" . to_string( ) ) ,
206+ host: "localhost" . to_string( ) ,
207+ port: Some ( 123 ) ,
208+ path: Some ( "something" . to_string( ) )
209+ }
210+ ) ;
211+ }
212+
213+ #[ test]
214+ fn test_auth_match ( ) {
215+ assert ! ( AuthUrl :: from( "localhost" ) . test( & AuthUrl :: from( "localhost" ) ) ) ;
216+ assert ! ( !AuthUrl :: from( "localhost" ) . test( & AuthUrl :: from( "ten.avaj" ) ) ) ;
217+
218+ assert ! ( AuthUrl :: from( "localhost" ) . test( & AuthUrl :: from( "https://localhost" ) ) ) ;
219+ assert ! ( AuthUrl :: from( "https://localhost" ) . test( & AuthUrl :: from( "https://localhost" ) ) ) ;
220+ assert ! ( AuthUrl :: from( "localhost" ) . test( & AuthUrl :: from( "tor+https://localhost" ) ) ) ;
221+ assert ! ( !AuthUrl :: from( "localhost" )
222+ . test( & AuthUrl :: from( "aosctexttransferprotocol://localhost" ) ) ) ;
223+ assert ! ( AuthUrl :: from( "attp://localhost" ) . test( & AuthUrl :: from( "attp://localhost" ) ) ) ;
224+ assert ! ( !AuthUrl :: from( "attp://localhost" ) . test( & AuthUrl :: from( "http://localhost" ) ) ) ;
225+
226+ assert ! ( AuthUrl :: from( "localhost" ) . test( & AuthUrl :: from( "https://localhost:456" ) ) ) ;
227+ assert ! ( !AuthUrl :: from( "localhost:123" ) . test( & AuthUrl :: from( "https://localhost:456" ) ) ) ;
228+ assert ! ( AuthUrl :: from( "localhost:123" ) . test( & AuthUrl :: from( "https://localhost:123" ) ) ) ;
229+
230+ assert ! (
231+ AuthUrl :: from( "localhost:123/foo" ) . test( & AuthUrl :: from( "https://localhost:123/foo" ) )
232+ ) ;
233+ assert ! (
234+ AuthUrl :: from( "localhost:123/bar" ) . test( & AuthUrl :: from( "https://localhost:123/bar" ) )
235+ ) ;
236+ assert ! (
237+ !AuthUrl :: from( "localhost:123/foo" ) . test( & AuthUrl :: from( "https://localhost:123/bar" ) )
238+ ) ;
239+ assert ! ( AuthUrl :: from( "localhost:123" ) . test( & AuthUrl :: from( "https://localhost:123/bar" ) ) ) ;
240+ assert ! ( AuthUrl :: from( "localhost:123" ) . test( & AuthUrl :: from( "https://localhost:123/foo" ) ) ) ;
241+ }
242+ }
0 commit comments