<commit_before>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ascii::{AsciiString};
use std::ascii::AsciiExt;

use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::io::{ErrorKind, Read, BufReader, BufWriter};

use std::net::SocketAddr;
use std::str::FromStr;

use common::{HTTPVersion, Method};
use util::{SequentialReader, SequentialReaderBuilder, SequentialWriterBuilder};
use util::RefinedTcpStream;

use Request;

/// A ClientConnection is an object that will store a socket to a client
/// and return Request objects.
pub struct ClientConnection {
    // address of the client
    remote_addr: IoResult<SocketAddr>,

    // sequence of Readers to the stream, so that the data is not read in
    //  the wrong order
    source: SequentialReaderBuilder<BufReader<RefinedTcpStream>>,

    // sequence of Writers to the stream, to avoid writing response #2 before
    //  response #1
    sink: SequentialWriterBuilder<BufWriter<RefinedTcpStream>>,

    // Reader to read the next header from
	next_header_source: SequentialReader<BufReader<RefinedTcpStream>>,

    // set to true if we know that the previous request is the last one
    no_more_requests: bool,

    // true if the connection goes through SSL
    secure: bool,
}

/// Error that can happen when reading a request.
enum ReadError {
    WrongRequestLine,
    WrongHeader(HTTPVersion),

    /// the client sent an unrecognized `Expect` header
    ExpectationFailed(HTTPVersion),

    ReadIoError(IoError),
}

impl ClientConnection {
    /// Creates a new ClientConnection that takes ownership of the TcpStream.
    pub fn new(write_socket: RefinedTcpStream, mut read_socket: RefinedTcpStream)
               -> ClientConnection
    {
        let remote_addr = read_socket.peer_addr();
        let secure = read_socket.secure();

        let mut source = SequentialReaderBuilder::new(BufReader::with_capacity(1024, read_socket));
        let first_header = source.next().unwrap();

        ClientConnection {
            source: source,
            sink: SequentialWriterBuilder::new(BufWriter::with_capacity(1024, write_socket)),
            remote_addr: remote_addr,
            next_header_source: first_header,
            no_more_requests: false,
            secure: secure,
        }
    }

    /// Reads the next line from self.next_header_source.
    ///
    /// Reads until `CRLF` is reached. The next read will start
    ///  at the first byte of the new line.
    fn read_next_line(&mut self) -> IoResult<AsciiString> {
        let mut buf = Vec::new();
        let mut prev_byte_was_cr = false;

        loop {
            let byte = self.next_header_source.by_ref().bytes().next();

            let byte = match byte {
                Some(b) => try!(b),
                None => return Err(IoError::new(ErrorKind::ConnectionAborted, "Unexpected EOF"))
            };

            if byte == b'\n' && prev_byte_was_cr {
                buf.pop();  // removing the '\r'
                return AsciiString::from_ascii(buf)
                    .map_err(|_| IoError::new(ErrorKind::InvalidInput, "Header is not in ASCII"))
            }

            prev_byte_was_cr = byte == b'\r';

            buf.push(byte);
        }
    }

    /// Reads a request from the stream.
    /// Blocks until the header has been read.
    fn read(&mut self) -> Result<Request, ReadError> {
        let (method, path, version, headers) = {
            // reading the request line
            let (method, path, version) = {
                let line = try!(self.read_next_line().map_err(|e| ReadError::ReadIoError(e)));

                try!(parse_request_line(
                    line.as_str().trim()    // TODO: remove this conversion
                ))
            };

            // getting all headers
            let headers = {
                let mut headers = Vec::new();
                loop {
                    let line = try!(self.read_next_line().map_err(|e| ReadError::ReadIoError(e)));

                    if line.len() == 0 { break };
                    headers.push(
                        match FromStr::from_str(line.as_str().trim()) {    // TODO: remove this conversion
                            Ok(h) => h,
                            _ => return Err(ReadError::WrongHeader(version))
                        }
                    );
                }

                headers
            };

            (method, path, version, headers)
        };

        // building the writer for the request
        let writer = self.sink.next().unwrap();

        // follow-up for next potential request
        let mut data_source = self.source.next().unwrap();
        ::std::mem::swap(&mut self.next_header_source, &mut data_source);

        // building the next reader
        let request = try!(::request::new_request(self.secure, method, path, version.clone(),
                headers, self.remote_addr.as_ref().unwrap().clone(), data_source, writer)
            .map_err(|e| {
                use request;
                match e {
                    request::RequestCreationError::CreationIoError(e) => ReadError::ReadIoError(e),
                    request::RequestCreationError::ExpectationFailed => ReadError::ExpectationFailed(version)
                }
            }));

        // return the request
        Ok(request)
    }
}

impl Iterator for ClientConnection {
    type Item = Request;
    /// Blocks until the next Request is available.
    /// Returns None when no new Requests will come from the client.
    fn next(&mut self) -> Option<Request> {
        use {Response, StatusCode};

        // the client sent a "connection: close" header in this previous request
        //  or is using HTTP 1.0, meaning that no new request will come
        if self.no_more_requests {
            return None
        }

        loop {
            let rq = match self.read() {
                Err(ReadError::WrongRequestLine) => {
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(400));
                    response.raw_print(writer, HTTPVersion(1, 1), &[], false, None).ok();
                    return None;    // we don't know where the next request would start,
                                    // se we have to close
                },

                Err(ReadError::WrongHeader(ver)) => {
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(400));
                    response.raw_print(writer, ver, &[], false, None).ok();
                    return None;    // we don't know where the next request would start,
                                    // se we have to close
                },

                Err(ReadError::ReadIoError(ref err)) if err.kind() == ErrorKind::TimedOut => {
                    // request timeout
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(408));
                    response.raw_print(writer, HTTPVersion(1, 1), &[], false, None).ok();
                    return None;    // closing the connection
                },

                Err(ReadError::ExpectationFailed(ver)) => {
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(417));
                    response.raw_print(writer, ver, &[], true, None).ok();
                    return None;    // TODO: should be recoverable, but needs handling in case of body
                },

                Err(ReadError::ReadIoError(_)) =>
                    return None,

                Ok(rq) => rq
            };

            // checking HTTP version
            if *rq.http_version() > (1, 1) {
                let writer = self.sink.next().unwrap();
                let response =
                    Response::from_string("This server only supports HTTP versions 1.0 and 1.1"
                        .to_owned()).with_status_code(StatusCode(505));
                response.raw_print(writer, HTTPVersion(1, 1), &[], false, None).ok();
                continue
            }

            // updating the status of the connection
            {
                let connection_header = rq.headers().iter()
                    .find(|h| h.field.equiv(&"Connection"))
                    .map(|h| AsRef::<str>::as_ref(h.value.as_ref()));

                let lowercase = connection_header.map(|h| h.to_ascii_lowercase());

                match lowercase {
                    Some(ref val) if val.contains("close") =>
                        self.no_more_requests = true,

                    Some(ref val) if val.contains("upgrade") =>
                        self.no_more_requests = true,

                    Some(ref val) if !val.contains("keep-alive") &&
                                    *rq.http_version() == HTTPVersion(1, 0) =>
                        self.no_more_requests = true,

                    None if *rq.http_version() == HTTPVersion(1, 0) =>
                        self.no_more_requests = true,

                    _ => ()
                };
            }

            // returning the request
            return Some(rq);
        }
    }
}

/// Parses a "HTTP/1.1" string.
fn parse_http_version(version: &str) -> Result<HTTPVersion, ReadError> {
    let elems = version.splitn(2, '/').map(|e| e.to_owned()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(ReadError::WrongRequestLine)
    }

    let elems = elems[1].splitn(2, '.')
        .map(|e| e.to_owned()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(ReadError::WrongRequestLine)
    }

    match (FromStr::from_str(&elems[0]), FromStr::from_str(&elems[1])) {
        (Ok(major), Ok(minor)) =>
            Ok(HTTPVersion(major, minor)),
        _ => Err(ReadError::WrongRequestLine)
    }
}

/// Parses the request line of the request.
/// eg. GET / HTTP/1.1
fn parse_request_line(line: &str) -> Result<(Method, String, HTTPVersion), ReadError> {
    let mut words = line.split(' ');

    let method = words.next();
    let path = words.next();
    let version = words.next();

    let (method, path, version) = match (method, path, version) {
        (Some(m), Some(p), Some(v)) => (m, p, v),
        _ => return Err(ReadError::WrongRequestLine)
    };

    let method = match FromStr::from_str(method) {
        Ok(method) => method,
        Err(()) => return Err(ReadError::WrongRequestLine)
    };

    let version = try!(parse_http_version(version));

    Ok((method, path.to_owned(), version))
}

#[cfg(test)]
mod test {
    #[test]
    fn test_parse_request_line() {
        let (method, path, ver) =
            match super::parse_request_line("GET /hello HTTP/1.1") {
                Err(_) => panic!(),
                Ok(v) => v
            };

        assert!(method == ::Method::Get);
        assert!(path == "/hello");
        assert!(ver == ::common::HTTPVersion(1, 1));

        assert!(super::parse_request_line("GET /hello").is_err());
        assert!(super::parse_request_line("qsd qsd qsd").is_err());
    }
}
<commit_msg>Fix `next_header_source` alignment<commit_after>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ascii::{AsciiString};
use std::ascii::AsciiExt;

use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::io::{ErrorKind, Read, BufReader, BufWriter};

use std::net::SocketAddr;
use std::str::FromStr;

use common::{HTTPVersion, Method};
use util::{SequentialReader, SequentialReaderBuilder, SequentialWriterBuilder};
use util::RefinedTcpStream;

use Request;

/// A ClientConnection is an object that will store a socket to a client
/// and return Request objects.
pub struct ClientConnection {
    // address of the client
    remote_addr: IoResult<SocketAddr>,

