From a4457e0b115c1d444b343739447db610db3ca580 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 12 Aug 2021 19:12:51 +0200 Subject: [PATCH] Initial work at making url no_std compatible --- url/Cargo.toml | 7 ++-- url/src/host.rs | 7 ++-- url/src/lib.rs | 70 +++++++++++++++++++++++++++------------- url/src/origin.rs | 5 ++- url/src/parser.rs | 14 ++++---- url/src/path_segments.rs | 3 +- url/src/quirks.rs | 2 ++ url/src/slicing.rs | 3 +- 8 files changed, 75 insertions(+), 36 deletions(-) diff --git a/url/Cargo.toml b/url/Cargo.toml index 3955078b5..e49f42fce 100644 --- a/url/Cargo.toml +++ b/url/Cargo.toml @@ -26,12 +26,13 @@ bencher = "0.1" [dependencies] form_urlencoded = { version = "1.0.0", path = "../form_urlencoded" } -idna = { version = "0.2.0", path = "../idna", optional = true } +idna = { version = "0.2.0", default-features = false, path = "../idna", optional = true } percent-encoding = { version = "2.1.0", path = "../percent_encoding" } -serde = {version = "1.0", optional = true, features = ["derive"]} +serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } [features] -default = ["idna"] +default = ["std", "idna"] +std = ["idna/std"] [[bench]] name = "parse_url" diff --git a/url/src/host.rs b/url/src/host.rs index 4678cb8a1..df0890fec 100644 --- a/url/src/host.rs +++ b/url/src/host.rs @@ -6,8 +6,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cmp; -use std::fmt::{self, Formatter}; +use alloc::borrow::ToOwned; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::cmp; +use core::fmt::{self, Formatter}; use std::net::{Ipv4Addr, Ipv6Addr}; use percent_encoding::{percent_decode, utf8_percent_encode, CONTROLS}; diff --git a/url/src/lib.rs b/url/src/lib.rs index 8bdd378b7..b0555f430 100644 --- a/url/src/lib.rs +++ b/url/src/lib.rs @@ -131,6 +131,10 @@ url = { version = "2", default-features = false } */ #![doc(html_root_url = "https://docs.rs/url/2.2.2")] +#![no_std] +#[macro_use] +extern crate alloc; +extern crate std; pub use form_urlencoded; @@ -138,20 +142,25 @@ pub use form_urlencoded; extern crate serde; use crate::host::HostInternal; -use crate::parser::{to_u32, Context, Parser, SchemeType, PATH_SEGMENT, USERINFO}; -use percent_encoding::{percent_decode, percent_encode, utf8_percent_encode}; -use std::borrow::Borrow; -use std::cmp; -use std::fmt::{self, Write}; -use std::hash; -use std::io; -use std::mem; -use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; -use std::ops::{Range, RangeFrom, RangeTo}; -use std::path::{Path, PathBuf}; -use std::str; - -use std::convert::TryFrom; +use crate::parser::{to_u32, Context, Parser, SchemeType, USERINFO}; +use alloc::borrow::ToOwned; +use alloc::string::{String, ToString}; +use core::borrow::Borrow; +use core::cmp; +use core::convert::TryFrom; +use core::fmt::{self, Write}; +use core::hash; +use core::mem; +use core::ops::{Range, RangeFrom, RangeTo}; +use core::str; +use percent_encoding::utf8_percent_encode; +use std::net::IpAddr; +#[cfg(feature = "std")] +use std::{ + io, + net::{SocketAddr, ToSocketAddrs}, + path::{Path, PathBuf}, +}; pub use crate::host::Host; pub use crate::origin::{OpaqueOrigin, Origin}; @@ -1144,10 +1153,11 @@ impl Url { /// }) /// } /// ``` + #[cfg(feature = "std")] pub fn socket_addrs( &self, default_port_number: impl Fn() -> Option, - ) -> io::Result> { + ) -> io::Result> { // Note: trying to avoid the Vec allocation by returning `impl AsRef<[SocketAddr]>` // causes borrowck issues because the return value borrows `default_port_number`: // @@ -1156,6 +1166,7 @@ impl Url { // > This RFC proposes that *all* type parameters are considered in scope // > for `impl Trait` in return position + // TODO: Return custom error type to support no_std fn io_result(opt: Option, message: &str) -> io::Result { opt.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, message)) } @@ -2314,7 +2325,9 @@ impl Url { /// # run().unwrap(); /// # } /// ``` - #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))] + /// + /// This method is only available if the `std` Cargo feature is enabled. + #[cfg(all(feature = "std", any(unix, windows, target_os = "redox", target_os = "wasi")))] #[allow(clippy::result_unit_err)] pub fn from_file_path>(path: P) -> Result { let mut serialization = "file://".to_owned(); @@ -2351,7 +2364,9 @@ impl Url { /// /// Note that `std::path` does not consider trailing slashes significant /// and usually does not include them (e.g. in `Path::parent()`). - #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))] + /// + /// This method is only available if the `std` Cargo feature is enabled. + #[cfg(all(feature = "std", any(unix, windows, target_os = "redox", target_os = "wasi")))] #[allow(clippy::result_unit_err)] pub fn from_directory_path>(path: P) -> Result { let mut url = Url::from_file_path(path)?; @@ -2467,8 +2482,10 @@ impl Url { /// or if `Path::new_opt()` returns `None`. /// (That is, if the percent-decoded path contains a NUL byte or, /// for a Windows path, is not UTF-8.) + /// + /// This method is only available if the `std` Cargo feature is enabled. #[inline] - #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))] + #[cfg(all(feature = "std", any(unix, windows, target_os = "redox", target_os = "wasi")))] #[allow(clippy::result_unit_err)] pub fn to_file_path(&self) -> Result { if let Some(segments) = self.path_segments() { @@ -2672,11 +2689,13 @@ impl<'de> serde::Deserialize<'de> for Url { } } -#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] +#[cfg(all(feature = "std", any(unix, target_os = "redox", target_os = "wasi")))] fn path_to_file_url_segments( path: &Path, serialization: &mut String, ) -> Result<(u32, HostInternal), ()> { + use crate::parser::PATH_SEGMENT; + use percent_encoding::percent_encode; #[cfg(any(unix, target_os = "redox"))] use std::os::unix::prelude::OsStrExt; #[cfg(target_os = "wasi")] @@ -2702,7 +2721,7 @@ fn path_to_file_url_segments( Ok((host_end, HostInternal::None)) } -#[cfg(windows)] +#[cfg(all(feature = "std", windows))] fn path_to_file_url_segments( path: &Path, serialization: &mut String, @@ -2710,12 +2729,15 @@ fn path_to_file_url_segments( path_to_file_url_segments_windows(path, serialization) } +#[cfg(feature = "std")] // Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102 #[cfg_attr(not(windows), allow(dead_code))] fn path_to_file_url_segments_windows( path: &Path, serialization: &mut String, ) -> Result<(u32, HostInternal), ()> { + use crate::parser::PATH_SEGMENT; + use percent_encoding::percent_encode; use std::path::{Component, Prefix}; if !path.is_absolute() { return Err(()); @@ -2770,11 +2792,13 @@ fn path_to_file_url_segments_windows( Ok((host_end, host_internal)) } -#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] +#[cfg(all(feature = "std", any(unix, target_os = "redox", target_os = "wasi")))] fn file_url_segments_to_pathbuf( host: Option<&str>, segments: str::Split<'_, char>, ) -> Result { + use alloc::vec::Vec; + use percent_encoding::percent_decode; use std::ffi::OsStr; #[cfg(any(unix, target_os = "redox"))] use std::os::unix::prelude::OsStrExt; @@ -2810,7 +2834,7 @@ fn file_url_segments_to_pathbuf( Ok(path) } -#[cfg(windows)] +#[cfg(all(feature = "std", windows))] fn file_url_segments_to_pathbuf( host: Option<&str>, segments: str::Split, @@ -2818,12 +2842,14 @@ fn file_url_segments_to_pathbuf( file_url_segments_to_pathbuf_windows(host, segments) } +#[cfg(feature = "std")] // Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102 #[cfg_attr(not(windows), allow(dead_code))] fn file_url_segments_to_pathbuf_windows( host: Option<&str>, mut segments: str::Split<'_, char>, ) -> Result { + use percent_encoding::percent_decode; let mut string = if let Some(host) = host { r"\\".to_owned() + host } else { diff --git a/url/src/origin.rs b/url/src/origin.rs index 838be55bd..c3d64fe00 100644 --- a/url/src/origin.rs +++ b/url/src/origin.rs @@ -9,7 +9,10 @@ use crate::host::Host; use crate::parser::default_port; use crate::Url; -use std::sync::atomic::{AtomicUsize, Ordering}; +use alloc::borrow::ToOwned; +use alloc::string::String; +use core::sync::atomic::{AtomicUsize, Ordering}; +use idna::domain_to_unicode; pub fn url_origin(url: &Url) -> Origin { let scheme = url.scheme(); diff --git a/url/src/parser.rs b/url/src/parser.rs index ed4ca3c4e..4b8df3a6b 100644 --- a/url/src/parser.rs +++ b/url/src/parser.rs @@ -6,9 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::error::Error; -use std::fmt::{self, Formatter, Write}; -use std::str; +use alloc::borrow::ToOwned; +use alloc::string::{String, ToString}; +use core::fmt::{self, Formatter, Write}; +use core::str; use crate::host::{Host, HostInternal}; use crate::Url; @@ -72,7 +73,8 @@ macro_rules! simple_enum_error { } } -impl Error for ParseError {} +#[cfg(feature = "std")] +impl std::error::Error for ParseError {} simple_enum_error! { EmptyHost => "empty host", @@ -1107,7 +1109,7 @@ impl<'a> Parser<'a> { while let (Some(c), remaining) = input.split_first() { if let Some(digit) = c.to_digit(10) { port = port * 10 + digit; - if port > ::std::u16::MAX as u32 { + if port > core::u16::MAX as u32 { return Err(ParseError::InvalidPort); } has_any_digit = true; @@ -1541,7 +1543,7 @@ pub fn ascii_alpha(ch: char) -> bool { #[inline] pub fn to_u32(i: usize) -> ParseResult { - if i <= ::std::u32::MAX as usize { + if i <= core::u32::MAX as usize { Ok(i as u32) } else { Err(ParseError::Overflow) diff --git a/url/src/path_segments.rs b/url/src/path_segments.rs index 29afc1e7e..131f0b82d 100644 --- a/url/src/path_segments.rs +++ b/url/src/path_segments.rs @@ -8,7 +8,8 @@ use crate::parser::{self, to_u32, SchemeType}; use crate::Url; -use std::str; +use alloc::string::String; +use core::str; /// Exposes methods to manipulate the path of an URL that is not cannot-be-base. /// diff --git a/url/src/quirks.rs b/url/src/quirks.rs index 3ecb3c24d..6ec774657 100644 --- a/url/src/quirks.rs +++ b/url/src/quirks.rs @@ -11,6 +11,8 @@ //! Unless you need to be interoperable with web browsers, //! you probably want to use `Url` method instead. +use alloc::string::{String, ToString}; + use crate::parser::{default_port, Context, Input, Parser, SchemeType}; use crate::{Host, ParseError, Position, Url}; diff --git a/url/src/slicing.rs b/url/src/slicing.rs index a90337bb6..1c6fe7616 100644 --- a/url/src/slicing.rs +++ b/url/src/slicing.rs @@ -6,8 +6,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::ops::{Index, Range, RangeFrom, RangeFull, RangeTo}; + use crate::Url; -use std::ops::{Index, Range, RangeFrom, RangeFull, RangeTo}; impl Index for Url { type Output = str;