<commit_before>use std::net::SocketAddr;
use std::str;
use std::str::FromStr;
use std::io;

// use mio::{EventLoop, Handler, Token, EventSet, PollOpt};
// use mio::tcp::{TcpListener, TcpStream};
use mio::*;
use mio::tcp::*;

use mio::util::Slab;
use interface::{ServerFactory, Protocol, Reason};
use transport::{Transport};

const CONNS_MAX: usize = 65_536;
const BUF_SIZE: usize = 4096;

#[derive(Clone)]
enum ConnectionType {
    Server,
    Client,
}

struct ServerConnection {
    server: Box<ServerFactory>,
    socket: TcpListener,
}

struct ClientConnection {
    protocol: Box<Protocol>,
    socket: TcpStream,
    interest: EventSet,
    peer_hup: bool,
    transport: Transport,
}

impl ClientConnection {

    fn new(protocol: Box<Protocol>, socket: TcpStream) -> ClientConnection {
        ClientConnection {
            protocol: protocol,
            socket: socket,
            interest: EventSet::hup() | EventSet::readable(),
            peer_hup: false,
            transport: Transport::new(),
        }
    }

    fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.socket.peer_addr()
    }

    fn is_finished(&self) -> bool {
        self.interest == EventSet::none()
    }

    fn reregister(&mut self,
                  event_loop: &mut EventLoop<MioHandler>,
                  token: Token)
                  -> io::Result<()> {

        // have somewhere to read to and someone to receive from
        if !self.peer_hup || false {
            info!("Insert read interest");
            self.interest.insert(EventSet::readable());
        } else {
            self.interest.remove(EventSet::readable());
        }

        event_loop.reregister(&self.socket,
                              token,
                              self.interest,
                              PollOpt::edge() | PollOpt::oneshot())
    }

    fn handle_hup(&mut self,
                  event_loop: &mut EventLoop<MioHandler>,
                  token: Token)
                  -> io::Result<()> {
        if self.interest == EventSet::hup() {
            self.interest = EventSet::none();
            try!(event_loop.deregister(&self.socket));
        } else {
            self.peer_hup = true;
            let _ = self.reregister(event_loop, token);
        }
        Ok(())
    }

    fn handle_read(&mut self,
                   event_loop: &mut EventLoop<MioHandler>,
                   token: Token)
                   -> io::Result<()> {
        {
            let mut read_bytes: Vec<u8> = Vec::new();
            loop {
                let (buf, read_len) = {
                    let mut buf = [0; BUF_SIZE];
                    let read_len = self.socket.try_read(&mut buf[..]);
                    // let s_data = str::from_utf8(&buf).unwrap();
                    // info!("<<< {}", s_data);
                    (buf, read_len)
                };
                match read_len {
                    Ok(None) => {
                        info!("read to end");
                        break;
                    }
                    Ok(Some(len)) => {
                        read_bytes.extend(buf[0..len].iter());
                        if len < BUF_SIZE {
                            info!("Nothing more to read");
                            break;
                        } else {
                            info!("More data to read");
                        }
                    }
                    Err(_) => {
                        info!("Error while reading to socket, consider to hang up");
                        break;
                    }
                }
            }
            let _ = self.reregister(event_loop, token);
            self.protocol.data_received(&read_bytes[..], &mut self.transport);
        }

        if self.transport.should_write() {
            let _ = self.handle_write(event_loop, token);
        }

        Ok(())
    }

    fn handle_write(&mut self,
                    event_loop: &mut EventLoop<MioHandler>,
                    token: Token)
                    -> io::Result<()> {
        {
            info!("handle write");
            loop {
                let (len, res) = {
                    let buf = &mut self.transport.buf();
                    let len = buf.len();
                    let s_data = str::from_utf8(&buf[..]).unwrap();
                    info!(">>> {}", s_data);

                    let res = self.socket.try_write(&buf[..]);
                    (len, res)
                };
                match res {
                    Ok(None) => {
                        break;
                    }
                    Ok(Some(written_len)) => {
                        info!("Write {}, attempt {}", written_len, len);
                        if written_len != len {
                            info!("Something is going wrong with the socket");
                            break;
                        }
                    }
                    Err(_) => {
                        info!("Error while writing to the socket");
                        self.peer_hup = true;
                        break;
                    }
                }
                break;
            }
            self.transport.clear();
            if self.transport.hup() {
                self.peer_hup = true;
            }
        }
        self.reregister(event_loop, token)
    }
}

struct Connection {
    connection_type: ConnectionType,
    server: Option<ServerConnection>,
    client: Option<ClientConnection>,
}

#[allow(dead_code)]
impl Connection {
    fn new_server(server: Box<ServerFactory>, socket: TcpListener) -> Connection {
        Connection {
            connection_type: ConnectionType::Server,
            server: Some(ServerConnection {
                server: server,
                socket: socket,
            }),
            client: None,
        }
    }

    fn new_client(protocol: Box<Protocol>, socket: TcpStream) -> Connection {
        Connection {
            connection_type: ConnectionType::Client,
            client: Some(ClientConnection::new(protocol, socket)),
            server: None,
        }
    }

    fn server_ref(&self) -> &ServerConnection {
        self.server.as_ref().unwrap()
    }

    fn client_ref(&self) -> &ClientConnection {
        self.client.as_ref().unwrap()
    }

    fn client_mut(&mut self) -> &mut ClientConnection {
        self.client.as_mut().unwrap()
    }

    fn alive(&self) -> bool {
        return match self.connection_type {
            ConnectionType::Server => {
                true
            }
            ConnectionType::Client => {
                match self.client_ref().peer_addr() {
                    Ok(_) => true,
                    Err(_) => false,
                }
            }
        };
    }

}

struct MioHandler {
    connections: Slab<Connection>,
}

impl MioHandler {

    pub fn new() -> MioHandler {
        MioHandler { connections: Slab::new(CONNS_MAX) }
    }

    fn listen(&mut self,
              event_loop: &mut EventLoop<MioHandler>,
              addr: &str,
              server: Box<ServerFactory>) {
        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();
        debug!("Bind the server socket {}", addr);
        let sock = TcpListener::bind(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_server(server, sock));
        match result {
            Ok(token) => {
                let _ = event_loop.register(&self.connections[token].server_ref().socket,
                                            token,
                                            EventSet::readable(),
                                            PollOpt::edge());
            }
            Err(_) => error!("Cannot register server"),
        }
    }

    fn handle_server(&mut self,
                     event_loop: &mut EventLoop<MioHandler>,
                     token: Token)
                     -> io::Result<()> {
        loop {
            let (sock, addr) = match try!(self.connections[token].server_ref().socket.accept()) {
                None => break,
                Some(sock) => sock,
            };

            info!("Accepting connection from {:?}", addr);

            debug!("Building procotol");
            let protocol = {
                let server = self.connections[token].server.as_ref();
                server.unwrap().server.build_protocol()
            };

            debug!("Take a token for the connection");
            let result = self.connections.insert(Connection::new_client(protocol, sock));
            match result {
                Ok(client_token) => {
                    debug!("Registering procotol");
                    let mut client = self.connections[client_token].client_mut();
                    client.protocol.connection_made(&mut client.transport);
                    try!(event_loop.register(&client.socket,
                                             client_token,
                                             EventSet::readable() | EventSet::writable(),
                                             PollOpt::edge() | PollOpt::oneshot()));
                }
                Err(_) => error!("Cannot register client"),

            }
        }
        Ok(())
    }

    fn handle_client_finished(&mut self, token: Token, finished: bool) {
        if finished {
            {
                let client = &self.connections[token].client_ref();
                info!("Connection closed {:?}", client.peer_addr().unwrap());
                if client.transport.hup() {
                    client.protocol.connection_lost(Reason::HangUp);
                } else {
                    client.protocol.connection_lost(Reason::ConnectionLost);
                }
            }
            self.connections.remove(token);
        }
    }

    fn handle_client(&mut self,
                     event_loop: &mut EventLoop<MioHandler>,
                     token: Token,
                     events: EventSet)
                     -> io::Result<()> {
        debug!("handle client",);
        if events.is_hup() {
            debug!("handle hup");
            let (_, finished) = {
                let mut client = self.connections[token].client_mut();
                let res = client.handle_hup(event_loop, token);
                (res, client.is_finished())
            };
            if finished {
                info!("Connection closed");
                self.connections.remove(token);
                self.handle_client_finished(token, true);
                info!("Token removed");
            }
        }

        if !&self.connections.contains(token) || !&self.connections[token].alive() {
            debug!("Don't pannic, not handling client");
            return Ok(());
        }

        let client_addr = &self.connections[token].client_ref().peer_addr().unwrap().clone();
        debug!("handle client {:?}", client_addr);
        if events.is_readable() {
            debug!("handle readable {:?}", client_addr);
            let (_, finished) = {
                let mut client = &mut self.connections[token].client_mut();
                let res = client.handle_read(event_loop, token);
                (res, client.is_finished())
            };
            self.handle_client_finished(token, finished);
        }

        if events.is_writable() {
            debug!("handle writable {:?}", client_addr);
            let (_, finished) = {
                let mut client = &mut self.connections[token].client_mut();
                let res = client.handle_write(event_loop, token);
                (res, client.is_finished())
            };
            self.handle_client_finished(token, finished);
        }
        let peer_hup = {
            let client = &self.connections[token].client_ref();
            client.peer_hup
        };
        self.handle_client_finished(token, peer_hup);
        debug!("end handle client {:?}", client_addr);
        Ok(())
    }

    fn connect(&mut self,
              event_loop: &mut EventLoop<MioHandler>,
              addr: &str,
              client: Box<Protocol>) {

        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();
        debug!("Connect to the socket {}", addr);

        let sock = TcpStream::connect(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_client(client, sock));
        match result {
            Ok(token) => {
                let client = self.connections[token].client_mut();
                client.protocol.connection_made(&mut client.transport);
                let _ = event_loop.register(&client.socket,
                                            token,
                                            EventSet::readable() | EventSet::writable(),
                                            PollOpt::edge());
            }
            Err(_) => error!("Cannot register server"),
        }

    }

}

impl Handler for MioHandler {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<MioHandler>, token: Token, events: EventSet) {

        let _ = match self.connections[token].connection_type {
            ConnectionType::Server => self.handle_server(event_loop, token),
            ConnectionType::Client => self.handle_client(event_loop, token, events),
        };
        return;
    }

}