    // sequence of Readers to the stream, so that the data is not read in
    //  the wrong order
    source: SequentialReaderBuilder<BufReader<RefinedTcpStream>>,

    // sequence of Writers to the stream, to avoid writing response #2 before
    //  response #1
    sink: SequentialWriterBuilder<BufWriter<RefinedTcpStream>>,

    // Reader to read the next header from
    next_header_source: SequentialReader<BufReader<RefinedTcpStream>>,

    // set to true if we know that the previous request is the last one
    no_more_requests: bool,

    // true if the connection goes through SSL
    secure: bool,
}

/// Error that can happen when reading a request.
enum ReadError {
    WrongRequestLine,
    WrongHeader(HTTPVersion),

    /// the client sent an unrecognized `Expect` header
    ExpectationFailed(HTTPVersion),

    ReadIoError(IoError),
}

impl ClientConnection {
    /// Creates a new ClientConnection that takes ownership of the TcpStream.
    pub fn new(write_socket: RefinedTcpStream, mut read_socket: RefinedTcpStream)
               -> ClientConnection
    {
        let remote_addr = read_socket.peer_addr();
        let secure = read_socket.secure();

        let mut source = SequentialReaderBuilder::new(BufReader::with_capacity(1024, read_socket));
        let first_header = source.next().unwrap();

        ClientConnection {
            source: source,
            sink: SequentialWriterBuilder::new(BufWriter::with_capacity(1024, write_socket)),
            remote_addr: remote_addr,
            next_header_source: first_header,
            no_more_requests: false,
            secure: secure,
        }
    }

    /// Reads the next line from self.next_header_source.
    ///
    /// Reads until `CRLF` is reached. The next read will start
    ///  at the first byte of the new line.
    fn read_next_line(&mut self) -> IoResult<AsciiString> {
        let mut buf = Vec::new();
        let mut prev_byte_was_cr = false;

        loop {
            let byte = self.next_header_source.by_ref().bytes().next();

            let byte = match byte {
                Some(b) => try!(b),
                None => return Err(IoError::new(ErrorKind::ConnectionAborted, "Unexpected EOF"))
            };

            if byte == b'\n' && prev_byte_was_cr {
                buf.pop();  // removing the '\r'
                return AsciiString::from_ascii(buf)
                    .map_err(|_| IoError::new(ErrorKind::InvalidInput, "Header is not in ASCII"))
            }

            prev_byte_was_cr = byte == b'\r';

            buf.push(byte);
        }
    }

    /// Reads a request from the stream.
    /// Blocks until the header has been read.
    fn read(&mut self) -> Result<Request, ReadError> {
        let (method, path, version, headers) = {
            // reading the request line
            let (method, path, version) = {
                let line = try!(self.read_next_line().map_err(|e| ReadError::ReadIoError(e)));

                try!(parse_request_line(
                    line.as_str().trim()    // TODO: remove this conversion
                ))
            };

            // getting all headers
            let headers = {
                let mut headers = Vec::new();
                loop {
                    let line = try!(self.read_next_line().map_err(|e| ReadError::ReadIoError(e)));

                    if line.len() == 0 { break };
                    headers.push(
                        match FromStr::from_str(line.as_str().trim()) {    // TODO: remove this conversion
                            Ok(h) => h,
                            _ => return Err(ReadError::WrongHeader(version))
                        }
                    );
                }

                headers
            };

            (method, path, version, headers)
        };

        // building the writer for the request
        let writer = self.sink.next().unwrap();

        // follow-up for next potential request
        let mut data_source = self.source.next().unwrap();
        ::std::mem::swap(&mut self.next_header_source, &mut data_source);

        // building the next reader
        let request = try!(::request::new_request(self.secure, method, path, version.clone(),
                headers, self.remote_addr.as_ref().unwrap().clone(), data_source, writer)
            .map_err(|e| {
                use request;
                match e {
                    request::RequestCreationError::CreationIoError(e) => ReadError::ReadIoError(e),
                    request::RequestCreationError::ExpectationFailed => ReadError::ExpectationFailed(version)
                }
            }));

        // return the request
        Ok(request)
    }
}

impl Iterator for ClientConnection {
    type Item = Request;
    /// Blocks until the next Request is available.
    /// Returns None when no new Requests will come from the client.
    fn next(&mut self) -> Option<Request> {
        use {Response, StatusCode};

        // the client sent a "connection: close" header in this previous request
        //  or is using HTTP 1.0, meaning that no new request will come
        if self.no_more_requests {
            return None
        }

        loop {
            let rq = match self.read() {
                Err(ReadError::WrongRequestLine) => {
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(400));
                    response.raw_print(writer, HTTPVersion(1, 1), &[], false, None).ok();
                    return None;    // we don't know where the next request would start,
                                    // se we have to close
                },

                Err(ReadError::WrongHeader(ver)) => {
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(400));
                    response.raw_print(writer, ver, &[], false, None).ok();
                    return None;    // we don't know where the next request would start,
                                    // se we have to close
                },

                Err(ReadError::ReadIoError(ref err)) if err.kind() == ErrorKind::TimedOut => {
                    // request timeout
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(408));
                    response.raw_print(writer, HTTPVersion(1, 1), &[], false, None).ok();
                    return None;    // closing the connection
                },

                Err(ReadError::ExpectationFailed(ver)) => {
                    let writer = self.sink.next().unwrap();
                    let response = Response::new_empty(StatusCode(417));
                    response.raw_print(writer, ver, &[], true, None).ok();
                    return None;    // TODO: should be recoverable, but needs handling in case of body
                },

                Err(ReadError::ReadIoError(_)) =>
                    return None,

                Ok(rq) => rq
            };

            // checking HTTP version
            if *rq.http_version() > (1, 1) {
                let writer = self.sink.next().unwrap();
                let response =
                    Response::from_string("This server only supports HTTP versions 1.0 and 1.1"
                        .to_owned()).with_status_code(StatusCode(505));
                response.raw_print(writer, HTTPVersion(1, 1), &[], false, None).ok();
                continue
            }

            // updating the status of the connection
            {
                let connection_header = rq.headers().iter()
                    .find(|h| h.field.equiv(&"Connection"))
                    .map(|h| AsRef::<str>::as_ref(h.value.as_ref()));

                let lowercase = connection_header.map(|h| h.to_ascii_lowercase());

                match lowercase {
                    Some(ref val) if val.contains("close") =>
                        self.no_more_requests = true,

                    Some(ref val) if val.contains("upgrade") =>
                        self.no_more_requests = true,

                    Some(ref val) if !val.contains("keep-alive") &&
                                    *rq.http_version() == HTTPVersion(1, 0) =>
                        self.no_more_requests = true,

                    None if *rq.http_version() == HTTPVersion(1, 0) =>
                        self.no_more_requests = true,

                    _ => ()
                };
            }

            // returning the request
            return Some(rq);
        }
    }
}

/// Parses a "HTTP/1.1" string.
fn parse_http_version(version: &str) -> Result<HTTPVersion, ReadError> {
    let elems = version.splitn(2, '/').map(|e| e.to_owned()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(ReadError::WrongRequestLine)
    }

    let elems = elems[1].splitn(2, '.')
        .map(|e| e.to_owned()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(ReadError::WrongRequestLine)
    }

    match (FromStr::from_str(&elems[0]), FromStr::from_str(&elems[1])) {
        (Ok(major), Ok(minor)) =>
            Ok(HTTPVersion(major, minor)),
        _ => Err(ReadError::WrongRequestLine)
    }
}

/// Parses the request line of the request.
/// eg. GET / HTTP/1.1
fn parse_request_line(line: &str) -> Result<(Method, String, HTTPVersion), ReadError> {
    let mut words = line.split(' ');

    let method = words.next();
    let path = words.next();
    let version = words.next();

    let (method, path, version) = match (method, path, version) {
        (Some(m), Some(p), Some(v)) => (m, p, v),
        _ => return Err(ReadError::WrongRequestLine)
    };

    let method = match FromStr::from_str(method) {
        Ok(method) => method,
        Err(()) => return Err(ReadError::WrongRequestLine)
    };

    let version = try!(parse_http_version(version));

    Ok((method, path.to_owned(), version))
}

