Skip to content

Commit d918771

Browse files
committed
fix(server): handle keep-alive closing
Closes #437
1 parent dac2f4d commit d918771

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

src/http.rs

+24-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use method::Method;
1212
use status::StatusCode;
1313
use uri::RequestUri;
1414
use version::HttpVersion::{self, Http10, Http11};
15-
use HttpError:: HttpTooLargeError;
15+
use HttpError::{HttpIoError, HttpTooLargeError};
1616
use {HttpError, HttpResult};
1717

1818
use self::HttpReader::{SizedReader, ChunkedReader, EofReader, EmptyReader};
@@ -353,6 +353,12 @@ fn parse<R: Read, T: TryParse<Subject=I>, I>(rdr: &mut BufReader<R>) -> HttpResu
353353
_partial => ()
354354
}
355355
match try!(rdr.read_into_buf()) {
356+
0 if rdr.get_buf().len() == 0 => {
357+
return Err(HttpIoError(io::Error::new(
358+
io::ErrorKind::ConnectionAborted,
359+
"Connection closed"
360+
)))
361+
},
356362
0 => return Err(HttpTooLargeError),
357363
_ => ()
358364
}
@@ -417,6 +423,7 @@ impl<'a> TryParse for httparse::Response<'a> {
417423
}
418424

419425
/// An Incoming Message head. Includes request/status line, and headers.
426+
#[derive(Debug)]
420427
pub struct Incoming<S> {
421428
/// HTTP version of the message.
422429
pub version: HttpVersion,
@@ -440,8 +447,10 @@ pub struct RawStatus(pub u16, pub Cow<'static, str>);
440447
mod tests {
441448
use std::io::{self, Write};
442449

443-
use super::{read_chunk_size};
450+
use buffer::BufReader;
451+
use mock::MockStream;
444452

453+
use super::{read_chunk_size, parse_request};
445454

446455
#[test]
447456
fn test_write_chunked() {
@@ -509,25 +518,30 @@ mod tests {
509518

510519
#[test]
511520
fn test_parse_incoming() {
512-
use buffer::BufReader;
513-
use mock::MockStream;
514-
515-
use super::parse_request;
516521
let mut raw = MockStream::with_input(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
517522
let mut buf = BufReader::new(&mut raw);
518523
parse_request(&mut buf).unwrap();
519524
}
520525

526+
#[test]
527+
fn test_parse_tcp_closed() {
528+
use std::io::ErrorKind;
529+
use error::HttpError::HttpIoError;
530+
531+
let mut empty = MockStream::new();
532+
let mut buf = BufReader::new(&mut empty);
533+
match parse_request(&mut buf) {
534+
Err(HttpIoError(ref e)) if e.kind() == ErrorKind::ConnectionAborted => (),
535+
other => panic!("unexpected result: {:?}", other)
536+
}
537+
}
538+
521539
#[cfg(feature = "nightly")]
522540
use test::Bencher;
523541

524542
#[cfg(feature = "nightly")]
525543
#[bench]
526544
fn bench_parse_incoming(b: &mut Bencher) {
527-
use buffer::BufReader;
528-
use mock::MockStream;
529-
530-
use super::parse_request;
531545
let mut raw = MockStream::with_input(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
532546
let mut buf = BufReader::new(&mut raw);
533547
b.iter(|| {

src/server/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! HTTP Server
2-
use std::io::{BufWriter, Write};
2+
use std::io::{ErrorKind, BufWriter, Write};
33
use std::marker::PhantomData;
44
use std::net::{SocketAddr, ToSocketAddrs};
55
use std::path::Path;
@@ -134,7 +134,11 @@ where S: NetworkStream + Clone, H: Handler {
134134
while keep_alive {
135135
let req = match Request::new(&mut rdr, addr) {
136136
Ok(req) => req,
137-
Err(e@HttpIoError(_)) => {
137+
Err(HttpIoError(ref e)) if e.kind() == ErrorKind::ConnectionAborted => {
138+
trace!("tcp closed, cancelling keep-alive loop");
139+
break;
140+
}
141+
Err(HttpIoError(e)) => {
138142
debug!("ioerror in keepalive loop = {:?}", e);
139143
break;
140144
}

0 commit comments

Comments
 (0)