1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! Iron middleware that makes sure requests are read in full before reusing sockets
//!
//! Hyper keeps sockets alive to reuse them between requests, to speed things up. If a request
//! that isn't supposed to have a body is sent with one, or if the server does not read out the
//! full body of a request, then the next request will be corrupted due to data remaining in
//! the network buffer.
//!
//! The `Drain` adapter in this module defines an iron `AfterMiddleware` that makes sure to empty
//! the buffer before the next request, whether the current request succeeded or failed. It reads
//! up to a configurable limit, and if there is still more data remaining, it closes the socket.
//!
//! Usage:
//!
//! ```rust
//! extern crate iron;
//! extern crate iron_drain;
//!
//! use iron::prelude::*;
//! use iron::status;
//! use iron_drain::Drain;
//!
//! # fn main() {
//! let mut srv = Chain::new(|_: &mut Request| {
//!     Ok(Response::with((status::Ok, "Hello world!")))
//! });
//! srv.link_after(Drain::new());
//! # || {
//! Iron::new(srv).http("localhost:3000").unwrap();
//! # };
//! # }
//! ```

extern crate iron;

use std::io::{self, Read};
use iron::prelude::*;
use iron::headers::Connection;
use iron::middleware::AfterMiddleware;

/// Iron middleware that makes sure requests are read in full before reusing sockets
pub struct Drain { limit: u64 }

impl Drain {
    /// Create a Drain with the default limit (1MB)
    pub fn new() -> Drain {
        Drain::with_limit(1024 * 1024)
    }

    /// Create a Drain with a custom limit
    pub fn with_limit(limit: u64) -> Drain {
        Drain {
            limit: limit
        }
    }

    fn drain(&self, req: &mut Request, resp: &mut Response) {
        // try reading up to the limit
        if io::copy(&mut req.body.by_ref().take(self.limit), &mut io::sink()).is_ok() {
            // see if there's anything left
            let mut buf = [0];
            if let Ok(n) = req.body.read(&mut buf) {
                if n == 0 {
                    return;
                }
            }
        }

        // there's too much data or an error occurred, so just close the connection
        resp.headers.set(Connection::close());
    }
}

impl AfterMiddleware for Drain {
    fn after(&self, req: &mut Request, mut resp: Response) -> IronResult<Response> {
        self.drain(req, &mut resp);
        Ok(resp)
    }

    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
        self.drain(req, &mut err.response);
        Err(err)
    }
}