#[cfg(test)]
mod test {
    #[test]
    fn test_parse_request_line() {
        let (method, path, ver) =
            match super::parse_request_line("GET /hello HTTP/1.1") {
                Err(_) => panic!(),
                Ok(v) => v
            };

        assert!(method == ::Method::Get);
        assert!(path == "/hello");
        assert!(ver == ::common::HTTPVersion(1, 1));

        assert!(super::parse_request_line("GET /hello").is_err());
        assert!(super::parse_request_line("qsd qsd qsd").is_err());
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::{Encodable, Encoder};
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use std::error::Error;

use error::{WebDriverResult, WebDriverError, ErrorStatus};

pub static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";

#[derive(RustcEncodable, PartialEq, Clone, Debug)]
pub struct Date(u64);

impl Date {
    pub fn new(timestamp: u64) -> Date {
        Date(timestamp)
    }
}

impl ToJson for Date {
    fn to_json(&self) -> Json {
        let &Date(x) = self;
        x.to_json()
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Nullable<T: ToJson> {
    Value(T),
    Null
}

impl<T: ToJson> Nullable<T> {
     pub fn is_null(&self) -> bool {
        match *self {
            Nullable::Value(_) => false,
            Nullable::Null => true
        }
    }

     pub fn is_value(&self) -> bool {
        match *self {
            Nullable::Value(_) => true,
            Nullable::Null => false
        }
    }
}

impl<T: ToJson> Nullable<T> {
    //This is not very pretty
    pub fn from_json<F: FnOnce(&Json) -> WebDriverResult<T>>(value: &Json, f: F) -> WebDriverResult<Nullable<T>> {
        if value.is_null() {
            Ok(Nullable::Null)
        } else {
            Ok(Nullable::Value(try!(f(value))))
        }
    }
}

impl<T: ToJson> ToJson for Nullable<T> {
    fn to_json(&self) -> Json {
        match *self {
            Nullable::Value(ref x) => x.to_json(),
            Nullable::Null => Json::Null
        }
    }
}

impl<T: ToJson> Encodable for Nullable<T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Nullable::Value(ref x) => x.to_json().encode(s),
            Nullable::Null => s.emit_option_none()
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct WebElement {
    pub id: String
}

impl WebElement {
    pub fn new(id: String) -> WebElement {
        WebElement {
            id: id
        }
    }

    pub fn from_json(data: &Json) -> WebDriverResult<WebElement> {
        let object = try_opt!(data.as_object(),
                              ErrorStatus::InvalidArgument,
                              "Could not convert webelement to object");
        let id_value = try_opt!(object.get(ELEMENT_KEY),
                                ErrorStatus::InvalidArgument,
                                "Could not find webelement key");

        let id = try_opt!(id_value.as_string(),
                          ErrorStatus::InvalidArgument,
                          "Could not convert web element to string").to_string();

        Ok(WebElement::new(id))
    }
}

impl ToJson for WebElement {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert(ELEMENT_KEY.to_string(), self.id.to_json());
        Json::Object(data)
    }
}

#[derive(PartialEq, Debug)]
pub enum FrameId {
    Short(u16),
    Element(WebElement),
    Null
}

impl FrameId {
    pub fn from_json(data: &Json) -> WebDriverResult<FrameId> {
        match data {
            &Json::U64(x) => {
                if x > u16::max_value() as u64 || x < u16::min_value() as u64 {
                    return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                                   "frame id out of range"))
                };
                Ok(FrameId::Short(x as u16))
            },
            &Json::Null => Ok(FrameId::Null),
            &Json::Object(_) => Ok(FrameId::Element(
                try!(WebElement::from_json(data)))),
            _ => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                         "frame id has unexpected type"))
        }
    }
}

impl ToJson for FrameId {
    fn to_json(&self) -> Json {
        match *self {
            FrameId::Short(x) => {
                Json::U64(x as u64)
            },
            FrameId::Element(ref x) => {
                Json::String(x.id.clone())
            },
            FrameId::Null => {
                Json::Null
            }
        }
    }
}

#[derive(PartialEq)]
pub enum LocatorStrategy {
    CSSSelector,
    LinkText,
    PartialLinkText,
    XPath
}

impl LocatorStrategy {
    pub fn from_json(body: &Json) -> WebDriverResult<LocatorStrategy> {
        match try_opt!(body.as_string(),
                       ErrorStatus::InvalidArgument,
                       "Cound not convert strategy to string") {
            "css selector" => Ok(LocatorStrategy::CSSSelector),
            "link text" => Ok(LocatorStrategy::LinkText),
            "partial link text" => Ok(LocatorStrategy::PartialLinkText),
            "xpath" => Ok(LocatorStrategy::XPath),
            x => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                         &format!("Unknown locator strategy {}", x)[..]))
        }
    }
}

impl ToJson for LocatorStrategy {
    fn to_json(&self) -> Json {
        Json::String(match *self {
            LocatorStrategy::CSSSelector => "css selector",
            LocatorStrategy::LinkText => "link text",
            LocatorStrategy::PartialLinkText => "partial link text",
            LocatorStrategy::XPath => "xpath"
        }.to_string())
    }
}
<commit_msg>Squash a warning.<commit_after>use rustc_serialize::{Encodable, Encoder};
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;

use error::{WebDriverResult, WebDriverError, ErrorStatus};

pub static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";

#[derive(RustcEncodable, PartialEq, Clone, Debug)]
pub struct Date(u64);

impl Date {
    pub fn new(timestamp: u64) -> Date {
        Date(timestamp)
    }
}

impl ToJson for Date {
    fn to_json(&self) -> Json {
        let &Date(x) = self;
        x.to_json()
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Nullable<T: ToJson> {
    Value(T),
    Null
}

impl<T: ToJson> Nullable<T> {
     pub fn is_null(&self) -> bool {
        match *self {
            Nullable::Value(_) => false,
            Nullable::Null => true
        }
    }

     pub fn is_value(&self) -> bool {
        match *self {
            Nullable::Value(_) => true,
            Nullable::Null => false
        }
    }
}

impl<T: ToJson> Nullable<T> {
    //This is not very pretty
    pub fn from_json<F: FnOnce(&Json) -> WebDriverResult<T>>(value: &Json, f: F) -> WebDriverResult<Nullable<T>> {
        if value.is_null() {
            Ok(Nullable::Null)
        } else {
            Ok(Nullable::Value(try!(f(value))))
        }
    }
}

impl<T: ToJson> ToJson for Nullable<T> {
    fn to_json(&self) -> Json {
        match *self {
            Nullable::Value(ref x) => x.to_json(),
            Nullable::Null => Json::Null
        }
    }
}

impl<T: ToJson> Encodable for Nullable<T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Nullable::Value(ref x) => x.to_json().encode(s),
            Nullable::Null => s.emit_option_none()
        }
    }
}

#[derive(PartialEq, Debug)]
pub struct WebElement {
    pub id: String
}

impl WebElement {
    pub fn new(id: String) -> WebElement {
        WebElement {
            id: id
        }
    }

    pub fn from_json(data: &Json) -> WebDriverResult<WebElement> {
        let object = try_opt!(data.as_object(),
                              ErrorStatus::InvalidArgument,
                              "Could not convert webelement to object");
        let id_value = try_opt!(object.get(ELEMENT_KEY),
                                ErrorStatus::InvalidArgument,
                                "Could not find webelement key");

        let id = try_opt!(id_value.as_string(),
                          ErrorStatus::InvalidArgument,
                          "Could not convert web element to string").to_string();

        Ok(WebElement::new(id))
    }
}

impl ToJson for WebElement {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert(ELEMENT_KEY.to_string(), self.id.to_json());
        Json::Object(data)
    }
}

#[derive(PartialEq, Debug)]
pub enum FrameId {
    Short(u16),
    Element(WebElement),
    Null
}

impl FrameId {
    pub fn from_json(data: &Json) -> WebDriverResult<FrameId> {
        match data {
            &Json::U64(x) => {
                if x > u16::max_value() as u64 || x < u16::min_value() as u64 {
                    return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                                   "frame id out of range"))
                };
                Ok(FrameId::Short(x as u16))
            },
            &Json::Null => Ok(FrameId::Null),
            &Json::Object(_) => Ok(FrameId::Element(
                try!(WebElement::from_json(data)))),
            _ => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                         "frame id has unexpected type"))
        }
    }
}

impl ToJson for FrameId {
    fn to_json(&self) -> Json {
        match *self {
            FrameId::Short(x) => {
                Json::U64(x as u64)
            },
            FrameId::Element(ref x) => {
                Json::String(x.id.clone())
            },
            FrameId::Null => {
                Json::Null
            }
        }
    }
}

#[derive(PartialEq)]
pub enum LocatorStrategy {
    CSSSelector,
    LinkText,
    PartialLinkText,
    XPath
}

impl LocatorStrategy {
    pub fn from_json(body: &Json) -> WebDriverResult<LocatorStrategy> {
        match try_opt!(body.as_string(),
                       ErrorStatus::InvalidArgument,
                       "Cound not convert strategy to string") {
            "css selector" => Ok(LocatorStrategy::CSSSelector),
            "link text" => Ok(LocatorStrategy::LinkText),
            "partial link text" => Ok(LocatorStrategy::PartialLinkText),
            "xpath" => Ok(LocatorStrategy::XPath),
            x => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                         &format!("Unknown locator strategy {}", x)[..]))
        }
    }
}

impl ToJson for LocatorStrategy {
    fn to_json(&self) -> Json {
        Json::String(match *self {
            LocatorStrategy::CSSSelector => "css selector",
            LocatorStrategy::LinkText => "link text",
            LocatorStrategy::PartialLinkText => "partial link text",
            LocatorStrategy::XPath => "xpath"
        }.to_string())
    }
}
<|endoftext|>


<commit_before>//! Process configurations for Lightning sites.

// First-party
use std::collections::HashMap;
use std::error::Error;
use std::io::Read;
use std::fs::File;
use std::path::PathBuf;

// Third-party
use yaml_rust::{Yaml, YamlLoader};

const CONFIG_FILE_NAME: &'static str = "lightning.yaml";
const CONTENT_DIRECTORY: &'static str = "content_directory";
const OUTPUT_DIRECTORY: &'static str = "output_directory";
const TEMPLATE_DIRECTORY: &'static str = "directory";

pub struct Config {
    pub site: Site,
    pub directories: Directories,
    pub taxonomies: Vec<Taxonomy>,
}

pub struct Directories {
    pub content: PathBuf,
    pub output: PathBuf,
    pub template: PathBuf,
}

pub enum Taxonomy {
    Binary { templates: Templates },
    Multiple {
        name: String,
        limit: Option<u8>,
        required: bool,
        hierarchical: bool,
        templates: Templates,
    },
    Temporal {
        required: bool,
        templates: Templates,
    },
}

pub struct Site {
    pub name: String,
    pub description: String,
    pub metadata: HashMap<Yaml, Yaml>,
    pub url: ValidatedUrl,
}

pub struct Templates {
    item: String,
}

pub struct ValidatedUrl(String);

impl ValidatedUrl {
    /// Get a URL. `Err` if the item passed in is not a spec-conformant URL.
    pub fn new(unvalidated_url: String) -> Result<ValidatedUrl, String> {
        // TODO: validate the URLs!
        Ok(ValidatedUrl(unvalidated_url))
    }

    pub fn value(&self) -> String {
        self.0.clone()
    }
}

fn path_buf_from_yaml(yaml: &Yaml, key: &str, config_path: &PathBuf) -> Result<PathBuf, String> {
    match yaml {
        &Yaml::String(ref path_str) => Ok(PathBuf::from(path_str)),
        value => Err(format!("invalid `{:}` value {:?} in {:?}", key, value, config_path)),
    }
}

pub fn load(directory: &PathBuf) -> Result<Config, String> {
    let config_path = directory.join(CONFIG_FILE_NAME);
    if !config_path.exists() {
        return Err(format!("The specified configuration path {:?} does not exist.",
                           config_path.to_string_lossy()));
    }

    let mut file = File::open(&config_path)
        .map_err(|reason| format!("Error reading {:?}: {:?}", config_path, reason))?;

    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(_) => (),
        Err(err) => return Err(String::from(err.description())),
    };

    // We need all these intermediate bindings because the temporaries created
    // along the way don't live long enough otherwise.
    let yaml_config = YamlLoader::load_from_str(&contents)
        .map_err(|err| format!("{} ({:?})", err, &config_path))?;
    let yaml_config = yaml_config.into_iter().next().ok_or("Empty configuration file")?;
    let yaml_config = yaml_config.as_hash().ok_or("Configuration is not a map")?;

    let content_directory_yaml = yaml_config.get(&Yaml::from_str(CONTENT_DIRECTORY))
        .ok_or(format!("No `{:}` key in {:?}", CONTENT_DIRECTORY, config_path))?;

    let content_directory =
        path_buf_from_yaml(&content_directory_yaml, CONTENT_DIRECTORY, &config_path)?;

    let output_directory_yaml = yaml_config.get(&Yaml::from_str(OUTPUT_DIRECTORY))
        .ok_or(format!("No `{:} key in `{:?}", OUTPUT_DIRECTORY, config_path))?;

    let output_directory =
        path_buf_from_yaml(output_directory_yaml, OUTPUT_DIRECTORY, &config_path)?;

    let structure = yaml_config.get(&Yaml::from_str("structure"))
        .ok_or(format!("No `structure` key in {:?}", config_path))?
        .as_hash()
        .ok_or(format!("`structure` is not a map in {:?}", config_path))?;

    let template_directory_yaml = structure.get(&Yaml::from_str(TEMPLATE_DIRECTORY))
        .ok_or(format!("No `directory` key in `structure` in {:?}", config_path))?;

    let template_directory =
        path_buf_from_yaml(&template_directory_yaml, TEMPLATE_DIRECTORY, &config_path)?;

    Ok(Config {
        site: Site {  // TODO
            name: String::new(),
            description: String::new(),
            metadata: HashMap::new(),
            url: ValidatedUrl(String::new()),
        },
        directories: Directories {
            content: content_directory,
            output: output_directory,
            template: template_directory,
        },
        taxonomies: Vec::new(),
    })
}
<commit_msg>Break up config::load, add internal `validated` module.<commit_after>//! Process configurations for Lightning sites.

// First-party
use std::collections::{BTreeMap, HashMap};
use std::error::Error;
use std::io::Read;
use std::fs::File;
use std::path::PathBuf;

// Third-party
use yaml_rust::{Yaml, YamlLoader};

const CONFIG_FILE_NAME: &'static str = "lightning.yaml";
const CONTENT_DIRECTORY: &'static str = "content_directory";
const OUTPUT_DIRECTORY: &'static str = "output_directory";
const TEMPLATE_DIRECTORY: &'static str = "directory";

pub struct Config {
    pub site: Site,
    pub directories: Directories,
    pub taxonomies: Vec<Taxonomy>,
}

pub struct Directories {
    pub content: PathBuf,
    pub output: PathBuf,
    pub template: PathBuf,
}

pub enum Taxonomy {
    Binary { templates: Templates },
    Multiple {
        name: String,
        limit: Option<u8>,
        required: bool,
        hierarchical: bool,
        templates: Templates,
    },
    Temporal {
        required: bool,
        templates: Templates,
    },
}

pub struct Site {
    pub name: String,
    pub description: String,
    pub metadata: HashMap<Yaml, Yaml>,
    pub url: ValidatedUrl,
}

pub struct Templates {
    item: String,
}

mod validated {
    pub struct Url(String);

    impl Url {
        /// Get a URL. `Err` if the item passed in is not a spec-conformant URL.
        pub fn new(unvalidated_url: String) -> Result<Url, String> {
            // TODO: validate the URLs!
            Ok(Url(unvalidated_url))
        }

        pub fn value(&self) -> String {
            self.0.clone()
        }
    }
}

pub use self::validated::Url as ValidatedUrl;

fn path_buf_from_yaml(yaml: &Yaml, key: &str, config_path: &PathBuf) -> Result<PathBuf, String> {
    match yaml {
        &Yaml::String(ref path_str) => Ok(PathBuf::from(path_str)),
        value => Err(format!("invalid `{:}` value {:?} in {:?}", key, value, config_path)),
    }
}

fn directories(config_map: &BTreeMap<Yaml, Yaml>, config_path: &PathBuf) -> Result<Directories, String> {
    let content_directory_yaml = config_map.get(&Yaml::from_str(CONTENT_DIRECTORY))
        .ok_or(format!("No `{:}` key in {:?}", CONTENT_DIRECTORY, config_path))?;

    let content_directory =
    path_buf_from_yaml(&content_directory_yaml, CONTENT_DIRECTORY, &config_path)?;

    let output_directory_yaml = config_map.get(&Yaml::from_str(OUTPUT_DIRECTORY))
        .ok_or(format!("No `{:} key in `{:?}", OUTPUT_DIRECTORY, config_path))?;

    let output_directory =
    path_buf_from_yaml(output_directory_yaml, OUTPUT_DIRECTORY, &config_path)?;

    let structure = config_map.get(&Yaml::from_str("structure"))
        .ok_or(format!("No `structure` key in {:?}", config_path))?
        .as_hash()
        .ok_or(format!("`structure` is not a map in {:?}", config_path))?;

    let template_directory_yaml = structure.get(&Yaml::from_str(TEMPLATE_DIRECTORY))
        .ok_or(format!("No `directory` key in `structure` in {:?}", config_path))?;

    let template_directory =
    path_buf_from_yaml(&template_directory_yaml, TEMPLATE_DIRECTORY, &config_path)?;

    Ok(Directories {
        content: content_directory,
        output: output_directory,
        template: template_directory,
    })
}

/// Load the site data from the configuration file.
fn site(config_map: &BTreeMap<Yaml, Yaml>) -> Result<Site, String> {
    // TODO: build these.
    let name = String::new();
    let description = String::new();
    let metadata = HashMap::new();
    let url = ValidatedUrl::new(String::new())?;

    Ok(Site {
        name: name,
        description: description,
        metadata: metadata,
        url: url,
    })
}

fn taxonomies(config_map: &BTreeMap<Yaml, Yaml>) -> Result<Vec<Taxonomy>, String> {
    // TODO: actually load these.
    Ok(Vec::new())
}

pub fn load(directory: &PathBuf) -> Result<Config, String> {
    let config_path = directory.join(CONFIG_FILE_NAME);
    if !config_path.exists() {
        return Err(format!("The specified configuration path {:?} does not exist.",
                           config_path.to_string_lossy()));
    }

    let mut file = File::open(&config_path)
        .map_err(|reason| format!("Error reading {:?}: {:?}", config_path, reason))?;

    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(_) => (),
        Err(err) => return Err(String::from(err.description())),
    };

    // We need all these intermediate bindings because the temporaries created
    // along the way don't live long enough otherwise.
    let yaml_config = YamlLoader::load_from_str(&contents)
        .map_err(|err| format!("{} ({:?})", err, &config_path))?;
    let yaml_config = yaml_config.into_iter().next().ok_or("Empty configuration file")?;
    let yaml_config = yaml_config.as_hash().ok_or("Configuration is not a map")?;

    Ok(Config {
        site: site(yaml_config)?,
        directories: directories(yaml_config, &config_path)?,
        taxonomies: taxonomies(yaml_config)?,
    })
}
<|endoftext|>


<commit_before>use gcrypt;
use gcrypt::mpi;
use gcrypt::sexp;
use gcrypt::digest;

use pgp;

pub type Token = gcrypt::Token;
pub type Result<T> = gcrypt::error::Result<T>;

pub struct PubKey {
    key: sexp::SExpression,
    token: Token,
}

pub struct PrivKey {
    key: sexp::SExpression,
    token: Token,
}

