Skip to content

Commit ce45540

Browse files
committed
Implement reporting of connection errors
1 parent 281e480 commit ce45540

File tree

5 files changed

+88
-4
lines changed

5 files changed

+88
-4
lines changed

examples/client.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use argparse::{ArgumentParser, Store};
1717
use rotor::{Scope, Time};
1818
use rotor_http::client::{connect_tcp, Request, Head, Client, RecvMode};
1919
use rotor_http::client::{Connection, Requester, Task, Version, ResponseError};
20+
use rotor_http::client::{ProtocolError};
2021

2122
struct Context;
2223

@@ -44,6 +45,12 @@ impl Client for Cli {
4445
}
4546
}
4647
}
48+
fn connection_error(self, err: &ProtocolError,
49+
_scope: &mut Scope<Context>)
50+
{
51+
writeln!(&mut stderr(), "----- Bad response: {} -----", err).ok();
52+
exit(1);
53+
}
4754
fn wakeup(self,
4855
_connection: &Connection,
4956
_scope: &mut Scope<<Self::Requester as Requester>::Context>)

src/client/error.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use std::io;
2+
13
use httparse;
4+
use rotor_stream;
25

36

47
quick_error!{
@@ -19,5 +22,48 @@ quick_error!{
1922
from()
2023
description("error parsing chunk size")
2124
}
25+
Connection(err: ProtocolError) {
26+
from()
27+
description("connection error")
28+
display("connection error: {}", err)
29+
}
30+
}
31+
}
32+
33+
quick_error!{
34+
/// Error
35+
#[derive(Debug)]
36+
pub enum ProtocolError {
37+
/// Error when connecting
38+
ConnectionError(err: io::Error) {
39+
description("connection error")
40+
display("connection error: {}", err)
41+
}
42+
/// Error on idle connection
43+
ConnectionClosed {
44+
description("connection closed")
45+
display("connection closed")
46+
}
47+
ReadError(err: io::Error) {
48+
description("error when reading from stream")
49+
display("read error: {}", err)
50+
}
51+
WriteError(err: io::Error) {
52+
description("error when writing to stream")
53+
display("write error: {}", err)
54+
}
55+
}
56+
}
57+
58+
impl From<rotor_stream::Exception> for ProtocolError {
59+
fn from(e: rotor_stream::Exception) -> ProtocolError {
60+
use rotor_stream::Exception as S;
61+
use self::ProtocolError as D;
62+
match e {
63+
S::EndOfStream => D::ConnectionClosed,
64+
S::LimitReached => unreachable!(),
65+
S::ReadError(e) => D::ReadError(e),
66+
S::WriteError(e) => D::WriteError(e),
67+
}
2268
}
2369
}

src/client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use version::Version;
2424
pub use self::request::{Request};
2525
pub use self::protocol::{Client, Requester, Task};
2626
pub use self::head::Head;
27-
pub use self::error::ResponseError;
27+
pub use self::error::{ResponseError, ProtocolError};
2828
pub use recvmode::RecvMode;
2929

3030
use self::parser::Parser;

src/client/parser.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::cmp::min;
44
use std::fmt;
55

66
use rotor::{Scope, Time};
7-
use rotor_stream::{Protocol, StreamSocket};
7+
use rotor_stream::{Protocol, StreamSocket, Exception};
88
use rotor_stream::{Intent, Expectation as E, Transport};
99
use rotor_stream::Buf;
1010
use httparse;
@@ -508,6 +508,27 @@ impl<M, S> Protocol for Parser<M, S>
508508
}
509509
}
510510
}
511+
fn exception(self, _transport: &mut Transport<Self::Socket>,
512+
reason: Exception, scope: &mut Scope<Self::Context>)
513+
-> Intent<Self>
514+
{
515+
use self::ParserImpl::*;
516+
let mut reason = reason.into();
517+
match self.1 {
518+
ReadHeaders { machine, .. } | Response { machine, .. } => {
519+
let err = ResponseError::Connection(reason);
520+
machine.bad_response(&err, scope);
521+
reason = if let ResponseError::Connection(r) = err {
522+
r
523+
} else {
524+
unreachable!();
525+
}
526+
}
527+
_ => {}
528+
}
529+
self.0.connection_error(&reason, scope);
530+
Intent::done()
531+
}
511532
fn timeout(self, transport: &mut Transport<Self::Socket>,
512533
scope: &mut Scope<Self::Context>)
513534
-> Intent<Self>
@@ -556,7 +577,7 @@ mod test {
556577
use rotor::{Scope, EventSet, Time, Machine};
557578
use rotor_test::{MemIo, MockLoop};
558579
use client::{Client, Requester, Connection, Task, Request, Version};
559-
use client::{Head, RecvMode, Fsm, ResponseError};
580+
use client::{Head, RecvMode, Fsm, ResponseError, ProtocolError};
560581

561582
#[derive(Debug, Default, PartialEq, Eq)]
562583
struct Context {
@@ -594,6 +615,11 @@ mod test {
594615
Task::Sleep(self, scope.now() + Duration::new(100, 0))
595616
}
596617
}
618+
fn connection_error(self, _err: &ProtocolError,
619+
scope: &mut Scope<Context>)
620+
{
621+
scope.errors += 1;
622+
}
597623
fn wakeup(self,
598624
_connection: &Connection,
599625
_scope: &mut Scope<<Self::Requester as Requester>::Context>)

src/client/protocol.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::time::Duration;
33
use rotor::{Scope, Time};
44

55
use recvmode::RecvMode;
6-
use super::{Head, Request, ResponseError};
6+
use super::{Head, Request, ResponseError, ProtocolError};
77
use super::{Connection};
88

99
pub enum Task<M: Client> {
@@ -32,6 +32,11 @@ pub trait Client: Sized {
3232
scope: &mut Scope<<Self::Requester as Requester>::Context>)
3333
-> Task<Self>;
3434

35+
/// Error when establishing connection or connection closed when in idle
36+
fn connection_error(self,
37+
reason: &ProtocolError,
38+
scope: &mut Scope<<Self::Requester as Requester>::Context>);
39+
3540
/// Standard rotor's wakeup handler
3641
///
3742
/// If `connection.is_idle()` you may initiate a new request

0 commit comments

Comments
 (0)