/// The I/O Loop
pub struct Rio {
    handler: MioHandler,
    event_loop: EventLoop<MioHandler>,
}

impl Rio {

    /// Instanciate the IOLoop, should be called once.
    pub fn new() -> Rio {
        let event_loop: EventLoop<MioHandler> = EventLoop::new().unwrap();
        let handler = MioHandler::new();
        Rio {
            handler: handler,
            event_loop: event_loop,
        }
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn listen(&mut self, addr: &str, server: Box<ServerFactory>) {
        info!("Rio is listenning on {}", addr);
        self.handler.listen(&mut self.event_loop, addr, server);
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn connect(&mut self, addr: &str, client: Box<Protocol>) {
        info!("Rio is connecting to {}", addr);
        self.handler.connect(&mut self.event_loop, addr, client);
    }

    /// Start the io loop
    pub fn run_forever(&mut self) {
        info!("Rio run forever");
        self.event_loop.run(&mut self.handler).unwrap();
    }

}
<commit_msg>Fix errors on disconnected socket<commit_after>use std::net::SocketAddr;
use std::str;
use std::str::FromStr;
use std::io;

// use mio::{EventLoop, Handler, Token, EventSet, PollOpt};
// use mio::tcp::{TcpListener, TcpStream};
use mio::*;
use mio::tcp::*;

use mio::util::Slab;
use interface::{ServerFactory, Protocol, Reason};
use transport::{Transport};

const CONNS_MAX: usize = 65_536;
const BUF_SIZE: usize = 4096;

#[derive(Clone)]
enum ConnectionType {
    Server,
    Client,
}

struct ServerConnection {
    server: Box<ServerFactory>,
    socket: TcpListener,
}

struct ClientConnection {
    protocol: Box<Protocol>,
    socket: TcpStream,
    interest: EventSet,
    peer_hup: bool,
    transport: Transport,
}

impl ClientConnection {

    fn new(protocol: Box<Protocol>, socket: TcpStream) -> ClientConnection {
        ClientConnection {
            protocol: protocol,
            socket: socket,
            interest: EventSet::hup() | EventSet::readable(),
            peer_hup: false,
            transport: Transport::new(),
        }
    }

    fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.socket.peer_addr()
    }

    fn is_finished(&self) -> bool {
        self.interest == EventSet::none()
    }

    fn reregister(&mut self,
                  event_loop: &mut EventLoop<MioHandler>,
                  token: Token)
                  -> io::Result<()> {

        // have somewhere to read to and someone to receive from
        if !self.peer_hup || false {
            info!("Insert read interest");
            self.interest.insert(EventSet::readable());
        } else {
            self.interest.remove(EventSet::readable());
        }

        event_loop.reregister(&self.socket,
                              token,
                              self.interest,
                              PollOpt::edge() | PollOpt::oneshot())
    }

    fn handle_hup(&mut self,
                  event_loop: &mut EventLoop<MioHandler>,
                  token: Token)
                  -> io::Result<()> {
        if self.interest == EventSet::hup() {
            self.interest = EventSet::none();
            try!(event_loop.deregister(&self.socket));
        } else {
            self.peer_hup = true;
            let _ = self.reregister(event_loop, token);
        }
        Ok(())
    }

    fn handle_read(&mut self,
                   event_loop: &mut EventLoop<MioHandler>,
                   token: Token)
                   -> io::Result<()> {
        {
            let mut read_bytes: Vec<u8> = Vec::new();
            loop {
                let (buf, read_len) = {
                    let mut buf = [0; BUF_SIZE];
                    let read_len = self.socket.try_read(&mut buf[..]);
                    // let s_data = str::from_utf8(&buf).unwrap();
                    // info!("<<< {}", s_data);
                    (buf, read_len)
                };
                match read_len {
                    Ok(None) => {
                        info!("read to end");
                        break;
                    }
                    Ok(Some(len)) => {
                        read_bytes.extend(buf[0..len].iter());
                        if len < BUF_SIZE {
                            info!("Nothing more to read");
                            break;
                        } else {
                            info!("More data to read");
                        }
                    }
                    Err(_) => {
                        info!("Error while reading to socket, consider to hang up");
                        break;
                    }
                }
            }
            let _ = self.reregister(event_loop, token);
            self.protocol.data_received(&read_bytes[..], &mut self.transport);
        }

        if self.transport.should_write() {
            let _ = self.handle_write(event_loop, token);
        }

        Ok(())
    }

    fn handle_write(&mut self,
                    event_loop: &mut EventLoop<MioHandler>,
                    token: Token)
                    -> io::Result<()> {
        {
            info!("handle write");
            loop {
                let (len, res) = {
                    let buf = &mut self.transport.buf();
                    let len = buf.len();
                    let s_data = str::from_utf8(&buf[..]).unwrap();
                    info!(">>> {}", s_data);

                    let res = self.socket.try_write(&buf[..]);
                    (len, res)
                };
                match res {
                    Ok(None) => {
                        break;
                    }
                    Ok(Some(written_len)) => {
                        info!("Write {}, attempt {}", written_len, len);
                        if written_len != len {
                            info!("Something is going wrong with the socket");
                            break;
                        }
                    }
                    Err(_) => {
                        info!("Error while writing to the socket");
                        self.peer_hup = true;
                        break;
                    }
                }
                break;
            }
            self.transport.clear();
            if self.transport.hup() {
                self.peer_hup = true;
            }
        }
        self.reregister(event_loop, token)
    }
}

struct Connection {
    connection_type: ConnectionType,
    server: Option<ServerConnection>,
    client: Option<ClientConnection>,
}

#[allow(dead_code)]
impl Connection {
    fn new_server(server: Box<ServerFactory>, socket: TcpListener) -> Connection {
        Connection {
            connection_type: ConnectionType::Server,
            server: Some(ServerConnection {
                server: server,
                socket: socket,
            }),
            client: None,
        }
    }

    fn new_client(protocol: Box<Protocol>, socket: TcpStream) -> Connection {
        Connection {
            connection_type: ConnectionType::Client,
            client: Some(ClientConnection::new(protocol, socket)),
            server: None,
        }
    }

    fn server_ref(&self) -> &ServerConnection {
        self.server.as_ref().unwrap()
    }

    fn client_ref(&self) -> &ClientConnection {
        self.client.as_ref().unwrap()
    }

    fn client_mut(&mut self) -> &mut ClientConnection {
        self.client.as_mut().unwrap()
    }

    fn alive(&self) -> bool {
        return match self.connection_type {
            ConnectionType::Server => {
                true
            }
            ConnectionType::Client => {
                match self.client_ref().peer_addr() {
                    Ok(_) => true,
                    Err(_) => false,
                }
            }
        };
    }

}

struct MioHandler {
    connections: Slab<Connection>,
}

impl MioHandler {

    pub fn new() -> MioHandler {
        MioHandler { connections: Slab::new(CONNS_MAX) }
    }

    fn listen(&mut self,
              event_loop: &mut EventLoop<MioHandler>,
              addr: &str,
              server: Box<ServerFactory>) {
        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();
        debug!("Bind the server socket {}", addr);
        let sock = TcpListener::bind(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_server(server, sock));
        match result {
            Ok(token) => {
                let _ = event_loop.register(&self.connections[token].server_ref().socket,
                                            token,
                                            EventSet::readable(),
                                            PollOpt::edge());
            }
            Err(_) => error!("Cannot register server"),
        }
    }

    fn handle_server(&mut self,
                     event_loop: &mut EventLoop<MioHandler>,
                     token: Token)
                     -> io::Result<()> {
        loop {
            let (sock, addr) = match try!(self.connections[token].server_ref().socket.accept()) {
                None => break,
                Some(sock) => sock,
            };

            info!("Accepting connection from {:?}", addr);

            debug!("Building procotol");
            let protocol = {
                let server = self.connections[token].server.as_ref();
                server.unwrap().server.build_protocol()
            };

            debug!("Take a token for the connection");
            let result = self.connections.insert(Connection::new_client(protocol, sock));
            match result {
                Ok(client_token) => {
                    debug!("Registering procotol");
                    let mut client = self.connections[client_token].client_mut();
                    client.protocol.connection_made(&mut client.transport);
                    try!(event_loop.register(&client.socket,
                                             client_token,
                                             EventSet::readable() | EventSet::writable(),
                                             PollOpt::edge() | PollOpt::oneshot()));
                }
                Err(_) => error!("Cannot register client"),

            }
        }
        Ok(())
    }

    fn handle_client_finished(&mut self, token: Token, finished: bool) {
        if finished {
            {
                let client = &self.connections[token].client_ref();
                match client.peer_addr() {
                    Ok(addr) => info!("Connection closed {:?}", addr),
                    Err(_) => error!("Connection closed (Peer already disconnected)"),
                }
                if client.transport.hup() {
                    client.protocol.connection_lost(Reason::HangUp);
                } else {
                    client.protocol.connection_lost(Reason::ConnectionLost);
                }
            }
            self.connections.remove(token);
        }
    }

    fn handle_client(&mut self,
                     event_loop: &mut EventLoop<MioHandler>,
                     token: Token,
                     events: EventSet)
                     -> io::Result<()> {
        debug!("handle client",);
        if events.is_hup() {
            debug!("handle hup");
            let (_, finished) = {
                let mut client = self.connections[token].client_mut();
                let res = client.handle_hup(event_loop, token);
                (res, client.is_finished())
            };
            if finished {
                info!("Connection closed");
                self.handle_client_finished(token, true);
                info!("Token removed");
            }
        }

        if !&self.connections.contains(token) || !&self.connections[token].alive() {
            debug!("Don't pannic, not handling client");
            return Ok(());
        }

        let client_addr = &self.connections[token].client_ref().peer_addr().unwrap().clone();
        debug!("handle client {:?}", client_addr);
        if events.is_readable() {
            debug!("handle readable {:?}", client_addr);
            let (_, finished) = {
                let mut client = &mut self.connections[token].client_mut();
                let res = client.handle_read(event_loop, token);
                (res, client.is_finished())
            };
            self.handle_client_finished(token, finished);
        }

        if events.is_writable() {
            debug!("handle writable {:?}", client_addr);
            let (_, finished) = {
                let mut client = &mut self.connections[token].client_mut();
                let res = client.handle_write(event_loop, token);
                (res, client.is_finished())
            };
            self.handle_client_finished(token, finished);
        }
        let peer_hup = {
            let client = &self.connections[token].client_ref();
            client.peer_hup
        };
        self.handle_client_finished(token, peer_hup);
        debug!("end handle client {:?}", client_addr);
        Ok(())
    }

