@@ -21,72 +21,85 @@ pub enum AuthConfigError {
21
21
ParseError ( #[ from] netrc:: Error ) ,
22
22
}
23
23
24
- #[ derive( Debug , Eq ) ]
24
+ #[ derive( Debug , PartialEq , Eq ) ]
25
25
pub struct AuthUrl {
26
26
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 > ,
40
30
}
41
31
42
32
impl From < & str > for AuthUrl {
43
33
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;
60
54
}
61
55
}
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
+ }
62
63
}
63
64
}
64
65
65
66
impl From < & Url > for AuthUrl {
66
67
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;
72
71
}
73
72
74
- host_and_path. push_str ( value. path ( ) ) ;
75
-
76
73
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 ( ) ) ,
79
81
}
80
82
}
81
83
}
82
84
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
+ }
87
95
}
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
90
103
}
91
104
}
92
105
@@ -139,7 +152,91 @@ impl AuthConfig {
139
152
pub fn find ( & self , url : & str ) -> Option < & Authenticator > {
140
153
self . 0
141
154
. iter ( )
142
- . find ( |x| AuthUrl :: from ( url) == x . 0 )
155
+ . find ( |( x , _ ) | x . test ( & AuthUrl :: from ( url) ) )
143
156
. map ( |x| & x. 1 )
144
157
}
145
158
}
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