Validate proxy urls better.

Use the url crate to handle proxies to make sure they conform to a
proper format.
This commit is contained in:
Johan Anderholm 2018-03-24 08:00:38 +00:00
parent 1a04e3b899
commit 3a14e9a6be
8 changed files with 35 additions and 24 deletions

View file

@ -50,7 +50,7 @@ serde_json = "0.9.5"
tokio-core = "0.1.2" tokio-core = "0.1.2"
tokio-io = "0.1" tokio-io = "0.1"
tokio-signal = "0.1.2" tokio-signal = "0.1.2"
url = "1.3" url = "1.7.0"
[build-dependencies] [build-dependencies]
rand = "0.3.13" rand = "0.3.13"

View file

@ -32,6 +32,7 @@ serde_json = "0.9.5"
shannon = "0.2.0" shannon = "0.2.0"
tokio-core = "0.1.2" tokio-core = "0.1.2"
tokio-io = "0.1" tokio-io = "0.1"
url = "1.7.0"
uuid = { version = "0.4", features = ["v4"] } uuid = { version = "0.4", features = ["v4"] }
[build-dependencies] [build-dependencies]

View file

@ -8,6 +8,7 @@ use hyper_proxy::{Intercept, Proxy, ProxyConnector};
use serde_json; use serde_json;
use std::str::FromStr; use std::str::FromStr;
use tokio_core::reactor::Handle; use tokio_core::reactor::Handle;
use url::Url;
error_chain!{} error_chain!{}
@ -16,14 +17,14 @@ pub struct APResolveData {
ap_list: Vec<String>, ap_list: Vec<String>,
} }
fn apresolve(handle: &Handle, proxy: &Option<String>) -> Box<Future<Item = String, Error = Error>> { fn apresolve(handle: &Handle, proxy: &Option<Url>) -> Box<Future<Item = String, Error = Error>> {
let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL"); let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL");
let use_proxy = proxy.is_some(); let use_proxy = proxy.is_some();
let mut req = Request::new(Method::Get, url.clone()); let mut req = Request::new(Method::Get, url.clone());
let response = match proxy { let response = match *proxy {
&Some(ref val) => { Some(ref val) => {
let proxy_url = Uri::from_str(&val).expect("invalid http proxy"); let proxy_url = Uri::from_str(val.as_str()).expect("invalid http proxy");
let proxy = Proxy::new(Intercept::All, proxy_url); let proxy = Proxy::new(Intercept::All, proxy_url);
let connector = HttpConnector::new(4, handle); let connector = HttpConnector::new(4, handle);
let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy); let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy);
@ -73,7 +74,7 @@ fn apresolve(handle: &Handle, proxy: &Option<String>) -> Box<Future<Item = Strin
pub(crate) fn apresolve_or_fallback<E>( pub(crate) fn apresolve_or_fallback<E>(
handle: &Handle, handle: &Handle,
proxy: &Option<String>, proxy: &Option<Url>,
) -> Box<Future<Item = String, Error = E>> ) -> Box<Future<Item = String, Error = E>>
where where
E: 'static, E: 'static,

View file

@ -1,5 +1,6 @@
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use url::Url;
use uuid::Uuid; use uuid::Uuid;
use version; use version;
@ -8,7 +9,7 @@ use version;
pub struct SessionConfig { pub struct SessionConfig {
pub user_agent: String, pub user_agent: String,
pub device_id: String, pub device_id: String,
pub proxy: Option<String>, pub proxy: Option<Url>,
} }
impl Default for SessionConfig { impl Default for SessionConfig {

View file

@ -5,14 +5,13 @@ pub use self::codec::APCodec;
pub use self::handshake::handshake; pub use self::handshake::handshake;
use futures::{Future, Sink, Stream}; use futures::{Future, Sink, Stream};
use hyper::Uri;
use protobuf::{self, Message}; use protobuf::{self, Message};
use std::io; use std::io;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use std::str::FromStr;
use tokio_core::net::TcpStream; use tokio_core::net::TcpStream;
use tokio_core::reactor::Handle; use tokio_core::reactor::Handle;
use tokio_io::codec::Framed; use tokio_io::codec::Framed;
use url::Url;
use authentication::Credentials; use authentication::Credentials;
use version; use version;
@ -24,22 +23,12 @@ pub type Transport = Framed<TcpStream, APCodec>;
pub fn connect( pub fn connect(
addr: String, addr: String,
handle: &Handle, handle: &Handle,
proxy: &Option<String>, proxy: &Option<Url>,
) -> Box<Future<Item = Transport, Error = io::Error>> { ) -> Box<Future<Item = Transport, Error = io::Error>> {
let (addr, connect_url) = match *proxy { let (addr, connect_url) = match *proxy {
Some(ref url) => { Some(ref url) => {
let url = Uri::from_str(url).expect("Malformed proxy address"); info!("Using proxy \"{}\"", url);
let host = url.host().expect("Malformed proxy address: no host"); (url.to_socket_addrs().unwrap().next().unwrap(), Some(addr))
let port = url.port().unwrap_or(3128);
(
format!("{}:{}", host, port)
.to_socket_addrs()
.unwrap()
.next()
.unwrap(),
Some(addr.clone()),
)
} }
None => (addr.to_socket_addrs().unwrap().next().unwrap(), None), None => (addr.to_socket_addrs().unwrap().next().unwrap(), None),
}; };

View file

@ -30,6 +30,7 @@ extern crate serde_json;
extern crate shannon; extern crate shannon;
extern crate tokio_core; extern crate tokio_core;
extern crate tokio_io; extern crate tokio_io;
extern crate url;
extern crate uuid; extern crate uuid;
extern crate librespot_protocol as protocol; extern crate librespot_protocol as protocol;

View file

@ -96,7 +96,7 @@ impl<T: AsyncRead + AsyncWrite> Future for ProxyTunnel<T> {
} }
fn proxy_connect<T: AsyncWrite>(connection: T, connect_url: &str) -> WriteAll<T, Vec<u8>> { fn proxy_connect<T: AsyncWrite>(connection: T, connect_url: &str) -> WriteAll<T, Vec<u8>> {
let uri = Uri::from_str(&connect_url).unwrap(); let uri = Uri::from_str(connect_url).unwrap();
let buffer = format!( let buffer = format!(
"CONNECT {0}:{1} HTTP/1.1\r\n\ "CONNECT {0}:{1} HTTP/1.1\r\n\
\r\n", \r\n",

View file

@ -9,6 +9,7 @@ extern crate rpassword;
extern crate tokio_core; extern crate tokio_core;
extern crate tokio_io; extern crate tokio_io;
extern crate tokio_signal; extern crate tokio_signal;
extern crate url;
use crypto::digest::Digest; use crypto::digest::Digest;
use crypto::sha1::Sha1; use crypto::sha1::Sha1;
@ -23,6 +24,7 @@ use std::process::exit;
use std::str::FromStr; use std::str::FromStr;
use tokio_core::reactor::{Core, Handle}; use tokio_core::reactor::{Core, Handle};
use tokio_io::IoStream; use tokio_io::IoStream;
use url::Url;
use librespot::core::authentication::{get_credentials, Credentials}; use librespot::core::authentication::{get_credentials, Credentials};
use librespot::core::cache::Cache; use librespot::core::cache::Cache;
@ -248,7 +250,23 @@ fn setup(args: &[String]) -> Setup {
SessionConfig { SessionConfig {
user_agent: version::version_string(), user_agent: version::version_string(),
device_id: device_id, device_id: device_id,
proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()), proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()).map(
|s| {
match Url::parse(&s) {
Ok(url) => {
if url.host().is_none() || url.port().is_none() {
panic!("Invalid proxy url, only urls on the format \"http://host:port\" are allowed");
}
if url.scheme() != "http" {
panic!("Only unsecure http:// proxies are supported");
}
url
},
Err(err) => panic!("Invalid proxy url: {}, only urls on the format \"http://host:port\" are allowed", err)
}
},
),
} }
}; };