    fn connect(&mut self,
              event_loop: &mut EventLoop<MioHandler>,
              addr: &str,
              client: Box<Protocol>) {

        let sock_addr: SocketAddr = FromStr::from_str(addr).unwrap();
        debug!("Connect to the socket {}", addr);

        let sock = TcpStream::connect(&sock_addr).unwrap();
        let result = self.connections.insert(Connection::new_client(client, sock));
        match result {
            Ok(token) => {
                let client = self.connections[token].client_mut();
                client.protocol.connection_made(&mut client.transport);
                let _ = event_loop.register(&client.socket,
                                            token,
                                            EventSet::readable() | EventSet::writable(),
                                            PollOpt::edge());
            }
            Err(_) => error!("Cannot register client"),
        }

    }

}

impl Handler for MioHandler {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<MioHandler>, token: Token, events: EventSet) {

        let _ = match self.connections[token].connection_type {
            ConnectionType::Server => self.handle_server(event_loop, token),
            ConnectionType::Client => self.handle_client(event_loop, token, events),
        };
        return;
    }

}

/// The I/O Loop
pub struct Rio {
    handler: MioHandler,
    event_loop: EventLoop<MioHandler>,
}

impl Rio {

    /// Instanciate the IOLoop, should be called once.
    pub fn new() -> Rio {
        let event_loop: EventLoop<MioHandler> = EventLoop::new().unwrap();
        let handler = MioHandler::new();
        Rio {
            handler: handler,
            event_loop: event_loop,
        }
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn listen(&mut self, addr: &str, server: Box<ServerFactory>) {
        info!("Rio is listenning on {}", addr);
        self.handler.listen(&mut self.event_loop, addr, server);
    }

    /// Will listen on the given address when the loop will start.
    /// The ServerFactory.build_protocol method will be called on every
    /// new client connection.
    pub fn connect(&mut self, addr: &str, client: Box<Protocol>) {
        info!("Rio is connecting to {}", addr);
        self.handler.connect(&mut self.event_loop, addr, client);
    }

    /// Start the io loop
    pub fn run_forever(&mut self) {
        info!("Rio run forever");
        self.event_loop.run(&mut self.handler).unwrap();
    }

}
<|endoftext|>


<commit_before>use std::to_str::ToStr;
use std::os::getenv;
use std::io::{Open, Write};
use std::io::{BufferedReader, IoResult};
use std::io::fs::{File, copy, rename};
use std::io::stdio::{stdout, stderr};
use std::default::Default;

use libc::pid_t;
use collections::treemap::TreeMap;
use argparse::{ArgumentParser, Store, StoreOption, List, StoreTrue, StoreConst};
use argparse::{StoreFalse};

use super::monitor::Monitor;
use super::env::{Environ, Container};
use super::linux::{ensure_dir, RunOptions, run_container, CPipe};
use super::options::env_options;
use super::build::ensure_container;
use libc::funcs::posix88::unistd::getuid;

use Pid1 = super::linux;

static DEFAULT_PATH: &'static str =
    "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin";

fn read_env_file(path: &Path, env: &mut TreeMap<String, String>)
    -> IoResult<()>
{
    let file = try!(File::open(path).map(|f| BufferedReader::new(f)));
    let mut reader = BufferedReader::new(file);
    for (n, line) in reader.lines().enumerate() {
        let line = try!(line);
        let pair: Vec<&str> = line.as_slice().splitn('=', 1).collect();
        match pair.as_slice() {
            [key, val] => {
                let nkey = key.trim().to_string();
                if !env.contains_key(&nkey) {
                    env.insert(nkey, val.trim().to_string());
                }
            }
            _ => {
                warn!("Invalid line {} in {}",
                    n+1, path.display());
            }
        }
    }
    return Ok(());
}

fn container_environ(container: &Container, env: &mut TreeMap<String, String>)
    -> Result<(), String>
{
    for (k, v) in container.environ.iter() {
        if !env.contains_key(k) {
            env.insert(k.clone(), v.clone());
        }
    }
    match container.environ_file {
        None => {}
        Some(ref suf) => {
            let path = container.container_root.as_ref().unwrap()
                       .join(suf.as_slice().trim_left_chars('/'));
            if path.exists() {
                try!(read_env_file(&path, env).map_err(|e| format!(
                    "Error reading environment file: {}", e)));
            }
        }

    }
    return Ok(());
}

pub fn run_command_line(env: &mut Environ, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut no_wrapper = false;
    let mut use_shell = false;
    let mut pid1mode = Pid1::Wait;
    let mut command: Option<String> = None;
    let mut cmdargs: Vec<String> = Vec::new();
    let mut resolv: bool = true;
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut command)
            .add_argument("command", box StoreOption::<String>,
                "A command to run inside container");
        ap.refer(&mut cmdargs)
            .add_argument("arguments", box List::<String>,
                "Arguments for the command")
            .required();
        ap.refer(&mut no_wrapper)
            .add_option(["-N", "--no-wrapper"], box StoreTrue,
                "Do not use `command-wrapper` configured for container");
        ap.refer(&mut use_shell)
            .add_option(["-S", "--shell"], box StoreTrue,
                "Run command with `shell` configured for container");
        ap.refer(&mut use_shell)
            .add_option(["-S", "--shell"], box StoreTrue,
                "Run command with `shell` configured for container");
        ap.refer(&mut resolv)
            .add_option(["--no-resolv"], box StoreFalse,
                "Do not copy /etc/resolv.conf");
        ap.refer(&mut pid1mode)
            .add_option(["--wait"], box StoreConst(Pid1::Wait),
                "Spawn a supervisor as pid 1 and wait until target command \
                 exits. But if it spawned any children, they will be killed \
                 at the death of the target command (default)")
            .add_option(["--wait-all-children"],
                box StoreConst(Pid1::WaitAllChildren),
                "Spawn a supervisor as pid 1 and wait until target command \
                 and all of its children are dead. (Dangerous in some cases \
                 as some non useful child process may block container \
                 shutdown).")
            .add_option(["--exec"], box StoreConst(Pid1::Exec),
                "Execute the target command as pid 1. Should not be used \
                 unless the target command is a process manager itself and/or \
                 supposed to work as pid 1.");
        env_options(env, &mut ap);
        ap.stop_on_first_argument(true);
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    let mut container = try!(env.get_container(&cname));

    if command.is_none() {
        if container.default_command.is_some() {
            let cmd = container.default_command.as_ref().unwrap();
            cmdargs.push_all(cmd.as_slice());
        } else {
            return Err(format!("No command specified and no default command"));
        }
    } else {
        cmdargs.insert(0, command.unwrap());
        if use_shell {
            cmdargs = container.shell.clone() + cmdargs;
        } else if !no_wrapper && container.command_wrapper.is_some() {
            cmdargs = container.command_wrapper.as_ref().unwrap().clone()+cmdargs;
        }
    }

    let cmd = cmdargs.shift().unwrap();
    try!(ensure_container(env, &mut container));

    let mut monitor = Monitor::new(true);
    let pid = try!(internal_run(env, &container, pid1mode, resolv,
        &env.work_dir, cmd, cmdargs, TreeMap::new()));
    monitor.add("child".to_string(), pid);
    monitor.wait_all();
    return Ok(monitor.get_status());
}

pub fn internal_run(env: &Environ, container: &Container,
    pid1mode: Pid1::Pid1Mode, resolv: bool, work_dir: &Path,
    command: String, cmdargs: Vec<String>, runenv: TreeMap<String, String>)
    -> Result<pid_t, String>
{
    let mut runenv = runenv;
    env.populate_environ(&mut runenv);
    try!(container_environ(container, &mut runenv));
    let container_root = container.container_root.as_ref().unwrap();
    info!("Running {}: {} {}", container_root.display(), command, cmdargs);

    let uid = unsafe { getuid() };

    let mount_dir = env.project_root.join_many([".vagga", ".mnt"]);
    try!(ensure_dir(&mount_dir));

    if resolv {
        try!(copy(&Path::new("/etc/resolv.conf"),
                  &container_root.join("etc/resolv.conf.tmp"))
            .map_err(|e| format!("Error copying resolv.conf: {}", e)));
        try!(rename(&container_root.join("etc/resolv.conf.tmp"),
                    &container_root.join("etc/resolv.conf"),)
            .map_err(|e| format!("Error copying resolv.conf: {}", e)));
    }

    let home = "HOME".to_string();
    if runenv.find(&home).is_none() {
        // TODO(tailhook) set home to real home if /home is mounted
        runenv.insert(home, "/homeless-shelter".to_string());
    }
    let term = "TERM".to_string();
    if runenv.find(&term).is_none() {
        runenv.insert(term, getenv("TERM").unwrap_or("linux".to_string()));
    }
    let path = "PATH".to_string();
    if runenv.find(&path).is_none() {
        runenv.insert(path, DEFAULT_PATH.to_string());
    }

    let pipe = try!(CPipe::new());
    let mut ropts: RunOptions = Default::default();
    ropts.pid1mode = pid1mode;
    let pid = try!(run_container(&pipe, env,
        container.container_root.as_ref().unwrap(),
        &ropts, work_dir, &command, cmdargs.as_slice(), &runenv));

    // TODO(tailhook) set uid map from config
    let uid_map = format!("0 {} 1", uid);
    debug!("Writing uid_map: {}", uid_map);
    match File::open_mode(&Path::new("/proc")
                      .join(pid.to_str())
                      .join("uid_map"), Open, Write)
            .write_str(uid_map.as_slice()) {
        Ok(()) => {}
        Err(e) => return Err(format!(
            "Error writing uid mapping: {}", e)),
    }

    try!(pipe.wakeup());
    return Ok(pid);
}
<commit_msg>Implement setting gid for namespaces<commit_after>use std::to_str::ToStr;
use std::os::getenv;
use std::io::{Open, Write};
use std::io::{BufferedReader, IoResult};
use std::io::fs::{File, copy, rename};
use std::io::stdio::{stdout, stderr};
use std::default::Default;

use libc::pid_t;
use collections::treemap::TreeMap;
use argparse::{ArgumentParser, Store, StoreOption, List, StoreTrue, StoreConst};
use argparse::{StoreFalse};

