@@ -57,8 +57,10 @@ pub fn decode_share_link(link: &str) -> Result<Proxy, DecodeError> {
57
57
_ => return Err ( DecodeError :: UnknownScheme ) ,
58
58
} ;
59
59
60
- if let Some ( ( first_extra_key, _) ) = queries. pop_first ( ) {
61
- return Err ( DecodeError :: ExtraParameters ( first_extra_key. into ( ) ) ) ;
60
+ while let Some ( ( extra_key, extra_value) ) = queries. pop_first ( ) {
61
+ if !matches ! ( & * extra_value, "" | "none" | "false" | "off" | "original" ) {
62
+ return Err ( DecodeError :: ExtraParameters ( extra_key. into ( ) ) ) ;
63
+ }
62
64
}
63
65
64
66
Ok ( proxy)
@@ -67,10 +69,15 @@ pub fn decode_share_link(link: &str) -> Result<Proxy, DecodeError> {
67
69
pub ( super ) fn extract_name_from_frag ( url : & Url , dest : & DestinationAddr ) -> DecodeResult < String > {
68
70
Ok ( url
69
71
. fragment ( )
70
- . map ( |s| percent_decode_str ( s) . decode_utf8 ( ) )
72
+ . map ( |s| {
73
+ let mut decoded = percent_decode_str ( s) . decode_utf8 ( ) . map ( |s| s. into_owned ( ) ) ;
74
+ if !( s. contains ( ' ' ) || s. contains ( "%20" ) ) {
75
+ decoded = decoded. map ( |s| s. replace ( '+' , " " ) ) ;
76
+ }
77
+ decoded
78
+ } )
71
79
. transpose ( )
72
80
. map_err ( |_| DecodeError :: InvalidEncoding ) ?
73
- . map ( |s| s. into_owned ( ) )
74
81
. unwrap_or_else ( || dest. to_string ( ) ) )
75
82
}
76
83
@@ -108,7 +115,7 @@ mod tests {
108
115
const SS_LINK : & str =
"ss://[email protected] :36326#US-1.1.1.1-0842" ;
109
116
const TROJAN_LINK : & str =
110
117
"trojan://[email protected] :19201?security=tls#5228" ;
111
- const HTTP_LINK : & str = "http://127.0.0.1:8080" ;
118
+ const HTTP_LINK : & str = "http://127.0.0.1:8080?a=&b=none&c=false&d=off&e=original " ;
112
119
const HTTPS_LINK : & str = "https://127.0.0.1:8443" ;
113
120
const SOCKS5_LINK : & str = "socks5://127.0.0.1:8080" ;
114
121
const VMESS_LINK : & str = "vmess://eyJhZGQiOiIxMTQ1MTQubmlwLmlvIiwiYWlkIjoiMCIsImFscG4iOiIiLCJmcCI6IiIsImhvc3QiOiIxMTQuY29tIiwiaWQiOiIzMDFkODE1Zi1hMDJhLTRjMmMtYTQyNC1iMTZjZjBhMjQxYWUiLCJuZXQiOiJ3cyIsInBhdGgiOiIvMTEiLCJwb3J0IjoiODAiLCJwcyI6IlVQRF8zLjAyLjIwMjQiLCJzY3kiOiJhdXRvIiwic25pIjoiIiwidGxzIjoiIiwidHlwZSI6IiIsInYiOiIyIn0=" ;
@@ -160,14 +167,38 @@ mod tests {
160
167
161
168
#[ test]
162
169
fn test_extract_name_from_frag ( ) {
163
- let url = Url :: parse ( "ss://test#cabc%2fabca" ) . unwrap ( ) ;
170
+ let url = Url :: parse ( "ss://test#cabc%2fabc+a" ) . unwrap ( ) ;
171
+ let dest = DestinationAddr {
172
+ host : ytflow:: flow:: HostName :: from_domain_name ( "example.com" . into ( ) ) . unwrap ( ) ,
173
+ port : 1234 ,
174
+ } ;
175
+ assert_eq ! (
176
+ extract_name_from_frag( & url, & dest) . unwrap( ) ,
177
+ "cabc/abc a" . to_string( )
178
+ ) ;
179
+ }
180
+ #[ test]
181
+ fn test_extract_name_from_frag_percent_space ( ) {
182
+ let url = Url :: parse ( "ss://test#cabc+%20abc" ) . unwrap ( ) ;
183
+ let dest = DestinationAddr {
184
+ host : ytflow:: flow:: HostName :: from_domain_name ( "example.com" . into ( ) ) . unwrap ( ) ,
185
+ port : 1234 ,
186
+ } ;
187
+ assert_eq ! (
188
+ extract_name_from_frag( & url, & dest) . unwrap( ) ,
189
+ "cabc+ abc" . to_string( )
190
+ ) ;
191
+ }
192
+ #[ test]
193
+ fn test_extract_name_from_frag_space_space ( ) {
194
+ let url = Url :: parse ( "ss://test#cabc+ abc" ) . unwrap ( ) ;
164
195
let dest = DestinationAddr {
165
196
host : ytflow:: flow:: HostName :: from_domain_name ( "example.com" . into ( ) ) . unwrap ( ) ,
166
197
port : 1234 ,
167
198
} ;
168
199
assert_eq ! (
169
200
extract_name_from_frag( & url, & dest) . unwrap( ) ,
170
- "cabc/abca " . to_string( )
201
+ "cabc+ abc " . to_string( )
171
202
) ;
172
203
}
173
204
0 commit comments