swindon 0.7.8

An HTTP edge (frontend) server with smart websockets support
use std::sync::Arc;
use std::mem;

use futures::{Async, Future, AsyncSink};
use futures::future::{ok};
use futures::sink::{Sink};
use futures::sync::oneshot;
use tk_http::Status;
use tk_http::server::{Error, RecvMode};
use tk_http::server as http;

use config::proxy::Proxy;
use incoming::{Input, Reply, Encoder, Context, IntoContext};
use default_error_page::error_page;
use http_pools::{HttpPools, REQUESTS, FAILED_503};
use proxy:: {RepReq, HalfReq, Response, backend};


enum State {
    Headers(HalfReq),
    Sent {
        /// Mostly to resend the request
        #[allow(dead_code)]
        request: RepReq,
        response: oneshot::Receiver<Response>,
    },
    Error(Status),
    Void,
}


pub struct Codec {
    settings: Arc<Proxy>,
    pools: HttpPools,
    state: State,
    context: Option<Context>,
}

impl<S: 'static> http::Codec<S> for Codec {
    type ResponseFuture = Reply<S>;
    fn recv_mode(&mut self) -> RecvMode {
        if self.settings.stream_requests {
            unimplemented!();
        } else {
            RecvMode::buffered_upfront(self.settings.max_payload_size)
        }
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        if self.settings.stream_requests {
            unimplemented!();
        }
        self.state = match mem::replace(&mut self.state, State::Void) {
            State::Error(e) => State::Error(e),
            State::Headers(r) => {
                assert!(end);
                let r = r.upgrade(data.to_vec());
                let dest_name = &self.settings.destination.upstream;
                let mut up = self.pools.upstream(dest_name);
                let (tx, rx) = oneshot::channel();
                let ref cfg = self.context.as_ref().unwrap().0;
                let opt_dest = cfg.http_destinations.get(dest_name);
                if let Some(dest_settings) = opt_dest {
                    let codec = Box::new(backend::Codec::new(r.clone(),
                        dest_settings, tx));
                    match up.get_mut().get_mut() {
                        Some(pool) => {
                            match pool.start_send(codec) {
                                Ok(AsyncSink::NotReady(_)) => {
                                    FAILED_503.incr(1);
                                    State::Error(Status::ServiceUnavailable)
                                }
                                Ok(AsyncSink::Ready) => {
                                    debug!("Sent request {:?} to proxy", r);
                                    REQUESTS.incr(1);
                                    State::Sent {
                                        request: r,
                                        response: rx,
                                    }
                                }
                                Err(e) => {
                                    error!("Error sending to pool {:?}: {}",
                                        self.settings.destination.upstream, e);
                                    State::Error(Status::InternalServerError)
                                }
                            }
                        }
                        None => {
                            error!("No such pool {:?}",
                                self.settings.destination.upstream);
                            State::Error(Status::NotFound)
                        }
                    }
                } else {
                    error!("No such destination {:?}",
                        self.settings.destination.upstream);
                    State::Error(Status::NotFound)
                }
            }
            State::Sent { .. } => unimplemented!(),
            State::Void => unreachable!(),
        };
        return Ok(Async::Ready(data.len()));
    }
    fn start_response(&mut self, e: http::Encoder<S>) -> Reply<S> {
        if self.settings.stream_requests {
            unimplemented!();
        } else {
            let ctx = self.context.take().unwrap();
            match mem::replace(&mut self.state, State::Void) {
                State::Sent { response, .. } => {
                    Box::new(response.then(move |result| {
                        let e = Encoder::new(e, ctx);
                        match result {
                            Ok(resp) => {
                                ok(resp.encode(e))
                            }
                            Err(err) => {
                                debug!("Proxy request error: {:?}", err);
                                error_page(Status::BadGateway, e)
                            }
                        }
                    }))
                }
                State::Error(status) => {
                    Box::new(error_page(status, Encoder::new(e, ctx)))
                }
                _ => unreachable!(),
            }
        }
    }
}

impl Codec {
    pub fn new(settings: &Arc<Proxy>, inp: Input) -> Codec {
        Codec {
            state: State::Headers(HalfReq::from_input(&inp, &settings)),
            pools: inp.runtime.http_pools.clone(),
            settings: settings.clone(),
            context: Some(inp.into_context()),
        }
    }
}