impl PubKey {
    pub fn from_pgp(key: &pgp::PublicKey, token: Token) -> Result<PubKey> {
        let n = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.n));
        let e = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.e));
        let template = try!(sexp::Template::new("(public-key (rsa (n %m) (e %m)))"));
        let mut builder = sexp::Builder::from(&template);
        builder
            .add_mpi(&n)
            .add_mpi(&e);
        let sexp = try!(builder.build(token));
        Ok(PubKey{key: sexp, token: token})
    }

    pub fn verify(&self, signature: &[u8], data: &[u8]) -> Result<()> {
        let sig = try!(mpi::Integer::from_bytes(self.token, mpi::integer::Format::Standard, signature));
        let sig_template = try!(sexp::Template::new("(sig-val (rsa (s %m)))"));
        let mut sig_builder = sexp::Builder::from(&sig_template);
        sig_builder.add_mpi(&sig);
        let sig_sexp = try!(sig_builder.build(self.token));

        let hash = try!(sha1(data, self.token));
        let template = try!(sexp::Template::new("(data (flags pkcs1) (hash sha1 %b))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_bytes(&hash);
        let data_sexp = try!(builder.build(self.token));

        self.key.verify(&sig_sexp, &data_sexp)
    }

    pub fn encrypt(&self, data: &[u8]) -> Result<gcrypt::Buffer> {
        let template = try!(sexp::Template::new("(data (flags pkcs1) (value %b))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_bytes(data);
        let data_sexp = try!(builder.build(self.token));
        let result = try!(self.key.encrypt(&data_sexp));
        result.find_token("a").unwrap()
            .get_integer(1, mpi::integer::Format::Standard).unwrap()
            .to_bytes(mpi::integer::Format::Standard)
    }

    pub fn blocklen(&self) -> usize {
        let remainder = self.key.num_bits().unwrap_or(0) % 8;
        let keybytes = self.key.num_bits().unwrap_or(0) / 8;
        if remainder != 0 { keybytes + 1 } else { keybytes }
    }
}

impl PrivKey {
    pub fn from_pgp(key: &pgp::PrivateKey, token: Token) -> Result<PrivKey> {
        // TODO: I don't think this is putting the MPI into secure memory
        let n = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.public.n));
        let e = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.public.e));
        let d = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.d));
        let p = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.p));
        let q = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.q));
        let u = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Standard, &key.u));
        let template = try!(sexp::Template::new("(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))"));
        let mut builder = sexp::Builder::from(&template);
        builder
            .add_mpi(&n)
            .add_mpi(&e)
            .add_mpi(&d)
            .add_mpi(&p)
            .add_mpi(&q)
            .add_mpi(&u);
        let sexp = try!(builder.build(token));
        Ok(PrivKey{key: sexp, token: token})
    }

    pub fn sign(&self, data: &[u8]) -> Result<gcrypt::Buffer> {
        let hash = try!(sha1(data, self.token));
        try!(self.key.test_key());
        let template = try!(sexp::Template::new("(data (flags pkcs1) (hash sha1 %b))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_bytes(&hash);
        let data_sexp = try!(builder.build(self.token));
        let result = try!(self.key.sign(&data_sexp));
        result.find_token("s").unwrap()
            .get_integer(1, mpi::integer::Format::Standard).unwrap()
            .to_bytes(mpi::integer::Format::Standard)
    }

    pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>> {
        let a = try!(mpi::Integer::from_bytes(self.token, mpi::integer::Format::Standard, data));
        let template = try!(sexp::Template::new("(enc-val (flags pkcs1) (rsa (a %m)))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_mpi(&a);
        let data_sexp = try!(builder.build(self.token));
        let result = try!(self.key.decrypt(&data_sexp));
        Ok(result.find_token("value").unwrap().get_bytes(1).unwrap().to_owned())
    }

    pub fn blocklen(&self) -> usize {
        let remainder = self.key.num_bits().unwrap_or(0) % 8;
        let keybytes = self.key.num_bits().unwrap_or(0) / 8;
        if remainder != 0 { keybytes + 1 } else { keybytes }
    }
}

pub fn sha1(bytes: &[u8], token: Token) -> Result<Vec<u8>> {
    let algo = digest::MD_SHA1;
    let mut sha = try!(digest::MessageDigest::new(token, algo, gcrypt::digest::Flags::empty()));
    sha.write(bytes);
    Ok(sha.get_digest(algo).unwrap().to_owned())
}
<commit_msg>Treat all RSA keys and output values as unsigned numbers<commit_after>use gcrypt;
use gcrypt::mpi;
use gcrypt::sexp;
use gcrypt::digest;

use pgp;

pub type Token = gcrypt::Token;
pub type Result<T> = gcrypt::error::Result<T>;

pub struct PubKey {
    key: sexp::SExpression,
    token: Token,
}

pub struct PrivKey {
    key: sexp::SExpression,
    token: Token,
}

impl PubKey {
    pub fn from_pgp(key: &pgp::PublicKey, token: Token) -> Result<PubKey> {
        let n = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.n));
        let e = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.e));
        let template = try!(sexp::Template::new("(public-key (rsa (n %m) (e %m)))"));
        let mut builder = sexp::Builder::from(&template);
        builder
            .add_mpi(&n)
            .add_mpi(&e);
        let sexp = try!(builder.build(token));
        Ok(PubKey{key: sexp, token: token})
    }

    pub fn verify(&self, signature: &[u8], data: &[u8]) -> Result<()> {
        let sig = try!(mpi::Integer::from_bytes(self.token, mpi::integer::Format::Unsigned, signature));
        let sig_template = try!(sexp::Template::new("(sig-val (rsa (s %m)))"));
        let mut sig_builder = sexp::Builder::from(&sig_template);
        sig_builder.add_mpi(&sig);
        let sig_sexp = try!(sig_builder.build(self.token));

        let hash = try!(sha1(data, self.token));
        let template = try!(sexp::Template::new("(data (flags pkcs1) (hash sha1 %b))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_bytes(&hash);
        let data_sexp = try!(builder.build(self.token));

        self.key.verify(&sig_sexp, &data_sexp)
    }

    pub fn encrypt(&self, data: &[u8]) -> Result<gcrypt::Buffer> {
        let template = try!(sexp::Template::new("(data (flags pkcs1) (value %b))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_bytes(data);
        let data_sexp = try!(builder.build(self.token));
        let result = try!(self.key.encrypt(&data_sexp));
        result.find_token("a").unwrap()
            .get_integer(1, mpi::integer::Format::Unsigned).unwrap()
            .to_bytes(mpi::integer::Format::Unsigned)
    }

    pub fn blocklen(&self) -> usize {
        let remainder = self.key.num_bits().unwrap_or(0) % 8;
        let keybytes = self.key.num_bits().unwrap_or(0) / 8;
        if remainder != 0 { keybytes + 1 } else { keybytes }
    }
}

impl PrivKey {
    pub fn from_pgp(key: &pgp::PrivateKey, token: Token) -> Result<PrivKey> {
        // TODO: I don't think this is putting the MPI into secure memory
        let n = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.public.n));
        let e = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.public.e));
        let d = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.d));
        let p = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.p));
        let q = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.q));
        let u = try!(mpi::Integer::from_bytes(token, mpi::integer::Format::Unsigned, &key.u));
        let template = try!(sexp::Template::new("(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))"));
        let mut builder = sexp::Builder::from(&template);
        builder
            .add_mpi(&n)
            .add_mpi(&e)
            .add_mpi(&d)
            .add_mpi(&p)
            .add_mpi(&q)
            .add_mpi(&u);
        let sexp = try!(builder.build(token));
        Ok(PrivKey{key: sexp, token: token})
    }

    pub fn sign(&self, data: &[u8]) -> Result<gcrypt::Buffer> {
        let hash = try!(sha1(data, self.token));
        try!(self.key.test_key());
        let template = try!(sexp::Template::new("(data (flags pkcs1) (hash sha1 %b))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_bytes(&hash);
        let data_sexp = try!(builder.build(self.token));
        let result = try!(self.key.sign(&data_sexp));
        result.find_token("s").unwrap()
            .get_integer(1, mpi::integer::Format::Unsigned).unwrap()
            .to_bytes(mpi::integer::Format::Unsigned)
    }

    pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>> {
        let a = try!(mpi::Integer::from_bytes(self.token, mpi::integer::Format::Unsigned, data));
        let template = try!(sexp::Template::new("(enc-val (flags pkcs1) (rsa (a %m)))"));
        let mut builder = sexp::Builder::from(&template);
        builder.add_mpi(&a);
        let data_sexp = try!(builder.build(self.token));
        let result = try!(self.key.decrypt(&data_sexp));
        Ok(result.find_token("value").unwrap().get_bytes(1).unwrap().to_owned())
    }

    pub fn blocklen(&self) -> usize {
        let remainder = self.key.num_bits().unwrap_or(0) % 8;
        let keybytes = self.key.num_bits().unwrap_or(0) / 8;
        if remainder != 0 { keybytes + 1 } else { keybytes }
    }
}

pub fn sha1(bytes: &[u8], token: Token) -> Result<Vec<u8>> {
    let algo = digest::MD_SHA1;
    let mut sha = try!(digest::MessageDigest::new(token, algo, gcrypt::digest::Flags::empty()));
    sha.write(bytes);
    Ok(sha.get_digest(algo).unwrap().to_owned())
}
<|endoftext|>


<commit_before>//! Cursor movement.

use std::fmt;
use std::io::{self, Write, Error, ErrorKind, Read};
use async::async_stdin;
use std::time::{SystemTime, Duration};
use raw::CONTROL_SEQUENCE_TIMEOUT;

derive_csi_sequence!("Hide the cursor.", Hide, "?25l");
derive_csi_sequence!("Show the cursor.", Show, "?25h");

/// Goto some position ((1,1)-based).
///
/// # Why one-based?
///
/// ANSI escapes are very poorly designed, and one of the many odd aspects is being one-based. This
/// can be quite strange at first, but it is not that big of an obstruction once you get used to
/// it.
///
/// # Example
///
/// ```rust
/// extern crate termion;
///
/// fn main() {
///     print!("{}{}Stuff", termion::clear::All, termion::cursor::Goto(5, 3));
/// }
/// ```
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Goto(pub u16, pub u16);

impl Default for Goto {
    fn default() -> Goto {
        Goto(1, 1)
    }
}

impl fmt::Display for Goto {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        debug_assert!(self != &Goto(0, 0), "Goto is one-based.");

        write!(f, csi!("{};{}H"), self.1, self.0)
    }
}

/// Move cursor left.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Left(pub u16);

impl fmt::Display for Left {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}D"), self.0)
    }
}

/// Move cursor right.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Right(pub u16);

impl fmt::Display for Right {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}C"), self.0)
    }
}

/// Move cursor up.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Up(pub u16);

impl fmt::Display for Up {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}A"), self.0)
    }
}

/// Move cursor down.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Down(pub u16);

