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
//! A tiny HTTP/1.1 server framework.
//!
//! # Examples
//!
//! ```
//! use std::io::{Read, Write};
//! use std::net::TcpStream;
//! use std::thread;
//! use std::time::Duration;
//! use bytecodec::bytes::Utf8Encoder;
//! use bytecodec::null::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)]
#[macro_use]
extern crate slog;
#[macro_use]
extern crate trackable;

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 bytecodec::bytes::Utf8Encoder;
    use bytecodec::null::NullDecoder;
    use futures::future::ok;
    use httpcodec::{BodyDecoder, BodyEncoder};
    use std::io::{Read, Write};
    use std::net::TcpStream;
    use std::thread;
    use std::time::Duration;

    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 mut builder = ServerBuilder::new(([127, 0, 0, 1], 0).into());
        builder.add_handler(Hello).unwrap();
        let server = builder.finish(fibers_global::handle());
        let (server, addr) = fibers_global::execute(server.local_addr()).unwrap();
        thread::spawn(move || {
            fibers_global::execute(server).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()
        );
    }
}