lib.rs (9443B)
1 /* -*- Mode: rust; rust-indent-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 extern crate urlpattern; 7 use urlpattern::quirks as Uq; 8 9 extern crate nsstring; 10 use nsstring::nsACString; 11 use nsstring::nsCString; 12 use thin_vec::ThinVec; 13 14 mod helpers; 15 use helpers::*; 16 17 pub mod base; 18 use base::*; 19 20 use log::debug; 21 22 #[no_mangle] 23 pub extern "C" fn urlp_parse_pattern_from_string( 24 input: *const nsACString, 25 base_url: *const nsACString, 26 options: UrlpOptions, 27 res: *mut UrlpPattern, 28 ) -> bool { 29 debug!("urlp_parse_pattern_from_string()"); 30 let init = if let Some(init) = init_from_string_and_base_url(input, base_url) { 31 init 32 } else { 33 return false; 34 }; 35 36 if let Ok(pattern) = Uq::parse_pattern(init, options.into()) { 37 unsafe { 38 *res = UrlpPattern(Box::into_raw(Box::new(pattern)) as *mut _); 39 } 40 return true; 41 } 42 false 43 } 44 45 #[no_mangle] 46 pub unsafe extern "C" fn urlp_parse_pattern_from_init( 47 init: &UrlpInit, 48 options: UrlpOptions, 49 res: *mut UrlpPattern, 50 ) -> bool { 51 debug!("urlp_parse_pattern_from_init()"); 52 if let Ok(pattern) = Uq::parse_pattern(init.into(), options.into()) { 53 *res = UrlpPattern(Box::into_raw(Box::new(pattern)) as *mut _); 54 return true; 55 } 56 false 57 } 58 59 #[no_mangle] 60 pub unsafe extern "C" fn urlp_pattern_free(pattern: UrlpPattern) { 61 drop(Box::from_raw(pattern.0 as *mut Uq::UrlPattern)); 62 } 63 64 #[no_mangle] 65 pub unsafe extern "C" fn urlp_get_protocol_component( 66 pattern: UrlpPattern, 67 res: *mut UrlpComponent, 68 ) { 69 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 70 let tmp: UrlpComponent = q_pattern.protocol.clone().into(); 71 *res = tmp; 72 } 73 74 #[no_mangle] 75 pub unsafe extern "C" fn urlp_get_username_component( 76 pattern: UrlpPattern, 77 res: *mut UrlpComponent, 78 ) { 79 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 80 let tmp: UrlpComponent = q_pattern.username.clone().into(); 81 *res = tmp; 82 } 83 84 #[no_mangle] 85 pub unsafe extern "C" fn urlp_get_password_component( 86 pattern: UrlpPattern, 87 res: *mut UrlpComponent, 88 ) { 89 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 90 let tmp: UrlpComponent = q_pattern.password.clone().into(); 91 *res = tmp; 92 } 93 94 #[no_mangle] 95 pub unsafe extern "C" fn urlp_get_hostname_component( 96 pattern: UrlpPattern, 97 res: *mut UrlpComponent, 98 ) { 99 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 100 let tmp: UrlpComponent = q_pattern.hostname.clone().into(); 101 *res = tmp; 102 } 103 104 #[no_mangle] 105 pub unsafe extern "C" fn urlp_get_port_component(pattern: UrlpPattern, res: *mut UrlpComponent) { 106 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 107 let tmp: UrlpComponent = q_pattern.port.clone().into(); 108 *res = tmp; 109 } 110 111 #[no_mangle] 112 pub unsafe extern "C" fn urlp_get_pathname_component( 113 pattern: UrlpPattern, 114 res: *mut UrlpComponent, 115 ) { 116 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 117 let tmp: UrlpComponent = q_pattern.pathname.clone().into(); 118 *res = tmp; 119 } 120 121 #[no_mangle] 122 pub unsafe extern "C" fn urlp_get_search_component(pattern: UrlpPattern, res: *mut UrlpComponent) { 123 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 124 let tmp: UrlpComponent = q_pattern.search.clone().into(); 125 *res = tmp; 126 } 127 128 #[no_mangle] 129 pub unsafe extern "C" fn urlp_get_hash_component(pattern: UrlpPattern, res: *mut UrlpComponent) { 130 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 131 let tmp: UrlpComponent = q_pattern.hash.clone().into(); 132 *res = tmp; 133 } 134 135 #[no_mangle] 136 pub unsafe extern "C" fn urlp_get_has_regexp_groups(pattern: UrlpPattern) -> bool { 137 let q_pattern = &*(pattern.0 as *const Uq::UrlPattern); 138 q_pattern.has_regexp_groups 139 } 140 141 // note: the ThinVec<MaybeString> is being returned as an out-param 142 // because if you attempt to return the vector in the normal way 143 // we end up with an incongruent ABI layout between C++ and rust 144 // which re-orders the input parameter pointers such that we cannot reference them 145 // by address reliably. 146 // Ie. ThinVec/nsTArray is a non-trivial for the purpose of calls 147 // so we use an out-param instead. We see similar patterns elsewhere in this file 148 // for return values on the C++/rust ffi boundary 149 #[no_mangle] 150 pub extern "C" fn urlp_matcher_matches_component( 151 matcher: &UrlpMatcher, 152 input: &nsACString, 153 ignore_case: bool, 154 res: &mut ThinVec<MaybeString>, 155 ) -> bool { 156 debug!("urlp_matcher_matches_component()"); 157 let q_matcher: Uq::Matcher = matcher.clone().into(); 158 let i: &str = &input.to_string(); 159 let matches = matcher_matches(&q_matcher, i, ignore_case); 160 if let Some(inner_vec) = matches { 161 for item in inner_vec { 162 match item { 163 Some(s) => { 164 res.push(MaybeString { 165 string: s.into(), 166 valid: true, 167 }); 168 } 169 None => { 170 res.push(MaybeString { 171 string: nsCString::from(""), 172 valid: false, 173 }); 174 } 175 } 176 } 177 true 178 } else { 179 false 180 } 181 } 182 183 // note: can't return Result<Option<...>> since cbindgen doesn't handle well 184 // so we need to return a type that can be used in C++ and rust 185 #[no_mangle] 186 pub extern "C" fn urlp_process_match_input_from_string( 187 url_str: *const nsACString, 188 base_url: *const nsACString, 189 res: *mut UrlpMatchInputAndInputs, 190 ) -> bool { 191 debug!("urlp_process_match_input_from_string()"); 192 if let Some(url) = unsafe { url_str.as_ref().map(|x| x.to_utf8().into_owned()) } { 193 let str_or_init = Uq::StringOrInit::String(url); 194 let maybe_base_url = if base_url.is_null() { 195 None 196 } else { 197 let x = unsafe { (*base_url).as_str_unchecked() }; 198 Some(x) 199 }; 200 201 let match_input_and_inputs = Uq::process_match_input(str_or_init, maybe_base_url); 202 if let Ok(Some(tuple_struct)) = match_input_and_inputs { 203 // parse "input" 204 let match_input = tuple_struct.0; 205 let maybe_match_input = Uq::parse_match_input(match_input); 206 207 if maybe_match_input.is_none() { 208 return false; 209 } 210 211 // convert "inputs" 212 let tuple_soi_and_string = tuple_struct.1; 213 let string = match tuple_soi_and_string.0 { 214 Uq::StringOrInit::String(x) => x, 215 _ => { 216 assert!( 217 false, 218 "Pulling init out of StringOrInit shouldn't happen in _from_string" 219 ); 220 return false; 221 } 222 }; 223 let base = match tuple_soi_and_string.1 { 224 Some(x) => MaybeString::new(&nsCString::from(x)), 225 _ => MaybeString::none(), 226 }; 227 let tmp = UrlpMatchInputAndInputs { 228 input: maybe_match_input.unwrap().into(), 229 inputs: UrlpInput { 230 string_or_init_type: UrlpStringOrInitType::String, 231 str: nsCString::from(string), 232 init: UrlpInit::none(), 233 base, 234 }, 235 }; 236 unsafe { *res = tmp }; 237 return true; 238 } else { 239 return false; 240 } 241 } 242 false 243 } 244 245 #[no_mangle] 246 pub extern "C" fn urlp_process_match_input_from_init( 247 init: &UrlpInit, 248 base_url: *const nsACString, 249 res: *mut UrlpMatchInputAndInputs, 250 ) -> bool { 251 debug!("urlp_process_match_input_from_init()"); 252 let q_init = init.into(); 253 let str_or_init = Uq::StringOrInit::Init(q_init); 254 255 let maybe_base_url = if base_url.is_null() { 256 None 257 } else { 258 Some(unsafe { (*base_url).as_str_unchecked() }) 259 }; 260 let match_input_and_inputs = Uq::process_match_input(str_or_init, maybe_base_url); 261 // an empty string passed to base_url will cause url-parsing failure 262 // in process_match_input, which we handle here 263 if let Ok(Some(tuple_struct)) = match_input_and_inputs { 264 let match_input = tuple_struct.0; 265 let maybe_match_input = Uq::parse_match_input(match_input); 266 if maybe_match_input.is_none() { 267 return false; 268 } 269 let tuple_soi_and_string = tuple_struct.1; 270 let init = match tuple_soi_and_string.0 { 271 Uq::StringOrInit::Init(x) => x, 272 _ => { 273 assert!( 274 false, 275 "Pulling string out of StringOrInit shouldn't happen in _from_init" 276 ); 277 return false; 278 } 279 }; 280 281 let base = match tuple_soi_and_string.1 { 282 Some(x) => MaybeString::new(&nsCString::from(x)), 283 _ => MaybeString::none(), 284 }; 285 286 let tmp = UrlpMatchInputAndInputs { 287 input: maybe_match_input.unwrap().into(), 288 inputs: UrlpInput { 289 string_or_init_type: UrlpStringOrInitType::Init, 290 str: nsCString::new(), 291 init: init.into(), 292 base, 293 }, 294 }; 295 unsafe { *res = tmp }; 296 return true; 297 } else { 298 return false; 299 } 300 }