message: Properly handles IPv6 host URI
diff: @@ -130,24 +130,62 @@ impl Future for ShadowSocksConnecting {
  }
  fn host_addr(uri: &Uri) -> Option<Address> {
  - let port = match uri.port_u16() {
  - Some(p) => p,
  + match uri.authority() {
  + None => None,
  + Some(authority) => {
  + // NOTE: Authority may include authentication info (user:password)
  + // Although it is already deprecated, but some very old application may still depending on it
  + //
  + // But ... We won't be compatible with it. :)
  +
  + // Check if URI has port
  + match authority.port_u16() {
  + Some(port) => {
  + // Well, it has port!
  + // 1. Maybe authority is a SocketAddr (127.0.0.1:1234, [::1]:1234)
  + // 2. Otherwise, it must be a domain name (google.com:443)
  +
  + match authority.as_str().parse::<SocketAddr>() {
  + Ok(saddr) => Some(Address::from(saddr)),
  + Err(..) => Some(Address::DomainNameAddress(authority.host().to_owned(), port)),
  + }
  + }
  None => {
  - match uri.scheme_str() {
  + // Ok, we don't have port
  + // 1. IPv4 Address 127.0.0.1
  + // 2. IPv6 Address: https://tools.ietf.org/html/rfc2732 , [::1]
  + // 3. Domain name
  +
  + // Uses default port
  + let port = match uri.scheme_str() {
  None => 80, // Assume it is http
  Some("http") => 80,
  Some("https") => 443,
  _ => return None, // Not supported
  - }
  - }
  };
  - match uri.host() {
  - None => None,
  - Some(host_str) => match host_str.parse::<IpAddr>() {
  - Ok(ip) => Some(Address::from(SocketAddr::new(ip, port))),
  - Err(..) => Some(Address::DomainNameAddress(host_str.to_owned(), port)),
  - },
  + // RFC2732 indicates that IPv6 address should be wrapped in [ and ]
  + let authority_str = authority.as_str();
  + if authority_str.starts_with('[') && authority_str.ends_with(']') {
  + // Must be a IPv6 address
  + let addr = authority_str.trim_start_matches('[').trim_end_matches(']');
  + match addr.parse::<IpAddr>() {
  + Ok(a) => Some(Address::from(SocketAddr::new(a, port))),
  + // Ignore invalid IPv6 address
  + Err(..) => None,
  + }
  + } else {
  + // Maybe it is a IPv4 address, or a non-standard IPv6
  + match authority_str.parse::<IpAddr>() {
  + Ok(a) => Some(Address::from(SocketAddr::new(a, port))),
  + // Should be a domain name, or a invalid IP address.
  + // Let DNS deal with it.
  + Err(..) => Some(Address::DomainNameAddress(authority_str.to_owned(), port)),
  + }
  + }
  + }
  + }
  + }
  }
  }
  