Skip to content

Commit a93e8cb

Browse files
author
bors-servo
authored
Auto merge of #535 - servo:socket_addrs, r=nox
Restore DNS resolution functionality from url 1.x This is an alternative to #533. I feel that an inherent method is more appropriate than an impl of the `ToSocketAddrs` trait: it is not the URL as a whole that is converted, only parts of it. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-url/535) <!-- Reviewable:end -->
2 parents f491cb4 + 2f199ff commit a93e8cb

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
name = "url"
44
# When updating version, also modify html_root_url in the lib.rs
5-
version = "2.0.0"
5+
version = "2.1.0"
66
authors = ["The rust-url developers"]
77

88
description = "URL library for Rust, based on the WHATWG URL Standard"

idna/tests/punycode.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
// except according to those terms.
88

99
use idna::punycode::{decode, encode_str};
10-
use serde_json::Value;
1110
use serde_json::map::Map;
11+
use serde_json::Value;
1212
use std::str::FromStr;
1313
use test::TestFn;
1414

idna/tests/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extern crate idna;
2-
extern crate serde_json;
32
extern crate rustc_test as test;
3+
extern crate serde_json;
44

55
mod punycode;
66
mod uts46;

src/lib.rs

+59-4
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@ use std::cmp;
123123
use std::error::Error;
124124
use std::fmt::{self, Write};
125125
use std::hash;
126+
use std::io;
126127
use std::mem;
127-
use std::net::IpAddr;
128+
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
128129
use std::ops::{Range, RangeFrom, RangeTo};
129130
use std::path::{Path, PathBuf};
130131
use std::str;
@@ -945,6 +946,61 @@ impl Url {
945946
self.port.or_else(|| parser::default_port(self.scheme()))
946947
}
947948

949+
/// Resolve a URL’s host and port number to `SocketAddr`.
950+
///
951+
/// If the URL has the default port number of a scheme that is unknown to this library,
952+
/// `default_port_number` provides an opportunity to provide the actual port number.
953+
/// In non-example code this should be implemented either simply as `|| None`,
954+
/// or by matching on the URL’s `.scheme()`.
955+
///
956+
/// If the host is a domain, it is resolved using the standard library’s DNS support.
957+
///
958+
/// # Examples
959+
///
960+
/// ```no_run
961+
/// let url = url::Url::parse("https://example.net/").unwrap();
962+
/// let addrs = url.socket_addrs(|| None).unwrap();
963+
/// std::net::TcpStream::connect(&*addrs)
964+
/// # ;
965+
/// ```
966+
///
967+
/// ```
968+
/// /// With application-specific known default port numbers
969+
/// fn socket_addrs(url: url::Url) -> std::io::Result<Vec<std::net::SocketAddr>> {
970+
/// url.socket_addrs(|| match url.scheme() {
971+
/// "socks5" | "socks5h" => Some(1080),
972+
/// _ => None,
973+
/// })
974+
/// }
975+
/// ```
976+
pub fn socket_addrs(
977+
&self,
978+
default_port_number: impl Fn() -> Option<u16>,
979+
) -> io::Result<Vec<SocketAddr>> {
980+
// Note: trying to avoid the Vec allocation by returning `impl AsRef<[SocketAddr]>`
981+
// causes borrowck issues because the return value borrows `default_port_number`:
982+
//
983+
// https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md#scoping-for-type-and-lifetime-parameters
984+
//
985+
// > This RFC proposes that *all* type parameters are considered in scope
986+
// > for `impl Trait` in return position
987+
988+
fn io_result<T>(opt: Option<T>, message: &str) -> io::Result<T> {
989+
opt.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, message))
990+
}
991+
992+
let host = io_result(self.host(), "No host name in the URL")?;
993+
let port = io_result(
994+
self.port_or_known_default().or_else(default_port_number),
995+
"No port number in the URL",
996+
)?;
997+
Ok(match host {
998+
Host::Domain(domain) => (domain, port).to_socket_addrs()?.collect(),
999+
Host::Ipv4(ip) => vec![(ip, port).into()],
1000+
Host::Ipv6(ip) => vec![(ip, port).into()],
1001+
})
1002+
}
1003+
9481004
/// Return the path for this URL, as a percent-encoded ASCII string.
9491005
/// For cannot-be-a-base URLs, this is an arbitrary string that doesn’t start with '/'.
9501006
/// For other URLs, this starts with a '/' slash
@@ -2296,9 +2352,8 @@ impl<'de> serde::Deserialize<'de> for Url {
22962352
where
22972353
E: Error,
22982354
{
2299-
Url::parse(s).map_err(|err| {
2300-
Error::invalid_value(Unexpected::Str(s), &err.description())
2301-
})
2355+
Url::parse(s)
2356+
.map_err(|err| Error::invalid_value(Unexpected::Str(s), &err.description()))
23022357
}
23032358
}
23042359

0 commit comments

Comments
 (0)