Skip to content

Commit e30bcfe

Browse files
committed
set_scheme should fail if url has host or port
Fixes servo#278
1 parent d19d5d0 commit e30bcfe

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

src/lib.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ impl Url {
301301
/// ```rust
302302
/// use url::Url;
303303
/// # use url::ParseError;
304-
///
304+
///
305305
/// # fn run() -> Result<(), ParseError> {
306306
/// let base = Url::parse("https://example.net/a/b.html")?;
307307
/// let url = base.join("c.png")?;
@@ -729,6 +729,28 @@ impl Url {
729729
!matches!(self.host, HostInternal::None)
730730
}
731731

732+
/// Equivalent to `url.port().is_some()`.
733+
///
734+
/// # Examples
735+
///
736+
/// ```
737+
/// use url::Url;
738+
/// # use url::ParseError;
739+
///
740+
/// # fn run() -> Result<(), ParseError> {
741+
/// let url = Url::parse("http://example.com:8080")?;
742+
/// assert!(url.has_port());
743+
///
744+
/// let url = Url::parse("file:///tmp/something")?;
745+
/// assert!(!url.has_port());
746+
/// # Ok(())
747+
/// # }
748+
/// # run().unwrap();
749+
/// ```
750+
pub fn has_port(&self) -> bool {
751+
self.port.is_some()
752+
}
753+
732754
/// Return the string representation of the host (domain or IP address) for this URL, if any.
733755
///
734756
/// Non-ASCII domains are punycode-encoded per IDNA.
@@ -1310,7 +1332,7 @@ impl Url {
13101332
/// ```
13111333
/// use url::Url;
13121334
/// # use url::ParseError;
1313-
///
1335+
///
13141336
/// # fn run() -> Result<(), ParseError> {
13151337
/// let mut url = Url::parse("foo://example.net")?;
13161338
/// let result = url.set_host(None);
@@ -1326,7 +1348,7 @@ impl Url {
13261348
/// ```
13271349
/// use url::Url;
13281350
/// # use url::ParseError;
1329-
///
1351+
///
13301352
/// # fn run() -> Result<(), ParseError> {
13311353
/// let mut url = Url::parse("https://example.net")?;
13321354
/// let result = url.set_host(None);
@@ -1342,7 +1364,7 @@ impl Url {
13421364
/// ```
13431365
/// use url::Url;
13441366
/// # use url::ParseError;
1345-
///
1367+
///
13461368
/// # fn run() -> Result<(), ParseError> {
13471369
/// let mut url = Url::parse("mailto:[email protected]")?;
13481370
///
@@ -1552,7 +1574,7 @@ impl Url {
15521574
/// ```
15531575
/// use url::Url;
15541576
/// # use url::ParseError;
1555-
///
1577+
///
15561578
/// # fn run() -> Result<(), ParseError> {
15571579
/// let mut url = Url::parse("https://example.net")?;
15581580
/// let result = url.set_scheme("foo");
@@ -1569,7 +1591,7 @@ impl Url {
15691591
/// ```
15701592
/// use url::Url;
15711593
/// # use url::ParseError;
1572-
///
1594+
///
15731595
/// # fn run() -> Result<(), ParseError> {
15741596
/// let mut url = Url::parse("https://example.net")?;
15751597
/// let result = url.set_scheme("foõ");
@@ -1585,7 +1607,7 @@ impl Url {
15851607
/// ```
15861608
/// use url::Url;
15871609
/// # use url::ParseError;
1588-
///
1610+
///
15891611
/// # fn run() -> Result<(), ParseError> {
15901612
/// let mut url = Url::parse("mailto:[email protected]")?;
15911613
/// let result = url.set_scheme("https");
@@ -1598,8 +1620,8 @@ impl Url {
15981620
pub fn set_scheme(&mut self, scheme: &str) -> Result<(), ()> {
15991621
let mut parser = Parser::for_setter(String::new());
16001622
let remaining = parser.parse_scheme(parser::Input::new(scheme))?;
1601-
if !remaining.is_empty() ||
1602-
(!self.has_host() && SchemeType::from(&parser.serialization).is_special()) {
1623+
if !(remaining.is_empty() &&
1624+
self.can_use_scheme(&parser.serialization)) {
16031625
return Err(())
16041626
}
16051627
let old_scheme_end = self.scheme_end;
@@ -1622,6 +1644,14 @@ impl Url {
16221644
Ok(())
16231645
}
16241646

1647+
fn can_use_scheme(&self, scheme: &str) -> bool {
1648+
match SchemeType::from(scheme) {
1649+
SchemeType::File => !(self.has_host() || self.has_port()),
1650+
SchemeType::SpecialNotFile => self.has_host(),
1651+
SchemeType::NotSpecial => true
1652+
}
1653+
}
1654+
16251655
/// Convert a file name as `std::path::Path` into an URL in the `file` scheme.
16261656
///
16271657
/// This returns `Err` if the given path is not absolute or,
@@ -1634,7 +1664,7 @@ impl Url {
16341664
/// ```
16351665
/// # if cfg!(unix) {
16361666
/// use url::Url;
1637-
///
1667+
///
16381668
/// # fn run() -> Result<(), ()> {
16391669
/// let url = Url::from_file_path("/tmp/foo.txt")?;
16401670
/// assert_eq!(url.as_str(), "file:///tmp/foo.txt");

tests/unit.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,13 @@ fn issue_241() {
326326
Url::parse("mailto:").unwrap().cannot_be_a_base();
327327
}
328328

329+
#[test]
330+
fn issue_278() {
331+
let mut url: Url = "http://localhost:6767/foo/bar".parse().unwrap();
332+
assert_eq!(url.to_string(), "http://localhost:6767/foo/bar");
333+
assert_eq!(url.set_scheme("file"), Err(()));
334+
}
335+
329336
#[test]
330337
/// https://github.com/servo/rust-url/issues/222
331338
fn append_trailing_slash() {

0 commit comments

Comments
 (0)