Skip to content

Commit 027ec43

Browse files
authored
Merge pull request #728 from shuoli84/master
init commit to make idna optional
2 parents 0840723 + 84de798 commit 027ec43

File tree

9 files changed

+72
-5
lines changed

9 files changed

+72
-5
lines changed

data-url/src/mime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn parse_parameters(s: &str, parameters: &mut Vec<(String, String)>) {
6969
while let Some(piece) = semicolon_separated.next() {
7070
let piece = piece.trim_start_matches(ascii_whitespace);
7171
let (name, value) = split2(piece, '=');
72-
if name.is_empty() || !only_http_token_code_points(name) || contains(&parameters, name) {
72+
if name.is_empty() || !only_http_token_code_points(name) || contains(parameters, name) {
7373
continue;
7474
}
7575
if let Some(value) = value {

url/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ bencher = "0.1"
2525

2626
[dependencies]
2727
form_urlencoded = { version = "1.0.0", path = "../form_urlencoded" }
28-
idna = { version = "0.2.0", path = "../idna" }
28+
idna = { version = "0.2.0", path = "../idna", optional = true }
2929
matches = "0.1"
3030
percent-encoding = { version = "2.1.0", path = "../percent_encoding" }
3131
serde = {version = "1.0", optional = true, features = ["derive"]}
3232

33+
[features]
34+
default = ["idna"]
35+
3336
[[bench]]
3437
name = "parse_url"
3538
path = "benches/parse_url.rs"

url/src/host.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ impl Host<String> {
8282
return parse_ipv6addr(&input[1..input.len() - 1]).map(Host::Ipv6);
8383
}
8484
let domain = percent_decode(input.as_bytes()).decode_utf8_lossy();
85-
let domain = idna::domain_to_ascii(&domain)?;
85+
86+
let domain = Self::domain_to_ascii(&domain)?;
87+
8688
if domain.is_empty() {
8789
return Err(ParseError::EmptyHost);
8890
}
@@ -156,6 +158,24 @@ impl Host<String> {
156158
))
157159
}
158160
}
161+
162+
/// convert domain with idna
163+
#[cfg(feature = "idna")]
164+
fn domain_to_ascii(domain: &str) -> Result<String, ParseError> {
165+
idna::domain_to_ascii(&domain).map_err(Into::into)
166+
}
167+
168+
/// checks domain is ascii
169+
#[cfg(not(feature = "idna"))]
170+
fn domain_to_ascii(domain: &str) -> Result<String, ParseError> {
171+
// without idna feature, we can't verify that xn-- domains correctness
172+
let domain = domain.to_lowercase();
173+
if domain.is_ascii() && domain.split('.').all(|s| !s.starts_with("xn--")) {
174+
Ok(domain)
175+
} else {
176+
Err(ParseError::InvalidDomainCharacter)
177+
}
178+
}
159179
}
160180

