зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1631722 - Add wrapper for structured-headers crate,r=valentin
Differential Revision: https://phabricator.services.mozilla.com/D81127
This commit is contained in:
Родитель
015552edde
Коммит
a0eda6935a
|
@ -1072,6 +1072,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72aa14c04dfae8dd7d8a2b1cb7ca2152618cd01336dbfe704b8dcbf8d41dbd69"
|
||||
|
||||
[[package]]
|
||||
name = "dbus"
|
||||
version = "0.6.4"
|
||||
|
@ -1972,6 +1978,7 @@ dependencies = [
|
|||
"gecko_logger",
|
||||
"geckoservo",
|
||||
"gkrust_utils",
|
||||
"http_sfv",
|
||||
"jsrust_shared",
|
||||
"kvstore",
|
||||
"lmdb-rkv-sys",
|
||||
|
@ -2255,6 +2262,17 @@ dependencies = [
|
|||
"neqo-transport",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http_sfv"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nserror",
|
||||
"nsstring",
|
||||
"sfv",
|
||||
"thin-vec",
|
||||
"xpcom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.3.3"
|
||||
|
@ -4233,6 +4251,16 @@ dependencies = [
|
|||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ba36e8c41bf675947e200af432325f332f60a0aea0ef2dc456636c2f6037d7"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.8"
|
||||
|
@ -4449,6 +4477,17 @@ dependencies = [
|
|||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sfv"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83166498beeaadbb6ddf69e7ed7b2b009e2b2d4e827aae762d2d310d4f648a3b"
|
||||
dependencies = [
|
||||
"data-encoding",
|
||||
"indexmap",
|
||||
"rust_decimal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.1"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "http_sfv"
|
||||
version = "0.1.0"
|
||||
authors = ["barabass <yalyna.ts@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
sfv = "0.4.0"
|
||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
||||
thin-vec = { version = "0.1.0", features = ["gecko-ffi"] }
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "SFVService.h"
|
||||
|
||||
// This anonymous namespace prevents outside C++ code from improperly accessing
|
||||
// these implementation details.
|
||||
namespace {
|
||||
extern "C" {
|
||||
// Implemented in Rust.
|
||||
void new_sfv_service(nsISFVService** result);
|
||||
}
|
||||
|
||||
static mozilla::StaticRefPtr<nsISFVService> sService;
|
||||
} // namespace
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
already_AddRefed<nsISFVService> GetSFVService() {
|
||||
nsCOMPtr<nsISFVService> service;
|
||||
|
||||
if (sService) {
|
||||
service = sService;
|
||||
} else {
|
||||
new_sfv_service(getter_AddRefs(service));
|
||||
sService = service;
|
||||
mozilla::ClearOnShutdown(&sService);
|
||||
}
|
||||
|
||||
return service.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsIStructuredFieldValues.h"
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
already_AddRefed<nsISFVService> GetSFVService();
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,17 @@
|
|||
# -*- 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIStructuredFieldValues.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'http-sfv'
|
||||
|
||||
EXPORTS.mozilla.net += ['SFVService.h']
|
||||
|
||||
SOURCES += ['SFVService.cpp']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
|
@ -0,0 +1,290 @@
|
|||
/* 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"
|
||||
|
||||
/**
|
||||
* Conceptually, there are three types of structured field (header) values:
|
||||
*
|
||||
* Item - can be an Integer, Decimal, String, Token, Byte Sequence, or Boolean.
|
||||
* It can have associated Parameters.
|
||||
* List - array of zero or more members, each of which can be an Item or an InnerList,
|
||||
* both of which can be Parameterized.
|
||||
* Dictionary - ordered map of name-value pairs, where the names are short textual strings
|
||||
* and the values are Items or arrays of Items (represented with InnerList),
|
||||
* both of which can be Parameterized. There can be zero or more members,
|
||||
* and their names are unique in the scope of the Dictionary they occur within.
|
||||
*
|
||||
*
|
||||
* There's also a few primitive types used to construct structured field values:
|
||||
* - BareItem used as Item's value or as a parameter value in Parameters.
|
||||
* - Parameters are an ordered map of key-value pairs that are associated with an Item or InnerList.
|
||||
* The keys are unique within the scope the Parameters they occur within, and the values are BareItem.
|
||||
* - InnerList is an array of zero or more Items. Can have Parameters.
|
||||
* - ListEntry represents either Item or InnerList as a member of List or as member-value in Dictionary.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsISFVBareItem is a building block for Item header value (nsISFVItem) and Parameters (nsISFVParams).
|
||||
* It can be of type BOOL, STRING, DECIMAL, INTEGER, TOKEN, BYTE_SEQUENCE.
|
||||
* Each type is represented by its own interface which is used to create
|
||||
* a bare item of that type.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(7072853f-215b-4a8a-92e5-9732bccc377b)]
|
||||
interface nsISFVBareItem : nsISupports {
|
||||
const long BOOL = 1;
|
||||
const long STRING = 2;
|
||||
const long DECIMAL = 3;
|
||||
const long INTEGER = 4;
|
||||
const long TOKEN = 5;
|
||||
const long BYTE_SEQUENCE = 6;
|
||||
|
||||
/**
|
||||
* Returns value associated with type of bare item.
|
||||
* Used to identify type of bare item without querying for interface
|
||||
* (like nsISFVString, etc).
|
||||
*/
|
||||
readonly attribute long long type;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(843eea44-990a-422c-bbf2-2aa4ba9ee4d2)]
|
||||
interface nsISFVInteger : nsISFVBareItem {
|
||||
attribute long long value;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(df6a0787-7caa-4fef-b145-08c1104c2fde)]
|
||||
interface nsISFVString : nsISFVBareItem {
|
||||
attribute ACString value;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(d263c6d7-4123-4c39-a121-ccf874a19012)]
|
||||
interface nsISFVBool : nsISFVBareItem {
|
||||
attribute boolean value;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(1098da8b-b4df-4526-b985-53dbd4160ad2)]
|
||||
interface nsISFVDecimal : nsISFVBareItem {
|
||||
attribute double value;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(8ad33d52-b9b2-4a17-8aa8-991250fc1214)]
|
||||
interface nsISFVToken : nsISFVBareItem {
|
||||
attribute ACString value;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(887eaef0-19fe-42bc-9a42-9ff773aa8fea)]
|
||||
interface nsISFVByteSeq : nsISFVBareItem {
|
||||
attribute ACString value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* nsISFVParams represents parameters, key-value pairs of ACString and nsISFVBareItem,
|
||||
* which parametrize Item type header or InnerList type withing List type header.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(b1a397d7-3333-43e7-993a-fbe8ab90ee96)]
|
||||
interface nsISFVParams : nsISupports {
|
||||
/**
|
||||
* Return value (nsISFVBareItem) stored for key, if it is present
|
||||
*
|
||||
* @throws NS_ERROR_UNEXPECTED if the key does not exist in parameters.
|
||||
*/
|
||||
nsISFVBareItem get(in ACString key);
|
||||
|
||||
/**
|
||||
* Insert a new key-value pair.
|
||||
* If an equivalent key already exists: the key remains and retains in its place in the order,
|
||||
* its corresponding value is updated with the new value.
|
||||
*
|
||||
* @throws NS_ERROR_UNEXPECTED if supplied item does not implement nsISFVBareItem interface.
|
||||
*/
|
||||
void set(in ACString key, in nsISFVBareItem item);
|
||||
|
||||
/**
|
||||
* Remove the key-value pair equivalent to key.
|
||||
*
|
||||
* @throws NS_ERROR_UNEXPECTED upon attempt to delete key that does not exist in parameters.
|
||||
*/
|
||||
void delete(in ACString key);
|
||||
|
||||
/**
|
||||
* Returns array of keys.
|
||||
*/
|
||||
Array<ACString> keys();
|
||||
};
|
||||
|
||||
/**
|
||||
* nsISFVParametrizable is implemented for types that
|
||||
* can be parametrized with nsISFVParams
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(6c0399f8-01de-4b25-b339-68e35e8d2e49)]
|
||||
interface nsISFVParametrizable : nsISupports {
|
||||
readonly attribute nsISFVParams params;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsISFVItemOrInnerList represents member in nsISFVList
|
||||
* or member-value in nsISFVDictionary.
|
||||
* nsISFVItemOrInnerList is implemented for
|
||||
* nsISFVItem or nsISFVInnerList, both of which are used
|
||||
* to create nsISFVList and nsISFVDictionary.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(99ac1b56-b5b3-44e7-ad96-db7444aae4b2)]
|
||||
interface nsISFVItemOrInnerList : nsISFVParametrizable {
|
||||
};
|
||||
|
||||
/**
|
||||
* nsISFVSerialize indicates that object can be serialized into ACString.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(28b9215d-c131-413c-9482-0004a371a5ec)]
|
||||
interface nsISFVSerialize : nsISupports {
|
||||
ACString serialize();
|
||||
};
|
||||
|
||||
/**
|
||||
* nsISFVItem represents Item structured header value.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(abe8826b-6af7-4e54-bd2c-46ab231700ce)]
|
||||
interface nsISFVItem : nsISFVItemOrInnerList {
|
||||
readonly attribute nsISFVBareItem value;
|
||||
ACString serialize();
|
||||
};
|
||||
|
||||
/**
|
||||
* nsISFVInnerList can be used as a member of nsISFVList
|
||||
* or a member-value of nsISFVDictionary.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(b2e52be2-8488-41b2-9ee2-3c48d92d095c)]
|
||||
interface nsISFVInnerList : nsISFVItemOrInnerList {
|
||||
attribute Array<nsISFVItem> items;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsISFVList represents List structured header value.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(02bb92a6-d1de-449c-b54f-d137f30c613d)]
|
||||
interface nsISFVList : nsISFVSerialize {
|
||||
/**
|
||||
* Returns array of members.
|
||||
* QueryInterface can be used on a member to get more specific type.
|
||||
*/
|
||||
attribute Array<nsISFVItemOrInnerList> members;
|
||||
|
||||
/**
|
||||
* In case when header value is split across lines, it's possible
|
||||
* this method parses supplied line and merges it with members of existing object.
|
||||
*/
|
||||
void parseMore(in ACString header);
|
||||
};
|
||||
|
||||
/**
|
||||
* nsISFVDictionary represents nsISFVDictionary structured header value.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(6642a7fe-7026-4eba-b730-05e230ee3437)]
|
||||
interface nsISFVDictionary : nsISFVSerialize {
|
||||
|
||||
/**
|
||||
* Return value (nsISFVItemOrInnerList) stored for key, if it is present.
|
||||
* QueryInterface can be used on a value to get more specific type.
|
||||
*
|
||||
* @throws NS_ERROR_UNEXPECTED if the key does not exist in parameters.
|
||||
*/
|
||||
nsISFVItemOrInnerList get(in ACString key);
|
||||
|
||||
/**
|
||||
* Insert a new key-value pair.
|
||||
* If an equivalent key already exists: the key remains and retains in its place in the order,
|
||||
* its corresponding value is updated with the new value.
|
||||
*
|
||||
* @throws NS_ERROR_UNEXPECTED if supplied item does not implement nsISFVItemOrInnerList interface.
|
||||
*/
|
||||
void set(in ACString key, in nsISFVItemOrInnerList member_value);
|
||||
|
||||
/**
|
||||
* Remove the key-value pair equivalent to key.
|
||||
*
|
||||
* @throws NS_ERROR_UNEXPECTED upon attempt to delete key that does not exist in parameters.
|
||||
*/
|
||||
void delete(in ACString key);
|
||||
|
||||
/**
|
||||
* Returns array of keys.
|
||||
*/
|
||||
Array<ACString> keys();
|
||||
|
||||
/**
|
||||
* In case when header value is split across lines, it's possible
|
||||
* this method parses supplied line and merges it with members of existing object.
|
||||
*/
|
||||
void parseMore(in ACString header);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* nsISFVService provides a set of functions for working with HTTP header value as an object.
|
||||
* It exposes functions for creating object from string containing header value,
|
||||
* as well as individual components for manual structured header object creation.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(049f4be1-2f22-4438-a8da-518552ed390c)]
|
||||
interface nsISFVService: nsISupports
|
||||
{
|
||||
/**
|
||||
* Parses provided string into Dictionary header value (nsISFVDictionary).
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE if parsing fails.
|
||||
*/
|
||||
nsISFVDictionary parseDictionary(in ACString header);
|
||||
|
||||
/**
|
||||
* Parses provided string into List header value (nsISFVList).
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE if parsing fails.
|
||||
*/
|
||||
nsISFVList parseList(in ACString header);
|
||||
|
||||
/**
|
||||
* Parses provided string into Item header value (nsISFVItem).
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE if parsing fails.
|
||||
*/
|
||||
nsISFVItem parseItem(in ACString header);
|
||||
|
||||
/**
|
||||
* The following functions create bare item of specific type.
|
||||
*/
|
||||
nsISFVInteger newInteger(in long long value);
|
||||
nsISFVBool newBool(in bool value);
|
||||
nsISFVDecimal newDecimal(in double value);
|
||||
nsISFVString newString(in ACString value);
|
||||
nsISFVByteSeq newByteSequence(in ACString value);
|
||||
nsISFVToken newToken(in ACString value);
|
||||
|
||||
/**
|
||||
* Creates nsISFVParams with no parameters. In other words, it's an empty map byt default.
|
||||
*/
|
||||
nsISFVParams newParameters();
|
||||
|
||||
/**
|
||||
* Creates nsISFVInnerList from nsISFVItem array and nsISFVParams.
|
||||
*/
|
||||
nsISFVInnerList newInnerList(in Array<nsISFVItem> items, in nsISFVParams params);
|
||||
|
||||
/**
|
||||
* Creates nsISFVItem, which represents Item header value, from nsISFVBareItem and associated nsISFVParams.
|
||||
*/
|
||||
nsISFVItem newItem(in nsISFVBareItem value, in nsISFVParams params);
|
||||
|
||||
/**
|
||||
* Creates nsISFVList, which represents List header value, from array of nsISFVItemOrInnerList.
|
||||
* nsISFVItemOrInnerList represens either Item (nsISFVItem) or Inner List (nsISFVInnerList).
|
||||
*/
|
||||
nsISFVList newList(in Array<nsISFVItemOrInnerList> members);
|
||||
|
||||
/**
|
||||
* Creates nsISFVDictionary representing Dictionary header value. It is empty by default.
|
||||
*/
|
||||
nsISFVDictionary newDictionary();
|
||||
};
|
|
@ -0,0 +1,862 @@
|
|||
/* 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/. */
|
||||
|
||||
use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_NULL_POINTER, NS_ERROR_UNEXPECTED, NS_OK};
|
||||
use nsstring::{nsACString, nsCString};
|
||||
use sfv::Parser;
|
||||
use sfv::SerializeValue;
|
||||
use sfv::{
|
||||
BareItem, Decimal, Dictionary, FromPrimitive, InnerList, Item, List, ListEntry, Parameters,
|
||||
ParseMore,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
use thin_vec::ThinVec;
|
||||
use xpcom::interfaces::{
|
||||
nsISFVBareItem, nsISFVBool, nsISFVByteSeq, nsISFVDecimal, nsISFVDictionary, nsISFVInnerList,
|
||||
nsISFVInteger, nsISFVItem, nsISFVItemOrInnerList, nsISFVList, nsISFVParams, nsISFVService,
|
||||
nsISFVString, nsISFVToken,
|
||||
};
|
||||
use xpcom::{xpcom, xpcom_method, RefPtr, XpCom};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn new_sfv_service(result: *mut *const nsISFVService) {
|
||||
let service: RefPtr<SFVService> = SFVService::new();
|
||||
RefPtr::new(service.coerce::<nsISFVService>()).forget(&mut *result);
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVService)]
|
||||
#[refcnt = "atomic"]
|
||||
struct InitSFVService {}
|
||||
|
||||
impl SFVService {
|
||||
fn new() -> RefPtr<SFVService> {
|
||||
SFVService::allocate(InitSFVService {})
|
||||
}
|
||||
|
||||
xpcom_method!(parse_dictionary => ParseDictionary(header: *const nsACString) -> *const nsISFVDictionary);
|
||||
fn parse_dictionary(&self, header: &nsACString) -> Result<RefPtr<nsISFVDictionary>, nsresult> {
|
||||
let parsed_dict = Parser::parse_dictionary(&header).map_err(|_| NS_ERROR_FAILURE)?;
|
||||
let sfv_dict = SFVDictionary::new();
|
||||
sfv_dict.value.replace(parsed_dict);
|
||||
Ok(RefPtr::new(sfv_dict.coerce::<nsISFVDictionary>()))
|
||||
}
|
||||
|
||||
xpcom_method!(parse_list => ParseList(field_value: *const nsACString) -> *const nsISFVList);
|
||||
fn parse_list(&self, header: &nsACString) -> Result<RefPtr<nsISFVList>, nsresult> {
|
||||
let parsed_list = Parser::parse_list(&header).map_err(|_| NS_ERROR_FAILURE)?;
|
||||
|
||||
let mut nsi_members = ThinVec::new();
|
||||
for item_or_inner_list in parsed_list.iter() {
|
||||
nsi_members.push(interface_from_list_entry(item_or_inner_list)?)
|
||||
}
|
||||
let sfv_list = SFVList::allocate(InitSFVList {
|
||||
members: RefCell::new(nsi_members),
|
||||
});
|
||||
Ok(RefPtr::new(sfv_list.coerce::<nsISFVList>()))
|
||||
}
|
||||
|
||||
xpcom_method!(parse_item => ParseItem(header: *const nsACString) -> *const nsISFVItem);
|
||||
fn parse_item(&self, header: &nsACString) -> Result<RefPtr<nsISFVItem>, nsresult> {
|
||||
let parsed_item = Parser::parse_item(&header).map_err(|_| NS_ERROR_FAILURE)?;
|
||||
interface_from_item(&parsed_item)
|
||||
}
|
||||
|
||||
xpcom_method!(new_integer => NewInteger(value: i64) -> *const nsISFVInteger);
|
||||
fn new_integer(&self, value: i64) -> Result<RefPtr<nsISFVInteger>, nsresult> {
|
||||
Ok(RefPtr::new(
|
||||
SFVInteger::new(value).coerce::<nsISFVInteger>(),
|
||||
))
|
||||
}
|
||||
|
||||
xpcom_method!(new_decimal => NewDecimal(value: f64) -> *const nsISFVDecimal);
|
||||
fn new_decimal(&self, value: f64) -> Result<RefPtr<nsISFVDecimal>, nsresult> {
|
||||
Ok(RefPtr::new(
|
||||
SFVDecimal::new(value).coerce::<nsISFVDecimal>(),
|
||||
))
|
||||
}
|
||||
|
||||
xpcom_method!(new_bool => NewBool(value: bool) -> *const nsISFVBool);
|
||||
fn new_bool(&self, value: bool) -> Result<RefPtr<nsISFVBool>, nsresult> {
|
||||
Ok(RefPtr::new(SFVBool::new(value).coerce::<nsISFVBool>()))
|
||||
}
|
||||
|
||||
xpcom_method!(new_string => NewString(value: *const nsACString) -> *const nsISFVString);
|
||||
fn new_string(&self, value: &nsACString) -> Result<RefPtr<nsISFVString>, nsresult> {
|
||||
Ok(RefPtr::new(SFVString::new(value).coerce::<nsISFVString>()))
|
||||
}
|
||||
|
||||
xpcom_method!(new_token => NewToken(value: *const nsACString) -> *const nsISFVToken);
|
||||
fn new_token(&self, value: &nsACString) -> Result<RefPtr<nsISFVToken>, nsresult> {
|
||||
Ok(RefPtr::new(SFVToken::new(value).coerce::<nsISFVToken>()))
|
||||
}
|
||||
|
||||
xpcom_method!(new_byte_sequence => NewByteSequence(value: *const nsACString) -> *const nsISFVByteSeq);
|
||||
fn new_byte_sequence(&self, value: &nsACString) -> Result<RefPtr<nsISFVByteSeq>, nsresult> {
|
||||
Ok(RefPtr::new(
|
||||
SFVByteSeq::new(value).coerce::<nsISFVByteSeq>(),
|
||||
))
|
||||
}
|
||||
|
||||
xpcom_method!(new_parameters => NewParameters() -> *const nsISFVParams);
|
||||
fn new_parameters(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
|
||||
Ok(RefPtr::new(SFVParams::new().coerce::<nsISFVParams>()))
|
||||
}
|
||||
|
||||
xpcom_method!(new_item => NewItem(value: *const nsISFVBareItem, params: *const nsISFVParams) -> *const nsISFVItem);
|
||||
fn new_item(
|
||||
&self,
|
||||
value: &nsISFVBareItem,
|
||||
params: &nsISFVParams,
|
||||
) -> Result<RefPtr<nsISFVItem>, nsresult> {
|
||||
Ok(RefPtr::new(
|
||||
SFVItem::new(value, params).coerce::<nsISFVItem>(),
|
||||
))
|
||||
}
|
||||
|
||||
xpcom_method!(new_inner_list => NewInnerList(items: *const thin_vec::ThinVec<RefPtr<nsISFVItem>>, params: *const nsISFVParams) -> *const nsISFVInnerList);
|
||||
fn new_inner_list(
|
||||
&self,
|
||||
items: &thin_vec::ThinVec<RefPtr<nsISFVItem>>,
|
||||
params: &nsISFVParams,
|
||||
) -> Result<RefPtr<nsISFVInnerList>, nsresult> {
|
||||
Ok(RefPtr::new(
|
||||
SFVInnerList::new(items, params).coerce::<nsISFVInnerList>(),
|
||||
))
|
||||
}
|
||||
|
||||
xpcom_method!(new_list => NewList(members: *const thin_vec::ThinVec<RefPtr<nsISFVItemOrInnerList>>) -> *const nsISFVList);
|
||||
fn new_list(
|
||||
&self,
|
||||
members: &thin_vec::ThinVec<RefPtr<nsISFVItemOrInnerList>>,
|
||||
) -> Result<RefPtr<nsISFVList>, nsresult> {
|
||||
Ok(RefPtr::new(SFVList::new(members).coerce::<nsISFVList>()))
|
||||
}
|
||||
|
||||
xpcom_method!(new_dictionary => NewDictionary() -> *const nsISFVDictionary);
|
||||
fn new_dictionary(&self) -> Result<RefPtr<nsISFVDictionary>, nsresult> {
|
||||
Ok(RefPtr::new(
|
||||
SFVDictionary::new().coerce::<nsISFVDictionary>(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVInteger, nsISFVBareItem)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVInteger {
|
||||
value: RefCell<i64>,
|
||||
}
|
||||
|
||||
impl SFVInteger {
|
||||
fn new(value: i64) -> RefPtr<SFVInteger> {
|
||||
SFVInteger::allocate(InitSFVInteger {
|
||||
value: RefCell::new(value),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(get_value => GetValue() -> i64);
|
||||
fn get_value(&self) -> Result<i64, nsresult> {
|
||||
Ok(*self.value.borrow())
|
||||
}
|
||||
|
||||
xpcom_method!(set_value => SetValue(value: i64));
|
||||
fn set_value(&self, value: i64) -> Result<(), nsresult> {
|
||||
self.value.replace(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(get_type => GetType() -> i64);
|
||||
fn get_type(&self) -> Result<i64, nsresult> {
|
||||
Ok(nsISFVBareItem::INTEGER)
|
||||
}
|
||||
|
||||
fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVBool, nsISFVBareItem)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVBool {
|
||||
value: RefCell<bool>,
|
||||
}
|
||||
|
||||
impl SFVBool {
|
||||
fn new(value: bool) -> RefPtr<SFVBool> {
|
||||
SFVBool::allocate(InitSFVBool {
|
||||
value: RefCell::new(value),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(get_value => GetValue() -> bool);
|
||||
fn get_value(&self) -> Result<bool, nsresult> {
|
||||
Ok(*self.value.borrow())
|
||||
}
|
||||
|
||||
xpcom_method!(set_value => SetValue(value: bool));
|
||||
fn set_value(&self, value: bool) -> Result<(), nsresult> {
|
||||
self.value.replace(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(get_type => GetType() -> i64);
|
||||
fn get_type(&self) -> Result<i64, nsresult> {
|
||||
Ok(nsISFVBareItem::BOOL)
|
||||
}
|
||||
|
||||
fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVString, nsISFVBareItem)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVString {
|
||||
value: RefCell<nsCString>,
|
||||
}
|
||||
|
||||
impl SFVString {
|
||||
fn new(value: &nsACString) -> RefPtr<SFVString> {
|
||||
SFVString::allocate(InitSFVString {
|
||||
value: RefCell::new(nsCString::from(value)),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_value => GetValue(
|
||||
) -> nsACString
|
||||
);
|
||||
|
||||
fn get_value(&self) -> Result<nsCString, nsresult> {
|
||||
Ok(self.value.borrow().clone())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
set_value => SetValue(value: *const nsACString)
|
||||
);
|
||||
|
||||
fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
|
||||
self.value.borrow_mut().assign(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(get_type => GetType() -> i64);
|
||||
fn get_type(&self) -> Result<i64, nsresult> {
|
||||
Ok(nsISFVBareItem::STRING)
|
||||
}
|
||||
|
||||
fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVToken, nsISFVBareItem)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVToken {
|
||||
value: RefCell<nsCString>,
|
||||
}
|
||||
|
||||
impl SFVToken {
|
||||
fn new(value: &nsACString) -> RefPtr<SFVToken> {
|
||||
SFVToken::allocate(InitSFVToken {
|
||||
value: RefCell::new(nsCString::from(value)),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_value => GetValue(
|
||||
) -> nsACString
|
||||
);
|
||||
|
||||
fn get_value(&self) -> Result<nsCString, nsresult> {
|
||||
Ok(self.value.borrow().clone())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
set_value => SetValue(value: *const nsACString)
|
||||
);
|
||||
|
||||
fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
|
||||
self.value.borrow_mut().assign(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(get_type => GetType() -> i64);
|
||||
fn get_type(&self) -> Result<i64, nsresult> {
|
||||
Ok(nsISFVBareItem::TOKEN)
|
||||
}
|
||||
|
||||
fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVByteSeq, nsISFVBareItem)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVByteSeq {
|
||||
value: RefCell<nsCString>,
|
||||
}
|
||||
|
||||
impl SFVByteSeq {
|
||||
fn new(value: &nsACString) -> RefPtr<SFVByteSeq> {
|
||||
SFVByteSeq::allocate(InitSFVByteSeq {
|
||||
value: RefCell::new(nsCString::from(value)),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_value => GetValue(
|
||||
) -> nsACString
|
||||
);
|
||||
|
||||
fn get_value(&self) -> Result<nsCString, nsresult> {
|
||||
Ok(self.value.borrow().clone())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
set_value => SetValue(value: *const nsACString)
|
||||
);
|
||||
|
||||
fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
|
||||
self.value.borrow_mut().assign(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(get_type => GetType() -> i64);
|
||||
fn get_type(&self) -> Result<i64, nsresult> {
|
||||
Ok(nsISFVBareItem::BYTE_SEQUENCE)
|
||||
}
|
||||
|
||||
fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVDecimal, nsISFVBareItem)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVDecimal {
|
||||
value: RefCell<f64>,
|
||||
}
|
||||
|
||||
impl SFVDecimal {
|
||||
fn new(value: f64) -> RefPtr<SFVDecimal> {
|
||||
SFVDecimal::allocate(InitSFVDecimal {
|
||||
value: RefCell::new(value),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_value => GetValue(
|
||||
) -> f64
|
||||
);
|
||||
|
||||
fn get_value(&self) -> Result<f64, nsresult> {
|
||||
Ok(*self.value.borrow())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
set_value => SetValue(value: f64)
|
||||
);
|
||||
|
||||
fn set_value(&self, value: f64) -> Result<(), nsresult> {
|
||||
self.value.replace(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(get_type => GetType() -> i64);
|
||||
fn get_type(&self) -> Result<i64, nsresult> {
|
||||
Ok(nsISFVBareItem::DECIMAL)
|
||||
}
|
||||
|
||||
fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVParams)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVParams {
|
||||
params: RefCell<Parameters>,
|
||||
}
|
||||
|
||||
impl SFVParams {
|
||||
fn new() -> RefPtr<SFVParams> {
|
||||
SFVParams::allocate(InitSFVParams {
|
||||
params: RefCell::new(Parameters::new()),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get => Get(key: *const nsACString) -> *const nsISFVBareItem
|
||||
);
|
||||
|
||||
fn get(&self, key: &nsACString) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
|
||||
let key = key.to_utf8();
|
||||
let params = self.params.borrow();
|
||||
let param_val = params.get(key.as_ref());
|
||||
|
||||
match param_val {
|
||||
Some(val) => interface_from_bare_item(val),
|
||||
None => return Err(NS_ERROR_UNEXPECTED),
|
||||
}
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
set => Set(key: *const nsACString, item: *const nsISFVBareItem)
|
||||
);
|
||||
|
||||
fn set(&self, key: &nsACString, item: &nsISFVBareItem) -> Result<(), nsresult> {
|
||||
let key = key.to_utf8().into_owned();
|
||||
let bare_item = bare_item_from_interface(item)?;
|
||||
self.params.borrow_mut().insert(key, bare_item);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
delete => Delete(key: *const nsACString)
|
||||
);
|
||||
fn delete(&self, key: &nsACString) -> Result<(), nsresult> {
|
||||
let key = key.to_utf8();
|
||||
self.params
|
||||
.borrow_mut()
|
||||
.shift_remove(key.as_ref())
|
||||
.ok_or(NS_ERROR_UNEXPECTED)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
keys => Keys() -> thin_vec::ThinVec<nsCString>
|
||||
);
|
||||
fn keys(&self) -> Result<thin_vec::ThinVec<nsCString>, nsresult> {
|
||||
let keys = self.params.borrow();
|
||||
let keys = keys
|
||||
.keys()
|
||||
.map(nsCString::from)
|
||||
.collect::<ThinVec<nsCString>>();
|
||||
Ok(keys)
|
||||
}
|
||||
|
||||
fn from_interface(obj: &nsISFVParams) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVItem, nsISFVItemOrInnerList)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVItem {
|
||||
value: RefPtr<nsISFVBareItem>,
|
||||
params: RefPtr<nsISFVParams>,
|
||||
}
|
||||
|
||||
impl SFVItem {
|
||||
fn new(value: &nsISFVBareItem, params: &nsISFVParams) -> RefPtr<SFVItem> {
|
||||
SFVItem::allocate(InitSFVItem {
|
||||
value: RefPtr::new(value),
|
||||
params: RefPtr::new(params),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_value => GetValue(
|
||||
) -> *const nsISFVBareItem
|
||||
);
|
||||
|
||||
fn get_value(&self) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
|
||||
Ok(self.value.clone())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_params => GetParams(
|
||||
) -> *const nsISFVParams
|
||||
);
|
||||
fn get_params(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
|
||||
Ok(self.params.clone())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
serialize => Serialize() -> nsACString
|
||||
);
|
||||
fn serialize(&self) -> Result<nsCString, nsresult> {
|
||||
let bare_item = bare_item_from_interface(self.value.deref())?;
|
||||
let params = params_from_interface(self.params.deref())?;
|
||||
let serialized = Item::with_params(bare_item, params)
|
||||
.serialize_value()
|
||||
.map_err(|_| NS_ERROR_FAILURE)?;
|
||||
Ok(nsCString::from(serialized))
|
||||
}
|
||||
|
||||
fn from_interface(obj: &nsISFVItem) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVInnerList, nsISFVItemOrInnerList)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVInnerList {
|
||||
items: RefCell<thin_vec::ThinVec<RefPtr<nsISFVItem>>>,
|
||||
params: RefPtr<nsISFVParams>,
|
||||
}
|
||||
|
||||
impl SFVInnerList {
|
||||
fn new(
|
||||
items: &thin_vec::ThinVec<RefPtr<nsISFVItem>>,
|
||||
params: &nsISFVParams,
|
||||
) -> RefPtr<SFVInnerList> {
|
||||
SFVInnerList::allocate(InitSFVInnerList {
|
||||
items: RefCell::new((*items).clone()),
|
||||
params: RefPtr::new(params),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_items => GetItems() -> thin_vec::ThinVec<RefPtr<nsISFVItem>>
|
||||
);
|
||||
|
||||
fn get_items(&self) -> Result<thin_vec::ThinVec<RefPtr<nsISFVItem>>, nsresult> {
|
||||
let items = self.items.borrow().clone();
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn SetItems(&self, value: *const thin_vec::ThinVec<RefPtr<nsISFVItem>>) -> nsresult {
|
||||
if value.is_null() {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
*self.items.borrow_mut() = (*value).clone();
|
||||
NS_OK
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_params => GetParams(
|
||||
) -> *const nsISFVParams
|
||||
);
|
||||
fn get_params(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
|
||||
Ok(self.params.clone())
|
||||
}
|
||||
|
||||
fn from_interface(obj: &nsISFVInnerList) -> &Self {
|
||||
unsafe { ::std::mem::transmute(obj) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVList, nsISFVSerialize)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVList {
|
||||
members: RefCell<thin_vec::ThinVec<RefPtr<nsISFVItemOrInnerList>>>,
|
||||
}
|
||||
|
||||
impl SFVList {
|
||||
fn new(members: &thin_vec::ThinVec<RefPtr<nsISFVItemOrInnerList>>) -> RefPtr<SFVList> {
|
||||
SFVList::allocate(InitSFVList {
|
||||
members: RefCell::new((*members).clone()),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get_members => GetMembers() -> thin_vec::ThinVec<RefPtr<nsISFVItemOrInnerList>>
|
||||
);
|
||||
|
||||
fn get_members(&self) -> Result<thin_vec::ThinVec<RefPtr<nsISFVItemOrInnerList>>, nsresult> {
|
||||
Ok(self.members.borrow().clone())
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn SetMembers(
|
||||
&self,
|
||||
value: *const thin_vec::ThinVec<RefPtr<nsISFVItemOrInnerList>>,
|
||||
) -> nsresult {
|
||||
if value.is_null() {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
*self.members.borrow_mut() = (*value).clone();
|
||||
NS_OK
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
parse_more => ParseMore(header: *const nsACString)
|
||||
);
|
||||
fn parse_more(&self, header: &nsACString) -> Result<(), nsresult> {
|
||||
// create List from SFVList to call parse_more on it
|
||||
let mut list = List::new();
|
||||
for interface_entry in self.get_members()?.iter() {
|
||||
let item_or_inner_list = list_entry_from_interface(interface_entry)?;
|
||||
list.push(item_or_inner_list);
|
||||
}
|
||||
|
||||
let _ = list.parse_more(&header).map_err(|_| NS_ERROR_FAILURE)?;
|
||||
|
||||
// replace SFVList's members with new_members
|
||||
let mut new_members = ThinVec::new();
|
||||
for item_or_inner_list in list.iter() {
|
||||
new_members.push(interface_from_list_entry(item_or_inner_list)?)
|
||||
}
|
||||
self.members.replace(new_members);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
serialize => Serialize() -> nsACString
|
||||
);
|
||||
fn serialize(&self) -> Result<nsCString, nsresult> {
|
||||
let mut list = List::new();
|
||||
|
||||
for interface_entry in self.get_members()?.iter() {
|
||||
let item_or_inner_list = list_entry_from_interface(interface_entry)?;
|
||||
list.push(item_or_inner_list);
|
||||
}
|
||||
|
||||
let serialized = list.serialize_value().map_err(|_| NS_ERROR_FAILURE)?;
|
||||
Ok(nsCString::from(serialized))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(xpcom)]
|
||||
#[xpimplements(nsISFVDictionary, nsISFVSerialize)]
|
||||
#[refcnt = "nonatomic"]
|
||||
struct InitSFVDictionary {
|
||||
value: RefCell<Dictionary>,
|
||||
}
|
||||
|
||||
impl SFVDictionary {
|
||||
fn new() -> RefPtr<SFVDictionary> {
|
||||
SFVDictionary::allocate(InitSFVDictionary {
|
||||
value: RefCell::new(Dictionary::new()),
|
||||
})
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
get => Get(key: *const nsACString) -> *const nsISFVItemOrInnerList
|
||||
);
|
||||
|
||||
fn get(&self, key: &nsACString) -> Result<RefPtr<nsISFVItemOrInnerList>, nsresult> {
|
||||
let key = key.to_utf8();
|
||||
let value = self.value.borrow();
|
||||
let member_value = value.get(key.as_ref());
|
||||
|
||||
match member_value {
|
||||
Some(member) => interface_from_list_entry(member),
|
||||
None => return Err(NS_ERROR_UNEXPECTED),
|
||||
}
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
set => Set(key: *const nsACString, item: *const nsISFVItemOrInnerList)
|
||||
);
|
||||
|
||||
fn set(&self, key: &nsACString, member_value: &nsISFVItemOrInnerList) -> Result<(), nsresult> {
|
||||
let key = key.to_utf8().into_owned();
|
||||
let value = list_entry_from_interface(member_value)?;
|
||||
self.value.borrow_mut().insert(key, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
delete => Delete(key: *const nsACString)
|
||||
);
|
||||
|
||||
fn delete(&self, key: &nsACString) -> Result<(), nsresult> {
|
||||
let key = key.to_utf8();
|
||||
self.value
|
||||
.borrow_mut()
|
||||
.shift_remove(key.as_ref())
|
||||
.ok_or(NS_ERROR_UNEXPECTED)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
keys => Keys() -> thin_vec::ThinVec<nsCString>
|
||||
);
|
||||
fn keys(&self) -> Result<thin_vec::ThinVec<nsCString>, nsresult> {
|
||||
let members = self.value.borrow();
|
||||
let keys = members
|
||||
.keys()
|
||||
.map(nsCString::from)
|
||||
.collect::<ThinVec<nsCString>>();
|
||||
Ok(keys)
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
parse_more => ParseMore(header: *const nsACString)
|
||||
);
|
||||
fn parse_more(&self, header: &nsACString) -> Result<(), nsresult> {
|
||||
let _ = self
|
||||
.value
|
||||
.borrow_mut()
|
||||
.parse_more(&header)
|
||||
.map_err(|_| NS_ERROR_FAILURE)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
serialize => Serialize() -> nsACString
|
||||
);
|
||||
fn serialize(&self) -> Result<nsCString, nsresult> {
|
||||
let serialized = self
|
||||
.value
|
||||
.borrow()
|
||||
.serialize_value()
|
||||
.map_err(|_| NS_ERROR_FAILURE)?;
|
||||
Ok(nsCString::from(serialized))
|
||||
}
|
||||
}
|
||||
|
||||
fn bare_item_from_interface(obj: &nsISFVBareItem) -> Result<BareItem, nsresult> {
|
||||
let obj = obj
|
||||
.query_interface::<nsISFVBareItem>()
|
||||
.ok_or(NS_ERROR_UNEXPECTED)?;
|
||||
let mut obj_type: i64 = -1;
|
||||
unsafe {
|
||||
obj.deref().GetType(&mut obj_type);
|
||||
}
|
||||
|
||||
match obj_type {
|
||||
nsISFVBareItem::BOOL => {
|
||||
let item_value = SFVBool::from_bare_item_interface(obj.deref()).get_value()?;
|
||||
Ok(BareItem::Boolean(item_value))
|
||||
}
|
||||
nsISFVBareItem::STRING => {
|
||||
let string_itm = SFVString::from_bare_item_interface(obj.deref()).get_value()?;
|
||||
let item_value = (*string_itm.to_utf8()).to_string();
|
||||
Ok(BareItem::String(item_value))
|
||||
}
|
||||
nsISFVBareItem::TOKEN => {
|
||||
let token_itm = SFVToken::from_bare_item_interface(obj.deref()).get_value()?;
|
||||
let item_value = (*token_itm.to_utf8()).to_string();
|
||||
Ok(BareItem::Token(item_value))
|
||||
}
|
||||
nsISFVBareItem::INTEGER => {
|
||||
let item_value = SFVInteger::from_bare_item_interface(obj.deref()).get_value()?;
|
||||
Ok(BareItem::Integer(item_value))
|
||||
}
|
||||
nsISFVBareItem::DECIMAL => {
|
||||
let item_value = SFVDecimal::from_bare_item_interface(obj.deref()).get_value()?;
|
||||
let decimal: Decimal = Decimal::from_f64(item_value).ok_or(NS_ERROR_UNEXPECTED)?;
|
||||
Ok(BareItem::Decimal(decimal))
|
||||
}
|
||||
nsISFVBareItem::BYTE_SEQUENCE => {
|
||||
let token_itm = SFVByteSeq::from_bare_item_interface(obj.deref()).get_value()?;
|
||||
let item_value: String = (*token_itm.to_utf8()).to_string();
|
||||
Ok(BareItem::ByteSeq(item_value.into_bytes()))
|
||||
}
|
||||
_ => return Err(NS_ERROR_UNEXPECTED),
|
||||
}
|
||||
}
|
||||
|
||||
fn params_from_interface(obj: &nsISFVParams) -> Result<Parameters, nsresult> {
|
||||
let params = SFVParams::from_interface(obj).params.borrow();
|
||||
Ok(params.clone())
|
||||
}
|
||||
|
||||
fn item_from_interface(obj: &nsISFVItem) -> Result<Item, nsresult> {
|
||||
let sfv_item = SFVItem::from_interface(obj);
|
||||
let bare_item = bare_item_from_interface(sfv_item.value.deref())?;
|
||||
let parameters = params_from_interface(sfv_item.params.deref())?;
|
||||
Ok(Item::with_params(bare_item, parameters))
|
||||
}
|
||||
|
||||
fn inner_list_from_interface(obj: &nsISFVInnerList) -> Result<InnerList, nsresult> {
|
||||
let sfv_inner_list = SFVInnerList::from_interface(obj);
|
||||
|
||||
let mut inner_list_items: Vec<Item> = vec![];
|
||||
for item in sfv_inner_list.items.borrow().iter() {
|
||||
let item = item_from_interface(item)?;
|
||||
inner_list_items.push(item);
|
||||
}
|
||||
let inner_list_params = params_from_interface(sfv_inner_list.params.deref())?;
|
||||
Ok(InnerList::with_params(inner_list_items, inner_list_params))
|
||||
}
|
||||
|
||||
fn list_entry_from_interface(obj: &nsISFVItemOrInnerList) -> Result<ListEntry, nsresult> {
|
||||
if let Some(nsi_item) = obj.query_interface::<nsISFVItem>() {
|
||||
let item = item_from_interface(nsi_item.deref())?;
|
||||
Ok(ListEntry::Item(item))
|
||||
} else if let Some(nsi_inner_list) = obj.query_interface::<nsISFVInnerList>() {
|
||||
let inner_list = inner_list_from_interface(nsi_inner_list.deref())?;
|
||||
Ok(ListEntry::InnerList(inner_list))
|
||||
} else {
|
||||
return Err(NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
|
||||
fn interface_from_bare_item(bare_item: &BareItem) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
|
||||
let bare_item = match bare_item {
|
||||
BareItem::Boolean(val) => RefPtr::new(SFVBool::new(*val).coerce::<nsISFVBareItem>()),
|
||||
BareItem::String(val) => {
|
||||
RefPtr::new(SFVString::new(&nsCString::from(val)).coerce::<nsISFVBareItem>())
|
||||
}
|
||||
BareItem::Token(val) => {
|
||||
RefPtr::new(SFVToken::new(&nsCString::from(val)).coerce::<nsISFVBareItem>())
|
||||
}
|
||||
BareItem::ByteSeq(val) => RefPtr::new(
|
||||
SFVByteSeq::new(&nsCString::from(String::from_utf8(val.to_vec()).unwrap()))
|
||||
.coerce::<nsISFVBareItem>(),
|
||||
),
|
||||
BareItem::Decimal(val) => {
|
||||
let val = val
|
||||
.to_string()
|
||||
.parse::<f64>()
|
||||
.map_err(|_| NS_ERROR_UNEXPECTED)?;
|
||||
RefPtr::new(SFVDecimal::new(val).coerce::<nsISFVBareItem>())
|
||||
}
|
||||
BareItem::Integer(val) => RefPtr::new(SFVInteger::new(*val).coerce::<nsISFVBareItem>()),
|
||||
};
|
||||
|
||||
Ok(bare_item)
|
||||
}
|
||||
|
||||
fn interface_from_item(item: &Item) -> Result<RefPtr<nsISFVItem>, nsresult> {
|
||||
let nsi_bare_item = interface_from_bare_item(&item.bare_item)?;
|
||||
let nsi_params = interface_from_params(&item.params)?;
|
||||
Ok(RefPtr::new(
|
||||
SFVItem::new(&nsi_bare_item, &nsi_params).coerce::<nsISFVItem>(),
|
||||
))
|
||||
}
|
||||
|
||||
fn interface_from_params(params: &Parameters) -> Result<RefPtr<nsISFVParams>, nsresult> {
|
||||
let sfv_params = SFVParams::new();
|
||||
for (key, value) in params.iter() {
|
||||
sfv_params
|
||||
.params
|
||||
.borrow_mut()
|
||||
.insert(key.clone(), value.clone());
|
||||
}
|
||||
Ok(RefPtr::new(sfv_params.coerce::<nsISFVParams>()))
|
||||
}
|
||||
|
||||
fn interface_from_list_entry(
|
||||
member: &ListEntry,
|
||||
) -> Result<RefPtr<nsISFVItemOrInnerList>, nsresult> {
|
||||
match member {
|
||||
ListEntry::Item(item) => {
|
||||
let nsi_bare_item = interface_from_bare_item(&item.bare_item)?;
|
||||
let nsi_params = interface_from_params(&item.params)?;
|
||||
Ok(RefPtr::new(
|
||||
SFVItem::new(&nsi_bare_item, &nsi_params).coerce::<nsISFVItemOrInnerList>(),
|
||||
))
|
||||
}
|
||||
ListEntry::InnerList(inner_list) => {
|
||||
let mut nsi_inner_list = ThinVec::new();
|
||||
for item in inner_list.items.iter() {
|
||||
let nsi_item = interface_from_item(item)?;
|
||||
nsi_inner_list.push(nsi_item);
|
||||
}
|
||||
|
||||
let nsi_params = interface_from_params(&inner_list.params)?;
|
||||
Ok(RefPtr::new(
|
||||
SFVInnerList::new(&nsi_inner_list, &nsi_params).coerce::<nsISFVItemOrInnerList>(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -312,7 +312,7 @@ EXTRA_JS_MODULES += [
|
|||
'NetUtil.jsm',
|
||||
]
|
||||
|
||||
DIRS += [ 'mozurl', 'rust-helper' ]
|
||||
DIRS += [ 'mozurl', 'rust-helper', 'http-sfv' ]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
|
|
@ -596,6 +596,13 @@ Classes = [
|
|||
'constructor': 'mozilla::net::CookieService::GetXPCOMSingleton',
|
||||
'headers': ['/netwerk/cookie/CookieService.h'],
|
||||
},
|
||||
{
|
||||
'cid': '{e1676f84-e6e5-45d0-a4bf-d9905efc5b2e}',
|
||||
'contract_ids': ['@mozilla.org/http-sfv-service;1'],
|
||||
'singleton': True,
|
||||
'constructor': 'mozilla::net::GetSFVService',
|
||||
'headers': ['mozilla/net/SFVService.h'],
|
||||
},
|
||||
]
|
||||
|
||||
if defined('NECKO_WIFI'):
|
||||
|
|
|
@ -0,0 +1,590 @@
|
|||
"use strict";
|
||||
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const gService = Cc["@mozilla.org/http-sfv-service;1"].getService(
|
||||
Ci.nsISFVService
|
||||
);
|
||||
|
||||
add_task(async function test_sfv_bare_item() {
|
||||
// tests bare item
|
||||
let item_int = gService.newInteger(19);
|
||||
Assert.equal(item_int.value, 19, "check bare item value");
|
||||
|
||||
let item_bool = gService.newBool(true);
|
||||
Assert.equal(item_bool.value, true, "check bare item value");
|
||||
item_bool.value = false;
|
||||
Assert.equal(item_bool.value, false, "check bare item value");
|
||||
|
||||
let item_float = gService.newDecimal(145.45);
|
||||
Assert.equal(item_float.value, 145.45);
|
||||
|
||||
let item_str = gService.newString("some_string");
|
||||
Assert.equal(item_str.value, "some_string", "check bare item value");
|
||||
|
||||
let item_byte_seq = gService.newByteSequence("aGVsbG8=");
|
||||
Assert.equal(item_byte_seq.value, "aGVsbG8=", "check bare item value");
|
||||
|
||||
let item_token = gService.newToken("*a");
|
||||
Assert.equal(item_token.value, "*a", "check bare item value");
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_params() {
|
||||
// test params
|
||||
let params = gService.newParameters();
|
||||
let bool_param = gService.newBool(false);
|
||||
let int_param = gService.newInteger(15);
|
||||
let decimal_param = gService.newDecimal(15.45);
|
||||
|
||||
params.set("bool_param", bool_param);
|
||||
params.set("int_param", int_param);
|
||||
params.set("decimal_param", decimal_param);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
params.get("some_param");
|
||||
},
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
"must throw exception as key does not exist in parameters"
|
||||
);
|
||||
Assert.equal(
|
||||
params.get("bool_param").QueryInterface(Ci.nsISFVBool).value,
|
||||
false,
|
||||
"get parameter by key and check its value"
|
||||
);
|
||||
Assert.equal(
|
||||
params.get("int_param").QueryInterface(Ci.nsISFVInteger).value,
|
||||
15,
|
||||
"get parameter by key and check its value"
|
||||
);
|
||||
Assert.equal(
|
||||
params.get("decimal_param").QueryInterface(Ci.nsISFVDecimal).value,
|
||||
15.45,
|
||||
"get parameter by key and check its value"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
params.keys(),
|
||||
["bool_param", "int_param", "decimal_param"],
|
||||
"check that parameters contain all the expected keys"
|
||||
);
|
||||
|
||||
params.delete("int_param");
|
||||
Assert.deepEqual(
|
||||
params.keys(),
|
||||
["bool_param", "decimal_param"],
|
||||
"check that parameter has been deleted"
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
params.delete("some_param");
|
||||
},
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
"must throw exception upon attempt to delete by non-existing key"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_inner_list() {
|
||||
// create primitives for inner list
|
||||
let item1_params = gService.newParameters();
|
||||
item1_params.set("param_1", gService.newToken("*smth"));
|
||||
let item1 = gService.newItem(gService.newDecimal(172.145865), item1_params);
|
||||
|
||||
let item2_params = gService.newParameters();
|
||||
item2_params.set("param_1", gService.newBool(true));
|
||||
item2_params.set("param_2", gService.newInteger(145454));
|
||||
let item2 = gService.newItem(
|
||||
gService.newByteSequence("weather"),
|
||||
item2_params
|
||||
);
|
||||
|
||||
// create inner list
|
||||
let inner_list_params = gService.newParameters();
|
||||
inner_list_params.set("inner_param", gService.newByteSequence("tests"));
|
||||
let inner_list = gService.newInnerList([item1, item2], inner_list_params);
|
||||
|
||||
// check inner list members & params
|
||||
let inner_list_members = inner_list.QueryInterface(Ci.nsISFVInnerList).items;
|
||||
let inner_list_parameters = inner_list
|
||||
.QueryInterface(Ci.nsISFVInnerList)
|
||||
.params.QueryInterface(Ci.nsISFVParams);
|
||||
Assert.equal(inner_list_members.length, 2, "check inner list length");
|
||||
|
||||
let inner_item1 = inner_list_members[0].QueryInterface(Ci.nsISFVItem);
|
||||
Assert.equal(
|
||||
inner_item1.value.QueryInterface(Ci.nsISFVDecimal).value,
|
||||
172.145865,
|
||||
"check inner list member value"
|
||||
);
|
||||
|
||||
let inner_item2 = inner_list_members[1].QueryInterface(Ci.nsISFVItem);
|
||||
Assert.equal(
|
||||
inner_item2.value.QueryInterface(Ci.nsISFVByteSeq).value,
|
||||
"weather",
|
||||
"check inner list member value"
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
inner_list_parameters.get("inner_param").QueryInterface(Ci.nsISFVByteSeq)
|
||||
.value,
|
||||
"tests",
|
||||
"get inner list parameter by key and check its value"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_item() {
|
||||
// create parameters for item
|
||||
let params = gService.newParameters();
|
||||
let param1 = gService.newBool(false);
|
||||
let param2 = gService.newString("str_value");
|
||||
let param3 = gService.newBool(true);
|
||||
params.set("param_1", param1);
|
||||
params.set("param_2", param2);
|
||||
params.set("param_3", param3);
|
||||
|
||||
// create item field
|
||||
let item = gService.newItem(gService.newToken("*abc"), params);
|
||||
|
||||
Assert.equal(
|
||||
item.value.QueryInterface(Ci.nsISFVToken).value,
|
||||
"*abc",
|
||||
"check items's value"
|
||||
);
|
||||
Assert.equal(
|
||||
item.params.get("param_1").QueryInterface(Ci.nsISFVBool).value,
|
||||
false,
|
||||
"get item parameter by key and check its value"
|
||||
);
|
||||
Assert.equal(
|
||||
item.params.get("param_2").QueryInterface(Ci.nsISFVString).value,
|
||||
"str_value",
|
||||
"get item parameter by key and check its value"
|
||||
);
|
||||
Assert.equal(
|
||||
item.params.get("param_3").QueryInterface(Ci.nsISFVBool).value,
|
||||
true,
|
||||
"get item parameter by key and check its value"
|
||||
);
|
||||
|
||||
// check item field serialization
|
||||
let serialized = item.serialize();
|
||||
Assert.equal(
|
||||
serialized,
|
||||
`*abc;param_1=?0;param_2="str_value";param_3`,
|
||||
"serialized output must match expected one"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_list() {
|
||||
// create primitives for List
|
||||
let item1_params = gService.newParameters();
|
||||
item1_params.set("param_1", gService.newToken("*smth"));
|
||||
let item1 = gService.newItem(gService.newDecimal(145454.14568), item1_params);
|
||||
|
||||
let item2_params = gService.newParameters();
|
||||
item2_params.set("param_1", gService.newBool(true));
|
||||
let item2 = gService.newItem(
|
||||
gService.newByteSequence("weather"),
|
||||
item2_params
|
||||
);
|
||||
|
||||
let inner_list = gService.newInnerList(
|
||||
[item1, item2],
|
||||
gService.newParameters()
|
||||
);
|
||||
|
||||
// create list field
|
||||
let list = gService.newList([item1, inner_list]);
|
||||
|
||||
// check list's members
|
||||
let list_members = list.members;
|
||||
Assert.equal(list_members.length, 2, "check list length");
|
||||
|
||||
// check list's member of item type
|
||||
let member1 = list_members[0].QueryInterface(Ci.nsISFVItem);
|
||||
Assert.equal(
|
||||
member1.value.QueryInterface(Ci.nsISFVDecimal).value,
|
||||
145454.14568,
|
||||
"check list member's value"
|
||||
);
|
||||
let member1_parameters = member1.params;
|
||||
Assert.equal(
|
||||
member1_parameters.get("param_1").QueryInterface(Ci.nsISFVToken).value,
|
||||
"*smth",
|
||||
"get list member's parameter by key and check its value"
|
||||
);
|
||||
|
||||
// check list's member of inner list type
|
||||
let inner_list_members = list_members[1].QueryInterface(Ci.nsISFVInnerList)
|
||||
.items;
|
||||
Assert.equal(inner_list_members.length, 2, "check inner list length");
|
||||
|
||||
let inner_item1 = inner_list_members[0].QueryInterface(Ci.nsISFVItem);
|
||||
Assert.equal(
|
||||
inner_item1.value.QueryInterface(Ci.nsISFVDecimal).value,
|
||||
145454.14568,
|
||||
"check inner list member's value"
|
||||
);
|
||||
|
||||
let inner_item2 = inner_list_members[1].QueryInterface(Ci.nsISFVItem);
|
||||
Assert.equal(
|
||||
inner_item2.value.QueryInterface(Ci.nsISFVByteSeq).value,
|
||||
"weather",
|
||||
"check inner list member's value"
|
||||
);
|
||||
|
||||
// check inner list member's params
|
||||
let inner_list_parameters = list_members[1]
|
||||
.QueryInterface(Ci.nsISFVInnerList)
|
||||
.params.QueryInterface(Ci.nsISFVParams);
|
||||
|
||||
// check serialization of list field
|
||||
let expected_serialized =
|
||||
"145454.146;param_1=*smth, (145454.146;param_1=*smth :d2VhdGhlcg==:;param_1)";
|
||||
let actual_serialized = list.serialize();
|
||||
Assert.equal(
|
||||
actual_serialized,
|
||||
expected_serialized,
|
||||
"serialized output must match expected one"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_dictionary() {
|
||||
// create primitives for dictionary field
|
||||
|
||||
// dict member1
|
||||
let params1 = gService.newParameters();
|
||||
params1.set("mp_1", gService.newBool(true));
|
||||
params1.set("mp_2", gService.newDecimal(68.758602));
|
||||
let member1 = gService.newItem(gService.newString("member_1"), params1);
|
||||
|
||||
// dict member2
|
||||
let params2 = gService.newParameters();
|
||||
let inner_item1 = gService.newItem(
|
||||
gService.newString("inner_item_1"),
|
||||
gService.newParameters()
|
||||
);
|
||||
let inner_item2 = gService.newItem(
|
||||
gService.newToken("tok"),
|
||||
gService.newParameters()
|
||||
);
|
||||
let member2 = gService.newInnerList([inner_item1, inner_item2], params2);
|
||||
|
||||
// dict member3
|
||||
let params_3 = gService.newParameters();
|
||||
params_3.set("mp_1", gService.newInteger(6586));
|
||||
let member3 = gService.newItem(gService.newString("member_3"), params_3);
|
||||
|
||||
// create dictionary field
|
||||
let dict = gService.newDictionary();
|
||||
dict.set("key_1", member1);
|
||||
dict.set("key_2", member2);
|
||||
dict.set("key_3", member3);
|
||||
|
||||
// check dictionary keys
|
||||
let expected = ["key_1", "key_2", "key_3"];
|
||||
Assert.deepEqual(
|
||||
expected,
|
||||
dict.keys(),
|
||||
"check dictionary contains all the expected keys"
|
||||
);
|
||||
|
||||
// check dictionary members
|
||||
Assert.throws(
|
||||
() => {
|
||||
dict.get("key_4");
|
||||
},
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
"must throw exception as key does not exist in dictionary"
|
||||
);
|
||||
|
||||
let dict_member1 = dict.get("key_1").QueryInterface(Ci.nsISFVItem);
|
||||
let dict_member2 = dict.get("key_2").QueryInterface(Ci.nsISFVInnerList);
|
||||
let dict_member3 = dict.get("key_3").QueryInterface(Ci.nsISFVItem);
|
||||
|
||||
// Assert.equal(
|
||||
// dict_member1.value.QueryInterface(Ci.nsISFVString).value,
|
||||
// "member_1",
|
||||
// "check dictionary member's value"
|
||||
// );
|
||||
// Assert.equal(
|
||||
// dict_member1.params.get("mp_1").QueryInterface(Ci.nsISFVBool).value,
|
||||
// true,
|
||||
// "get dictionary member's parameter by key and check its value"
|
||||
// );
|
||||
// Assert.equal(
|
||||
// dict_member1.params.get("mp_2").QueryInterface(Ci.nsISFVDecimal).value,
|
||||
// "68.758602",
|
||||
// "get dictionary member's parameter by key and check its value"
|
||||
// );
|
||||
|
||||
let dict_member2_items = dict_member2.QueryInterface(Ci.nsISFVInnerList)
|
||||
.items;
|
||||
let dict_member2_params = dict_member2
|
||||
.QueryInterface(Ci.nsISFVInnerList)
|
||||
.params.QueryInterface(Ci.nsISFVParams);
|
||||
Assert.equal(
|
||||
dict_member2_items[0]
|
||||
.QueryInterface(Ci.nsISFVItem)
|
||||
.value.QueryInterface(Ci.nsISFVString).value,
|
||||
"inner_item_1",
|
||||
"get dictionary member of inner list type, and check inner list member's value"
|
||||
);
|
||||
Assert.equal(
|
||||
dict_member2_items[1]
|
||||
.QueryInterface(Ci.nsISFVItem)
|
||||
.value.QueryInterface(Ci.nsISFVToken).value,
|
||||
"tok",
|
||||
"get dictionary member of inner list type, and check inner list member's value"
|
||||
);
|
||||
Assert.throws(
|
||||
() => {
|
||||
dict_member2_params.get("some_param");
|
||||
},
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
"must throw exception as dict member's parameters are empty"
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
dict_member3.value.QueryInterface(Ci.nsISFVString).value,
|
||||
"member_3",
|
||||
"check dictionary member's value"
|
||||
);
|
||||
Assert.equal(
|
||||
dict_member3.params.get("mp_1").QueryInterface(Ci.nsISFVInteger).value,
|
||||
6586,
|
||||
"get dictionary member's parameter by key and check its value"
|
||||
);
|
||||
|
||||
// check serialization of Dictionary field
|
||||
let expected_serialized = `key_1="member_1";mp_1;mp_2=68.759, key_2=("inner_item_1" tok), key_3="member_3";mp_1=6586`;
|
||||
let actual_serialized = dict.serialize();
|
||||
Assert.equal(
|
||||
actual_serialized,
|
||||
expected_serialized,
|
||||
"serialized output must match expected one"
|
||||
);
|
||||
|
||||
// check deleting dict member
|
||||
dict.delete("key_2");
|
||||
Assert.deepEqual(
|
||||
dict.keys(),
|
||||
["key_1", "key_3"],
|
||||
"check that dictionary member has been deleted"
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
dict.delete("some_key");
|
||||
},
|
||||
/NS_ERROR_UNEXPECTED/,
|
||||
"must throw exception upon attempt to delete by non-existing key"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_item_parsing() {
|
||||
Assert.ok(gService.parseItem(`"str"`), "input must be parsed into Item");
|
||||
Assert.ok(gService.parseItem("12.35;a "), "input must be parsed into Item");
|
||||
Assert.ok(gService.parseItem("12.35; a "), "input must be parsed into Item");
|
||||
Assert.ok(gService.parseItem("12.35 "), "input must be parsed into Item");
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
gService.parseItem("12.35;\ta ");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"item parsing must fail: invalid parameters delimiter"
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
gService.parseItem("125666.3565648855455");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"item parsing must fail: decimal too long"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_list_parsing() {
|
||||
Assert.ok(
|
||||
gService.parseList(
|
||||
"(?1;param_1=*smth :d2VhdGhlcg==:;param_1;param_2=145454);inner_param=:d2VpcmR0ZXN0cw==:"
|
||||
),
|
||||
"input must be parsed into List"
|
||||
);
|
||||
Assert.ok("a, (b c)", "input must be parsed into List");
|
||||
|
||||
Assert.throws(() => {
|
||||
gService.parseList("?tok", "list parsing must fail");
|
||||
}, /NS_ERROR_FAILURE/);
|
||||
|
||||
Assert.throws(() => {
|
||||
gService.parseList(
|
||||
"a, (b, c)",
|
||||
"list parsing must fail: invalid delimiter within inner list"
|
||||
);
|
||||
}, /NS_ERROR_FAILURE/);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
gService.parseList("a, b c");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"list parsing must fail: invalid delimiter"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_dict_parsing() {
|
||||
Assert.ok(
|
||||
gService.parseDictionary(`abc=123;a=1;b=2, def=456, ghi=789;q=9;r="+w"`),
|
||||
"input must be parsed into Dictionary"
|
||||
);
|
||||
Assert.ok(
|
||||
gService.parseDictionary("a=1\t,\t\t\t c=*"),
|
||||
"input must be parsed into Dictionary"
|
||||
);
|
||||
Assert.ok(
|
||||
gService.parseDictionary("a=1\t,\tc=* \t\t"),
|
||||
"input must be parsed into Dictionary"
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
gService.parseDictionary("a=1\t,\tc=*,");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"dictionary parsing must fail: trailing comma"
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
gService.parseDictionary("a=1 c=*");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"dictionary parsing must fail: invalid delimiter"
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
gService.parseDictionary("INVALID_key=1, c=*");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"dictionary parsing must fail: invalid key format, can't be in uppercase"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_list_parse_serialize() {
|
||||
let list_field = gService.parseList("1 , 42, (42 43)");
|
||||
Assert.equal(
|
||||
list_field.serialize(),
|
||||
"1, 42, (42 43)",
|
||||
"serialized output must match expected one"
|
||||
);
|
||||
|
||||
// create new inner list with parameters
|
||||
let inner_list_params = gService.newParameters();
|
||||
inner_list_params.set("key1", gService.newString("value1"));
|
||||
inner_list_params.set("key2", gService.newBool(true));
|
||||
inner_list_params.set("key3", gService.newBool(false));
|
||||
let inner_list_items = [
|
||||
gService.newItem(
|
||||
gService.newDecimal(-1865.75653),
|
||||
gService.newParameters()
|
||||
),
|
||||
gService.newItem(gService.newToken("token"), gService.newParameters()),
|
||||
gService.newItem(gService.newString(`no"yes`), gService.newParameters()),
|
||||
];
|
||||
let new_list_member = gService.newInnerList(
|
||||
inner_list_items,
|
||||
inner_list_params
|
||||
);
|
||||
|
||||
// set one of list members to inner list and check it's serialized as expected
|
||||
let members = list_field.members;
|
||||
members[1] = new_list_member;
|
||||
list_field.members = members;
|
||||
Assert.equal(
|
||||
list_field.serialize(),
|
||||
`1, (-1865.757 token "no\\"yes");key1="value1";key2;key3=?0, (42 43)`,
|
||||
"update list member and check list is serialized as expected"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_dict_parse_serialize() {
|
||||
let dict_field = gService.parseDictionary(
|
||||
"a=1, b; foo=*, \tc=3, \t \tabc=123;a=1;b=2\t"
|
||||
);
|
||||
Assert.equal(
|
||||
dict_field.serialize(),
|
||||
"a=1, b;foo=*, c=3, abc=123;a=1;b=2",
|
||||
"serialized output must match expected one"
|
||||
);
|
||||
|
||||
// set new value for existing dict's key
|
||||
dict_field.set(
|
||||
"a",
|
||||
gService.newItem(gService.newInteger(165), gService.newParameters())
|
||||
);
|
||||
|
||||
// add new member to dict
|
||||
dict_field.set(
|
||||
"key",
|
||||
gService.newItem(gService.newDecimal(45.0), gService.newParameters())
|
||||
);
|
||||
|
||||
// check dict is serialized properly after the above changes
|
||||
Assert.equal(
|
||||
dict_field.serialize(),
|
||||
"a=165, b;foo=*, c=3, abc=123;a=1;b=2, key=45.0",
|
||||
"update dictionary members and dictionary list is serialized as expected"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_list_parse_more() {
|
||||
// check parsing of multiline header of List type
|
||||
let list_field = gService.parseList("(12 abc), 12.456\t\t ");
|
||||
list_field.parseMore("11, 15, tok");
|
||||
Assert.equal(
|
||||
list_field.serialize(),
|
||||
"(12 abc), 12.456, 11, 15, tok",
|
||||
"multi-line field value parsed and serialized successfully"
|
||||
);
|
||||
|
||||
// should fail parsing one more line
|
||||
Assert.throws(
|
||||
() => {
|
||||
list_field.parseMore("(tk\t1)");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"line parsing must fail: invalid delimiter in inner list"
|
||||
);
|
||||
Assert.equal(
|
||||
list_field.serialize(),
|
||||
"(12 abc), 12.456, 11, 15, tok",
|
||||
"parsed value must not change if parsing one more line of header fails"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_sfv_dict_parse_more() {
|
||||
// check parsing of multiline header of Dictionary type
|
||||
let dict_field = gService.parseDictionary("");
|
||||
dict_field.parseMore("key2=?0, key3=?1, key4=itm");
|
||||
dict_field.parseMore("key1, key5=11, key4=45");
|
||||
|
||||
Assert.equal(
|
||||
dict_field.serialize(),
|
||||
"key2=?0, key3, key4=45, key1, key5=11",
|
||||
"multi-line field value parsed and serialized successfully"
|
||||
);
|
||||
|
||||
// should fail parsing one more line
|
||||
Assert.throws(
|
||||
() => {
|
||||
dict_field.parseMore("c=12, _k=13");
|
||||
},
|
||||
/NS_ERROR_FAILURE/,
|
||||
"line parsing must fail: invalid key format"
|
||||
);
|
||||
});
|
|
@ -440,5 +440,6 @@ skip-if = os == "android"
|
|||
skip-if = os == "android"
|
||||
[test_trr_proxy.js]
|
||||
[test_trr_cname_chain.js]
|
||||
[test_http_sfv.js]
|
||||
skip-if = os == "android"
|
||||
[test_blob_channelname.js]
|
||||
|
|
|
@ -50,7 +50,7 @@ mapped_hyph = { git = "https://github.com/jfkthame/mapped_hyph.git", tag = "v0.3
|
|||
remote = { path = "../../../../remote", optional = true }
|
||||
fog_control = { path = "../../../components/glean", optional = true }
|
||||
app_services_logger = { path = "../../../../services/common/app_services_logger" }
|
||||
|
||||
http_sfv = { path = "../../../../netwerk/base/http-sfv" }
|
||||
unic-langid = { version = "0.8", features = ["likelysubtags"] }
|
||||
unic-langid-ffi = { path = "../../../../intl/locale/rust/unic-langid-ffi" }
|
||||
fluent-langneg = { version = "0.12.1", features = ["cldr"] }
|
||||
|
|
|
@ -31,6 +31,7 @@ extern crate firefox_accounts_bridge;
|
|||
#[cfg(feature = "glean")]
|
||||
extern crate fog_control;
|
||||
extern crate gkrust_utils;
|
||||
extern crate http_sfv;
|
||||
extern crate jsrust_shared;
|
||||
extern crate kvstore;
|
||||
extern crate mapped_hyph;
|
||||
|
|
Загрузка…
Ссылка в новой задаче