impl fmt::Display for Down {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}B"), self.0)
    }
}

/// Types that allow detection of the cursor position.
pub trait DetectCursorPos {
    /// Get the (1,1)-based cursor position from the terminal.
    fn cursor_pos(&mut self) -> io::Result<(u16, u16)>;
}

impl<W: Write> DetectCursorPos for W {
    fn cursor_pos(&mut self) -> io::Result<(u16, u16)> {
        let mut stdin = async_stdin();

        // Where is the cursor?
        // Use `ESC [ 6 n`.
        write!(self, "\x1B[6n")?;
        self.flush()?;

        let mut buf: [u8; 1] = [0];
        let mut read_chars = Vec::new();

        let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT);
        let now = SystemTime::now();

        // Either consume all data up to R or wait for a timeout.
        while buf[0] != b'R' && now.elapsed().unwrap() < timeout {
            if stdin.read(&mut buf)? > 0 {
                read_chars.push(buf[0]);
            }
        }

        if read_chars.len() == 0 {
            return Err(Error::new(ErrorKind::Other, "Cursor position detection timed out."));
        }

        // The answer will look like `ESC [ Cy ; Cx R`.

        read_chars.pop(); // remove trailing R.
        let read_str = String::from_utf8(read_chars).unwrap();
        let beg = read_str.rfind('[').unwrap();
        let coords: String = read_str.chars().skip(beg + 1).collect();
        let mut nums = coords.split(';');

        let cy = nums.next()
            .unwrap()
            .parse::<u16>()
            .unwrap();
        let cx = nums.next()
            .unwrap()
            .parse::<u16>()
            .unwrap();

        Ok((cx, cy))
    }
}
<commit_msg>Implement hide cursor wrapper type<commit_after>//! Cursor movement.

use std::fmt;
use std::ops;
use std::io::{self, Write, Error, ErrorKind, Read};
use async::async_stdin;
use std::time::{SystemTime, Duration};
use raw::CONTROL_SEQUENCE_TIMEOUT;

derive_csi_sequence!("Hide the cursor.", Hide, "?25l");
derive_csi_sequence!("Show the cursor.", Show, "?25h");

/// Goto some position ((1,1)-based).
///
/// # Why one-based?
///
/// ANSI escapes are very poorly designed, and one of the many odd aspects is being one-based. This
/// can be quite strange at first, but it is not that big of an obstruction once you get used to
/// it.
///
/// # Example
///
/// ```rust
/// extern crate termion;
///
/// fn main() {
///     print!("{}{}Stuff", termion::clear::All, termion::cursor::Goto(5, 3));
/// }
/// ```
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Goto(pub u16, pub u16);

impl Default for Goto {
    fn default() -> Goto {
        Goto(1, 1)
    }
}

impl fmt::Display for Goto {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        debug_assert!(self != &Goto(0, 0), "Goto is one-based.");

        write!(f, csi!("{};{}H"), self.1, self.0)
    }
}

/// Move cursor left.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Left(pub u16);

impl fmt::Display for Left {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}D"), self.0)
    }
}

/// Move cursor right.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Right(pub u16);

impl fmt::Display for Right {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}C"), self.0)
    }
}

/// Move cursor up.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Up(pub u16);

impl fmt::Display for Up {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}A"), self.0)
    }
}

/// Move cursor down.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Down(pub u16);

impl fmt::Display for Down {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("{}B"), self.0)
    }
}

/// Types that allow detection of the cursor position.
pub trait DetectCursorPos {
    /// Get the (1,1)-based cursor position from the terminal.
    fn cursor_pos(&mut self) -> io::Result<(u16, u16)>;
}

impl<W: Write> DetectCursorPos for W {
    fn cursor_pos(&mut self) -> io::Result<(u16, u16)> {
        let mut stdin = async_stdin();

        // Where is the cursor?
        // Use `ESC [ 6 n`.
        write!(self, "\x1B[6n")?;
        self.flush()?;

        let mut buf: [u8; 1] = [0];
        let mut read_chars = Vec::new();

        let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT);
        let now = SystemTime::now();

        // Either consume all data up to R or wait for a timeout.
        while buf[0] != b'R' && now.elapsed().unwrap() < timeout {
            if stdin.read(&mut buf)? > 0 {
                read_chars.push(buf[0]);
            }
        }

        if read_chars.len() == 0 {
            return Err(Error::new(ErrorKind::Other, "Cursor position detection timed out."));
        }

        // The answer will look like `ESC [ Cy ; Cx R`.

        read_chars.pop(); // remove trailing R.
        let read_str = String::from_utf8(read_chars).unwrap();
        let beg = read_str.rfind('[').unwrap();
        let coords: String = read_str.chars().skip(beg + 1).collect();
        let mut nums = coords.split(';');

        let cy = nums.next()
            .unwrap()
            .parse::<u16>()
            .unwrap();
        let cx = nums.next()
            .unwrap()
            .parse::<u16>()
            .unwrap();

        Ok((cx, cy))
    }
}

/// Hide the cursor for the lifetime of this struct.
/// It will hide the cursor on creation with from() and show it back on drop().
pub struct HideCursor<W: Write> {
    /// The output target.
    output: W,
}

impl<W: Write> HideCursor<W> {
    /// Create a hide cursor wrapper struct for the provided output and hides the cursor.
    pub fn from(mut output: W) -> Self {
        write!(output, "{}", Hide).expect("hide the cursor");
        HideCursor { output: output }
    }
}

impl<W: Write> Drop for HideCursor<W> {
    fn drop(&mut self) {
        write!(self, "{}", Show).expect("show the cursor");
    }
}

impl<W: Write> ops::Deref for HideCursor<W> {
    type Target = W;

    fn deref(&self) -> &W {
        &self.output
    }
}

impl<W: Write> ops::DerefMut for HideCursor<W> {
    fn deref_mut(&mut self) -> &mut W {
        &mut self.output
    }
}

impl<W: Write> Write for HideCursor<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.output.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.output.flush()
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::ptr;
use libc::{c_void, size_t, c_int};
use libc::{PROT_READ, PROT_WRITE};
use libc::{MAP_PRIVATE, MAP_ANONYMOUS, MAP_GROWSDOWN, MAP_STACK};
use libc::{CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, SIGCHLD};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};

fn mmap_stack(stack_size: size_t) -> *mut c_void {
    unsafe {
        let p = libc::mmap(ptr::null_mut(), stack_size, PROT_READ | PROT_WRITE,
                           MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_STACK, -1, 0);
        assert!(p != libc::MAP_FAILED);
        //TODO add guard pages
        p
    }

}

// a lot copied from man USER_NAMESPACES(7)

use std::thread;

extern "C" fn child_func(args: *mut c_void) -> c_int {
    println!("I'm called from child_func");

    let args = args as *mut ChildArgs;
    let r_pipe_fd = unsafe { (*args).r_pipe_fd };
    let w_pipe_fd = unsafe { (*args).w_pipe_fd };
    println!("r_pipe_fd: {}", r_pipe_fd);

    // run everything in a new thread so exceptions bubble up to rust
    let h = thread::spawn(move || {
        // wait for parent
        println!("waiting for parent to set up mapping, ...");
        assert_eq!(unsafe { libc::close(w_pipe_fd) } , 0);
        unsafe {
            let mut buf = 0u8;
            libc::read(r_pipe_fd, (&mut buf) as *mut u8 as *mut c_void, 1);
        }

        {
            println!("Child status");
            let mut fstatus = File::open("/proc/self/status").expect("open status");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                if l.starts_with("Seccomp") || l.starts_with("Cap"){
                    println!("{}", l);
                }
            }
        }

        panic!("Oops!");
    });

    match h.join() {
        Ok(_) => 0,
        Err(_) => 1,
    }
}

struct ChildArgs {
    r_pipe_fd: c_int,
    w_pipe_fd: c_int,
}

fn write(path: &String, content: &[u8]) {
    println!("Writing to {}", path);
    let mut file = OpenOptions::new().read(false).write(true).create(false).open(path).expect("open");
    // needs to happen in one write call
    assert_eq!(file.write(content).expect("write"), content.len());
    //file gets dropped
}
fn main() {
    println!("Hello, world!");

    let mut pipe_fd = vec![0;2];  /* Pipe used to synchronize parent and child */
    assert_eq!(unsafe { libc::pipe(pipe_fd.as_mut_ptr()) }, 0);
    println!("r pipe: {} w pipe: {}", pipe_fd[0], pipe_fd[1]);
    let ptr_child_args = {
        let child_args = Box::new(ChildArgs { r_pipe_fd: pipe_fd[0], w_pipe_fd: pipe_fd[1]});
        Box::into_raw(child_args) as *mut c_void
    };

    let stack_size = 4 * 1024 * 1024;
    let child_stack = mmap_stack(stack_size);

    // stack grows down
    let child_stack_top = unsafe { child_stack.offset(stack_size as isize) };

    let child_pid = unsafe {
        libc::clone(child_func, child_stack_top, CLONE_NEWUSER|CLONE_NEWNS|CLONE_NEWPID|SIGCHLD, ptr_child_args)
    };
    assert!(child_pid != -1);

    let uid = unsafe { libc::getuid() };
    write(&format!("/proc/{}/uid_map", child_pid), &format!("0 {} 1", uid).into_bytes());

    //proc_setgroups_write man user_namespaces
    write(&format!("/proc/{}/setgroups", child_pid), &format!("deny").into_bytes());

    let gid = unsafe { libc::getgid() };
    write(&format!("/proc/{}/gid_map", child_pid), &format!("0 {} 1", gid).into_bytes());

    //unleash child
    assert_eq!(unsafe { libc::close(pipe_fd[1]) }, 0);

    let mut child_status: c_int = 0;
    assert!(unsafe { libc::waitpid(child_pid, &mut child_status, 0) } != -1);
    println!("Child terminated: {}", child_status);

    unsafe {
        drop(Box::from_raw(ptr_child_args));
    }

    //TODO munmap child_stack
}
<commit_msg>setting up child stack correctly<commit_after>extern crate libc;

