tor-browser

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

lib.rs (5950B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use nsstring::{nsCString, nsString};
      6 use thin_vec::ThinVec;
      7 pub mod fragment_directive_impl;
      8 
      9 /// This struct contains the percent-decoded parts of a text directive.
     10 /// All parts besides `start` are optional (which is indicated by an empty string).
     11 ///
     12 /// This struct uses Gecko String types, whereas the parser internally uses Rust types.
     13 /// Therefore, conversion functions are provided.
     14 #[repr(C)]
     15 pub struct TextDirective {
     16    prefix: nsString,
     17    start: nsString,
     18    end: nsString,
     19    suffix: nsString,
     20 }
     21 
     22 impl TextDirective {
     23    /// Creates a `FragmentDirectiveElement` object from a `FragmentDirectiveElementInternal` object
     24    /// (which uses Rust string types).
     25    fn from_rust_type(element: &fragment_directive_impl::TextDirective) -> Self {
     26        Self {
     27            prefix: element
     28                .prefix()
     29                .as_ref()
     30                .map_or_else(nsString::new, |token| nsString::from(token.value())),
     31            start: element
     32                .start()
     33                .as_ref()
     34                .map_or_else(nsString::new, |token| nsString::from(token.value())),
     35            end: element
     36                .end()
     37                .as_ref()
     38                .map_or_else(nsString::new, |token| nsString::from(token.value())),
     39            suffix: element
     40                .suffix()
     41                .as_ref()
     42                .map_or_else(nsString::new, |token| nsString::from(token.value())),
     43        }
     44    }
     45 
     46    /// Converts the contents of this object into Rust types.
     47    /// Returns `None` if the given fragment is not valid.
     48    /// The only invalid condition is a fragment that is missing the `start` token.
     49    fn to_rust_type(&self) -> Option<fragment_directive_impl::TextDirective> {
     50        fragment_directive_impl::TextDirective::from_parts(
     51            self.prefix.to_string(),
     52            self.start.to_string(),
     53            self.end.to_string(),
     54            self.suffix.to_string(),
     55        )
     56    }
     57 }
     58 
     59 /// Result of the `parse_fragment_directive()` function.
     60 ///
     61 /// The result contains the original given URL without the fragment directive,
     62 /// a unsanitized string version of the extracted fragment directive,
     63 /// and an array of the parsed text directives.
     64 #[repr(C)]
     65 pub struct ParsedFragmentDirectiveResult {
     66    hash_without_fragment_directive: nsCString,
     67    fragment_directive: nsCString,
     68    text_directives: ThinVec<TextDirective>,
     69 }
     70 
     71 /// Parses the fragment directive from a given URL fragment.
     72 ///
     73 /// This function writes the result data into `result`.
     74 /// The result consists of
     75 ///   - the input url fragment without the fragment directive,
     76 ///   - the fragment directive as unparsed string,
     77 ///   - a list of the parsed and percent-decoded text directives.
     78 ///
     79 /// Directives which are unknown will be ignored.
     80 /// If new directive types are added in the future, they should also be considered here.
     81 /// This function returns false if no fragment directive is found. If there is any
     82 /// fragment directive (even if invalid), this function returns true.
     83 #[no_mangle]
     84 pub extern "C" fn parse_fragment_directive(
     85    hash: &nsCString,
     86    result: &mut ParsedFragmentDirectiveResult,
     87 ) -> bool {
     88    // sanitize inputs
     89    result.hash_without_fragment_directive = nsCString::new();
     90    result.fragment_directive = nsCString::new();
     91    result.text_directives.clear();
     92 
     93    let url_as_rust_string = hash.to_utf8();
     94    if let Some((stripped_hash, fragment_directive, text_directives)) =
     95        fragment_directive_impl::parse_fragment_directive_and_remove_it_from_hash(
     96            &url_as_rust_string,
     97        )
     98    {
     99        result
    100            .hash_without_fragment_directive
    101            .assign(&stripped_hash);
    102        result.fragment_directive.assign(&fragment_directive);
    103        result.text_directives.extend(
    104            text_directives
    105                .iter()
    106                .map(|text_directive| TextDirective::from_rust_type(text_directive)),
    107        );
    108        return true;
    109    }
    110    false
    111 }
    112 
    113 /// Creates a percent-encoded fragment directive string from a given list of `FragmentDirectiveElement`s.
    114 ///
    115 /// The returned string has this form:
    116 /// `:~:text=[prefix1-,]start1[,end1][,-suffix1]&text=[prefix2-,]start2[,end2][,-suffix2]`
    117 ///
    118 /// Invalid `FragmentDirectiveElement`s are ignored, where "invalid" means that no `start` token is provided.
    119 ///  If there are no valid `FragmentDirectiveElement`s, an empty string is returned.
    120 #[no_mangle]
    121 pub extern "C" fn create_fragment_directive(
    122    text_directives: &ThinVec<TextDirective>,
    123    fragment_directive: &mut nsCString,
    124 ) -> bool {
    125    let directives_rust = Vec::from_iter(
    126        text_directives
    127            .iter()
    128            .filter_map(|fragment| fragment.to_rust_type()),
    129    );
    130    if let Some(fragment_directive_rust) =
    131        fragment_directive_impl::create_fragment_directive_string(&directives_rust)
    132    {
    133        fragment_directive.assign(&fragment_directive_rust);
    134        return true;
    135    }
    136 
    137    false
    138 }
    139 
    140 /// Creates a percent-encoded text directive string for a single text directive.
    141 /// The returned string has the form `text=[prefix-,]start[,end][,-suffix]`.
    142 /// If the provided `TextDirective` is invalid (i.e. it has no `start` attribute),
    143 /// the outparam `directive_string` is empty and the function returns false.
    144 #[no_mangle]
    145 pub extern "C" fn create_text_directive(
    146    text_directive: &TextDirective,
    147    directive_string: &mut nsCString,
    148 ) -> bool {
    149    if let Some(text_directive_rust) = text_directive.to_rust_type() {
    150        if let Some(text_directive_string_rust) =
    151            fragment_directive_impl::create_text_directive_string(&text_directive_rust)
    152        {
    153            directive_string.assign(&text_directive_string_rust);
    154            return true;
    155        }
    156    }
    157    false
    158 }