use super::monitor::Monitor;
use super::env::{Environ, Container};
use super::linux::{ensure_dir, RunOptions, run_container, CPipe};
use super::options::env_options;
use super::build::ensure_container;
use libc::funcs::posix88::unistd::{geteuid, getegid};

use Pid1 = super::linux;

static DEFAULT_PATH: &'static str =
    "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin";

fn read_env_file(path: &Path, env: &mut TreeMap<String, String>)
    -> IoResult<()>
{
    let file = try!(File::open(path).map(|f| BufferedReader::new(f)));
    let mut reader = BufferedReader::new(file);
    for (n, line) in reader.lines().enumerate() {
        let line = try!(line);
        let pair: Vec<&str> = line.as_slice().splitn('=', 1).collect();
        match pair.as_slice() {
            [key, val] => {
                let nkey = key.trim().to_string();
                if !env.contains_key(&nkey) {
                    env.insert(nkey, val.trim().to_string());
                }
            }
            _ => {
                warn!("Invalid line {} in {}",
                    n+1, path.display());
            }
        }
    }
    return Ok(());
}

fn container_environ(container: &Container, env: &mut TreeMap<String, String>)
    -> Result<(), String>
{
    for (k, v) in container.environ.iter() {
        if !env.contains_key(k) {
            env.insert(k.clone(), v.clone());
        }
    }
    match container.environ_file {
        None => {}
        Some(ref suf) => {
            let path = container.container_root.as_ref().unwrap()
                       .join(suf.as_slice().trim_left_chars('/'));
            if path.exists() {
                try!(read_env_file(&path, env).map_err(|e| format!(
                    "Error reading environment file: {}", e)));
            }
        }

    }
    return Ok(());
}

pub fn run_command_line(env: &mut Environ, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut no_wrapper = false;
    let mut use_shell = false;
    let mut pid1mode = Pid1::Wait;
    let mut command: Option<String> = None;
    let mut cmdargs: Vec<String> = Vec::new();
    let mut resolv: bool = true;
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut command)
            .add_argument("command", box StoreOption::<String>,
                "A command to run inside container");
        ap.refer(&mut cmdargs)
            .add_argument("arguments", box List::<String>,
                "Arguments for the command")
            .required();
        ap.refer(&mut no_wrapper)
            .add_option(["-N", "--no-wrapper"], box StoreTrue,
                "Do not use `command-wrapper` configured for container");
        ap.refer(&mut use_shell)
            .add_option(["-S", "--shell"], box StoreTrue,
                "Run command with `shell` configured for container");
        ap.refer(&mut use_shell)
            .add_option(["-S", "--shell"], box StoreTrue,
                "Run command with `shell` configured for container");
        ap.refer(&mut resolv)
            .add_option(["--no-resolv"], box StoreFalse,
                "Do not copy /etc/resolv.conf");
        ap.refer(&mut pid1mode)
            .add_option(["--wait"], box StoreConst(Pid1::Wait),
                "Spawn a supervisor as pid 1 and wait until target command \
                 exits. But if it spawned any children, they will be killed \
                 at the death of the target command (default)")
            .add_option(["--wait-all-children"],
                box StoreConst(Pid1::WaitAllChildren),
                "Spawn a supervisor as pid 1 and wait until target command \
                 and all of its children are dead. (Dangerous in some cases \
                 as some non useful child process may block container \
                 shutdown).")
            .add_option(["--exec"], box StoreConst(Pid1::Exec),
                "Execute the target command as pid 1. Should not be used \
                 unless the target command is a process manager itself and/or \
                 supposed to work as pid 1.");
        env_options(env, &mut ap);
        ap.stop_on_first_argument(true);
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    let mut container = try!(env.get_container(&cname));

    if command.is_none() {
        if container.default_command.is_some() {
            let cmd = container.default_command.as_ref().unwrap();
            cmdargs.push_all(cmd.as_slice());
        } else {
            return Err(format!("No command specified and no default command"));
        }
    } else {
        cmdargs.insert(0, command.unwrap());
        if use_shell {
            cmdargs = container.shell.clone() + cmdargs;
        } else if !no_wrapper && container.command_wrapper.is_some() {
            cmdargs = container.command_wrapper.as_ref().unwrap().clone()+cmdargs;
        }
    }

    let cmd = cmdargs.shift().unwrap();
    try!(ensure_container(env, &mut container));

    let mut monitor = Monitor::new(true);
    let pid = try!(internal_run(env, &container, pid1mode, resolv,
        &env.work_dir, cmd, cmdargs, TreeMap::new()));
    monitor.add("child".to_string(), pid);
    monitor.wait_all();
    return Ok(monitor.get_status());
}

pub fn internal_run(env: &Environ, container: &Container,
    pid1mode: Pid1::Pid1Mode, resolv: bool, work_dir: &Path,
    command: String, cmdargs: Vec<String>, runenv: TreeMap<String, String>)
    -> Result<pid_t, String>
{
    let mut runenv = runenv;
    env.populate_environ(&mut runenv);
    try!(container_environ(container, &mut runenv));
    let container_root = container.container_root.as_ref().unwrap();
    info!("Running {}: {} {}", container_root.display(), command, cmdargs);

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };

    let mount_dir = env.project_root.join_many([".vagga", ".mnt"]);
    try!(ensure_dir(&mount_dir));

    if resolv {
        try!(copy(&Path::new("/etc/resolv.conf"),
                  &container_root.join("etc/resolv.conf.tmp"))
            .map_err(|e| format!("Error copying resolv.conf: {}", e)));
        try!(rename(&container_root.join("etc/resolv.conf.tmp"),
                    &container_root.join("etc/resolv.conf"),)
            .map_err(|e| format!("Error copying resolv.conf: {}", e)));
    }

    let home = "HOME".to_string();
    if runenv.find(&home).is_none() {
        // TODO(tailhook) set home to real home if /home is mounted
        runenv.insert(home, "/homeless-shelter".to_string());
    }
    let term = "TERM".to_string();
    if runenv.find(&term).is_none() {
        runenv.insert(term, getenv("TERM").unwrap_or("linux".to_string()));
    }
    let path = "PATH".to_string();
    if runenv.find(&path).is_none() {
        runenv.insert(path, DEFAULT_PATH.to_string());
    }

    let pipe = try!(CPipe::new());
    let mut ropts: RunOptions = Default::default();
    ropts.pid1mode = pid1mode;
    let pid = try!(run_container(&pipe, env,
        container.container_root.as_ref().unwrap(),
        &ropts, work_dir, &command, cmdargs.as_slice(), &runenv));

    // TODO(tailhook) set uid map from config
    let uid_map = format!("0 {} 1", uid);
    debug!("Writing uid_map: {}", uid_map);
    match File::open_mode(&Path::new("/proc")
                      .join(pid.to_str())
                      .join("uid_map"), Open, Write)
            .write_str(uid_map.as_slice()) {
        Ok(()) => {}
        Err(e) => return Err(format!(
            "Error writing uid mapping: {}", e)),
    }

    let gid_map = format!("0 {} 1", gid);
    debug!("Writing gid_map: {}", gid_map);
    match File::open_mode(&Path::new("/proc")
                      .join(pid.to_str())
                      .join("gid_map"), Open, Write)
            .write_str(gid_map.as_slice()) {
        Ok(()) => {}
        Err(e) => return Err(format!(
            "Error writing gid mapping: {}", e)),
    }

    try!(pipe.wakeup());
    return Ok(pid);
}
<|endoftext|>


<commit_before>use crate::common::*;
use crate::d2s;
use crate::d2s_intrinsics::*;
use crate::parse::Error;
#[cfg(feature = "no-panic")]
use no_panic::no_panic;

const DOUBLE_EXPONENT_BIAS: usize = 1023;

fn floor_log2(value: u64) -> u32 {
    63_u32.wrapping_sub(value.leading_zeros())
}

#[cfg_attr(feature = "no-panic", no_panic)]
pub fn s2d(buffer: &[u8]) -> Result<f64, Error> {
    let len = buffer.len();
    if len == 0 {
        return Err(Error::InputTooShort);
    }

    let mut m10digits = 0;
    let mut e10digits = 0;
    let mut dot_index = len;
    let mut e_index = len;
    let mut m10 = 0u64;
    let mut e10 = 0i32;
    let mut signed_m = false;
    let mut signed_e = false;

    let mut i = 0;
    if unsafe { *buffer.get_unchecked(0) } == b'-' {
        signed_m = true;
        i += 1;
    }

    while let Some(c) = buffer.get(i).copied() {
        if c == b'.' {
            if dot_index != len {
                return Err(Error::MalformedInput);
            }
            dot_index = i;
            i += 1;
            continue;
        }
        if c < b'0' || c > b'9' {
            break;
        }
        if m10digits >= 17 {
            return Err(Error::InputTooLong);
        }
        m10 = 10 * m10 + (c - b'0') as u64;
        if m10 != 0 {
            m10digits += 1;
        }
        i += 1;
    }

    if let Some(b'e') | Some(b'E') = buffer.get(i) {
        e_index = i;
        i += 1;
        match buffer.get(i) {
            Some(b'-') => {
                signed_e = true;
                i += 1;
            }
            Some(b'+') => i += 1,
            _ => {}
        }
        while let Some(c) = buffer.get(i).copied() {
            if c < b'0' || c > b'9' {
                return Err(Error::MalformedInput);
            }
            if e10digits > 3 {
                // TODO: Be more lenient. Return +/-Infinity or +/-0 instead.
                return Err(Error::InputTooLong);
            }
            e10 = 10 * e10 + (c - b'0') as i32;
            if e10 != 0 {
                e10digits += 1;
            }
            i += 1;
        }
    }

    if i < len {
        return Err(Error::MalformedInput);
    }
    if signed_e {
        e10 = -e10;
    }
    e10 -= if dot_index < e_index {
        (e_index - dot_index - 1) as i32
    } else {
        0
    };
    if m10 == 0 {
        return Ok(if signed_m { -0.0 } else { 0.0 });
    }

    if m10digits + e10 <= -324 || m10 == 0 {
        // Number is less than 1e-324, which should be rounded down to 0; return
        // +/-0.0.
        let ieee = (signed_m as u64) << (d2s::DOUBLE_EXPONENT_BITS + d2s::DOUBLE_MANTISSA_BITS);
        return Ok(f64::from_bits(ieee));
    }
    if m10digits + e10 >= 310 {
        // Number is larger than 1e+309, which should be rounded to +/-Infinity.
        let ieee = ((signed_m as u64) << (d2s::DOUBLE_EXPONENT_BITS + d2s::DOUBLE_MANTISSA_BITS))
            | (0x7ff_u64 << d2s::DOUBLE_MANTISSA_BITS);
        return Ok(f64::from_bits(ieee));
    }

    // Convert to binary float m2 * 2^e2, while retaining information about
    // whether the conversion was exact (trailing_zeros).
    let e2: i32;
    let m2: u64;
    let mut trailing_zeros: bool;
    if e10 >= 0 {
        // The length of m * 10^e in bits is:
        //   log2(m10 * 10^e10) = log2(m10) + e10 log2(10) = log2(m10) + e10 + e10 * log2(5)
        //
        // We want to compute the DOUBLE_MANTISSA_BITS + 1 top-most bits (+1 for
        // the implicit leading one in IEEE format). We therefore choose a
        // binary output exponent of
        //   log2(m10 * 10^e10) - (DOUBLE_MANTISSA_BITS + 1).
        //
        // We use floor(log2(5^e10)) so that we get at least this many bits; better to
        // have an additional bit than to not have enough bits.
        e2 = floor_log2(m10)
            .wrapping_add(e10 as u32)
            .wrapping_add(log2_pow5(e10) as u32)
            .wrapping_sub(d2s::DOUBLE_MANTISSA_BITS + 1) as i32;

        // We now compute [m10 * 10^e10 / 2^e2] = [m10 * 5^e10 / 2^(e2-e10)].
        // To that end, we use the DOUBLE_POW5_SPLIT table.
        let j = e2
            .wrapping_sub(e10)
            .wrapping_sub(ceil_log2_pow5(e10))
            .wrapping_add(d2s::DOUBLE_POW5_BITCOUNT);
        debug_assert!(j >= 0);
        debug_assert!(e10 < d2s::DOUBLE_POW5_SPLIT.len() as i32);
        m2 = mul_shift_64(
            m10,
            unsafe { d2s::DOUBLE_POW5_SPLIT.get_unchecked(e10 as usize) },
            j as u32,
        );

        // We also compute if the result is exact, i.e.,
        //   [m10 * 10^e10 / 2^e2] == m10 * 10^e10 / 2^e2.
        // This can only be the case if 2^e2 divides m10 * 10^e10, which in turn
        // requires that the largest power of 2 that divides m10 + e10 is
        // greater than e2. If e2 is less than e10, then the result must be
        // exact. Otherwise we use the existing multiple_of_power_of_2 function.
        trailing_zeros =
            e2 < e10 || e2 - e10 < 64 && multiple_of_power_of_2(m10, (e2 - e10) as u32);
    } else {
        e2 = floor_log2(m10)
            .wrapping_add(e10 as u32)
            .wrapping_sub(ceil_log2_pow5(-e10) as u32)
            .wrapping_sub(d2s::DOUBLE_MANTISSA_BITS + 1) as i32;
        let j = e2
            .wrapping_sub(e10)
            .wrapping_add(ceil_log2_pow5(-e10))
            .wrapping_sub(1)
            .wrapping_add(d2s::DOUBLE_POW5_INV_BITCOUNT);
        debug_assert!(-e10 < d2s::DOUBLE_POW5_INV_SPLIT.len() as i32);
        m2 = mul_shift_64(
            m10,
            unsafe { d2s::DOUBLE_POW5_INV_SPLIT.get_unchecked(-e10 as usize) },
            j as u32,
        );
        trailing_zeros = multiple_of_power_of_5(m10, -e10 as u32);
    }

    // Compute the final IEEE exponent.
    let mut ieee_e2 = i32::max(0, e2 + DOUBLE_EXPONENT_BIAS as i32 + floor_log2(m2) as i32) as u32;

    if ieee_e2 > 0x7fe {
        // Final IEEE exponent is larger than the maximum representable; return +/-Infinity.
        let ieee = ((signed_m as u64) << (d2s::DOUBLE_EXPONENT_BITS + d2s::DOUBLE_MANTISSA_BITS))
            | (0x7ff_u64 << d2s::DOUBLE_MANTISSA_BITS);
        return Ok(f64::from_bits(ieee));
    }

    // We need to figure out how much we need to shift m2. The tricky part is that we need to take
    // the final IEEE exponent into account, so we need to reverse the bias and also special-case
    // the value 0.
    let shift = if ieee_e2 == 0 { 1 } else { ieee_e2 as i32 }
        .wrapping_sub(e2)
        .wrapping_sub(DOUBLE_EXPONENT_BIAS as i32)
        .wrapping_sub(d2s::DOUBLE_MANTISSA_BITS as i32);
    debug_assert!(shift >= 0);

    // We need to round up if the exact value is more than 0.5 above the value we computed. That's
    // equivalent to checking if the last removed bit was 1 and either the value was not just
    // trailing zeros or the result would otherwise be odd.
    //
    // We need to update trailing_zeros given that we have the exact output exponent ieee_e2 now.
    trailing_zeros &= (m2 & ((1_u64 << (shift - 1)) - 1)) == 0;
    let last_removed_bit = (m2 >> (shift - 1)) & 1;
    let round_up = last_removed_bit != 0 && (!trailing_zeros || ((m2 >> shift) & 1) != 0);

    let mut ieee_m2 = (m2 >> shift).wrapping_add(round_up as u64);
    if ieee_m2 == (1_u64 << (d2s::DOUBLE_MANTISSA_BITS + 1)) {
        // Due to how the IEEE represents +/-Infinity, we don't need to check for overflow here.
        ieee_e2 += 1;
    }
    ieee_m2 &= (1_u64 << d2s::DOUBLE_MANTISSA_BITS) - 1;
    let ieee = ((((signed_m as u64) << d2s::DOUBLE_EXPONENT_BITS) | ieee_e2 as u64)
        << d2s::DOUBLE_MANTISSA_BITS)
        | ieee_m2;
    Ok(f64::from_bits(ieee))
}
<commit_msg>Wrap parser comments<commit_after>use crate::common::*;
use crate::d2s;
use crate::d2s_intrinsics::*;
use crate::parse::Error;
#[cfg(feature = "no-panic")]
use no_panic::no_panic;

const DOUBLE_EXPONENT_BIAS: usize = 1023;

fn floor_log2(value: u64) -> u32 {
    63_u32.wrapping_sub(value.leading_zeros())
}

