Skip to content

Commit e689f20

Browse files
committed
fix(client): check for drained stream in Response::drop
1 parent 306f39c commit e689f20

File tree

3 files changed

+33
-34
lines changed

3 files changed

+33
-34
lines changed

src/client/pool.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ impl<C: NetworkConnector<Stream=S>, S: NetworkStream + Send> NetworkConnector fo
116116
Ok(PooledStream {
117117
inner: Some((key, conn)),
118118
is_closed: false,
119-
is_drained: false,
120119
pool: self.inner.clone()
121120
})
122121
}
@@ -130,20 +129,13 @@ impl<C: NetworkConnector<Stream=S>, S: NetworkStream + Send> NetworkConnector fo
130129
pub struct PooledStream<S> {
131130
inner: Option<(Key, S)>,
132131
is_closed: bool,
133-
is_drained: bool,
134132
pool: Arc<Mutex<PoolImpl<S>>>
135133
}
136134

137135
impl<S: NetworkStream> Read for PooledStream<S> {
138136
#[inline]
139137
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
140-
match self.inner.as_mut().unwrap().1.read(buf) {
141-
Ok(0) => {
142-
self.is_drained = true;
143-
Ok(0)
144-
}
145-
r => r
146-
}
138+
self.inner.as_mut().unwrap().1.read(buf)
147139
}
148140
}
149141

@@ -174,8 +166,8 @@ impl<S: NetworkStream> NetworkStream for PooledStream<S> {
174166

175167
impl<S> Drop for PooledStream<S> {
176168
fn drop(&mut self) {
177-
trace!("PooledStream.drop, is_closed={}, is_drained={}", self.is_closed, self.is_drained);
178-
if !self.is_closed && self.is_drained {
169+
trace!("PooledStream.drop, is_closed={}", self.is_closed);
170+
if !self.is_closed {
179171
self.inner.take().map(|(key, conn)| {
180172
if let Ok(mut pool) = self.pool.lock() {
181173
pool.reuse(key, conn);
@@ -205,13 +197,13 @@ mod tests {
205197
fn test_connect_and_drop() {
206198
let pool = mocked!();
207199
let key = key("127.0.0.1", 3000, "http");
208-
pool.connect("127.0.0.1", 3000, "http").unwrap().is_drained = true;
200+
pool.connect("127.0.0.1", 3000, "http").unwrap();
209201
{
210202
let locked = pool.inner.lock().unwrap();
211203
assert_eq!(locked.conns.len(), 1);
212204
assert_eq!(locked.conns.get(&key).unwrap().len(), 1);
213205
}
214-
pool.connect("127.0.0.1", 3000, "http").unwrap().is_drained = true; //reused
206+
pool.connect("127.0.0.1", 3000, "http").unwrap(); //reused
215207
{
216208
let locked = pool.inner.lock().unwrap();
217209
assert_eq!(locked.conns.len(), 1);

src/client/response.rs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct Response {
1919
pub version: version::HttpVersion,
2020
status_raw: RawStatus,
2121
message: Box<HttpMessage>,
22+
is_drained: bool,
2223
}
2324

2425
impl Response {
@@ -43,41 +44,54 @@ impl Response {
4344
headers: headers,
4445
message: message,
4546
status_raw: raw_status,
47+
is_drained: false,
4648
})
4749
}
4850

4951
/// Get the raw status code and reason.
5052
pub fn status_raw(&self) -> &RawStatus {
5153
&self.status_raw
5254
}
55+
5356
}
5457

5558
impl Read for Response {
5659
#[inline]
5760
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
58-
let count = try!(self.message.read(buf));
61+
match self.message.read(buf) {
62+
Ok(0) => {
63+
self.is_drained = true;
64+
Ok(0)
65+
},
66+
r => r
67+
}
68+
}
69+
}
5970

60-
if count == 0 {
61-
if !http::should_keep_alive(self.version, &self.headers) {
62-
try!(self.message.close_connection()
63-
.map_err(|_| io::Error::new(io::ErrorKind::Other,
64-
"Error closing connection")));
71+
impl Drop for Response {
72+
fn drop(&mut self) {
73+
// if not drained, theres old bits in the Reader. we can't reuse this,
74+
// since those old bits would end up in new Responses
75+
//
76+
// otherwise, the response has been drained. we should check that the
77+
// server has agreed to keep the connection open
78+
trace!("Response.is_drained = {:?}", self.is_drained);
79+
if !(self.is_drained && http::should_keep_alive(self.version, &self.headers)) {
80+
trace!("closing connection");
81+
if let Err(e) = self.message.close_connection() {
82+
error!("error closing connection: {}", e);
6583
}
6684
}
67-
68-
Ok(count)
6985
}
7086
}
7187

7288
#[cfg(test)]
7389
mod tests {
74-
use std::borrow::Cow::Borrowed;
7590
use std::io::{self, Read};
7691

77-
use header::Headers;
7892
use header::TransferEncoding;
7993
use header::Encoding;
80-
use http::RawStatus;
94+
use http::HttpMessage;
8195
use mock::MockStream;
8296
use status;
8397
use version;
@@ -94,18 +108,10 @@ mod tests {
94108

95109
#[test]
96110
fn test_into_inner() {
97-
let res = Response {
98-
status: status::StatusCode::Ok,
99-
headers: Headers::new(),
100-
version: version::HttpVersion::Http11,
101-
message: Box::new(Http11Message::with_stream(Box::new(MockStream::new()))),
102-
status_raw: RawStatus(200, Borrowed("OK")),
103-
};
104-
105-
let message = res.message.downcast::<Http11Message>().ok().unwrap();
111+
let message: Box<HttpMessage> = Box::new(Http11Message::with_stream(Box::new(MockStream::new())));
112+
let message = message.downcast::<Http11Message>().ok().unwrap();
106113
let b = message.into_inner().downcast::<MockStream>().ok().unwrap();
107114
assert_eq!(b, Box::new(MockStream::new()));
108-
109115
}
110116

111117
#[test]

src/http/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub struct RawStatus(pub u16, pub Cow<'static, str>);
2020
/// Checks if a connection should be kept alive.
2121
#[inline]
2222
pub fn should_keep_alive(version: HttpVersion, headers: &Headers) -> bool {
23+
trace!("should_keep_alive( {:?}, {:?} )", version, headers.get::<Connection>());
2324
match (version, headers.get::<Connection>()) {
2425
(Http10, Some(conn)) if !conn.contains(&KeepAlive) => false,
2526
(Http11, Some(conn)) if conn.contains(&Close) => false,

0 commit comments

Comments
 (0)