diff --git a/Cargo.lock b/Cargo.lock index 2b23503bd817..fd1932ee6c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -611,7 +611,6 @@ version = "0.1.0" dependencies = [ "nserror", "nsstring", - "rental", "rust_cascade", "thin-vec", "xpcom", @@ -632,12 +631,9 @@ dependencies = [ "crossbeam-utils 0.8.6", "cstr", "log", - "malloc_size_of_derive", - "memmap2 0.3.1", "moz_task", "nserror", "nsstring", - "rental", "rkv", "rust_cascade", "sha2", @@ -4431,9 +4427,9 @@ checksum = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263" [[package]] name = "rust_cascade" -version = "0.6.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5b9bba8f5b985e4923dadd273a987f83669083f3355d65c699e02b9d3d854d" +checksum = "d09c17a9310f1eb79a67d307adffa7fa1c5943eaadcc21d4fb7f611536d66c4f" dependencies = [ "byteorder", "digest", diff --git a/security/manager/ssl/cert_storage/Cargo.toml b/security/manager/ssl/cert_storage/Cargo.toml index b29d252eaa2e..4e66f0233ed6 100644 --- a/security/manager/ssl/cert_storage/Cargo.toml +++ b/security/manager/ssl/cert_storage/Cargo.toml @@ -9,18 +9,15 @@ byteorder = "1.2.7" crossbeam-utils = "0.8" cstr = "0.2" log = "0.4" -memmap2 = "0.3" moz_task = { path = "../../../../xpcom/rust/moz_task" } nserror = { path = "../../../../xpcom/rust/nserror" } nsstring = { path = "../../../../xpcom/rust/nsstring" } -rental = "0.5.5" rkv = { version = "0.17", default-features = false } -rust_cascade = "0.6.0" +rust_cascade = "1.2.0" sha2 = "^0.8" storage_variant = { path = "../../../../storage/variant" } tempfile = "3" thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } time = "0.1" xpcom = { path = "../../../../xpcom/rust/xpcom" } -malloc_size_of_derive = "0.1" wr_malloc_size_of = { path = "../../../../gfx/wr/wr_malloc_size_of" } diff --git a/security/manager/ssl/cert_storage/src/lib.rs b/security/manager/ssl/cert_storage/src/lib.rs index 69e7b54a278a..1242832242ec 100644 --- a/security/manager/ssl/cert_storage/src/lib.rs +++ b/security/manager/ssl/cert_storage/src/lib.rs @@ -9,12 +9,9 @@ extern crate crossbeam_utils; extern crate cstr; #[macro_use] extern crate log; -extern crate memmap2; extern crate moz_task; extern crate nserror; extern crate nsstring; -#[macro_use] -extern crate rental; extern crate rkv; extern crate rust_cascade; extern crate sha2; @@ -22,8 +19,6 @@ extern crate thin_vec; extern crate time; #[macro_use] extern crate xpcom; -#[macro_use] -extern crate malloc_size_of_derive; extern crate storage_variant; extern crate tempfile; @@ -33,7 +28,6 @@ use wr_malloc_size_of as malloc_size_of; use byteorder::{LittleEndian, NetworkEndian, ReadBytesExt, WriteBytesExt}; use crossbeam_utils::atomic::AtomicCell; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -use memmap2::Mmap; use moz_task::{create_background_task_queue, is_main_thread, Task, TaskRunnable}; use nserror::{ nsresult, NS_ERROR_FAILURE, NS_ERROR_NOT_SAME_THREAD, NS_ERROR_NO_AGGREGATION, @@ -132,30 +126,12 @@ impl MallocSizeOf for EnvAndStore { } } -// In Rust, structs cannot have self references (if a struct gets moved, the compiler has no -// guarantees that the references are still valid). In our case, since the memmapped data is at a -// particular place in memory (and that's what we're referencing), we can use the rental crate to -// create a struct that does reference itself. -rental! { - mod holding { - use super::{Cascade, Mmap}; - - #[rental] - pub struct CRLiteFilter { - backing_file: Box, - cascade: Box>, - } - } -} - /// `SecurityState` -#[derive(MallocSizeOf)] struct SecurityState { profile_path: PathBuf, env_and_store: Option, int_prefs: HashMap, - #[ignore_malloc_size_of = "rental crate does not allow impls for rental structs"] - crlite_filter: Option, + crlite_filter: Option, /// Maps issuer spki hashes to sets of serial numbers. crlite_stash: Option, HashSet>>>, /// Maps an RFC 6962 LogID to a pair of 64 bit unix timestamps @@ -529,15 +505,12 @@ impl SecurityState { if !path.exists() { return Ok(()); } - let filter_file = File::open(path)?; - let mmap = unsafe { Mmap::map(&filter_file)? }; - let crlite_filter = holding::CRLiteFilter::try_new(Box::new(mmap), |mmap| { - match Cascade::from_bytes(mmap)? { - Some(cascade) => Ok(cascade), - None => Err(SecurityStateError::from("invalid CRLite filter")), - } - }) - .map_err(|_| SecurityStateError::from("unable to initialize CRLite filter"))?; + let mut filter_file = File::open(path)?; + let mut filter_bytes = Vec::new(); + let _ = filter_file.read_to_end(&mut filter_bytes)?; + let crlite_filter = *Cascade::from_bytes(filter_bytes) + .map_err(|_| SecurityStateError::from("invalid CRLite filter"))? + .ok_or(SecurityStateError::from("expecting non-empty filter"))?; let mut path = get_store_path(&self.profile_path)?; path.push("crlite.coverage"); @@ -672,7 +645,7 @@ impl SecurityState { lookup_key.extend_from_slice(serial_number); debug!("CRLite lookup key: {:?}", lookup_key); let result = match &self.crlite_filter { - Some(crlite_filter) => crlite_filter.rent(|filter| filter.has(&lookup_key)), + Some(crlite_filter) => crlite_filter.has(&lookup_key), // This can only happen if the backing file was deleted or if it or our database has // become corrupted. In any case, we have no information. None => return nsICertStorage::STATE_NOT_COVERED, @@ -881,6 +854,21 @@ impl SecurityState { } } +impl MallocSizeOf for SecurityState { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.profile_path.size_of(ops) + + self.env_and_store.size_of(ops) + + self.int_prefs.size_of(ops) + + self + .crlite_filter + .as_ref() + .map_or(0, |crlite_filter| crlite_filter.approximate_size_of()) + + self.crlite_stash.size_of(ops) + + self.crlite_coverage.size_of(ops) + + self.remaining_ops.size_of(ops) + } +} + const CERT_SERIALIZATION_VERSION_1: u8 = 1; // A Cert consists of its DER encoding, its DER-encoded subject, and its trust (currently diff --git a/third_party/rust/rust_cascade/.cargo-checksum.json b/third_party/rust/rust_cascade/.cargo-checksum.json index 3224196f6f52..1dfd54e58343 100644 --- a/third_party/rust/rust_cascade/.cargo-checksum.json +++ b/third_party/rust/rust_cascade/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"411cb740d6be8346206164df646ac9df304e9a84bb9f10eb4b07d2ef2f6566ec","README.md":"a4396d1adf63a77ae9aa0d1d850d02d09eec4a92810a52d675163688f312b3e8","license.txt":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","src/lib.rs":"2c6d1e01ae3a39baad99cd4567b0164dec4dcf77688bc2c3b43798215c857943","test_data/make-sample-data.py":"68bcb106c3ac1929da52e1abb71cd2a6d59eb79549f6e40042368161baa920e0","test_data/requirements.txt":"cb9372b33ed2774e0d5040459fd63a2f9abae2be599869be43a2a077b2c08aa3","test_data/test_v1_murmur_mlbf":"243df0b7f2f55bfe3cefbba2d4be5eb7957c0a063559c9f284ca4c1ee4211eb5","test_data/test_v1_murmur_short_mlbf":"3d4f03dc0a65cf5800efed6ac0b3c73e5b61e5d62bc82ac42744abc67f4c30fa","test_data/test_v2_murmur_inverted_mlbf":"efdd0ab309883f6a3148ec2ddaf0dcb768790e6f130e4e0556994202b1fd7cc4","test_data/test_v2_murmur_mlbf":"80e8e148fbf95aed39783f1fcc2d4576074f8c487656ca2d53571da4b17e20a9","test_data/test_v2_sha256_inverted_mlbf":"e5148cabb45c4899f8220ca51f96a6c76c688e39dfd340ae56bf9dc5226eada2","test_data/test_v2_sha256_mlbf":"08986847b8b2f3bdf4d2df51e465938f88f7a7c401b1740094fc40b033e80b51","test_data/test_v2_sha256_salt_mlbf":"d7b9bf88872162a1917eb14d0340a88b61b574fb1a7120fa54d061e43a9f5460"},"package":"9a5b9bba8f5b985e4923dadd273a987f83669083f3355d65c699e02b9d3d854d"} \ No newline at end of file +{"files":{"Cargo.toml":"001e85e1a2fb801d92db560e0c6abbdfbff246c0bce600e1908f674819acb1d7","README.md":"a4396d1adf63a77ae9aa0d1d850d02d09eec4a92810a52d675163688f312b3e8","license.txt":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","src/lib.rs":"ea99597d605feb5a33fbe678ae86fae525042ce48704383e61ee54dd95e0e854","test_data/make-sample-data.py":"68bcb106c3ac1929da52e1abb71cd2a6d59eb79549f6e40042368161baa920e0","test_data/requirements.txt":"cb9372b33ed2774e0d5040459fd63a2f9abae2be599869be43a2a077b2c08aa3","test_data/test_v1_murmur_mlbf":"243df0b7f2f55bfe3cefbba2d4be5eb7957c0a063559c9f284ca4c1ee4211eb5","test_data/test_v1_murmur_short_mlbf":"3d4f03dc0a65cf5800efed6ac0b3c73e5b61e5d62bc82ac42744abc67f4c30fa","test_data/test_v2_murmur_inverted_mlbf":"efdd0ab309883f6a3148ec2ddaf0dcb768790e6f130e4e0556994202b1fd7cc4","test_data/test_v2_murmur_mlbf":"80e8e148fbf95aed39783f1fcc2d4576074f8c487656ca2d53571da4b17e20a9","test_data/test_v2_sha256_inverted_mlbf":"e5148cabb45c4899f8220ca51f96a6c76c688e39dfd340ae56bf9dc5226eada2","test_data/test_v2_sha256_mlbf":"08986847b8b2f3bdf4d2df51e465938f88f7a7c401b1740094fc40b033e80b51","test_data/test_v2_sha256_salt_mlbf":"d7b9bf88872162a1917eb14d0340a88b61b574fb1a7120fa54d061e43a9f5460"},"package":"d09c17a9310f1eb79a67d307adffa7fa1c5943eaadcc21d4fb7f611536d66c4f"} \ No newline at end of file diff --git a/third_party/rust/rust_cascade/Cargo.toml b/third_party/rust/rust_cascade/Cargo.toml index d1621fe71c8e..1161cf0eb58f 100644 --- a/third_party/rust/rust_cascade/Cargo.toml +++ b/third_party/rust/rust_cascade/Cargo.toml @@ -3,18 +3,17 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] name = "rust_cascade" -version = "0.6.0" +version = "1.2.0" authors = ["Mark Goodwin ", "Dana Keeler ", "J.C. Jones "] -description = "A simple mmh3 based bloom filter cascade implementation in Rust." +description = "A simple bloom filter cascade implementation in Rust." homepage = "https://github.com/mozilla/rust-cascade" documentation = "https://docs.rs/rust_cascade/" license = "MPL-2.0" diff --git a/third_party/rust/rust_cascade/src/lib.rs b/third_party/rust/rust_cascade/src/lib.rs index 77c39331585d..0c96b36fef00 100644 --- a/third_party/rust/rust_cascade/src/lib.rs +++ b/third_party/rust/rust_cascade/src/lib.rs @@ -8,25 +8,26 @@ use murmurhash3::murmurhash3_x86_32; use sha2::{Digest, Sha256}; use std::convert::{TryFrom, TryInto}; use std::fmt; -use std::io::{Error, ErrorKind}; +use std::io::{Error, ErrorKind, Read}; +use std::mem::size_of; -/// Helper struct to provide read-only bit access to a slice of bytes. -struct BitSlice<'a> { - /// The slice of bytes we're interested in. - bytes: &'a [u8], - /// The number of bits that are valid to access in the slice. +/// Helper struct to provide read-only bit access to a vector of bytes. +struct BitVector { + /// The bytes we're interested in. + bytes: Vec, + /// The number of bits that are valid to access in the vector. /// Not necessarily equal to `bytes.len() * 8`, but it will not be greater than that. bit_len: usize, } -impl<'a> BitSlice<'a> { - /// Creates a new `BitSlice` of the given bit length over the given slice of data. - /// Panics if the indicated bit length is larger than fits in the slice. +impl BitVector { + /// Creates a new `BitVector` of the given bit length over the given data. + /// Panics if the indicated bit length is larger than fits in the vector. /// /// # Arguments - /// * `bytes` - The slice of bytes we need bit-access to - /// * `bit_len` - The number of bits that are valid to access in the slice - fn new(bytes: &'a [u8], bit_len: usize) -> BitSlice<'a> { + /// * `bytes` - The bytes we need bit-access to + /// * `bit_len` - The number of bits that are valid to access in the vector + fn new(bytes: Vec, bit_len: usize) -> BitVector { if bit_len > bytes.len() * 8 { panic!( "bit_len too large for given data: {} > {} * 8", @@ -34,7 +35,7 @@ impl<'a> BitSlice<'a> { bytes.len() ); } - BitSlice { bytes, bit_len } + BitVector { bytes, bit_len } } /// Get the value of the specified bit. @@ -45,7 +46,7 @@ impl<'a> BitSlice<'a> { fn get(&self, bit_index: usize) -> bool { if bit_index >= self.bit_len { panic!( - "bit index out of range for bit slice: {} >= {}", + "bit index out of range for bit vector: {} >= {}", bit_index, self.bit_len ); } @@ -68,7 +69,7 @@ impl<'a> BitSlice<'a> { } /// A Bloom filter representing a specific level in a multi-level cascading Bloom filter. -struct Bloom<'a> { +struct Bloom { /// What level this filter is in level: u8, /// How many hash functions this filter uses @@ -76,7 +77,7 @@ struct Bloom<'a> { /// The bit length of the filter size: u32, /// The data of the filter - bit_slice: BitSlice<'a>, + bit_vector: BitVector, /// The hash algorithm enumeration in use hash_algorithm: HashAlgorithm, } @@ -108,13 +109,12 @@ impl TryFrom for HashAlgorithm { } } -impl<'a> Bloom<'a> { - /// Attempts to decode and return a pair that consists of the Bloom filter represented by the - /// given bytes and any remaining unprocessed bytes in the given bytes. +impl Bloom { + /// Attempts to decode the Bloom filter represented by the bytes in the given reader. /// /// # Arguments - /// * `bytes` - The encoded representation of this Bloom filter. May include additional data - /// describing further Bloom filters. Any additional data is returned unconsumed. + /// * `reader` - The encoded representation of this Bloom filter. May be empty. May include + /// additional data describing further Bloom filters. /// The format of an encoded Bloom filter is: /// [1 byte] - the hash algorithm to use in the filter /// [4 little endian bytes] - the length in bits of the filter @@ -122,11 +122,15 @@ impl<'a> Bloom<'a> { /// [1 byte] - which level in the cascade this filter is /// [variable length bytes] - the filter itself (the length is determined by Ceiling(bit length /// / 8) - pub fn from_bytes(bytes: &'a [u8]) -> Result<(Bloom<'a>, &'a [u8]), Error> { - let mut cursor = bytes; + pub fn read(reader: &mut R) -> Result, Error> { // Load the layer metadata. bloomer.py writes size, nHashFuncs and level as little-endian // unsigned ints. - let hash_algorithm_val = cursor.read_u8()?; + let hash_algorithm_val = match reader.read_u8() { + Ok(val) => val, + // If reader is at EOF, there is no bloom filter. + Err(e) if e.kind() == ErrorKind::UnexpectedEof => return Ok(None), + Err(e) => return Err(e), + }; let hash_algorithm = match HashAlgorithm::try_from(hash_algorithm_val) { Ok(algo) => algo, Err(()) => { @@ -137,9 +141,9 @@ impl<'a> Bloom<'a> { } }; - let size = cursor.read_u32::()?; - let n_hash_funcs = cursor.read_u32::()?; - let level = cursor.read_u8()?; + let size = reader.read_u32::()?; + let n_hash_funcs = reader.read_u32::()?; + let level = reader.read_u8()?; let shifted_size = size.wrapping_shr(3) as usize; let byte_count = if size % 8 != 0 { @@ -147,24 +151,19 @@ impl<'a> Bloom<'a> { } else { shifted_size }; - if byte_count > cursor.len() { - return Err(Error::new( - ErrorKind::InvalidData, - "Invalid Bloom filter: too short", - )); - } - let (bits_bytes, rest_of_bytes) = cursor.split_at(byte_count); + let mut bits_bytes = vec![0; byte_count]; + reader.read_exact(&mut bits_bytes)?; let bloom = Bloom { level, n_hash_funcs, size, - bit_slice: BitSlice::new(bits_bytes, size as usize), + bit_vector: BitVector::new(bits_bytes, size as usize), hash_algorithm, }; - Ok((bloom, rest_of_bytes)) + Ok(Some(bloom)) } - fn hash(&self, n_fn: u32, key: &[u8], salt: Option<&[u8]>) -> u32 { + fn hash(&self, n_fn: u32, key: &[u8], salt: Option<&Vec>) -> u32 { match self.hash_algorithm { HashAlgorithm::MurmurHash3 => { if salt.is_some() { @@ -195,9 +194,9 @@ impl<'a> Bloom<'a> { /// /// # Arguments /// `item` - The slice of bytes to test for - pub fn has(&self, item: &[u8], salt: Option<&[u8]>) -> bool { + fn has(&self, item: &[u8], salt: Option<&Vec>) -> bool { for i in 0..self.n_hash_funcs { - if !self.bit_slice.get(self.hash(i, item, salt) as usize) { + if !self.bit_vector.get(self.hash(i, item, salt) as usize) { return false; } } @@ -205,7 +204,7 @@ impl<'a> Bloom<'a> { } } -impl<'a> fmt::Display for Bloom<'a> { +impl fmt::Display for Bloom { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, @@ -216,21 +215,19 @@ impl<'a> fmt::Display for Bloom<'a> { } /// A multi-level cascading Bloom filter. -pub struct Cascade<'a> { +pub struct Cascade { /// The Bloom filter for this level in the cascade - filter: Bloom<'a>, + filter: Bloom, /// The next (lower) level in the cascade - child_layer: Option>>, + child_layer: Option>, /// The salt in use, if any - salt: Option<&'a [u8]>, + salt: Option>, /// Whether the logic should be inverted inverted: bool, } -impl<'a> Cascade<'a> { - /// Attempts to decode and return a multi-level cascading Bloom filter. NB: `Cascade` does not - /// take ownership of the given data. This is to facilitate decoding cascading filters - /// backed by memory-mapped files. +impl Cascade { + /// Attempts to decode and return a multi-level cascading Bloom filter. /// /// # Arguments /// `bytes` - The encoded representation of the Bloom filters in this cascade. Starts with 2 @@ -239,31 +236,23 @@ impl<'a> Cascade<'a> { /// https://github.com/mozilla/filter-cascade/blob/v0.3.0/filtercascade/fileformats.py /// /// May be of length 0, in which case `None` is returned. - pub fn from_bytes(bytes: &'a [u8]) -> Result>>, Error> { + pub fn from_bytes(bytes: Vec) -> Result>, Error> { if bytes.is_empty() { return Ok(None); } - let mut cursor = bytes; - let version = cursor.read_u16::()?; + let mut reader = bytes.as_slice(); + let version = reader.read_u16::()?; let mut salt = None; let mut inverted = false; if version >= 2 { - inverted = cursor.read_u8()? != 0; - let salt_len = cursor.read_u8()? as usize; - - if salt_len > cursor.len() { - return Err(Error::new( - ErrorKind::InvalidData, - "Invalid Bloom filter: too short", - )); - } - - let (salt_bytes, remaining_bytes) = cursor.split_at(salt_len); + inverted = reader.read_u8()? != 0; + let salt_len = reader.read_u8()? as usize; if salt_len > 0 { - salt = Some(salt_bytes) + let mut salt_bytes = vec![0; salt_len]; + reader.read_exact(&mut salt_bytes)?; + salt = Some(salt_bytes); } - cursor = remaining_bytes; } if version > 2 { @@ -273,22 +262,23 @@ impl<'a> Cascade<'a> { )); } - Cascade::child_layer_from_bytes(cursor, salt, inverted) + Cascade::child_layer_from_bytes(reader, salt, inverted) } - fn child_layer_from_bytes( - bytes: &'a [u8], - salt: Option<&'a [u8]>, + fn child_layer_from_bytes( + mut reader: R, + salt: Option>, inverted: bool, - ) -> Result>>, Error> { - if bytes.is_empty() { - return Ok(None); - } - let (filter, rest_of_bytes) = Bloom::from_bytes(bytes)?; + ) -> Result>, Error> { + let filter = match Bloom::read(&mut reader)? { + Some(filter) => filter, + None => return Ok(None), + }; + let our_salt = salt.as_ref().cloned(); Ok(Some(Box::new(Cascade { filter, - child_layer: Cascade::child_layer_from_bytes(rest_of_bytes, salt, inverted)?, - salt, + child_layer: Cascade::child_layer_from_bytes(reader, salt, inverted)?, + salt: our_salt, inverted, }))) } @@ -305,8 +295,8 @@ impl<'a> Cascade<'a> { result } - pub fn has_internal(&self, entry: &[u8]) -> bool { - if self.filter.has(&entry, self.salt) { + fn has_internal(&self, entry: &[u8]) -> bool { + if self.filter.has(entry, self.salt.as_ref()) { match self.child_layer { Some(ref child) => { let child_value = !child.has_internal(entry); @@ -319,9 +309,25 @@ impl<'a> Cascade<'a> { } false } + + /// Determine the approximate amount of memory in bytes used by this + /// Cascade. Because this implementation does not integrate with the + /// allocator, it can't get an accurate measurement of how much memory it + /// uses. However, it can make a reasonable guess, assuming the sizes of + /// the bloom filters are large enough to dominate the overall allocated + /// size. + pub fn approximate_size_of(&self) -> usize { + size_of::() + + self.filter.bit_vector.bytes.len() + + self + .child_layer + .as_ref() + .map_or(0, |child_layer| child_layer.approximate_size_of()) + + self.salt.as_ref().map_or(0, |salt| salt.len()) + } } -impl<'a> fmt::Display for Cascade<'a> { +impl fmt::Display for Cascade { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, @@ -345,34 +351,41 @@ mod tests { let src: Vec = vec![ 0x01, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x41, 0x00, ]; + let mut reader = src.as_slice(); - match Bloom::from_bytes(&src) { - Ok((bloom, rest_of_bytes)) => { - assert!(rest_of_bytes.len() == 0); + match Bloom::read(&mut reader) { + Ok(Some(bloom)) => { assert!(bloom.has(b"this", None) == true); assert!(bloom.has(b"that", None) == true); assert!(bloom.has(b"other", None) == false); } - Err(_) => { - panic!("Parsing failed"); - } + Ok(None) => panic!("Parsing failed"), + Err(_) => panic!("Parsing failed"), }; + assert!(reader.is_empty()); let short: Vec = vec![ 0x01, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x41, ]; - assert!(Bloom::from_bytes(&short).is_err()); + assert!(Bloom::read(&mut short.as_slice()).is_err()); + + let empty: Vec = Vec::new(); + let mut reader = empty.as_slice(); + match Bloom::read(&mut reader) { + Ok(should_be_none) => assert!(should_be_none.is_none()), + Err(_) => panic!("Parsing failed"), + }; } #[test] fn bloom_v3_unsupported() { let src: Vec = vec![0x03, 0x01, 0x00]; - assert!(Bloom::from_bytes(&src).is_err()); + assert!(Bloom::read(&mut src.as_slice()).is_err()); } #[test] fn cascade_v1_murmur_from_file_bytes_test() { - let v = include_bytes!("../test_data/test_v1_murmur_mlbf"); + let v = include_bytes!("../test_data/test_v1_murmur_mlbf").to_vec(); let cascade = Cascade::from_bytes(v) .expect("parsing Cascade should succeed") .expect("Cascade should be Some"); @@ -401,13 +414,15 @@ mod tests { 0x77, 0x8e ]; assert!(!cascade.has(&key_for_valid_cert)); - let v = include_bytes!("../test_data/test_v1_murmur_short_mlbf"); + assert_eq!(cascade.approximate_size_of(), 15632); + + let v = include_bytes!("../test_data/test_v1_murmur_short_mlbf").to_vec(); assert!(Cascade::from_bytes(v).is_err()); } #[test] fn cascade_v2_sha256_from_file_bytes_test() { - let v = include_bytes!("../test_data/test_v2_sha256_mlbf"); + let v = include_bytes!("../test_data/test_v2_sha256_mlbf").to_vec(); let cascade = Cascade::from_bytes(v) .expect("parsing Cascade should succeed") .expect("Cascade should be Some"); @@ -417,25 +432,27 @@ mod tests { assert!(cascade.has(b"this") == true); assert!(cascade.has(b"that") == true); assert!(cascade.has(b"other") == false); + assert_eq!(cascade.approximate_size_of(), 10247); } #[test] fn cascade_v2_sha256_with_salt_from_file_bytes_test() { - let v = include_bytes!("../test_data/test_v2_sha256_salt_mlbf"); + let v = include_bytes!("../test_data/test_v2_sha256_salt_mlbf").to_vec(); let cascade = Cascade::from_bytes(v) .expect("parsing Cascade should succeed") .expect("Cascade should be Some"); - assert!(cascade.salt == Some(b"nacl")); + assert!(cascade.salt == Some(b"nacl".to_vec())); assert!(cascade.inverted == false); assert!(cascade.has(b"this") == true); assert!(cascade.has(b"that") == true); assert!(cascade.has(b"other") == false); + assert_eq!(cascade.approximate_size_of(), 10251); } #[test] fn cascade_v2_murmur_from_file_bytes_test() { - let v = include_bytes!("../test_data/test_v2_murmur_mlbf"); + let v = include_bytes!("../test_data/test_v2_murmur_mlbf").to_vec(); let cascade = Cascade::from_bytes(v) .expect("parsing Cascade should succeed") .expect("Cascade should be Some"); @@ -445,11 +462,12 @@ mod tests { assert!(cascade.has(b"this") == true); assert!(cascade.has(b"that") == true); assert!(cascade.has(b"other") == false); + assert_eq!(cascade.approximate_size_of(), 10247); } #[test] fn cascade_v2_murmur_inverted_from_file_bytes_test() { - let v = include_bytes!("../test_data/test_v2_murmur_inverted_mlbf"); + let v = include_bytes!("../test_data/test_v2_murmur_inverted_mlbf").to_vec(); let cascade = Cascade::from_bytes(v) .expect("parsing Cascade should succeed") .expect("Cascade should be Some"); @@ -459,11 +477,12 @@ mod tests { assert!(cascade.has(b"this") == true); assert!(cascade.has(b"that") == true); assert!(cascade.has(b"other") == false); + assert_eq!(cascade.approximate_size_of(), 10247); } #[test] fn cascade_v2_sha256_inverted_from_file_bytes_test() { - let v = include_bytes!("../test_data/test_v2_sha256_inverted_mlbf"); + let v = include_bytes!("../test_data/test_v2_sha256_inverted_mlbf").to_vec(); let cascade = Cascade::from_bytes(v) .expect("parsing Cascade should succeed") .expect("Cascade should be Some"); @@ -473,5 +492,12 @@ mod tests { assert!(cascade.has(b"this") == true); assert!(cascade.has(b"that") == true); assert!(cascade.has(b"other") == false); + assert_eq!(cascade.approximate_size_of(), 10247); + } + + #[test] + fn cascade_empty() { + let cascade = Cascade::from_bytes(Vec::new()).expect("parsing Cascade should succeed"); + assert!(cascade.is_none()); } } diff --git a/toolkit/components/cascade_bloom_filter/Cargo.toml b/toolkit/components/cascade_bloom_filter/Cargo.toml index 851f4e696f15..14a0c343cf39 100644 --- a/toolkit/components/cascade_bloom_filter/Cargo.toml +++ b/toolkit/components/cascade_bloom_filter/Cargo.toml @@ -6,7 +6,6 @@ authors = ["Rob Wu "] [dependencies] nserror = { path = "../../../xpcom/rust/nserror" } nsstring = { path = "../../../xpcom/rust/nsstring" } -rental = "0.5.5" -rust_cascade = "0.6.0" +rust_cascade = "1.2.0" thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } xpcom = { path = "../../../xpcom/rust/xpcom" } diff --git a/toolkit/components/cascade_bloom_filter/src/lib.rs b/toolkit/components/cascade_bloom_filter/src/lib.rs index 471c69ca26c6..3b5dcdb6a133 100644 --- a/toolkit/components/cascade_bloom_filter/src/lib.rs +++ b/toolkit/components/cascade_bloom_filter/src/lib.rs @@ -4,8 +4,6 @@ extern crate nserror; extern crate nsstring; -#[macro_use] -extern crate rental; extern crate rust_cascade; extern crate thin_vec; #[macro_use] @@ -19,25 +17,11 @@ use thin_vec::ThinVec; use xpcom::interfaces::nsICascadeFilter; use xpcom::{xpcom_method, RefPtr}; -// Cascade does not take ownership of the data, so we must own the data in order to pass its -// reference to Cascade. -rental! { - mod rentals { - use super::Cascade; - - #[rental] - pub struct CascadeWithOwnedData { - owndata: Box<[u8]>, - cascade: Box>, - } - } -} - #[derive(xpcom)] #[xpimplements(nsICascadeFilter)] #[refcnt = "nonatomic"] pub struct InitCascadeFilter { - filter: RefCell>, + filter: RefCell>, } impl CascadeFilter { @@ -49,14 +33,9 @@ impl CascadeFilter { xpcom_method!(set_filter_data => SetFilterData(data: *const ThinVec)); fn set_filter_data(&self, data: &ThinVec) -> Result<(), nsresult> { - let filter = rentals::CascadeWithOwnedData::try_new_or_drop( - Vec::from(data.as_slice()).into_boxed_slice(), - |data| { - Cascade::from_bytes(data) - .unwrap_or(None) - .ok_or(NS_ERROR_INVALID_ARG) - }, - )?; + let filter = *Cascade::from_bytes(data.to_vec()) + .unwrap_or(None) + .ok_or(NS_ERROR_INVALID_ARG)?; self.filter.borrow_mut().replace(filter); Ok(()) } @@ -66,7 +45,7 @@ impl CascadeFilter { fn has(&self, key: &nsACString) -> Result { match self.filter.borrow().as_ref() { None => Err(NS_ERROR_NOT_INITIALIZED), - Some(filter) => Ok(filter.rent(|cascade| cascade.has(&*key))), + Some(filter) => Ok(filter.has(&*key)), } } }