#[cfg_attr(feature = "no-panic", no_panic)]
pub fn s2d(buffer: &[u8]) -> Result<f64, Error> {
    let len = buffer.len();
    if len == 0 {
        return Err(Error::InputTooShort);
    }

    let mut m10digits = 0;
    let mut e10digits = 0;
    let mut dot_index = len;
    let mut e_index = len;
    let mut m10 = 0u64;
    let mut e10 = 0i32;
    let mut signed_m = false;
    let mut signed_e = false;

    let mut i = 0;
    if unsafe { *buffer.get_unchecked(0) } == b'-' {
        signed_m = true;
        i += 1;
    }

    while let Some(c) = buffer.get(i).copied() {
        if c == b'.' {
            if dot_index != len {
                return Err(Error::MalformedInput);
            }
            dot_index = i;
            i += 1;
            continue;
        }
        if c < b'0' || c > b'9' {
            break;
        }
        if m10digits >= 17 {
            return Err(Error::InputTooLong);
        }
        m10 = 10 * m10 + (c - b'0') as u64;
        if m10 != 0 {
            m10digits += 1;
        }
        i += 1;
    }

    if let Some(b'e') | Some(b'E') = buffer.get(i) {
        e_index = i;
        i += 1;
        match buffer.get(i) {
            Some(b'-') => {
                signed_e = true;
                i += 1;
            }
            Some(b'+') => i += 1,
            _ => {}
        }
        while let Some(c) = buffer.get(i).copied() {
            if c < b'0' || c > b'9' {
                return Err(Error::MalformedInput);
            }
            if e10digits > 3 {
                // TODO: Be more lenient. Return +/-Infinity or +/-0 instead.
                return Err(Error::InputTooLong);
            }
            e10 = 10 * e10 + (c - b'0') as i32;
            if e10 != 0 {
                e10digits += 1;
            }
            i += 1;
        }
    }

    if i < len {
        return Err(Error::MalformedInput);
    }
    if signed_e {
        e10 = -e10;
    }
    e10 -= if dot_index < e_index {
        (e_index - dot_index - 1) as i32
    } else {
        0
    };
    if m10 == 0 {
        return Ok(if signed_m { -0.0 } else { 0.0 });
    }

    if m10digits + e10 <= -324 || m10 == 0 {
        // Number is less than 1e-324, which should be rounded down to 0; return
        // +/-0.0.
        let ieee = (signed_m as u64) << (d2s::DOUBLE_EXPONENT_BITS + d2s::DOUBLE_MANTISSA_BITS);
        return Ok(f64::from_bits(ieee));
    }
    if m10digits + e10 >= 310 {
        // Number is larger than 1e+309, which should be rounded to +/-Infinity.
        let ieee = ((signed_m as u64) << (d2s::DOUBLE_EXPONENT_BITS + d2s::DOUBLE_MANTISSA_BITS))
            | (0x7ff_u64 << d2s::DOUBLE_MANTISSA_BITS);
        return Ok(f64::from_bits(ieee));
    }

    // Convert to binary float m2 * 2^e2, while retaining information about
    // whether the conversion was exact (trailing_zeros).
    let e2: i32;
    let m2: u64;
    let mut trailing_zeros: bool;
    if e10 >= 0 {
        // The length of m * 10^e in bits is:
        //   log2(m10 * 10^e10) = log2(m10) + e10 log2(10) = log2(m10) + e10 + e10 * log2(5)
        //
        // We want to compute the DOUBLE_MANTISSA_BITS + 1 top-most bits (+1 for
        // the implicit leading one in IEEE format). We therefore choose a
        // binary output exponent of
        //   log2(m10 * 10^e10) - (DOUBLE_MANTISSA_BITS + 1).
        //
        // We use floor(log2(5^e10)) so that we get at least this many bits;
        // better to have an additional bit than to not have enough bits.
        e2 = floor_log2(m10)
            .wrapping_add(e10 as u32)
            .wrapping_add(log2_pow5(e10) as u32)
            .wrapping_sub(d2s::DOUBLE_MANTISSA_BITS + 1) as i32;

        // We now compute [m10 * 10^e10 / 2^e2] = [m10 * 5^e10 / 2^(e2-e10)].
        // To that end, we use the DOUBLE_POW5_SPLIT table.
        let j = e2
            .wrapping_sub(e10)
            .wrapping_sub(ceil_log2_pow5(e10))
            .wrapping_add(d2s::DOUBLE_POW5_BITCOUNT);
        debug_assert!(j >= 0);
        debug_assert!(e10 < d2s::DOUBLE_POW5_SPLIT.len() as i32);
        m2 = mul_shift_64(
            m10,
            unsafe { d2s::DOUBLE_POW5_SPLIT.get_unchecked(e10 as usize) },
            j as u32,
        );

        // We also compute if the result is exact, i.e.,
        //   [m10 * 10^e10 / 2^e2] == m10 * 10^e10 / 2^e2.
        // This can only be the case if 2^e2 divides m10 * 10^e10, which in turn
        // requires that the largest power of 2 that divides m10 + e10 is
        // greater than e2. If e2 is less than e10, then the result must be
        // exact. Otherwise we use the existing multiple_of_power_of_2 function.
        trailing_zeros =
            e2 < e10 || e2 - e10 < 64 && multiple_of_power_of_2(m10, (e2 - e10) as u32);
    } else {
        e2 = floor_log2(m10)
            .wrapping_add(e10 as u32)
            .wrapping_sub(ceil_log2_pow5(-e10) as u32)
            .wrapping_sub(d2s::DOUBLE_MANTISSA_BITS + 1) as i32;
        let j = e2
            .wrapping_sub(e10)
            .wrapping_add(ceil_log2_pow5(-e10))
            .wrapping_sub(1)
            .wrapping_add(d2s::DOUBLE_POW5_INV_BITCOUNT);
        debug_assert!(-e10 < d2s::DOUBLE_POW5_INV_SPLIT.len() as i32);
        m2 = mul_shift_64(
            m10,
            unsafe { d2s::DOUBLE_POW5_INV_SPLIT.get_unchecked(-e10 as usize) },
            j as u32,
        );
        trailing_zeros = multiple_of_power_of_5(m10, -e10 as u32);
    }

    // Compute the final IEEE exponent.
    let mut ieee_e2 = i32::max(0, e2 + DOUBLE_EXPONENT_BIAS as i32 + floor_log2(m2) as i32) as u32;

    if ieee_e2 > 0x7fe {
        // Final IEEE exponent is larger than the maximum representable; return +/-Infinity.
        let ieee = ((signed_m as u64) << (d2s::DOUBLE_EXPONENT_BITS + d2s::DOUBLE_MANTISSA_BITS))
            | (0x7ff_u64 << d2s::DOUBLE_MANTISSA_BITS);
        return Ok(f64::from_bits(ieee));
    }

    // We need to figure out how much we need to shift m2. The tricky part is
    // that we need to take the final IEEE exponent into account, so we need to
    // reverse the bias and also special-case the value 0.
    let shift = if ieee_e2 == 0 { 1 } else { ieee_e2 as i32 }
        .wrapping_sub(e2)
        .wrapping_sub(DOUBLE_EXPONENT_BIAS as i32)
        .wrapping_sub(d2s::DOUBLE_MANTISSA_BITS as i32);
    debug_assert!(shift >= 0);

    // We need to round up if the exact value is more than 0.5 above the value
    // we computed. That's equivalent to checking if the last removed bit was 1
    // and either the value was not just trailing zeros or the result would
    // otherwise be odd.
    //
    // We need to update trailing_zeros given that we have the exact output
    // exponent ieee_e2 now.
    trailing_zeros &= (m2 & ((1_u64 << (shift - 1)) - 1)) == 0;
    let last_removed_bit = (m2 >> (shift - 1)) & 1;
    let round_up = last_removed_bit != 0 && (!trailing_zeros || ((m2 >> shift) & 1) != 0);

    let mut ieee_m2 = (m2 >> shift).wrapping_add(round_up as u64);
    if ieee_m2 == (1_u64 << (d2s::DOUBLE_MANTISSA_BITS + 1)) {
        // Due to how the IEEE represents +/-Infinity, we don't need to check
        // for overflow here.
        ieee_e2 += 1;
    }
    ieee_m2 &= (1_u64 << d2s::DOUBLE_MANTISSA_BITS) - 1;
    let ieee = ((((signed_m as u64) << d2s::DOUBLE_EXPONENT_BITS) | ieee_e2 as u64)
        << d2s::DOUBLE_MANTISSA_BITS)
        | ieee_m2;
    Ok(f64::from_bits(ieee))
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::from_str::FromStr;
use std::hash;
use std::uint;
use std::path::BytesContainer;

#[deriving(Clone, PartialEq, Eq)]
pub struct Url {
    pub scheme: String,
    pub user: Option<UserInfo>,
    pub host: String,
    pub port: Option<u16>,
    pub path: Path,
}

#[deriving(Clone, PartialEq, Eq)]
pub struct Path {
    pub path: String,
    pub query: Query,
    pub fragment: Option<String>
}

#[deriving(Clone, PartialEq, Eq)]
pub struct UserInfo {
    pub user: String,
    pub pass: Option<String>
}

pub type Query = Vec<(String, String)>;

impl Url {
    pub fn new(scheme: String,
               user: Option<UserInfo>,
               host: String,
               port: Option<u16>,
               path: String,
               query: Query,
               fragment: Option<String>)
               -> Url {
        Url {
            scheme: scheme,
            user: user,
            host: host,
            port: port,
            path: Path::new(path, query, fragment)
        }
    }

    pub fn parse(rawurl: &str) -> DecodeResult<Url> {
        // scheme
        let (scheme, rest) = try!(get_scheme(rawurl));

        // authority
        let (userinfo, host, port, rest) = try!(get_authority(rest));

        // path
        let has_authority = host.len() > 0;
        let (path, rest) = try!(get_path(rest, has_authority));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest));

        let url = Url::new(scheme.to_string(),
                            userinfo,
                            host.to_string(),
                            port,
                            path,
                            query,
                            fragment);
        Ok(url)
    }
}

impl Path {
    pub fn new(path: String,
               query: Query,
               fragment: Option<String>)
               -> Path {
        Path {
            path: path,
            query: query,
            fragment: fragment,
        }
    }

    pub fn parse(rawpath: &str) -> DecodeResult<Path> {
        let (path, rest) = try!(get_path(rawpath, false));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest.as_slice()));

        Ok(Path{ path: path, query: query, fragment: fragment })
    }
}

impl UserInfo {
    #[inline]
    pub fn new(user: String, pass: Option<String>) -> UserInfo {
        UserInfo { user: user, pass: pass }
    }
}

fn encode_inner<T: BytesContainer>(c: T, full_url: bool) -> String {
    c.container_as_bytes().iter().fold(String::new(), |mut out, &b| {
        match b as char {
            // unreserved:
            'A' ... 'Z'
            | 'a' ... 'z'
            | '0' ... '9'
            | '-' | '.' | '_' | '~' => out.push(b as char),

            // gen-delims:
            ':' | '/' | '?' | '#' | '[' | ']' | '@' |
            // sub-delims:
            '!' | '$' | '&' | '"' | '(' | ')' | '*' |
            '+' | ',' | ';' | '='
                if full_url => out.push(b as char),

            ch => out.push_str(format!("%{:02X}", ch as uint).as_slice()),
        };

        out
    })
}

pub fn encode_component<T: BytesContainer>(container: T) -> String {
    encode_inner(container, false)
}

pub type DecodeResult<T> = Result<T, String>;

pub fn decode_component<T: BytesContainer>(container: T) -> DecodeResult<String> {
    decode_inner(container, false)
}

fn decode_inner<T: BytesContainer>(c: T, full_url: bool) -> DecodeResult<String> {
    let mut out = String::new();
    let mut iter = c.container_as_bytes().iter().map(|&b| b);

    loop {
        match iter.next() {
            Some(b) => match b as char {
                '%' => {
                    let bytes = match (iter.next(), iter.next()) {
                        (Some(one), Some(two)) => [one as u8, two as u8],
                        _ => return Err(format!("Malformed input: found '%' \
                                                without two trailing bytes")),
                    };

                    // Only decode some characters if full_url:
                    match uint::parse_bytes(bytes, 16u).unwrap() as u8 as char {
                        // gen-delims:
                        ':' | '/' | '?' | '#' | '[' | ']' | '@' |

                        // sub-delims:
                        '!' | '$' | '&' | '"' | '(' | ')' | '*' |
                        '+' | ',' | ';' | '='
                            if full_url => {
                            out.push('%');
                            out.push(bytes[0u] as char);
                            out.push(bytes[1u] as char);
                        }

                        ch => out.push(ch)
                    }
                }
                ch => out.push(ch)
            },
            None => return Ok(out),
        }
    }
}

fn split_char_first(s: &str, c: char) -> (&str, &str) {
    let mut iter = s.splitn(1, c);

    match (iter.next(), iter.next()) {
        (Some(a), Some(b)) => (a, b),
        (Some(a), None) => (a, ""),
        (None, _) => unreachable!(),
    }
}

impl fmt::Show for UserInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.pass {
            Some(ref pass) => write!(f, "{}:{}@", self.user, *pass),
            None => write!(f, "{}@", self.user),
        }
    }
}

fn query_from_str(rawquery: &str) -> DecodeResult<Query> {
    let mut query: Query = vec!();
    if !rawquery.is_empty() {
        for p in rawquery.split('&') {
            let (k, v) = split_char_first(p, '=');
            query.push((try!(decode_component(k)),
                        try!(decode_component(v))));
        }
    }

    Ok(query)
}

pub fn query_to_str(query: &Query) -> String {
    query.iter().enumerate().fold(String::new(), |mut out, (i, &(ref k, ref v))| {
        if i != 0 {
            out.push('&');
        }

        out.push_str(encode_component(k.as_slice()).as_slice());
        out.push('=');
        out.push_str(encode_component(v.as_slice()).as_slice());
        out
    })
}

pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
    for (i,c) in rawurl.chars().enumerate() {
        let result = match c {
            'A' ... 'Z'
            | 'a' ... 'z' => continue,
            '0' ... '9' | '+' | '-' | '.' => {
                if i != 0 { continue }

                Err("url: Scheme must begin with a letter.".to_string())
            }
            ':' => {
                if i == 0 {
                    Err("url: Scheme cannot be empty.".to_string())
                } else {
                    Ok((rawurl.slice(0,i), rawurl.slice(i+1,rawurl.len())))
                }
            }
            _ => Err("url: Invalid character in scheme.".to_string()),
        };

        return result;
    }

    Err("url: Scheme must be terminated with a colon.".to_string())
}

