tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }