From 580e159268a2c474e58a6f5a6fbc2faedb4f058c Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Mon, 9 Sep 2019 19:26:36 +0100 Subject: [PATCH] handle server CloseNotifying connection --- src/stream.rs | 27 ++++++++++++++++++++++++++- tests/https-agent.rs | 11 +++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 tests/https-agent.rs diff --git a/src/stream.rs b/src/stream.rs index bbe9d04..8917ec6 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -4,6 +4,9 @@ use std::net::TcpStream; use std::net::ToSocketAddrs; use std::time::Duration; +use rustls::StreamOwned; +use rustls::ClientSession; + use crate::error::Error; use crate::unit::Unit; @@ -58,7 +61,7 @@ impl Read for Stream { match self { Stream::Http(sock) => sock.read(buf), #[cfg(feature = "tls")] - Stream::Https(stream) => stream.read(buf), + Stream::Https(stream) => read_https(stream, buf), Stream::Cursor(read) => read.read(buf), #[cfg(test)] Stream::Test(reader, _) => reader.read(buf), @@ -66,6 +69,28 @@ impl Read for Stream { } } +fn read_https(stream: &mut StreamOwned, buf: &mut [u8]) -> IoResult { + match stream.read(buf) { + Ok(size) => Ok(size), + Err(ref e) if is_close_notify(e) => Ok(0), + Err(e) => Err(e), + } +} + +fn is_close_notify(e: &std::io::Error) -> bool { + if e.kind() != std::io::ErrorKind::ConnectionAborted { + return false; + } + + if let Some(msg) = e.get_ref() { + // :( + + return msg.description().contains("CloseNotify"); + } + + false +} + impl Write for Stream { fn write(&mut self, buf: &[u8]) -> IoResult { match self { diff --git a/tests/https-agent.rs b/tests/https-agent.rs new file mode 100644 index 0000000..2fc7125 --- /dev/null +++ b/tests/https-agent.rs @@ -0,0 +1,11 @@ +use std::io::Read; + +#[test] +fn connection_close() { + let agent = ureq::Agent::default().build(); + let resp = agent.get("https://example.com/404") + .set("Connection", "close") + .call(); + assert_eq!(resp.status(), 404); + resp.into_reader().read_to_end(&mut vec![]).unwrap(); +}