// returns userinfo, host, port, and unparsed part, or an error
fn get_authority(rawurl: &str) ->
    DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
    enum State {
        Start, // starting state
        PassHostPort, // could be in user or port
        Ip6Port, // either in ipv6 host or port
        Ip6Host, // are in an ipv6 host
        InHost, // are in a host - may be ipv6, but don't know yet
        InPort // are in port
    }

    #[deriving(Clone, PartialEq)]
    enum Input {
        Digit, // all digits
        Hex, // digits and letters a-f
        Unreserved // all other legal characters
    }

    if !rawurl.starts_with("//") {
        // there is no authority.
        return Ok((None, "", None, rawurl));
    }

    let len = rawurl.len();
    let mut st = Start;
    let mut input = Digit; // most restricted, start here.

    let mut userinfo = None;
    let mut host = "";
    let mut port = None;

    let mut colon_count = 0u;
    let mut pos = 0;
    let mut begin = 2;
    let mut end = len;

    for (i,c) in rawurl.chars().enumerate()
                               // ignore the leading '//' handled by early return
                               .skip(2) {
        // deal with input class first
        match c {
            '0' ... '9' => (),
            'A' ... 'F'
            | 'a' ... 'f' => {
                if input == Digit {
                    input = Hex;
                }
            }
            'G' ... 'Z'
            | 'g' ... 'z'
            | '-' | '.' | '_' | '~' | '%'
            | '&' |'\'' | '(' | ')' | '+'
            | '!' | '*' | ',' | ';' | '=' => input = Unreserved,
            ':' | '@' | '?' | '#' | '/' => {
                // separators, don't change anything
            }
            _ => return Err("Illegal character in authority".to_string()),
        }

        // now process states
        match c {
          ':' => {
            colon_count += 1;
            match st {
              Start => {
                pos = i;
                st = PassHostPort;
              }
              PassHostPort => {
                // multiple colons means ipv6 address.
                if input == Unreserved {
                    return Err(
                        "Illegal characters in IPv6 address.".to_string());
                }
                st = Ip6Host;
              }
              InHost => {
                pos = i;
                if input == Unreserved {
                    // must be port
                    host = rawurl.slice(begin, i);
                    st = InPort;
                } else {
                    // can't be sure whether this is an ipv6 address or a port
                    st = Ip6Port;
                }
              }
              Ip6Port => {
                if input == Unreserved {
                    return Err("Illegal characters in authority.".to_string());
                }
                st = Ip6Host;
              }
              Ip6Host => {
                if colon_count > 7 {
                    host = rawurl.slice(begin, i);
                    pos = i;
                    st = InPort;
                }
              }
              _ => return Err("Invalid ':' in authority.".to_string()),
            }
            input = Digit; // reset input class
          }

          '@' => {
            input = Digit; // reset input class
            colon_count = 0; // reset count
            match st {
              Start => {
                let user = rawurl.slice(begin, i).to_string();
                userinfo = Some(UserInfo::new(user, None));
                st = InHost;
              }
              PassHostPort => {
                let user = rawurl.slice(begin, pos).to_string();
                let pass = rawurl.slice(pos+1, i).to_string();
                userinfo = Some(UserInfo::new(user, Some(pass)));
                st = InHost;
              }
              _ => return Err("Invalid '@' in authority.".to_string()),
            }
            begin = i+1;
          }

          '?' | '#' | '/' => {
            end = i;
            break;
          }
          _ => ()
        }
    }

    // finish up
    match st {
      Start => host = rawurl.slice(begin, end),
      PassHostPort
      | Ip6Port => {
        if input != Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        host = rawurl.slice(begin, pos);
        port = Some(rawurl.slice(pos+1, end));
      }
      Ip6Host
      | InHost => host = rawurl.slice(begin, end),
      InPort => {
        if input != Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        port = Some(rawurl.slice(pos+1, end));
      }
    }

    let rest = rawurl.slice(end, len);
    // If we have a port string, ensure it parses to u16.
    let port = match port {
        None => None,
        opt => match opt.and_then(|p| FromStr::from_str(p)) {
            None => return Err(format!("Failed to parse port: {}", port)),
            opt => opt
        }
    };

    Ok((userinfo, host, port, rest))
}

// returns the path and unparsed part of url, or an error
fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
    let len = rawurl.len();
    let mut end = len;
    for (i,c) in rawurl.chars().enumerate() {
        match c {
          'A' ... 'Z'
          | 'a' ... 'z'
          | '0' ... '9'
          | '&' |'\'' | '(' | ')' | '.'
          | '@' | ':' | '%' | '/' | '+'
          | '!' | '*' | ',' | ';' | '='
          | '_' | '-' | '~' => continue,
          '?' | '#' => {
            end = i;
            break;
          }
          _ => return Err("Invalid character in path.".to_string())
        }
    }

    if is_authority && end != 0 && !rawurl.starts_with("/") {
        Err("Non-empty path must begin with \
            '/' in presence of authority.".to_string())
    } else {
        Ok((try!(decode_component(rawurl.slice(0, end))),
            rawurl.slice(end, len)))
    }
}

// returns the parsed query and the fragment, if present
fn get_query_fragment(rawurl: &str) -> DecodeResult<(Query, Option<String>)> {
    let (before_fragment, raw_fragment) = split_char_first(rawurl, '#');

    // Parse the fragment if available
    let fragment = match raw_fragment {
        "" => None,
        raw => Some(try!(decode_component(raw)))
    };

    match before_fragment.slice_shift_char() {
        (Some('?'), rest) => Ok((try!(query_from_str(rest)), fragment)),
        (None, "") => Ok((vec!(), fragment)),
        _ => Err(format!("Query didn't start with '?': '{}..'", before_fragment)),
    }
}

impl FromStr for Url {
    fn from_str(s: &str) -> Option<Url> {
        Url::parse(s).ok()
    }
}

impl FromStr for Path {
    fn from_str(s: &str) -> Option<Path> {
        Path::parse(s).ok()
    }
}

impl fmt::Show for Url {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}:", self.scheme));

        if !self.host.is_empty() {
            try!(write!(f, "//"));
            match self.user {
                Some(ref user) => try!(write!(f, "{}", *user)),
                None => {}
            }
            match self.port {
                Some(ref port) => try!(write!(f, "{}:{}", self.host,
                                                *port)),
                None => try!(write!(f, "{}", self.host)),
            }
        }

        write!(f, "{}", self.path)
    }
}

impl fmt::Show for Path {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.path));
        if !self.query.is_empty() {
            try!(write!(f, "?{}", query_to_str(&self.query)))
        }

        match self.fragment {
            Some(ref fragment) => {
                write!(f, "#{}", encode_component(fragment.as_slice()))
            }
            None => Ok(())
        }
    }
}

impl<S: hash::Writer> hash::Hash<S> for Url {
    fn hash(&self, state: &mut S) {
        self.to_string().hash(state)
    }
}

impl<S: hash::Writer> hash::Hash<S> for Path {
    fn hash(&self, state: &mut S) {
        self.to_string().hash(state)
    }
}

<commit_msg>Remove parse_bytes to work with latest rustc<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::from_str::FromStr;
use std::hash;
use std::path::BytesContainer;
use std::num;
use std::str;

#[deriving(Clone, PartialEq, Eq)]
pub struct Url {
    pub scheme: String,
    pub user: Option<UserInfo>,
    pub host: String,
    pub port: Option<u16>,
    pub path: Path,
}

#[deriving(Clone, PartialEq, Eq)]
pub struct Path {
    pub path: String,
    pub query: Query,
    pub fragment: Option<String>
}

#[deriving(Clone, PartialEq, Eq)]
pub struct UserInfo {
    pub user: String,
    pub pass: Option<String>
}

pub type Query = Vec<(String, String)>;

impl Url {
    pub fn new(scheme: String,
               user: Option<UserInfo>,
               host: String,
               port: Option<u16>,
               path: String,
               query: Query,
               fragment: Option<String>)
               -> Url {
        Url {
            scheme: scheme,
            user: user,
            host: host,
            port: port,
            path: Path::new(path, query, fragment)
        }
    }

    pub fn parse(rawurl: &str) -> DecodeResult<Url> {
        // scheme
        let (scheme, rest) = try!(get_scheme(rawurl));

        // authority
        let (userinfo, host, port, rest) = try!(get_authority(rest));

        // path
        let has_authority = host.len() > 0;
        let (path, rest) = try!(get_path(rest, has_authority));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest));

        let url = Url::new(scheme.to_string(),
                            userinfo,
                            host.to_string(),
                            port,
                            path,
                            query,
                            fragment);
        Ok(url)
    }
}

impl Path {
    pub fn new(path: String,
               query: Query,
               fragment: Option<String>)
               -> Path {
        Path {
            path: path,
            query: query,
            fragment: fragment,
        }
    }

    pub fn parse(rawpath: &str) -> DecodeResult<Path> {
        let (path, rest) = try!(get_path(rawpath, false));

        // query and fragment
        let (query, fragment) = try!(get_query_fragment(rest.as_slice()));

        Ok(Path{ path: path, query: query, fragment: fragment })
    }
}

impl UserInfo {
    #[inline]
    pub fn new(user: String, pass: Option<String>) -> UserInfo {
        UserInfo { user: user, pass: pass }
    }
}

fn encode_inner<T: BytesContainer>(c: T, full_url: bool) -> String {
    c.container_as_bytes().iter().fold(String::new(), |mut out, &b| {
        match b as char {
            // unreserved:
            'A' ... 'Z'
            | 'a' ... 'z'
            | '0' ... '9'
            | '-' | '.' | '_' | '~' => out.push(b as char),

            // gen-delims:
            ':' | '/' | '?' | '#' | '[' | ']' | '@' |
            // sub-delims:
            '!' | '$' | '&' | '"' | '(' | ')' | '*' |
            '+' | ',' | ';' | '='
                if full_url => out.push(b as char),

            ch => out.push_str(format!("%{:02X}", ch as uint).as_slice()),
        };

        out
    })
}

pub fn encode_component<T: BytesContainer>(container: T) -> String {
    encode_inner(container, false)
}

