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
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! A tiny HTTP/1.1 server framework.
//!
//! # Examples
//!
//! ```
//! # extern crate bytecodec;
//! # extern crate fibers;
//! # extern crate fibers_http_server;
//! # extern crate futures;
//! # extern crate httpcodec;
//! use std::io::{Read, Write};
//! use std::net::TcpStream;
//! use std::thread;
//! use std::time::Duration;
//! use bytecodec::bytes::Utf8Encoder;
//! use bytecodec::value::NullDecoder;
//! use fibers::{Executor, Spawn, InPlaceExecutor};
//! use fibers_http_server::{HandleRequest, Reply, Req, Res, ServerBuilder, Status};
//! use futures::future::{ok, Future};
//! use httpcodec::{BodyDecoder, BodyEncoder};
//!
//! // Request handler
//! struct Hello;
//! impl HandleRequest for Hello {
//!     const METHOD: &'static str = "GET";
//!     const PATH: &'static str = "/hello";
//!
//!     type ReqBody = ();
//!     type ResBody = String;
//!     type Decoder = BodyDecoder<NullDecoder>;
//!     type Encoder = BodyEncoder<Utf8Encoder>;
//!     type Reply = Reply<Self::ResBody>;
//!
//!     fn handle_request(&self, _req: Req<Self::ReqBody>) -> Self::Reply {
//!         Box::new(ok(Res::new(Status::Ok, "hello".to_owned())))
//!     }
//! }
//!
//! # fn main() {
//! let addr = "127.0.0.1:14758".parse().unwrap();
//!
//! // HTTP server
//! thread::spawn(move || {
//!     let executor = InPlaceExecutor::new().unwrap();
//!     let mut builder = ServerBuilder::new(addr);
//!     builder.add_handler(Hello).unwrap();
//!     let server = builder.finish(executor.handle());
//!     executor.spawn(server.map_err(|e| panic!("{}", e)));
//!     executor.run().unwrap()
//! });
//! thread::sleep(Duration::from_millis(100));
//!
//! // HTTP client
//! let mut client = TcpStream::connect(addr).unwrap();
//! client
//!     .write_all(b"GET /hello HTTP/1.1\r\nContent-Length: 0\r\n\r\n")
//!     .unwrap();
//! thread::sleep(Duration::from_millis(100));
//!
//! let mut buf = [0; 1024];
//! let size = client.read(&mut buf).unwrap();
//! assert_eq!(
//!     &buf[..size],
//!     b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello".as_ref()
//! );
//! # }
//! ```
#![warn(missing_docs)]
extern crate atomic_immut;
extern crate bytecodec;
extern crate factory;
extern crate fibers;
extern crate futures;
extern crate httpcodec;
extern crate prometrics;
#[macro_use]
extern crate slog;
#[macro_use]
extern crate trackable;
extern crate url;

pub use error::{Error, ErrorKind};
pub use handler::{HandleRequest, HandlerOptions, Reply};
pub use request::Req;
pub use response::Res;
pub use server::{Server, ServerBuilder};
pub use status::Status;

pub mod metrics;

mod connection;
mod dispatcher;
mod error;
mod handler;
mod header;
mod request;
mod response;
mod server;
mod status;

/// This crate specific `Result` type.
pub type Result<T> = std::result::Result<T, Error>;

#[cfg(test)]
mod test {
    use std::io::{Read, Write};
    use std::net::TcpStream;
    use std::thread;
    use std::time::Duration;
    use bytecodec::bytes::Utf8Encoder;
    use bytecodec::value::NullDecoder;
    use fibers::{Executor, InPlaceExecutor, Spawn};
    use futures::future::{ok, Future};
    use httpcodec::{BodyDecoder, BodyEncoder};

    use super::*;

    struct Hello;
    impl HandleRequest for Hello {
        const METHOD: &'static str = "GET";
        const PATH: &'static str = "/hello";

        type ReqBody = ();
        type ResBody = String;
        type Decoder = BodyDecoder<NullDecoder>;
        type Encoder = BodyEncoder<Utf8Encoder>;
        type Reply = Reply<Self::ResBody>;

        fn handle_request(&self, _req: Req<Self::ReqBody>) -> Self::Reply {
            Box::new(ok(Res::new(Status::Ok, "hello".to_owned())))
        }
    }

    #[test]
    fn it_works() {
        let addr = "127.0.0.1:14757".parse().unwrap();
        thread::spawn(move || {
            let executor = InPlaceExecutor::new().unwrap();
            let mut builder = ServerBuilder::new(addr);
            builder.add_handler(Hello).unwrap();
            let server = builder.finish(executor.handle());
            executor.spawn(server.map_err(|e| panic!("{}", e)));
            executor.run().unwrap()
        });
        thread::sleep(Duration::from_millis(100));

        let mut client = TcpStream::connect(addr).unwrap();
        client
            .write_all(b"GET /hello HTTP/1.1\r\nContent-Length: 0\r\n\r\n")
            .unwrap();
        thread::sleep(Duration::from_millis(100));

        let mut buf = [0; 1024];
        let size = client.read(&mut buf).unwrap();
        assert_eq!(
            &buf[..size],
            b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello".as_ref()
        );
    }
}