Add Proxy field to PoolKey. (#114)

Fixes #109
This commit is contained in:
Alex L
2020-07-09 00:41:43 +09:00
committed by GitHub
parent 87b8a381bc
commit ea3b93dcab
3 changed files with 42 additions and 8 deletions

View File

@@ -3,6 +3,7 @@ use std::io::{Read, Result as IoResult};
use crate::stream::Stream; use crate::stream::Stream;
use crate::unit::Unit; use crate::unit::Unit;
use crate::Proxy;
use url::Url; use url::Url;
@@ -35,8 +36,8 @@ impl ConnectionPool {
} }
/// How the unit::connect tries to get a pooled connection. /// How the unit::connect tries to get a pooled connection.
pub fn try_get_connection(&mut self, url: &Url) -> Option<Stream> { pub fn try_get_connection(&mut self, url: &Url, proxy: &Option<Proxy>) -> Option<Stream> {
let key = PoolKey::new(url); let key = PoolKey::new(url, proxy);
self.remove(&key) self.remove(&key)
} }
@@ -87,6 +88,7 @@ struct PoolKey {
scheme: String, scheme: String,
hostname: String, hostname: String,
port: Option<u16>, port: Option<u16>,
proxy: Option<Proxy>,
} }
use std::fmt; use std::fmt;
@@ -103,12 +105,13 @@ impl fmt::Debug for PoolKey {
} }
impl PoolKey { impl PoolKey {
fn new(url: &Url) -> Self { fn new(url: &Url, proxy: &Option<Proxy>) -> Self {
let port = url.port_or_known_default(); let port = url.port_or_known_default();
PoolKey { PoolKey {
scheme: url.scheme().to_string(), scheme: url.scheme().to_string(),
hostname: url.host_str().unwrap_or("").to_string(), hostname: url.host_str().unwrap_or("").to_string(),
port, port,
proxy: proxy.clone(),
} }
} }
} }
@@ -116,7 +119,7 @@ impl PoolKey {
#[test] #[test]
fn poolkey_new() { fn poolkey_new() {
// Test that PoolKey::new() does not panic on unrecognized schemes. // Test that PoolKey::new() does not panic on unrecognized schemes.
PoolKey::new(&Url::parse("zzz:///example.com").unwrap()); PoolKey::new(&Url::parse("zzz:///example.com").unwrap(), &None);
} }
#[test] #[test]
@@ -128,6 +131,7 @@ fn pool_size_limit() {
scheme: "https".to_string(), scheme: "https".to_string(),
hostname, hostname,
port: Some(999), port: Some(999),
proxy: None,
}); });
for key in poolkeys.clone() { for key in poolkeys.clone() {
pool.add(key, Stream::Cursor(std::io::Cursor::new(vec![]))); pool.add(key, Stream::Cursor(std::io::Cursor::new(vec![])));
@@ -152,6 +156,7 @@ fn pool_duplicates_limit() {
scheme: "https".to_string(), scheme: "https".to_string(),
hostname, hostname,
port: Some(999), port: Some(999),
proxy: None,
}); });
for key in poolkeys.clone() { for key in poolkeys.clone() {
pool.add(key.clone(), Stream::Cursor(std::io::Cursor::new(vec![]))); pool.add(key.clone(), Stream::Cursor(std::io::Cursor::new(vec![])));
@@ -165,6 +170,35 @@ fn pool_duplicates_limit() {
} }
} }
#[test]
fn pool_checks_proxy() {
// Test inserting different poolkeys with same address but different proxies.
// Each insertion should result in an additional entry in the pool.
let mut pool = ConnectionPool::new();
let url = Url::parse("zzz:///example.com").unwrap();
pool.add(
PoolKey::new(&url, &None),
Stream::Cursor(std::io::Cursor::new(vec![])),
);
assert_eq!(pool.len(), 1);
pool.add(
PoolKey::new(&url, &Some(Proxy::new("localhost:9999").unwrap())),
Stream::Cursor(std::io::Cursor::new(vec![])),
);
assert_eq!(pool.len(), 2);
pool.add(
PoolKey::new(
&url,
&Some(Proxy::new("user:password@localhost:9999").unwrap()),
),
Stream::Cursor(std::io::Cursor::new(vec![])),
);
assert_eq!(pool.len(), 3);
}
/// Read wrapper that returns the stream to the pool once the /// Read wrapper that returns the stream to the pool once the
/// read is exhausted (reached a 0). /// read is exhausted (reached a 0).
/// ///
@@ -196,7 +230,7 @@ impl<R: Read + Sized + Into<Stream>> PoolReturnRead<R> {
return; return;
} }
// insert back into pool // insert back into pool
let key = PoolKey::new(&unit.url); let key = PoolKey::new(&unit.url, &unit.proxy);
agent.pool().add(key, stream); agent.pool().add(key, stream);
} }
} }

View File

@@ -1,14 +1,14 @@
use crate::error::Error; use crate::error::Error;
/// Proxy protocol /// Proxy protocol
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Proto { pub enum Proto {
HTTPConnect, HTTPConnect,
SOCKS5, SOCKS5,
} }
/// Proxy server definition /// Proxy server definition
#[derive(Clone, Debug)] #[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Proxy { pub struct Proxy {
pub(crate) server: String, pub(crate) server: String,
pub(crate) port: u32, pub(crate) port: u32,

View File

@@ -301,7 +301,7 @@ fn connect_socket(unit: &Unit, use_pooled: bool) -> Result<(Stream, bool), Error
// The connection may have been closed by the server // The connection may have been closed by the server
// due to idle timeout while it was sitting in the pool. // due to idle timeout while it was sitting in the pool.
// Loop until we find one that is still good or run out of connections. // Loop until we find one that is still good or run out of connections.
while let Some(stream) = agent.pool.try_get_connection(&unit.url) { while let Some(stream) = agent.pool.try_get_connection(&unit.url, &unit.proxy) {
let server_closed = stream.server_closed()?; let server_closed = stream.server_closed()?;
if !server_closed { if !server_closed {
return Ok((stream, true)); return Ok((stream, true));