зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1620621 - Add XPCOM FFI for rust_cascade r=emilio,vporof
Differential Revision: https://phabricator.services.mozilla.com/D66166
This commit is contained in:
Родитель
6b57ac9c48
Коммит
4294b3bca0
|
@ -485,6 +485,18 @@ dependencies = [
|
|||
"ppv-lite86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cascade_bloom_filter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nserror",
|
||||
"nsstring",
|
||||
"rental",
|
||||
"rust_cascade",
|
||||
"thin-vec",
|
||||
"xpcom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.2.2"
|
||||
|
@ -1812,6 +1824,7 @@ dependencies = [
|
|||
"authenticator",
|
||||
"bitsdownload",
|
||||
"bookmark_sync",
|
||||
"cascade_bloom_filter",
|
||||
"cert_storage",
|
||||
"chardetng_c",
|
||||
"cose-c",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "cascade_bloom_filter"
|
||||
version = "0.1.0"
|
||||
authors = ["Rob Wu <rob@robwu.nl>"]
|
||||
|
||||
[dependencies]
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
rental = "0.5.5"
|
||||
rust_cascade = "0.6.0"
|
||||
thin-vec = { version = "0.1.0", features = ["gecko-ffi"] }
|
||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
|
@ -0,0 +1,25 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "CascadeFilter.h"
|
||||
|
||||
namespace {
|
||||
extern "C" {
|
||||
|
||||
// Implemented in Rust.
|
||||
void cascade_filter_construct(nsICascadeFilter** aResult);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
already_AddRefed<nsICascadeFilter> ConstructCascadeFilter() {
|
||||
nsCOMPtr<nsICascadeFilter> filter;
|
||||
cascade_filter_construct(getter_AddRefs(filter));
|
||||
return filter.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,17 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CASCADE_BLOOM_FILTER_CASCADE_FILTER_H_
|
||||
#define CASCADE_BLOOM_FILTER_CASCADE_FILTER_H_
|
||||
|
||||
#include "nsICascadeFilter.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
already_AddRefed<nsICascadeFilter> ConstructCascadeFilter();
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // CASCADE_BLOOM_FILTER_CASCADE_FILTER_H_
|
|
@ -0,0 +1,15 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{c8d0b0b3-17f8-458b-9264-7b67b288fe79}',
|
||||
'contract_ids': ['@mozilla.org/cascade-filter;1'],
|
||||
'type': 'nsICascadeFilter',
|
||||
'headers': ['mozilla/CascadeFilter.h'],
|
||||
'constructor': 'mozilla::ConstructCascadeFilter',
|
||||
},
|
||||
]
|
|
@ -0,0 +1,30 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Toolkit', 'Blocklist Implementation')
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsICascadeFilter.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'cascade_bindings'
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"CascadeFilter.h"
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
"CascadeFilter.cpp"
|
||||
]
|
||||
|
||||
XPCOM_MANIFESTS += [
|
||||
'components.conf',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
|
@ -0,0 +1,28 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* A consumer of a filter cascade, i.e. a cascaded bloom filter as generated by
|
||||
* https://github.com/mozilla/filter-cascade
|
||||
*/
|
||||
[scriptable, uuid(c8d0b0b3-17f8-458b-9264-7b67b288fe79)]
|
||||
interface nsICascadeFilter : nsISupports {
|
||||
/**
|
||||
* Initialize with the data that represents the filter cascade.
|
||||
* This method can be called repeatedly.
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG if the input is malformed.
|
||||
*/
|
||||
void setFilterData(in Array<octet> data);
|
||||
|
||||
/**
|
||||
* Check whether a given key is a member of the filter cascade.
|
||||
* The result can only be relied upon if the key was known at the time of the
|
||||
* filter generation. If the key is unknown, the method may incorrectly
|
||||
* return true (due to the probabilistic nature of bloom filters).
|
||||
*/
|
||||
boolean has(in ACString key);
|
||||
};
|
|
@ -0,0 +1,75 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
extern crate nserror;
|
||||
extern crate nsstring;
|
||||
#[macro_use]
|
||||
extern crate rental;
|
||||
extern crate rust_cascade;
|
||||
extern crate thin_vec;
|
||||
#[macro_use]
|
||||
extern crate xpcom;
|
||||
|
||||
use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_ERROR_NOT_INITIALIZED, NS_OK};
|
||||
use nsstring::nsACString;
|
||||
use rust_cascade::Cascade;
|
||||
use std::cell::RefCell;
|
||||
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<Cascade<'owndata>>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsICascadeFilter)]
|
||||
#[refcnt = "nonatomic"]
|
||||
pub struct InitCascadeFilter {
|
||||
filter: RefCell<Option<rentals::CascadeWithOwnedData>>,
|
||||
}
|
||||
|
||||
impl CascadeFilter {
|
||||
fn new() -> RefPtr<CascadeFilter> {
|
||||
CascadeFilter::allocate(InitCascadeFilter {
|
||||
filter: RefCell::new(None),
|
||||
})
|
||||
}
|
||||
xpcom_method!(set_filter_data => SetFilterData(data: *const ThinVec<u8>));
|
||||
|
||||
fn set_filter_data(&self, data: &ThinVec<u8>) -> 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)
|
||||
)?;
|
||||
self.filter.borrow_mut().replace(filter);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(has => Has(key: *const nsACString) -> bool);
|
||||
|
||||
fn has(&self, key: &nsACString) -> Result<bool, nsresult> {
|
||||
match self.filter.borrow().as_ref() {
|
||||
None => Err(NS_ERROR_NOT_INITIALIZED),
|
||||
Some(filter) => Ok(filter.rent(|cascade| cascade.has(&*key))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn cascade_filter_construct(result: &mut *const nsICascadeFilter) {
|
||||
let inst: RefPtr<CascadeFilter> = CascadeFilter::new();
|
||||
*result = inst.coerce::<nsICascadeFilter>();
|
||||
std::mem::forget(inst);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
"use strict";
|
||||
|
||||
const CASCADE_CID = "@mozilla.org/cascade-filter;1";
|
||||
const CASCADE_IID = Ci.nsICascadeFilter;
|
||||
const CascadeFilter = Components.Constructor(CASCADE_CID, CASCADE_IID);
|
||||
|
||||
add_task(function CascadeFilter_uninitialized() {
|
||||
let filter = new CascadeFilter();
|
||||
Assert.throws(
|
||||
() => filter.has(""),
|
||||
e => e.result === Cr.NS_ERROR_NOT_INITIALIZED,
|
||||
"Cannot use has() if the filter is not initialized"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function CascadeFilter_with_setFilterData() {
|
||||
let filter = new CascadeFilter();
|
||||
Assert.throws(
|
||||
() => filter.setFilterData(),
|
||||
e => e.result === Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
|
||||
"setFilterData without parameters should throw"
|
||||
);
|
||||
Assert.throws(
|
||||
() => filter.setFilterData(null),
|
||||
e => e.result === Cr.NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY,
|
||||
"setFilterData with null parameter is invalid"
|
||||
);
|
||||
Assert.throws(
|
||||
() => filter.setFilterData(new Uint8Array()),
|
||||
e => e.result === Cr.NS_ERROR_INVALID_ARG,
|
||||
"setFilterData with empty array is invalid"
|
||||
);
|
||||
|
||||
// Test data based on rust_cascade's unit tests (bloom_v1_test_from_bytes),
|
||||
// with two bytes in front to have a valid format.
|
||||
const TEST_DATA = [1, 0, 1, 9, 0, 0, 0, 1, 0, 0, 0, 1, 0x41, 0];
|
||||
Assert.throws(
|
||||
() => filter.setFilterData(new Uint8Array(TEST_DATA.slice(1))),
|
||||
e => e.result === Cr.NS_ERROR_INVALID_ARG,
|
||||
"setFilterData with invalid data (missing head) is invalid"
|
||||
);
|
||||
Assert.throws(
|
||||
() => filter.setFilterData(new Uint8Array(TEST_DATA.slice(0, -1))),
|
||||
e => e.result === Cr.NS_ERROR_INVALID_ARG,
|
||||
"setFilterData with invalid data (missing tail) is invalid"
|
||||
);
|
||||
filter.setFilterData(new Uint8Array(TEST_DATA));
|
||||
Assert.equal(filter.has("this"), true, "has(this) should be true");
|
||||
Assert.equal(filter.has("that"), true, "has(that) should be true");
|
||||
Assert.equal(filter.has("other"), false, "has(other) should be false");
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
[test_cascade_bindings.js]
|
|
@ -23,6 +23,7 @@ DIRS += [
|
|||
'backgroundhangmonitor',
|
||||
'bitsdownload',
|
||||
'browser',
|
||||
'cascade_bloom_filter',
|
||||
'certviewer',
|
||||
'cleardata',
|
||||
'clearsitedata',
|
||||
|
|
|
@ -34,6 +34,7 @@ log = {version = "0.4", features = ["release_max_level_info"]}
|
|||
env_logger = {version = "0.6", default-features = false} # disable `regex` to reduce code size
|
||||
cose-c = { version = "0.1.5" }
|
||||
jsrust_shared = { path = "../../../../js/src/rust/shared" }
|
||||
cascade_bloom_filter = { path = "../../../components/cascade_bloom_filter" }
|
||||
cert_storage = { path = "../../../../security/manager/ssl/cert_storage", optional = true }
|
||||
bitsdownload = { path = "../../../components/bitsdownload", optional = true }
|
||||
storage = { path = "../../../../storage/rust" }
|
||||
|
|
|
@ -15,6 +15,7 @@ extern crate authenticator;
|
|||
extern crate bitsdownload;
|
||||
#[cfg(feature = "moz_places")]
|
||||
extern crate bookmark_sync;
|
||||
extern crate cascade_bloom_filter;
|
||||
#[cfg(feature = "new_cert_storage")]
|
||||
extern crate cert_storage;
|
||||
extern crate chardetng_c;
|
||||
|
|
Загрузка…
Ссылка в новой задаче