161181
impl<S: AsRef<str>> fmt::Display for Host<S> {

url/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ See [serde documentation](https://serde.rs) for more information.
118118
```toml
119119
url = { version = "2", features = ["serde"] }
120120
```
121+
122+
# Feature: `idna`
123+
124+
You can opt out [idna](https://en.wikipedia.org/wiki/Internationalized_domain_name) support
125+
to reduce final binary size.
126+
127+
```toml
128+
url = { version = "2", default-features = false }
129+
```
130+
121131
*/
122132

123133
#![doc(html_root_url = "https://docs.rs/url/2.2.2")]

url/src/origin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use crate::host::Host;
1010
use crate::parser::default_port;
1111
use crate::Url;
12-
use idna::domain_to_unicode;
1312
use std::sync::atomic::{AtomicUsize, Ordering};
1413

1514
pub fn url_origin(url: &Url) -> Origin {
@@ -87,13 +86,14 @@ impl Origin {
8786
}
8887

8988
/// <https://html.spec.whatwg.org/multipage/#unicode-serialisation-of-an-origin>
89+
#[cfg(feature = "idna")]
9090
pub fn unicode_serialization(&self) -> String {
9191
match *self {
9292
Origin::Opaque(_) => "null".to_owned(),
9393
Origin::Tuple(ref scheme, ref host, port) => {
9494
let host = match *host {
9595
Host::Domain(ref domain) => {
96-
let (domain, _errors) = domain_to_unicode(domain);
96+
let (domain, _errors) = idna::domain_to_unicode(domain);
9797
Host::Domain(domain)
9898
}
9999
_ => host.clone(),

url/src/parser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ simple_enum_error! {
9393
Overflow => "URLs more than 4 GB are not supported",
9494
}
9595

96+
#[cfg(feature = "idna")]
9697
impl From<::idna::Errors> for ParseError {
9798
fn from(_: ::idna::Errors) -> ParseError {
9899
ParseError::IdnaError

url/src/quirks.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub fn domain_to_ascii(domain: &str) -> String {
2323
}
2424

2525
/// https://url.spec.whatwg.org/#dom-url-domaintounicode
26+
#[cfg(feature = "idna")]
2627
pub fn domain_to_unicode(domain: &str) -> String {
2728
match Host::parse(domain) {
2829
Ok(Host::Domain(ref domain)) => {

url/tests/data.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ use url::{quirks, Url};
1616

1717
#[test]
1818
fn urltestdata() {
19+
#[cfg(not(feature = "idna"))]
20+
let idna_skip_inputs = [
21+
"http://www.foo。bar.com",
22+
"http://Go.com",
23+
"http://你好你好",
24+
"https://faß.ExAmPlE/",
25+
"http://0Xc0.0250.01",
26+
"ftp://%e2%98%83",
27+
"https://%e2%98%83",
28+
"file://a\u{ad}b/p",
29+
"file://a%C2%ADb/p",
30+
"http://GOO\u{200b}\u{2060}\u{feff}goo.com",
31+
];
32+
1933
// Copied form https://github.com/w3c/web-platform-tests/blob/master/url/
2034
let mut json = Value::from_str(include_str!("urltestdata.json"))
2135
.expect("JSON parse error in urltestdata.json");
@@ -30,6 +44,13 @@ fn urltestdata() {
3044
let input = entry.take_string("input");
3145
let failure = entry.take_key("failure").is_some();
3246

47+
#[cfg(not(feature = "idna"))]
48+
{
49+
if idna_skip_inputs.contains(&input.as_str()) {
50+
continue;
51+
}
52+
}
53+
3354
let base = match Url::parse(&base) {
3455
Ok(base) => base,
3556
Err(_) if failure => continue,
@@ -106,6 +127,14 @@ fn setters_tests() {
106127
let mut tests = json.take_key(attr).unwrap();
107128
for mut test in tests.as_array_mut().unwrap().drain(..) {
108129
let comment = test.take_key("comment").map(|s| s.string());
130+
#[cfg(not(feature = "idna"))]
131+
{
132+
if let Some(comment) = comment.as_ref() {
133+
if comment.starts_with("IDNA Nontransitional_Processing") {
134+
continue;
135+
}
136+
}
137+
}
109138
let href = test.take_string("href");
110139
let new_value = test.take_string("new_value");
111140
let name = format!("{:?}.{} = {:?}", href, attr, new_value);

url/tests/unit.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ fn host_serialization() {
296296
);
297297
}
298298

299+
#[cfg(feature = "idna")]
299300
#[test]
300301
fn test_idna() {
301302
assert!("http://goșu.ro".parse::<Url>().is_ok());
@@ -531,6 +532,7 @@ fn test_origin_opaque() {
531532
assert!(!&Url::parse("blob:malformed//").unwrap().origin().is_tuple())
532533
}
533534

535+
#[cfg(feature = "idna")]
534536
#[test]
535537
fn test_origin_unicode_serialization() {
536538
let data = [
@@ -703,6 +705,7 @@ fn test_set_href() {
703705
);
704706
}
705707

708+
#[cfg(feature = "idna")]
706709
#[test]
707710
fn test_domain_encoding_quirks() {
708711
use url::quirks::{domain_to_ascii, domain_to_unicode};

0 commit comments

Comments
 (0)