cargo_web/
http_utils.rs

1use std::io::Cursor;
2use std::sync::Arc;
3use std::fs::File;
4use std::net::SocketAddr;
5use futures::{Poll, Async};
6use futures::future::{self, Future};
7use hyper::body::Payload;
8use hyper::{self, StatusCode, Request, Response, Server};
9use hyper::service::{NewService, Service};
10use hyper::server::conn::AddrIncoming;
11use hyper::header::{CONTENT_TYPE, CONTENT_LENGTH, CACHE_CONTROL, EXPIRES, PRAGMA, ACCESS_CONTROL_ALLOW_ORIGIN};
12use http::response::Builder;
13use memmap::Mmap;
14use mime_guess::Mime;
15
16pub enum BodyContents {
17    Owned( Vec< u8 > ),
18    Mmap( Mmap )
19}
20
21impl AsRef< [u8] > for BodyContents {
22    fn as_ref( &self ) -> &[u8] {
23        match *self {
24            BodyContents::Owned( ref buffer ) => &buffer,
25            BodyContents::Mmap( ref map ) => &map
26        }
27    }
28}
29
30pub struct Body( Option< Cursor< BodyContents > > );
31
32impl Payload for Body {
33    type Data = Cursor< BodyContents >;
34    type Error = hyper::Error;
35
36    fn poll_data(&mut self) -> Poll< Option< Self::Data >, Self::Error > {
37        Ok( Async::Ready( self.0.take() ) )
38    }
39}
40
41impl From< Vec< u8 > > for Body {
42    fn from( buffer: Vec< u8 > ) -> Self {
43        Body( Some( Cursor::new( BodyContents::Owned( buffer ) ) ) )
44    }
45}
46
47impl From< Mmap > for Body {
48    fn from( map: Mmap ) -> Self {
49        Body( Some( Cursor::new( BodyContents::Mmap( map ) ) ) )
50    }
51}
52
53pub type ResponseFuture = Box< Future< Item = Response< Body >, Error = hyper::Error > + Send >;
54pub type FnHandler = Box< Fn( Request< hyper::Body > ) -> ResponseFuture + Send + Sync >;
55pub type ServiceFuture = Box< Future< Item = SimpleService, Error = hyper::Error > + Send >;
56
57pub struct SimpleService {
58    handler: Arc< FnHandler >
59}
60
61impl Service for SimpleService {
62    type ReqBody = hyper::Body;
63    type ResBody = Body;
64    type Error = hyper::Error;
65
66    type Future = ResponseFuture;
67
68    fn call( &mut self, request: Request< hyper::Body > ) -> ResponseFuture {
69        ( *self.handler )( request )
70    }
71}
72
73pub struct NewSimpleService {
74    handler: Arc< FnHandler >
75}
76
77impl NewService for NewSimpleService {
78    type ReqBody = hyper::Body;
79    type ResBody = Body;
80    type Error = hyper::Error;
81
82    type Service = SimpleService;
83    type Future = ServiceFuture;
84    type InitError = hyper::Error;
85
86    fn new_service( &self ) -> Self::Future {
87        Box::new( future::ok( SimpleService {
88            handler: self.handler.clone()
89        } ) )
90    }
91}
92
93pub struct SimpleServer {
94    server: Server< AddrIncoming, NewSimpleService >
95}
96
97impl SimpleServer {
98    pub fn new< F >( address: &SocketAddr, handler: F ) -> Self
99    where
100        F: Send + Sync + 'static + Fn( Request< hyper::Body > ) -> ResponseFuture
101    {
102        let server = Server::bind( address )
103            .serve( NewSimpleService {
104                handler: Arc::new( Box::new( handler ) )
105            } );
106        SimpleServer { server }
107    }
108
109    pub fn server_addr( &self ) -> SocketAddr {
110        self.server.local_addr()
111    }
112
113    pub fn run( self ) {
114        hyper::rt::run(self.server.map_err(|e| {
115            eprintln!("server error: {}", e);
116        }));
117    }
118}
119
120fn add_headers( builder: &mut Builder ) {
121    builder.header( CACHE_CONTROL, "no-cache" );
122    builder.header( CACHE_CONTROL, "no-store" );
123    builder.header( CACHE_CONTROL, "must-revalidate" );
124    builder.header( EXPIRES, "0" );
125    builder.header( PRAGMA, "no-cache" );
126    builder.header( ACCESS_CONTROL_ALLOW_ORIGIN, "*" );
127}
128
129pub fn response_from_file( mime_type: &Mime, fp: File ) -> ResponseFuture {
130    if let Ok( metadata ) = fp.metadata() {
131        if metadata.len() == 0 {
132            // This is necessary since `Mmap::map` will return an error for empty files.
133            return response_from_data( mime_type, Vec::new() );
134        }
135    }
136
137    let map = match unsafe { Mmap::map( &fp ) } {
138        Ok( map ) => map,
139        Err( error ) => {
140            warn!( "Mmap failed: {}", error );
141            let status = StatusCode::INTERNAL_SERVER_ERROR;
142            let message = format!( "{}\n\n{}", status, error ).into_bytes();
143            let mut response = sync_response_from_data(
144                &"text/plain".parse().unwrap(),
145                message );
146            *response.status_mut() = status;
147            return Box::new( future::ok( response ) );
148        }
149    };
150
151    let length = map.len();
152    let body: Body = map.into();
153    let mut response = Response::builder();
154    add_headers( &mut response );
155    response.header( CONTENT_TYPE, mime_type.to_string() );
156    response.header( CONTENT_LENGTH, length );
157
158    Box::new( future::ok( response.body( body ).unwrap() ) )
159}
160
161fn sync_response_from_data( mime_type: &Mime, data: Vec< u8 > ) -> Response< Body > {
162    let length = data.len();
163    let body: Body = data.into();
164    let mut response = Response::builder();
165    add_headers( &mut response );
166    response.header( CONTENT_TYPE, mime_type.to_string());
167    response.header( CONTENT_LENGTH, length );
168    response.body( body ).unwrap()
169}
170
171pub fn response_from_data( mime_type: &Mime, data: Vec< u8 > ) -> ResponseFuture {
172    Box::new( future::ok( sync_response_from_data( mime_type, data ) ) )
173}
174
175pub fn response_from_status( status: StatusCode ) -> ResponseFuture {
176    let mut response = sync_response_from_data(
177        &"text/plain".parse().unwrap(),
178        format!( "{}", status ).into_bytes() );
179    *response.status_mut() = status;
180    Box::new( future::ok( response ) )
181}