Skip to content

Commit

Permalink
fix #557: read proxy response until \r\n\r\n
Browse files Browse the repository at this point in the history
Headers are terminated by CRLF according to the spec [0]. Between
headers and the body there's an additional CRLF. This means we have to
parse until we get 2 CRLFs right after each other to know when we can
stop reading from the stream.

Since the `Response` struct already handles this, we can reuse that
instead of custom stream reading and response parsing.

[0] https://www.ietf.org/rfc/rfc2068.txt (6 Response)

Signed-off-by: Mira Limbeck <[email protected]>
  • Loading branch information
puffi authored and algesten committed Sep 30, 2023
1 parent bbc6be7 commit a07f4f4
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 27 deletions.
23 changes: 8 additions & 15 deletions src/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use base64::{prelude::BASE64_STANDARD, Engine};

use crate::error::{Error, ErrorKind};
use crate::{
error::{Error, ErrorKind},
Response,
};

/// Proxy protocol
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
Expand Down Expand Up @@ -187,20 +190,10 @@ Proxy-Connection: Keep-Alive\r\n\
)
}

pub(crate) fn verify_response(response: &[u8]) -> Result<(), Error> {
let response_string = String::from_utf8_lossy(response);
let top_line = response_string
.lines()
.next()
.ok_or_else(|| ErrorKind::ProxyConnect.new())?;
let status_code = top_line
.split_whitespace()
.nth(1)
.ok_or_else(|| ErrorKind::ProxyConnect.new())?;

match status_code {
"200" => Ok(()),
"401" | "407" => Err(ErrorKind::ProxyUnauthorized.new()),
pub(crate) fn verify_response(response: &Response) -> Result<(), Error> {
match response.status() {
200 => Ok(()),
401 | 407 => Err(ErrorKind::ProxyUnauthorized.new()),
_ => Err(ErrorKind::ProxyConnect.new()),
}
}
Expand Down
19 changes: 7 additions & 12 deletions src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::error::ErrorKind;
use crate::pool::{PoolKey, PoolReturner};
use crate::proxy::Proxy;
use crate::unit::Unit;
use crate::Response;
use crate::{error::Error, proxy::Proto};

/// Trait for things implementing [std::io::Read] + [std::io::Write]. Used in [TlsConnector].
Expand Down Expand Up @@ -441,18 +442,12 @@ pub(crate) fn connect_host(
.unwrap();
stream.flush()?;

let mut proxy_response = Vec::new();

loop {
let mut buf = vec![0; 256];
let total = stream.read(&mut buf)?;
proxy_response.append(&mut buf);
if total < 256 {
break;
}
}

Proxy::verify_response(&proxy_response)?;
let s = stream.try_clone()?;
let pool_key = PoolKey::from_parts(unit.url.scheme(), hostname, port);
let pool_returner = PoolReturner::new(&unit.agent, pool_key);
let s = Stream::new(s, remote_addr, pool_returner);
let response = Response::do_from_stream(s, unit.clone())?;
Proxy::verify_response(&response)?;
}
}

Expand Down

0 comments on commit a07f4f4

Please sign in to comment.