use std::ptr;
use libc::{c_void, size_t, c_int};
use libc::{PROT_READ, PROT_WRITE, PROT_NONE};
use libc::{MAP_PRIVATE, MAP_ANONYMOUS, MAP_GROWSDOWN, MAP_STACK};
use libc::{CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, SIGCHLD};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};

struct Stack {
    p: *mut c_void,
    len: usize,
    pub top: *mut c_void,
}

impl Stack {
    fn new(stack_size: size_t) -> Self {
        //TODO what if stack size is not a mupltiple of pagesize?
        let pagesize = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
        assert!(pagesize > 1);
        let pagesize = pagesize as usize;
        println!("Pagesize is {}k", pagesize / 1024);
        let len = stack_size + 2*pagesize; // guard pages

        let p = unsafe {
            let p = libc::mmap(ptr::null_mut(),
                               len,
                               PROT_READ | PROT_WRITE,
                               MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_STACK, -1, 0);
            assert!(p != libc::MAP_FAILED);
            assert_eq!(p as usize % pagesize, 0); // aligned to page boundary
            p
        };

        // guard pages
        assert_eq!(unsafe { libc::mprotect(p, pagesize, PROT_NONE) }, 0);
        let start_of_end = p as usize + pagesize + (stack_size / pagesize)*pagesize;
        assert_eq!(unsafe { libc::mprotect(start_of_end as *mut c_void, pagesize, PROT_NONE) }, 0);

        // stack grows down
        let stack_top = p as usize + pagesize + stack_size;

        Stack{ p:p, len:len, top:stack_top as *mut c_void }
    }
}

impl Drop for Stack {
    fn drop(&mut self) {
        println!("munmap stack");
        assert_eq!(unsafe { libc::munmap(self.p, self.len) }, 0);
    }
}

// a lot copied from man USER_NAMESPACES(7)

use std::thread;

extern "C" fn child_func(args: *mut c_void) -> c_int {
    println!("I'm called from child_func");

    let args = args as *mut ChildArgs;
    let r_pipe_fd = unsafe { (*args).r_pipe_fd };
    let w_pipe_fd = unsafe { (*args).w_pipe_fd };
    println!("r_pipe_fd: {}", r_pipe_fd);

    // run everything in a new thread so exceptions bubble up to rust
    let h = thread::spawn(move || {
        // wait for parent
        println!("waiting for parent to set up mapping, ...");
        assert_eq!(unsafe { libc::close(w_pipe_fd) } , 0);
        unsafe {
            let mut buf = 0u8;
            libc::read(r_pipe_fd, (&mut buf) as *mut u8 as *mut c_void, 1);
        }

        {
            println!("Child status");
            let mut fstatus = File::open("/proc/self/status").expect("open status");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                if l.starts_with("Seccomp") || l.starts_with("Cap"){
                    println!("{}", l);
                }
            }
        }

        panic!("Oops!");
    });

    match h.join() {
        Ok(_) => 0,
        Err(_) => 1,
    }
}

struct ChildArgs {
    r_pipe_fd: c_int,
    w_pipe_fd: c_int,
}

fn write(path: &String, content: &[u8]) {
    println!("Writing to {}", path);
    let mut file = OpenOptions::new().read(false).write(true).create(false).open(path).expect("open");
    // needs to happen in one write call
    assert_eq!(file.write(content).expect("write"), content.len());
    //file gets dropped
}
fn main() {
    println!("Hello, world!");

    let mut pipe_fd = vec![0;2];  /* Pipe used to synchronize parent and child */
    assert_eq!(unsafe { libc::pipe(pipe_fd.as_mut_ptr()) }, 0);
    println!("r pipe: {} w pipe: {}", pipe_fd[0], pipe_fd[1]);
    let ptr_child_args = {
        let child_args = Box::new(ChildArgs { r_pipe_fd: pipe_fd[0], w_pipe_fd: pipe_fd[1]});
        Box::into_raw(child_args) as *mut c_void
    };

    let stack_size = 4*1024*1024;
    let child_stack = Stack::new(stack_size);

    let child_pid = unsafe {
        libc::clone(child_func, child_stack.top, CLONE_NEWUSER|CLONE_NEWNS|CLONE_NEWPID|SIGCHLD, ptr_child_args)
    };
    assert!(child_pid != -1);

    let uid = unsafe { libc::getuid() };
    write(&format!("/proc/{}/uid_map", child_pid), &format!("0 {} 1", uid).into_bytes());

    //proc_setgroups_write man user_namespaces
    write(&format!("/proc/{}/setgroups", child_pid), &format!("deny").into_bytes());

    let gid = unsafe { libc::getgid() };
    write(&format!("/proc/{}/gid_map", child_pid), &format!("0 {} 1", gid).into_bytes());

    //unleash child
    assert_eq!(unsafe { libc::close(pipe_fd[1]) }, 0);

    let mut child_status: c_int = 0;
    assert!(unsafe { libc::waitpid(child_pid, &mut child_status, 0) } != -1);
    println!("Child terminated: {}", child_status);

    unsafe {
        drop(Box::from_raw(ptr_child_args));
    }

    //child_stack gets unmapped
}
<|endoftext|>


<commit_before>use futures_01::executor::{
    Spawn as Spawn01, spawn as spawn01,
    UnsafeNotify as UnsafeNotify01,
    Notify as Notify01,
    NotifyHandle as NotifyHandle01,
};
use futures_01::{Async as Async01, Future as Future01, Stream as Stream01};
use futures_core::{task as task03, Future as Future03, Stream as Stream03};
use std::mem;
use std::task::{LocalWaker, Waker};
use std::pin::{Pin, Unpin};

/// Converts a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
/// object to a futures 0.3-compatible version,
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat01As03<T> {
    pub(crate) inner: Spawn01<T>,
}

impl<T> Unpin for Compat01As03<T> {}

impl<T> Compat01As03<T> {
    /// Wraps a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
    /// object in a futures 0.3-compatible wrapper.
    pub fn new(object: T) -> Compat01As03<T> {
        Compat01As03 {
            inner: spawn01(object),
        }
    }

    fn in_notify<R>(&mut self, lw: &LocalWaker, f: impl FnOnce(&mut T) -> R) -> R {
        let notify = &WakerToHandle(lw.as_waker());
        self.inner.poll_fn_notify(notify, 0, f)
    }
}

/// Extension trait for futures 0.1 [`Future`](futures::future::Future)
pub trait Future01CompatExt: Future01 {
    /// Converts a futures 0.1
    /// [`Future<Item = T, Error = E>`](futures::future::Future)
    /// into a futures 0.3
    /// [`Future<Output = Result<T, E>>`](futures_core::future::Future).
    fn compat(self) -> Compat01As03<Self> where Self: Sized {
        Compat01As03::new(self)
    }
}
impl<Fut: Future01> Future01CompatExt for Fut {}

/// Extension trait for futures 0.1 [`Stream`](futures::stream::Stream)
pub trait Stream01CompatExt: Stream01 {
    /// Converts a futures 0.1
    /// [`Stream<Item = T, Error = E>`](futures::stream::Stream)
    /// into a futures 0.3
    /// [`Stream<Item = Result<T, E>>`](futures_core::stream::Stream).
    fn compat(self) -> Compat01As03<Self> where Self: Sized {
        Compat01As03::new(self)
    }
}
impl<St: Stream01> Stream01CompatExt for St {}

fn poll_01_to_03<T, E>(x: Result<Async01<T>, E>)
    -> task03::Poll<Result<T, E>>
{
    match x {
        Ok(Async01::Ready(t)) => task03::Poll::Ready(Ok(t)),
        Ok(Async01::NotReady) => task03::Poll::Pending,
        Err(e) => task03::Poll::Ready(Err(e)),
    }
}

impl<Fut: Future01> Future03 for Compat01As03<Fut> {
    type Output = Result<Fut::Item, Fut::Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Self::Output> {
        poll_01_to_03(self.in_notify(lw, |f| f.poll()))
    }
}

impl<St: Stream01> Stream03 for Compat01As03<St> {
    type Item = Result<St::Item, St::Error>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Option<Self::Item>> {
        match self.in_notify(lw, |f| f.poll()) {
            Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
            Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
            Ok(Async01::NotReady) => task03::Poll::Pending,
            Err(e) => task03::Poll::Ready(Some(Err(e))),
        }
    }
}

struct NotifyWaker(task03::Waker);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a task03::Waker);

impl<'a> From<WakerToHandle<'a>> for NotifyHandle01 {
    fn from(handle: WakerToHandle<'a>) -> NotifyHandle01 {
        let ptr = Box::new(NotifyWaker(handle.0.clone()));

        unsafe { NotifyHandle01::new(Box::into_raw(ptr)) }
    }
}

impl Notify01 for NotifyWaker {
    fn notify(&self, _: usize) {
        self.0.wake();
    }
}

unsafe impl UnsafeNotify01 for NotifyWaker {
    unsafe fn clone_raw(&self) -> NotifyHandle01 {
        WakerToHandle(&self.0).into()
    }