pub type DecodeResult<T> = Result<T, String>;

pub fn decode_component<T: BytesContainer>(container: T) -> DecodeResult<String> {
    decode_inner(container, false)
}

fn decode_inner<T: BytesContainer>(c: T, full_url: bool) -> DecodeResult<String> {
    let mut out = String::new();
    let mut iter = c.container_as_bytes().iter().map(|&b| b);

    loop {
        match iter.next() {
            Some(b) => match b as char {
                '%' => {
                    let bytes = match (iter.next(), iter.next()) {
                        (Some(one), Some(two)) => [one as u8, two as u8],
                        _ => return Err(format!("Malformed input: found '%' \
                                                without two trailing bytes")),
                    };

                    // Only decode some characters if full_url:
                    match num::from_str_radix::<uint>(str::from_utf8(bytes).unwrap(), 16u).unwrap() as u8 as char {
                        // gen-delims:
                        ':' | '/' | '?' | '#' | '[' | ']' | '@' |

                        // sub-delims:
                        '!' | '$' | '&' | '"' | '(' | ')' | '*' |
                        '+' | ',' | ';' | '='
                            if full_url => {
                            out.push('%');
                            out.push(bytes[0u] as char);
                            out.push(bytes[1u] as char);
                        }

                        ch => out.push(ch)
                    }
                }
                ch => out.push(ch)
            },
            None => return Ok(out),
        }
    }
}

fn split_char_first(s: &str, c: char) -> (&str, &str) {
    let mut iter = s.splitn(1, c);

    match (iter.next(), iter.next()) {
        (Some(a), Some(b)) => (a, b),
        (Some(a), None) => (a, ""),
        (None, _) => unreachable!(),
    }
}

impl fmt::Show for UserInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.pass {
            Some(ref pass) => write!(f, "{}:{}@", self.user, *pass),
            None => write!(f, "{}@", self.user),
        }
    }
}

fn query_from_str(rawquery: &str) -> DecodeResult<Query> {
    let mut query: Query = vec!();
    if !rawquery.is_empty() {
        for p in rawquery.split('&') {
            let (k, v) = split_char_first(p, '=');
            query.push((try!(decode_component(k)),
                        try!(decode_component(v))));
        }
    }

    Ok(query)
}

pub fn query_to_str(query: &Query) -> String {
    query.iter().enumerate().fold(String::new(), |mut out, (i, &(ref k, ref v))| {
        if i != 0 {
            out.push('&');
        }

        out.push_str(encode_component(k.as_slice()).as_slice());
        out.push('=');
        out.push_str(encode_component(v.as_slice()).as_slice());
        out
    })
}

pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
    for (i,c) in rawurl.chars().enumerate() {
        let result = match c {
            'A' ... 'Z'
            | 'a' ... 'z' => continue,
            '0' ... '9' | '+' | '-' | '.' => {
                if i != 0 { continue }

                Err("url: Scheme must begin with a letter.".to_string())
            }
            ':' => {
                if i == 0 {
                    Err("url: Scheme cannot be empty.".to_string())
                } else {
                    Ok((rawurl.slice(0,i), rawurl.slice(i+1,rawurl.len())))
                }
            }
            _ => Err("url: Invalid character in scheme.".to_string()),
        };

        return result;
    }

    Err("url: Scheme must be terminated with a colon.".to_string())
}

// returns userinfo, host, port, and unparsed part, or an error
fn get_authority(rawurl: &str) ->
    DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
    enum State {
        Start, // starting state
        PassHostPort, // could be in user or port
        Ip6Port, // either in ipv6 host or port
        Ip6Host, // are in an ipv6 host
        InHost, // are in a host - may be ipv6, but don't know yet
        InPort // are in port
    }

    #[deriving(Clone, PartialEq)]
    enum Input {
        Digit, // all digits
        Hex, // digits and letters a-f
        Unreserved // all other legal characters
    }

    if !rawurl.starts_with("//") {
        // there is no authority.
        return Ok((None, "", None, rawurl));
    }

    let len = rawurl.len();
    let mut st = Start;
    let mut input = Digit; // most restricted, start here.

    let mut userinfo = None;
    let mut host = "";
    let mut port = None;

    let mut colon_count = 0u;
    let mut pos = 0;
    let mut begin = 2;
    let mut end = len;

    for (i,c) in rawurl.chars().enumerate()
                               // ignore the leading '//' handled by early return
                               .skip(2) {
        // deal with input class first
        match c {
            '0' ... '9' => (),
            'A' ... 'F'
            | 'a' ... 'f' => {
                if input == Digit {
                    input = Hex;
                }
            }
            'G' ... 'Z'
            | 'g' ... 'z'
            | '-' | '.' | '_' | '~' | '%'
            | '&' |'\'' | '(' | ')' | '+'
            | '!' | '*' | ',' | ';' | '=' => input = Unreserved,
            ':' | '@' | '?' | '#' | '/' => {
                // separators, don't change anything
            }
            _ => return Err("Illegal character in authority".to_string()),
        }

        // now process states
        match c {
          ':' => {
            colon_count += 1;
            match st {
              Start => {
                pos = i;
                st = PassHostPort;
              }
              PassHostPort => {
                // multiple colons means ipv6 address.
                if input == Unreserved {
                    return Err(
                        "Illegal characters in IPv6 address.".to_string());
                }
                st = Ip6Host;
              }
              InHost => {
                pos = i;
                if input == Unreserved {
                    // must be port
                    host = rawurl.slice(begin, i);
                    st = InPort;
                } else {
                    // can't be sure whether this is an ipv6 address or a port
                    st = Ip6Port;
                }
              }
              Ip6Port => {
                if input == Unreserved {
                    return Err("Illegal characters in authority.".to_string());
                }
                st = Ip6Host;
              }
              Ip6Host => {
                if colon_count > 7 {
                    host = rawurl.slice(begin, i);
                    pos = i;
                    st = InPort;
                }
              }
              _ => return Err("Invalid ':' in authority.".to_string()),
            }
            input = Digit; // reset input class
          }

          '@' => {
            input = Digit; // reset input class
            colon_count = 0; // reset count
            match st {
              Start => {
                let user = rawurl.slice(begin, i).to_string();
                userinfo = Some(UserInfo::new(user, None));
                st = InHost;
              }
              PassHostPort => {
                let user = rawurl.slice(begin, pos).to_string();
                let pass = rawurl.slice(pos+1, i).to_string();
                userinfo = Some(UserInfo::new(user, Some(pass)));
                st = InHost;
              }
              _ => return Err("Invalid '@' in authority.".to_string()),
            }
            begin = i+1;
          }

          '?' | '#' | '/' => {
            end = i;
            break;
          }
          _ => ()
        }
    }

    // finish up
    match st {
      Start => host = rawurl.slice(begin, end),
      PassHostPort
      | Ip6Port => {
        if input != Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        host = rawurl.slice(begin, pos);
        port = Some(rawurl.slice(pos+1, end));
      }
      Ip6Host
      | InHost => host = rawurl.slice(begin, end),
      InPort => {
        if input != Digit {
            return Err("Non-digit characters in port.".to_string());
        }
        port = Some(rawurl.slice(pos+1, end));
      }
    }

    let rest = rawurl.slice(end, len);
    // If we have a port string, ensure it parses to u16.
    let port = match port {
        None => None,
        opt => match opt.and_then(|p| FromStr::from_str(p)) {
            None => return Err(format!("Failed to parse port: {}", port)),
            opt => opt
        }
    };

    Ok((userinfo, host, port, rest))
}

// returns the path and unparsed part of url, or an error
fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
    let len = rawurl.len();
    let mut end = len;
    for (i,c) in rawurl.chars().enumerate() {
        match c {
          'A' ... 'Z'
          | 'a' ... 'z'
          | '0' ... '9'
          | '&' |'\'' | '(' | ')' | '.'
          | '@' | ':' | '%' | '/' | '+'
          | '!' | '*' | ',' | ';' | '='
          | '_' | '-' | '~' => continue,
          '?' | '#' => {
            end = i;
            break;
          }
          _ => return Err("Invalid character in path.".to_string())
        }
    }

    if is_authority && end != 0 && !rawurl.starts_with("/") {
        Err("Non-empty path must begin with \
            '/' in presence of authority.".to_string())
    } else {
        Ok((try!(decode_component(rawurl.slice(0, end))),
            rawurl.slice(end, len)))
    }
}

// returns the parsed query and the fragment, if present
fn get_query_fragment(rawurl: &str) -> DecodeResult<(Query, Option<String>)> {
    let (before_fragment, raw_fragment) = split_char_first(rawurl, '#');

    // Parse the fragment if available
    let fragment = match raw_fragment {
        "" => None,
        raw => Some(try!(decode_component(raw)))
    };

    match before_fragment.slice_shift_char() {
        (Some('?'), rest) => Ok((try!(query_from_str(rest)), fragment)),
        (None, "") => Ok((vec!(), fragment)),
        _ => Err(format!("Query didn't start with '?': '{}..'", before_fragment)),
    }
}

impl FromStr for Url {
    fn from_str(s: &str) -> Option<Url> {
        Url::parse(s).ok()
    }
}

impl FromStr for Path {
    fn from_str(s: &str) -> Option<Path> {
        Path::parse(s).ok()
    }
}

impl fmt::Show for Url {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}:", self.scheme));

        if !self.host.is_empty() {
            try!(write!(f, "//"));
            match self.user {
                Some(ref user) => try!(write!(f, "{}", *user)),
                None => {}
            }
            match self.port {
                Some(ref port) => try!(write!(f, "{}:{}", self.host,
                                                *port)),
                None => try!(write!(f, "{}", self.host)),
            }
        }

        write!(f, "{}", self.path)
    }
}

impl fmt::Show for Path {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.path));
        if !self.query.is_empty() {
            try!(write!(f, "?{}", query_to_str(&self.query)))
        }

        match self.fragment {
            Some(ref fragment) => {
                write!(f, "#{}", encode_component(fragment.as_slice()))
            }
            None => Ok(())
        }
    }
}

impl<S: hash::Writer> hash::Hash<S> for Url {
    fn hash(&self, state: &mut S) {
        self.to_string().hash(state)
    }
}

impl<S: hash::Writer> hash::Hash<S> for Path {
    fn hash(&self, state: &mut S) {
        self.to_string().hash(state)
    }
}

<|endoftext|>