1#![doc(html_root_url="https://docs.rs/hyper-socks/0.4.0")]
3#![warn(missing_docs)]
4
5extern crate socks;
6extern crate hyper;
7
8#[cfg(test)]
9extern crate hyper_openssl;
10
11use hyper::net::{NetworkConnector, HttpStream, HttpsStream, SslClient};
12use socks::{Socks4Stream, Socks5Stream};
13use std::io;
14use std::net::{SocketAddr, ToSocketAddrs};
15
16#[derive(Debug)]
18pub struct Socks4HttpConnector {
19 addrs: Vec<SocketAddr>,
20 userid: String,
21}
22
23impl Socks4HttpConnector {
24 pub fn new<T: ToSocketAddrs>(proxy: T, userid: &str) -> io::Result<Socks4HttpConnector> {
27 Ok(Socks4HttpConnector {
28 addrs: try!(proxy.to_socket_addrs()).collect(),
29 userid: userid.to_owned(),
30 })
31 }
32}
33
34impl NetworkConnector for Socks4HttpConnector {
35 type Stream = HttpStream;
36
37 fn connect(&self, host: &str, port: u16, scheme: &str) -> hyper::Result<HttpStream> {
38 if scheme != "http" {
39 return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid scheme for HTTP")
40 .into());
41 }
42
43 let socket = try!(Socks4Stream::connect(&self.addrs[..], (host, port), &self.userid));
44 Ok(HttpStream(socket.into_inner()))
45 }
46}
47
48#[derive(Debug)]
50pub struct Socks4HttpsConnector<S> {
51 addrs: Vec<SocketAddr>,
52 userid: String,
53 ssl: S,
54}
55
56impl<S: SslClient> Socks4HttpsConnector<S> {
57 pub fn new<T: ToSocketAddrs>(proxy: T, userid: &str, ssl: S) -> io::Result<Self> {
61 Ok(Socks4HttpsConnector {
62 addrs: try!(proxy.to_socket_addrs()).collect(),
63 userid: userid.to_owned(),
64 ssl: ssl,
65 })
66 }
67}
68
69impl<S: SslClient> NetworkConnector for Socks4HttpsConnector<S> {
70 type Stream = HttpsStream<S::Stream>;
71
72 fn connect(&self, host: &str, port: u16, scheme: &str) -> hyper::Result<Self::Stream> {
73 if scheme != "http" && scheme != "https" {
74 return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid scheme for HTTPS")
75 .into());
76 }
77
78 let socket = try!(Socks4Stream::connect(&self.addrs[..], (host, port), &self.userid));
79 let stream = HttpStream(socket.into_inner());
80
81 if scheme == "http" {
82 Ok(HttpsStream::Http(stream))
83 } else {
84 Ok(HttpsStream::Https(try!(self.ssl.wrap_client(stream, host))))
85 }
86 }
87}
88
89#[derive(Debug)]
91pub struct Socks5HttpConnector {
92 addrs: Vec<SocketAddr>,
93}
94
95impl Socks5HttpConnector {
96 pub fn new<T: ToSocketAddrs>(proxy: T) -> io::Result<Socks5HttpConnector> {
99 Ok(Socks5HttpConnector {
100 addrs: try!(proxy.to_socket_addrs()).collect(),
101 })
102 }
103}
104
105impl NetworkConnector for Socks5HttpConnector {
106 type Stream = HttpStream;
107
108 fn connect(&self, host: &str, port: u16, scheme: &str) -> hyper::Result<HttpStream> {
109 if scheme != "http" {
110 return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid scheme for HTTP")
111 .into());
112 }
113
114 let socket = try!(Socks5Stream::connect(&self.addrs[..], (host, port)));
115 Ok(HttpStream(socket.into_inner()))
116 }
117}
118
119#[derive(Debug)]
121pub struct Socks5HttpsConnector<S> {
122 addrs: Vec<SocketAddr>,
123 ssl: S,
124}
125
126impl<S: SslClient> Socks5HttpsConnector<S> {
127 pub fn new<T: ToSocketAddrs>(proxy: T, ssl: S) -> io::Result<Self> {
130 Ok(Socks5HttpsConnector {
131 addrs: try!(proxy.to_socket_addrs()).collect(),
132 ssl: ssl,
133 })
134 }
135}
136
137impl<S: SslClient> NetworkConnector for Socks5HttpsConnector<S> {
138 type Stream = HttpsStream<S::Stream>;
139
140 fn connect(&self, host: &str, port: u16, scheme: &str) -> hyper::Result<Self::Stream> {
141 if scheme != "http" && scheme != "https" {
142 return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid scheme for HTTPS")
143 .into());
144 }
145
146 let socket = try!(Socks5Stream::connect(&self.addrs[..], (host, port)));
147 let stream = HttpStream(socket.into_inner());
148
149 if scheme == "http" {
150 Ok(HttpsStream::Http(stream))
151 } else {
152 Ok(HttpsStream::Https(try!(self.ssl.wrap_client(stream, host))))
153 }
154 }
155}
156
157#[cfg(test)]
158mod test {
159 use hyper;
160 use hyper_openssl::OpensslClient;
161 use std::io::Read;
162
163 use super::*;
164
165 #[test]
166 fn google() {
167 let connector = Socks4HttpConnector::new("127.0.0.1:8080", "").unwrap();
168 let client = hyper::Client::with_connector(connector);
169 let mut response = client.get("http://www.google.com").send().unwrap();
170
171 assert!(response.status.is_success());
172 let mut body = vec![];
173 response.read_to_end(&mut body).unwrap();
174 }
175
176 #[test]
177 fn google_ssl_http() {
178 let ssl = OpensslClient::new().unwrap();
179 let connector = Socks4HttpsConnector::new("127.0.0.1:8080", "", ssl).unwrap();
180 let client = hyper::Client::with_connector(connector);
181 let mut response = client.get("http://www.google.com").send().unwrap();
182
183 assert!(response.status.is_success());
184 let mut body = vec![];
185 response.read_to_end(&mut body).unwrap();
186 }
187
188 #[test]
189 fn google_ssl_https() {
190 let ssl = OpensslClient::new().unwrap();
191 let connector = Socks4HttpsConnector::new("127.0.0.1:8080", "", ssl).unwrap();
192 let client = hyper::Client::with_connector(connector);
193 let mut response = client.get("https://www.google.com").send().unwrap();
194
195 assert!(response.status.is_success());
196 let mut body = vec![];
197 response.read_to_end(&mut body).unwrap();
198 }
199
200 #[test]
201 fn google_v5() {
202 let connector = Socks5HttpConnector::new("127.0.0.1:8080").unwrap();
203 let client = hyper::Client::with_connector(connector);
204 let mut response = client.get("http://www.google.com").send().unwrap();
205
206 assert!(response.status.is_success());
207 let mut body = vec![];
208 response.read_to_end(&mut body).unwrap();
209 }
210
211 #[test]
212 fn google_ssl_http_v5() {
213 let ssl = OpensslClient::new().unwrap();
214 let connector = Socks5HttpsConnector::new("127.0.0.1:8080", ssl).unwrap();
215 let client = hyper::Client::with_connector(connector);
216 let mut response = client.get("http://www.google.com").send().unwrap();
217
218 assert!(response.status.is_success());
219 let mut body = vec![];
220 response.read_to_end(&mut body).unwrap();
221 }
222
223 #[test]
224 fn google_ssl_https_v5() {
225 let ssl = OpensslClient::new().unwrap();
226 let connector = Socks5HttpsConnector::new("127.0.0.1:8080", ssl).unwrap();
227 let client = hyper::Client::with_connector(connector);
228 let mut response = client.get("https://www.google.com").send().unwrap();
229
230 assert!(response.status.is_success());
231 let mut body = vec![];
232 response.read_to_end(&mut body).unwrap();
233 }
234}