Bug 1953750 - Move mozurl to Rust 2021. r=necko-reviewers,valentin
Bump `mozurl` to Rust edition 2021 Differential Revision: https://phabricator.services.mozilla.com/D241372
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
edition = "2015"
|
edition = "2021"
|
||||||
name = "mozurl"
|
name = "mozurl"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
authors = ["Nika Layzell <nika@thelayzells.com>"]
|
authors = ["Nika Layzell <nika@thelayzells.com>"]
|
||||||
@@ -11,3 +11,75 @@ nserror = { path = "../../../xpcom/rust/nserror" }
|
|||||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
||||||
uuid = { version = "1.0", features = ["v4"] }
|
uuid = { version = "1.0", features = ["v4"] }
|
||||||
|
|
||||||
|
# Keep in sync with neqo
|
||||||
|
[lints.rust]
|
||||||
|
absolute_paths_not_starting_with_crate = "warn"
|
||||||
|
ambiguous_negative_literals = "warn"
|
||||||
|
explicit_outlives_requirements = "warn"
|
||||||
|
macro_use_extern_crate = "warn"
|
||||||
|
missing_abi = "warn"
|
||||||
|
non_ascii_idents = "warn"
|
||||||
|
redundant_imports = "warn"
|
||||||
|
redundant_lifetimes = "warn"
|
||||||
|
trivial_numeric_casts = "warn"
|
||||||
|
unit_bindings = "warn"
|
||||||
|
unused_import_braces = "warn"
|
||||||
|
unused_lifetimes = "warn"
|
||||||
|
unused_macro_rules = "warn"
|
||||||
|
unused_qualifications = "warn"
|
||||||
|
|
||||||
|
# Keep in sync with neqo
|
||||||
|
[lints.clippy]
|
||||||
|
cargo = { level = "warn", priority = -1 }
|
||||||
|
nursery = { level = "warn", priority = -1 }
|
||||||
|
pedantic = { level = "warn", priority = -1 }
|
||||||
|
allow_attributes = "warn"
|
||||||
|
allow_attributes_without_reason = "warn"
|
||||||
|
cfg_not_test = "warn"
|
||||||
|
clone_on_ref_ptr = "warn"
|
||||||
|
create_dir = "warn"
|
||||||
|
dbg_macro = "warn"
|
||||||
|
empty_drop = "warn"
|
||||||
|
empty_enum_variants_with_brackets = "warn"
|
||||||
|
filetype_is_file = "warn"
|
||||||
|
float_cmp_const = "warn"
|
||||||
|
fn_to_numeric_cast_any = "warn"
|
||||||
|
get_unwrap = "warn"
|
||||||
|
if_then_some_else_none = "warn"
|
||||||
|
infinite_loop = "warn"
|
||||||
|
large_include_file = "warn"
|
||||||
|
let_underscore_must_use = "warn"
|
||||||
|
let_underscore_untyped = "warn"
|
||||||
|
literal_string_with_formatting_args = "allow" # FIXME: Re-enable "warn" when MSRV is > 1.87. See https://github.com/rust-lang/rust-clippy/pull/13953#issuecomment-2676336899
|
||||||
|
lossy_float_literal = "warn"
|
||||||
|
mem_forget = "warn"
|
||||||
|
mixed_read_write_in_expression = "warn"
|
||||||
|
multiple_crate_versions = "allow"
|
||||||
|
multiple_inherent_impl = "warn"
|
||||||
|
mutex_atomic = "warn"
|
||||||
|
mutex_integer = "warn"
|
||||||
|
needless_raw_strings = "warn"
|
||||||
|
pathbuf_init_then_push = "warn"
|
||||||
|
pub_without_shorthand = "warn"
|
||||||
|
rc_buffer = "warn"
|
||||||
|
rc_mutex = "warn"
|
||||||
|
redundant_type_annotations = "warn"
|
||||||
|
ref_patterns = "warn"
|
||||||
|
renamed_function_params = "warn"
|
||||||
|
rest_pat_in_fully_bound_structs = "warn"
|
||||||
|
self_named_module_files = "warn"
|
||||||
|
semicolon_inside_block = "warn"
|
||||||
|
string_lit_chars_any = "warn"
|
||||||
|
string_to_string = "warn"
|
||||||
|
suspicious_xor_used_as_pow = "warn"
|
||||||
|
try_err = "warn"
|
||||||
|
unnecessary_safety_comment = "warn"
|
||||||
|
unnecessary_safety_doc = "warn"
|
||||||
|
unnecessary_self_imports = "warn"
|
||||||
|
unneeded_field_pattern = "warn"
|
||||||
|
unused_result_ok = "warn"
|
||||||
|
unused_trait_names = "warn"
|
||||||
|
unwrap_in_result = "warn"
|
||||||
|
unwrap_used = "warn"
|
||||||
|
verbose_file_reads = "warn"
|
||||||
|
|||||||
@@ -3,35 +3,35 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#![expect(
|
||||||
|
clippy::missing_safety_doc,
|
||||||
|
clippy::missing_panics_doc,
|
||||||
|
reason = "OK here"
|
||||||
|
)]
|
||||||
|
|
||||||
extern crate url;
|
extern crate url;
|
||||||
use url::quirks;
|
use url::{quirks, ParseOptions, Position, Url};
|
||||||
use url::{ParseOptions, Position, Url};
|
|
||||||
|
|
||||||
extern crate nsstring;
|
extern crate nsstring;
|
||||||
use nsstring::{nsACString, nsCString};
|
use nsstring::{nsACString, nsCString};
|
||||||
|
|
||||||
extern crate nserror;
|
extern crate nserror;
|
||||||
use nserror::*;
|
use nserror::{nsresult, NS_ERROR_MALFORMED_URI, NS_ERROR_UNEXPECTED, NS_OK};
|
||||||
|
|
||||||
extern crate xpcom;
|
extern crate xpcom;
|
||||||
use xpcom::{AtomicRefcnt, RefCounted, RefPtr};
|
use xpcom::{AtomicRefcnt, RefCounted, RefPtr};
|
||||||
|
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
use uuid::Uuid;
|
use std::{fmt::Write as _, marker::PhantomData, ops, ptr, str};
|
||||||
|
|
||||||
use std::fmt::Write;
|
use uuid::Uuid;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem;
|
|
||||||
use std::ops;
|
|
||||||
use std::ptr;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn Gecko_StrictFileOriginPolicy() -> bool;
|
fn Gecko_StrictFileOriginPolicy() -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper macro. If the expression $e is Ok(t) evaluates to t, otherwise,
|
/// Helper macro. If the expression $e is Ok(t) evaluates to t, otherwise,
|
||||||
/// returns NS_ERROR_MALFORMED_URI.
|
/// returns `NS_ERROR_MALFORMED_URI`.
|
||||||
macro_rules! try_or_malformed {
|
macro_rules! try_or_malformed {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
match $e {
|
match $e {
|
||||||
@@ -49,21 +49,19 @@ fn default_port(scheme: &str) -> Option<u16> {
|
|||||||
match scheme {
|
match scheme {
|
||||||
"ftp" => Some(21),
|
"ftp" => Some(21),
|
||||||
"gopher" => Some(70),
|
"gopher" => Some(70),
|
||||||
"http" => Some(80),
|
"http" | "ws" => Some(80),
|
||||||
"https" => Some(443),
|
"https" | "wss" | "rtsp" | "android" => Some(443),
|
||||||
"ws" => Some(80),
|
|
||||||
"wss" => Some(443),
|
|
||||||
"rtsp" => Some(443),
|
|
||||||
"android" => Some(443),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A slice into the backing string. This type is only valid as long as the
|
/// A slice into the backing string.
|
||||||
/// MozURL which it was pulled from is valid. In C++, this type implicitly
|
|
||||||
/// converts to a nsDependentCString, and is an implementation detail.
|
|
||||||
///
|
///
|
||||||
/// This type exists because, unlike &str, this type is safe to return over FFI.
|
/// This type is only valid as long as the [`MozURL`] which it was pulled from is
|
||||||
|
/// valid. In C++, this type implicitly converts to a `nsDependentCString`, and is
|
||||||
|
/// an implementation detail.
|
||||||
|
///
|
||||||
|
/// This type exists because, unlike `&str`, this type is safe to return over FFI.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct SpecSlice<'a> {
|
pub struct SpecSlice<'a> {
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
@@ -72,17 +70,16 @@ pub struct SpecSlice<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for SpecSlice<'a> {
|
impl<'a> From<&'a str> for SpecSlice<'a> {
|
||||||
fn from(s: &'a str) -> SpecSlice<'a> {
|
fn from(s: &'a str) -> Self {
|
||||||
assert!(s.len() < u32::max_value() as usize);
|
|
||||||
SpecSlice {
|
SpecSlice {
|
||||||
data: s.as_ptr(),
|
data: s.as_ptr(),
|
||||||
len: s.len() as u32,
|
len: u32::try_from(s.len()).expect("string length not representable in u32"),
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The MozURL reference-counted threadsafe URL type. This type intentionally
|
/// The [`MozURL`] reference-counted threadsafe URL type. This type intentionally
|
||||||
/// implements no XPCOM interfaces, and all method calls are non-virtual.
|
/// implements no XPCOM interfaces, and all method calls are non-virtual.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct MozURL {
|
pub struct MozURL {
|
||||||
@@ -91,15 +88,16 @@ pub struct MozURL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MozURL {
|
impl MozURL {
|
||||||
pub fn from_url(url: Url) -> RefPtr<MozURL> {
|
#[must_use]
|
||||||
|
pub fn from_url(url: Url) -> RefPtr<Self> {
|
||||||
// Actually allocate the URL on the heap. This is the only place we actually
|
// Actually allocate the URL on the heap. This is the only place we actually
|
||||||
// create a MozURL, other than in clone().
|
// create a [`MozURL`], other than in `clone()`.
|
||||||
unsafe {
|
unsafe {
|
||||||
RefPtr::from_raw(Box::into_raw(Box::new(MozURL {
|
RefPtr::from_raw(Box::into_raw(Box::new(Self {
|
||||||
url: url,
|
url,
|
||||||
refcnt: AtomicRefcnt::new(),
|
refcnt: AtomicRefcnt::new(),
|
||||||
})))
|
})))
|
||||||
.unwrap()
|
.expect("MozURL created OK")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +124,7 @@ pub unsafe extern "C" fn mozurl_addref(url: &MozURL) {
|
|||||||
pub unsafe extern "C" fn mozurl_release(url: &MozURL) {
|
pub unsafe extern "C" fn mozurl_release(url: &MozURL) {
|
||||||
let rc = url.refcnt.dec();
|
let rc = url.refcnt.dec();
|
||||||
if rc == 0 {
|
if rc == 0 {
|
||||||
mem::drop(Box::from_raw(url as *const MozURL as *mut MozURL));
|
drop(Box::from_raw(ptr::from_ref::<MozURL>(url).cast_mut()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +159,7 @@ pub extern "C" fn mozurl_new(
|
|||||||
NS_OK
|
NS_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate a new MozURL object which is a clone of the original, and store a
|
/// Allocate a new [`MozURL`] object which is a clone of the original, and store a
|
||||||
/// pointer to it into newurl.
|
/// pointer to it into newurl.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mozurl_clone(url: &MozURL, newurl: &mut *const MozURL) {
|
pub extern "C" fn mozurl_clone(url: &MozURL, newurl: &mut *const MozURL) {
|
||||||
@@ -200,15 +198,14 @@ pub extern "C" fn mozurl_host(url: &MozURL) -> SpecSlice {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mozurl_port(url: &MozURL) -> i32 {
|
pub extern "C" fn mozurl_port(url: &MozURL) -> i32 {
|
||||||
// NOTE: Gecko uses -1 to represent the default port.
|
// NOTE: Gecko uses -1 to represent the default port.
|
||||||
url.port().map(|p| p as i32).unwrap_or(-1)
|
url.port().map_or(-1, i32::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mozurl_real_port(url: &MozURL) -> i32 {
|
pub extern "C" fn mozurl_real_port(url: &MozURL) -> i32 {
|
||||||
url.port()
|
url.port()
|
||||||
.or_else(|| default_port(url.scheme()))
|
.or_else(|| default_port(url.scheme()))
|
||||||
.map(|p| p as i32)
|
.map_or(-1, i32::from)
|
||||||
.unwrap_or(-1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -256,11 +253,10 @@ pub extern "C" fn mozurl_has_query(url: &MozURL) -> bool {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mozurl_directory(url: &MozURL) -> SpecSlice {
|
pub extern "C" fn mozurl_directory(url: &MozURL) -> SpecSlice {
|
||||||
if let Some(position) = url.path().rfind('/') {
|
url.path().rfind('/').map_or_else(
|
||||||
url.path()[..position + 1].into()
|
|| url.path().into(),
|
||||||
} else {
|
|position| url.path()[..=position].into(),
|
||||||
url.path().into()
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -281,7 +277,12 @@ fn get_origin(url: &MozURL) -> Option<String> {
|
|||||||
if port == default_port(url.scheme()) {
|
if port == default_port(url.scheme()) {
|
||||||
Some(format!("{}://{}", url.scheme(), host))
|
Some(format!("{}://{}", url.scheme(), host))
|
||||||
} else {
|
} else {
|
||||||
Some(format!("{}://{}:{}", url.scheme(), host, port.unwrap()))
|
Some(format!(
|
||||||
|
"{}://{}:{}",
|
||||||
|
url.scheme(),
|
||||||
|
host,
|
||||||
|
port.expect("got a port")
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"file" => {
|
"file" => {
|
||||||
@@ -298,10 +299,10 @@ fn get_origin(url: &MozURL) -> Option<String> {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mozurl_origin(url: &MozURL, origin: &mut nsACString) {
|
pub extern "C" fn mozurl_origin(url: &MozURL, origin: &mut nsACString) {
|
||||||
let origin_str = if !url.as_ref().starts_with("about:blank") {
|
let origin_str = if url.as_ref().starts_with("about:blank") {
|
||||||
get_origin(url)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
get_origin(url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let origin_str = origin_str.unwrap_or_else(|| {
|
let origin_str = origin_str.unwrap_or_else(|| {
|
||||||
@@ -375,7 +376,7 @@ pub extern "C" fn mozurl_set_hostname(url: &mut MozURL, host: &nsACString) -> ns
|
|||||||
pub extern "C" fn mozurl_set_port_no(url: &mut MozURL, new_port: i32) -> nsresult {
|
pub extern "C" fn mozurl_set_port_no(url: &mut MozURL, new_port: i32) -> nsresult {
|
||||||
debug_assert_mut!(url);
|
debug_assert_mut!(url);
|
||||||
|
|
||||||
if new_port > u16::MAX as i32 {
|
if new_port > i32::from(u16::MAX) {
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,8 +384,9 @@ pub extern "C" fn mozurl_set_port_no(url: &mut MozURL, new_port: i32) -> nsresul
|
|||||||
return NS_ERROR_MALFORMED_URI;
|
return NS_ERROR_MALFORMED_URI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(clippy::cast_sign_loss, reason = "not possible due to first match arm")]
|
||||||
let port = match new_port {
|
let port = match new_port {
|
||||||
new if new < 0 || u16::max_value() as i32 <= new => None,
|
new if new < 0 || i32::from(u16::MAX) <= new => None,
|
||||||
new if Some(new as u16) == default_port(url.scheme()) => None,
|
new if Some(new as u16) == default_port(url.scheme()) => None,
|
||||||
new => Some(new as u16),
|
new => Some(new as u16),
|
||||||
};
|
};
|
||||||
@@ -419,7 +421,7 @@ pub extern "C" fn mozurl_set_fragment(url: &mut MozURL, fragment: &nsACString) -
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mozurl_sizeof(url: &MozURL) -> usize {
|
pub extern "C" fn mozurl_sizeof(url: &MozURL) -> usize {
|
||||||
debug_assert_mut!(url);
|
debug_assert_mut!(url);
|
||||||
mem::size_of::<MozURL>() + url.as_str().len()
|
size_of::<MozURL>() + url.as_str().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -485,7 +487,7 @@ pub extern "C" fn mozurl_relative(
|
|||||||
match (url1.path_segments(), url2.path_segments()) {
|
match (url1.path_segments(), url2.path_segments()) {
|
||||||
(Some(mut path1), Some(mut path2)) => {
|
(Some(mut path1), Some(mut path2)) => {
|
||||||
// Exhaust the part of the iterators that match
|
// Exhaust the part of the iterators that match
|
||||||
while let (Some(ref p1), Some(ref p2)) = (path1.next(), path2.next()) {
|
while let (Some(p1), Some(p2)) = (&path1.next(), &path2.next()) {
|
||||||
if p1 != p2 {
|
if p1 != p2 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -512,6 +514,6 @@ pub extern "C" fn mozurl_relative(
|
|||||||
pub extern "C" fn rusturl_parse_ipv6addr(input: &nsACString, addr: &mut nsACString) -> nsresult {
|
pub extern "C" fn rusturl_parse_ipv6addr(input: &nsACString, addr: &mut nsACString) -> nsresult {
|
||||||
let ip6 = try_or_malformed!(str::from_utf8(input));
|
let ip6 = try_or_malformed!(str::from_utf8(input));
|
||||||
let host = try_or_malformed!(url::Host::parse(ip6));
|
let host = try_or_malformed!(url::Host::parse(ip6));
|
||||||
let _ = write!(addr, "{}", host);
|
_ = write!(addr, "{host}");
|
||||||
NS_OK
|
NS_OK
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user