    unsafe fn drop_raw(&self) {
        let ptr: *const dyn UnsafeNotify01 = self;
        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify01));
    }
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{
        AsyncRead as AsyncRead03,
        AsyncWrite as AsyncWrite03,
        Initializer,
    };
    use std::io::Error;
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    impl<R: AsyncRead01> AsyncRead03 for Compat01As03<R> {
        unsafe fn initializer(&self) -> Initializer {
            // check if `prepare_uninitialized_buffer` needs zeroing
            if self.inner.get_ref().prepare_uninitialized_buffer(&mut [1]) {
                Initializer::zeroing()
            } else {
                Initializer::nop()
            }
        }

        fn poll_read(&mut self, lw: &task03::LocalWaker, buf: &mut [u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.poll_read(buf)))
        }
    }

    impl<W: AsyncWrite01> AsyncWrite03 for Compat01As03<W> {
        fn poll_write(&mut self, lw: &task03::LocalWaker, buf: &[u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.poll_write(buf)))
        }

        fn poll_flush(&mut self, lw: &task03::LocalWaker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.poll_flush()))
        }

        fn poll_close(&mut self, lw: &task03::LocalWaker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.shutdown()))
        }
    }
}
<commit_msg>Resolved a pair of unused import warnings<commit_after>use futures_01::executor::{
    Spawn as Spawn01, spawn as spawn01,
    UnsafeNotify as UnsafeNotify01,
    Notify as Notify01,
    NotifyHandle as NotifyHandle01,
};
use futures_01::{Async as Async01, Future as Future01, Stream as Stream01};
use futures_core::{task as task03, Future as Future03, Stream as Stream03};
use std::task::LocalWaker;
use std::pin::{Pin, Unpin};

/// Converts a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
/// object to a futures 0.3-compatible version,
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat01As03<T> {
    pub(crate) inner: Spawn01<T>,
}

impl<T> Unpin for Compat01As03<T> {}

impl<T> Compat01As03<T> {
    /// Wraps a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
    /// object in a futures 0.3-compatible wrapper.
    pub fn new(object: T) -> Compat01As03<T> {
        Compat01As03 {
            inner: spawn01(object),
        }
    }

    fn in_notify<R>(&mut self, lw: &LocalWaker, f: impl FnOnce(&mut T) -> R) -> R {
        let notify = &WakerToHandle(lw.as_waker());
        self.inner.poll_fn_notify(notify, 0, f)
    }
}

/// Extension trait for futures 0.1 [`Future`](futures::future::Future)
pub trait Future01CompatExt: Future01 {
    /// Converts a futures 0.1
    /// [`Future<Item = T, Error = E>`](futures::future::Future)
    /// into a futures 0.3
    /// [`Future<Output = Result<T, E>>`](futures_core::future::Future).
    fn compat(self) -> Compat01As03<Self> where Self: Sized {
        Compat01As03::new(self)
    }
}
impl<Fut: Future01> Future01CompatExt for Fut {}

/// Extension trait for futures 0.1 [`Stream`](futures::stream::Stream)
pub trait Stream01CompatExt: Stream01 {
    /// Converts a futures 0.1
    /// [`Stream<Item = T, Error = E>`](futures::stream::Stream)
    /// into a futures 0.3
    /// [`Stream<Item = Result<T, E>>`](futures_core::stream::Stream).
    fn compat(self) -> Compat01As03<Self> where Self: Sized {
        Compat01As03::new(self)
    }
}
impl<St: Stream01> Stream01CompatExt for St {}

fn poll_01_to_03<T, E>(x: Result<Async01<T>, E>)
    -> task03::Poll<Result<T, E>>
{
    match x {
        Ok(Async01::Ready(t)) => task03::Poll::Ready(Ok(t)),
        Ok(Async01::NotReady) => task03::Poll::Pending,
        Err(e) => task03::Poll::Ready(Err(e)),
    }
}

impl<Fut: Future01> Future03 for Compat01As03<Fut> {
    type Output = Result<Fut::Item, Fut::Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Self::Output> {
        poll_01_to_03(self.in_notify(lw, |f| f.poll()))
    }
}

impl<St: Stream01> Stream03 for Compat01As03<St> {
    type Item = Result<St::Item, St::Error>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Option<Self::Item>> {
        match self.in_notify(lw, |f| f.poll()) {
            Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
            Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
            Ok(Async01::NotReady) => task03::Poll::Pending,
            Err(e) => task03::Poll::Ready(Some(Err(e))),
        }
    }
}

struct NotifyWaker(task03::Waker);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a task03::Waker);

impl<'a> From<WakerToHandle<'a>> for NotifyHandle01 {
    fn from(handle: WakerToHandle<'a>) -> NotifyHandle01 {
        let ptr = Box::new(NotifyWaker(handle.0.clone()));

        unsafe { NotifyHandle01::new(Box::into_raw(ptr)) }
    }
}

impl Notify01 for NotifyWaker {
    fn notify(&self, _: usize) {
        self.0.wake();
    }
}

unsafe impl UnsafeNotify01 for NotifyWaker {
    unsafe fn clone_raw(&self) -> NotifyHandle01 {
        WakerToHandle(&self.0).into()
    }

    unsafe fn drop_raw(&self) {
        let ptr: *const dyn UnsafeNotify01 = self;
        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify01));
    }
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{
        AsyncRead as AsyncRead03,
        AsyncWrite as AsyncWrite03,
        Initializer,
    };
    use std::io::Error;
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    impl<R: AsyncRead01> AsyncRead03 for Compat01As03<R> {
        unsafe fn initializer(&self) -> Initializer {
            // check if `prepare_uninitialized_buffer` needs zeroing
            if self.inner.get_ref().prepare_uninitialized_buffer(&mut [1]) {
                Initializer::zeroing()
            } else {
                Initializer::nop()
            }
        }

        fn poll_read(&mut self, lw: &task03::LocalWaker, buf: &mut [u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.poll_read(buf)))
        }
    }

    impl<W: AsyncWrite01> AsyncWrite03 for Compat01As03<W> {
        fn poll_write(&mut self, lw: &task03::LocalWaker, buf: &[u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.poll_write(buf)))
        }

        fn poll_flush(&mut self, lw: &task03::LocalWaker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.poll_flush()))
        }

        fn poll_close(&mut self, lw: &task03::LocalWaker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(lw, |x| x.shutdown()))
        }
    }
}
<|endoftext|>


<commit_before>//! BookmarkCollection module
//!
//! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions
//! from the libimagentrylink::external::ExternalLinker trait on this to generate external links.
//!
//! The BookmarkCollection type offers helper functions to get all links or such things.
use std::ops::Deref;
use std::ops::DerefMut;

use error::BookmarkError as BE;
use error::BookmarkErrorKind as BEK;
use error::MapErrInto;
use result::Result;
use module_path::ModuleEntryPath;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentrylink::internal::Link;
use libimagerror::into::IntoError;
use url::Url;

pub struct BookmarkCollection<'a> {
    fle: FileLockEntry<'a>,
    store: &'a Store,
}

/// {Internal, External}Linker is implemented as Deref is implemented
impl<'a> Deref for BookmarkCollection<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.fle
    }

}

impl<'a> DerefMut for BookmarkCollection<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.fle
    }

}

impl<'a> BookmarkCollection<'a> {

    pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.create(id)
            .map(|fle| {
                BookmarkCollection {
                    fle: fle,
                    store: store,
                }
            })
            .map_err_into(BEK::StoreReadError)
    }

    pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.get(id)
            .map_err_into(BEK::StoreReadError)
            .and_then(|fle| {
                match fle {
                    None => Err(BEK::CollectionNotFound.into_error()),
                    Some(e) => Ok(BookmarkCollection {
                        fle: e,
                        store: store,
                    }),
                }
            })
    }

    pub fn delete(store: &Store, name: &str) -> Result<()> {
        unimplemented!()
    }

    pub fn links(&self) -> Result<Vec<Url>> {
        self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
    }

    pub fn link_entries(&self) -> Result<Vec<Link>> {
        use libimagentrylink::external::is_external_link_storeid;

        self.fle
            .get_internal_links()
            .map(|v| v.into_iter().filter(|id| is_external_link_storeid(id)).collect())
            .map_err_into(BEK::StoreReadError)
    }

}

<commit_msg>Impl BookmarkCollection::delete()<commit_after>//! BookmarkCollection module
//!
//! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions
//! from the libimagentrylink::external::ExternalLinker trait on this to generate external links.
//!
//! The BookmarkCollection type offers helper functions to get all links or such things.
use std::ops::Deref;
use std::ops::DerefMut;

use error::BookmarkError as BE;
use error::BookmarkErrorKind as BEK;
use error::MapErrInto;
use result::Result;
use module_path::ModuleEntryPath;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentrylink::internal::Link;
use libimagerror::into::IntoError;
use url::Url;

pub struct BookmarkCollection<'a> {
    fle: FileLockEntry<'a>,
    store: &'a Store,
}

/// {Internal, External}Linker is implemented as Deref is implemented
impl<'a> Deref for BookmarkCollection<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.fle
    }

}

impl<'a> DerefMut for BookmarkCollection<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.fle
    }

}

impl<'a> BookmarkCollection<'a> {

    pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.create(id)
            .map(|fle| {
                BookmarkCollection {
                    fle: fle,
                    store: store,
                }
            })
            .map_err_into(BEK::StoreReadError)
    }

    pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.get(id)
            .map_err_into(BEK::StoreReadError)
            .and_then(|fle| {
                match fle {
                    None => Err(BEK::CollectionNotFound.into_error()),
                    Some(e) => Ok(BookmarkCollection {
                        fle: e,
                        store: store,
                    }),
                }
            })
    }

    pub fn delete(store: &Store, name: &str) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid()).map_err_into(BEK::StoreReadError)
    }

    pub fn links(&self) -> Result<Vec<Url>> {
        self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
    }

    pub fn link_entries(&self) -> Result<Vec<Link>> {
        use libimagentrylink::external::is_external_link_storeid;

        self.fle
            .get_internal_links()
            .map(|v| v.into_iter().filter(|id| is_external_link_storeid(id)).collect())
            .map_err_into(BEK::StoreReadError)
    }

}

<|endoftext|>