<commit_before>use redox::*;
use common::*;
mod crypto;
use crypto::{Sha512, PubKey, RsaSignature};

/// Version
#[derive(Hash, Clone)]
pub enum Version {
    NewerThan(u64),
    OlderThan(u64),
    Between(u64, u64),
    Excatly(u64),
    Newest,
}

// TODO: Implement format

#[derive(Hash, Clone)]
/// A package developer
pub struct Developer {
    /// The name of the developer
    pub name: String,
    /// The public key of the developer
    pub key: PubKey,
}

#[derive(Hash, Clone)]
/// An installable package for Oxide
pub struct Package {
    /// The id of this package
    pub id: Id,
    /// Description
    pub desc: String,
    /// The developer of the package
    pub dev: Developer,
    /// The developer's signature of this package's content (tarball)
    pub dev_sign: RsaSignature,
    /// The signatures of this package
    pub sign: Vec<RsaSignature>,
    /// The files this package will create on the computer.
    pub files: Vec<String>,
    /// Dependencies of this package
    pub deps: Vec<Id>,
}

impl Package {
    /// Get content
    pub fn get_content(&self) -> Tarball {

    }

    /// Get package from string
    pub fn from_string(s: String) -> Option<Package> {

        // TODO

        for i in resp {
            let data = i.substr(5, i.len() - 5);
            let key = i.substr(0, 4);

            if key == "name" {
                name = data;
            } else if key == "desc" {
                desc = data;
            } else if key == "host" {
                host = data;
            } else if key == "file" {
                files = data;
            } else if key == "vers" {
                version = data;
            }
        }

        Package {
            host: host,
            name: name,
            desc: desc,
            files: files.split(",".to_string()).collect::<Vec<_>>(),
            version: version,
        }
    }

    /// Install package
    pub fn install(&self, col: &Collection) -> Result<(), InstallError> {
        // Install deps
        for d in self.deps {
            d.install();
        }

        // TODO install + add to local package list
    }

    /// Check validity
    pub fn check(&self, col: &Collection) -> TrustLevel {
        let con = self.get_content();

        for s in self.sign {
            if s.check(con) && col.keys.contains(s) {
                return TrustLevel::TrustedPackage
            } else if !s.check(con) {
                return TrustLevel::InvalidSignature
            }
        }

        if !self.dev_sign.check(con) {
            TrustLevel::InvalidSignature
        } else if !col.devs.contains(self.dev_sign) {
            TrustLevel::UntrustedSignature
        } else {
            TrustLevel::TrustedDev
        }
    }

}

/// Trust level
pub enum TrustLevel {
    /// 0
    InvalidSignature,
    /// 1
    UntrustedSignature,
    /// 2
    TrustedDeveloper,
    /// 3
    TrustedPackage,
}

impl TrustLevel {
    /// Is this package trusted?
    pub fn is_trusted(&self) -> bool {
        match self {
            &TrustLevel::TrustedDeveloper | TrustLevel::TrustedPackage => true,
            _ => false,
        }
    }
}

/// An error
pub enum PackageError {
    InvalidSyntax,
    InvalidSignature,
    UntrustedSignature,
    UntrustedDev,
    NotFound,
    E404,
    InfiniteDeps,
    Unknown,
}

#[derive(Hash, Clone)]
/// An package descriptor
pub struct Id {
    pub name: String,
    pub version: Version,
}

impl Id {
    pub fn to_string(&self) -> String {
        format!("{}-{}", self.name, self.version)
    }
}

/// Database of trusted developers
#[derive(Hash, Clone)]
pub struct DevDb {
    pub data: HashSet<Developer>,
}

/// Database of trusted keys
#[derive(Hash, Clone)]
pub struct KeyDb {
    pub data: HashSet<PubKey>,
}

/// An index of packages
#[derive(Hash, Clone)]
pub struct Index {
    /// Where the search queries can be send to
    pub host: String,
}

impl Index {
    /// Get a given package
    pub fn get(&self, id: Id) -> Result<Package, PackageError> {
        let con = File::open("tcp://".to_string() + self.host);

        con.write("GET /ox/".to_string() + id.to_string() + " HTTP/1.1".to_string());

        let res = Vec::new();
        con.read_to_end(&mut res);

        Package::from_string(String::from_utf8(&res))
    }
}

/// A collection of indexes, trusted keys, and trusted developers (all stored on the users
/// computer)
#[derive(Hash, Clone)]
pub struct Collection {
    /// Indexes
    pub index: Vec<Index>,
    /// The trusted devs
    pub devs: DevDb,
    /// The trusted keys
    pub keys: KeyDb,
    /// The installed packages
    pub installed: Vec<LocalPackage>,
}

/// A package installed locally
pub struct LocalPackage {
    /// Files it owns
    pub owns: Vec<String>,
    /// Is this package installed as root (i.e. isnt just installed as a dep for another package)?
    pub root: bool,
    /// The package
    pub package: Package,
}

impl LocalPackage {
    pub fn uninstall(&self) -> bool {

    }
}

impl Collection {
    /// Get a given package (guaranteed to be valid)
    pub fn get(&self, id: Id) -> Result<Package, PackageError> {
        for i in self.index {
            if let Ok(p) = i.get(id) {
                if p.check().is_trusted() {
                    return Ok(p);
                }
            }
        }
        None
    }
}

<commit_msg>Add cyclic dep check<commit_after>use redox::*;
use common::*;
mod crypto;
use crypto::{Sha512, PubKey, RsaSignature};

/// Version
#[derive(Hash, Clone)]
pub enum Version {
    NewerThan(u64),
    OlderThan(u64),
    Between(u64, u64),
    Excatly(u64),
    Newest,
}

// TODO: Implement format

#[derive(Hash, Clone)]
/// A package developer
pub struct Developer {
    /// The name of the developer
    pub name: String,
    /// The public key of the developer
    pub key: PubKey,
}

#[derive(Hash, Clone)]
/// An installable package for Oxide
pub struct Package {
    /// The id of this package
    pub id: Id,
    /// Description
    pub desc: String,
    /// The developer of the package
    pub dev: Developer,
    /// The developer's signature of this package's content (tarball)
    pub dev_sign: RsaSignature,
    /// The signatures of this package
    pub sign: Vec<RsaSignature>,
    /// The files this package will create on the computer.
    pub files: Vec<String>,
    /// Dependencies of this package
    pub deps: Vec<Id>,
}

impl Package {
    /// Get content
    pub fn get_content(&self) -> Tarball {

    }

    /// Get package from string
    pub fn from_string(s: String) -> Option<Package> {

        // TODO

        for i in resp {
            let data = i.substr(5, i.len() - 5);
            let key = i.substr(0, 4);

            if key == "name" {
                name = data;
            } else if key == "desc" {
                desc = data;
            } else if key == "host" {
                host = data;
            } else if key == "file" {
                files = data;
            } else if key == "vers" {
                version = data;
            }
        }

        Package {
            host: host,
            name: name,
            desc: desc,
            files: files.split(",".to_string()).collect::<Vec<_>>(),
            version: version,
        }
    }

    /// Install package
    pub fn install(&self, col: &Collection) -> Result<u64, InstallError> {
        // Install deps
        let mut installed = 0;
        for d in self.deps {
            let pkg = d.install();
            if let Err(n) = pkg {
                installed += n;
                if n > 10000 {
                    println!("Warning: Potential infinite recursion (cyclic dependencies)");
                }
            } else {
                return pkg;
            }

        }

        // TODO install + add to local package list
    }

    /// Check validity
    pub fn check(&self, col: &Collection) -> TrustLevel {
        let con = self.get_content();

        for s in self.sign {
            if s.check(con) && col.keys.contains(s) {
                return TrustLevel::TrustedPackage
            } else if !s.check(con) {
                return TrustLevel::InvalidSignature
            }
        }

        if !self.dev_sign.check(con) {
            TrustLevel::InvalidSignature
        } else if !col.devs.contains(self.dev_sign) {
            TrustLevel::UntrustedSignature
        } else {
            TrustLevel::TrustedDev
        }
    }

}

/// Trust level
pub enum TrustLevel {
    /// 0
    InvalidSignature,
    /// 1
    UntrustedSignature,
    /// 2
    TrustedDeveloper,
    /// 3
    TrustedPackage,
}

impl TrustLevel {
    /// Is this package trusted?
    pub fn is_trusted(&self) -> bool {
        match self {
            &TrustLevel::TrustedDeveloper | TrustLevel::TrustedPackage => true,
            _ => false,
        }
    }
}

/// An error
pub enum PackageError {
    InvalidSyntax,
    InvalidSignature,
    UntrustedSignature,
    UntrustedDev,
    NotFound,
    E404,
    InfiniteDeps,
    Unknown,
}

#[derive(Hash, Clone)]
/// An package descriptor
pub struct Id {
    pub name: String,
    pub version: Version,
    pub dist_type: DistType,
}

/// Distribution type
pub enum DistType {
    Binary,
    Source,
    Other,
}

impl Id {
    pub fn to_string(&self) -> String {
        format!("{}-{}-{}", self.name, self.dist_type, self.version)
    }
}

/// Database of trusted developers
#[derive(Hash, Clone)]
pub struct DevDb {
    pub data: HashSet<Developer>,
}

/// Database of trusted keys
#[derive(Hash, Clone)]
pub struct KeyDb {
    pub data: HashSet<PubKey>,
}

/// An index of packages
#[derive(Hash, Clone)]
pub struct Index {
    /// Where the search queries can be send to
    pub host: String,
}

impl Index {
    /// Get a given package
    pub fn get(&self, id: Id) -> Result<Package, PackageError> {
        let con = File::open("tcp://".to_string() + self.host);

        con.write("GET /ox/".to_string() + id.to_string() + " HTTP/1.1".to_string());

        let res = Vec::new();
        con.read_to_end(&mut res);

        Package::from_string(String::from_utf8(&res))
    }
}

/// A collection of indexes, trusted keys, and trusted developers (all stored on the users
/// computer)
#[derive(Hash, Clone)]
pub struct Collection {
    /// Indexes
    pub index: Vec<Index>,
    /// The trusted devs
    pub devs: DevDb,
    /// The trusted keys
    pub keys: KeyDb,
    /// The installed packages
    pub installed: Vec<LocalPackage>,
}

/// A package installed locally
pub struct LocalPackage {
    /// Files it owns
    pub owns: Vec<String>,
    /// Is this package installed as root (i.e. isnt just installed as a dep for another package)?
    pub root: bool,
    /// The package
    pub package: Package,
}

impl LocalPackage {
    pub fn uninstall(&self) -> bool {

    }
}

impl Collection {
    /// Get a given package (guaranteed to be valid)
    pub fn get(&self, id: Id) -> Result<Package, PackageError> {
        for i in self.index {
            if let Ok(p) = i.get(id) {
                if p.check().is_trusted() {
                    return Ok(p);
                }
            }
        }
        None
    }
}

<|endoftext|>


<commit_before>//! Utilities for building HTTP endpoints in a library-agnostic manner

use serde::ser;
use serde::ser::SerializeMap;

use {GraphQLError, GraphQLType, RootNode, Value, Variables};
use ast::InputValue;
use executor::ExecutionError;

/// The expected structure of the decoded JSON document for either POST or GET requests.
///
/// For POST, you can use Serde to deserialize the incoming JSON data directly
/// into this struct - it derives Deserialize for exactly this reason.
///
/// For GET, you will need to parse the query string and exctract "query",
/// "operationName", and "variables" manually.
#[derive(Deserialize)]
pub struct GraphQLRequest {
    query: String,
    #[serde(rename = "operationName")]
    operation_name: Option<String>,
    variables: Option<InputValue>,
}

impl GraphQLRequest {
    fn operation_name(&self) -> Option<&str> {
        self.operation_name.as_ref().map(|oper_name| &**oper_name)
    }

    fn variables(&self) -> Variables {
        self.variables
            .as_ref()
            .and_then(|iv| {
                iv.to_object_value().map(|o| {
                    o.into_iter()
                        .map(|(k, v)| (k.to_owned(), v.clone()))
                        .collect()
                })
            })
            .unwrap_or_default()
    }

    /// Construct a new GraphQL request from parts
    pub fn new(
        query: String,
        operation_name: Option<String>,
        variables: Option<InputValue>,
    ) -> GraphQLRequest {
        GraphQLRequest {
            query: query,
            operation_name: operation_name,
            variables: variables,
        }
    }

    /// Execute a GraphQL request using the specified schema and context
    ///
    /// This is a simple wrapper around the `execute` function exposed at the
    /// top level of this crate.
    pub fn execute<'a, CtxT, QueryT, MutationT>(
        &'a self,
        root_node: &RootNode<QueryT, MutationT>,
        context: &CtxT,
    ) -> GraphQLResponse<'a>
    where
        QueryT: GraphQLType<Context = CtxT>,
        MutationT: GraphQLType<Context = CtxT>,
    {
        GraphQLResponse(::execute(
            &self.query,
            self.operation_name(),
            root_node,
            &self.variables(),
            context,
        ))
    }
}

/// Simple wrapper around the result from executing a GraphQL query
///
/// This struct implements Serialize, so you can simply serialize this
/// to JSON and send it over the wire. Use the `is_ok` method to determine
/// whether to send a 200 or 400 HTTP status code.
pub struct GraphQLResponse<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);

impl<'a> GraphQLResponse<'a> {
    /// Was the request successful or not?
    ///
    /// Note that there still might be errors in the response even though it's
    /// considered OK. This is by design in GraphQL.
    pub fn is_ok(&self) -> bool {
        self.0.is_ok()
    }
}

impl<'a> ser::Serialize for GraphQLResponse<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match self.0 {
            Ok((ref res, ref err)) => {
                let mut map = try!(serializer.serialize_map(None));

                try!(map.serialize_key("data"));
                try!(map.serialize_value(res));

                if !err.is_empty() {
                    try!(map.serialize_key("errors"));
                    try!(map.serialize_value(err));
                }

                map.end()
            }
            Err(ref err) => {
                let mut map = try!(serializer.serialize_map(Some(1)));
                try!(map.serialize_key("errors"));
                try!(map.serialize_value(err));
                map.end()
            }
        }
    }
}

#[cfg(any(test, feature = "expose-test-schema"))]
pub mod tests {
    use serde_json::Value as Json;
    use serde_json;

    pub struct TestResponse {
        pub status_code: i32,
        pub body: Option<String>,
        pub content_type: String,
    }

    pub trait HTTPIntegration {
        fn get(&self, url: &str) -> TestResponse;
        fn post(&self, url: &str, body: &str) -> TestResponse;
    }

    pub fn run_http_test_suite<T: HTTPIntegration>(integration: &T) {
        println!("Running HTTP Test suite for integration");

        println!("  - test_simple_get");
        test_simple_get(integration);

        println!("  - test_encoded_get");
        test_encoded_get(integration);

        println!("  - test_get_with_variables");
        test_get_with_variables(integration);

        println!("  - test_simple_post");
        test_simple_post(integration);
    }

    fn unwrap_json_response(response: &TestResponse) -> Json {
        serde_json::from_str::<Json>(
            response
                .body
                .as_ref()
                .expect("No data returned from request"),
        ).expect("Could not parse JSON object")
    }

    fn test_simple_get<T: HTTPIntegration>(integration: &T) {
        let response = integration.get("/?query={hero{name}}");

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type.as_str(), "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                .expect("Invalid JSON constant in test")
        );
    }

    fn test_encoded_get<T: HTTPIntegration>(integration: &T) {
        let response = integration.get(
            "/?query=query%20{%20%20%20human(id:%20\"1000\")%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}");

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type.as_str(), "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(
                r#"{
                    "data": {
                        "human": {
                            "appearsIn": [
                                "NEW_HOPE",
                                "EMPIRE",
                                "JEDI"
                                ],
                                "homePlanet": "Tatooine",
                                "name": "Luke Skywalker",
                                "id": "1000"
                            }
                        }
                    }"#
            ).expect("Invalid JSON constant in test")
        );
    }

    fn test_get_with_variables<T: HTTPIntegration>(integration: &T) {
        let response = integration.get(
            "/?query=query($id:%20String!)%20{%20%20%20human(id:%20$id)%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}&variables={%20%20%20\"id\":%20%20\"1000\"%20}");

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type, "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(
                r#"{
                    "data": {
                        "human": {
                            "appearsIn": [
                                "NEW_HOPE",
                                "EMPIRE",
                                "JEDI"
                                ],
                                "homePlanet": "Tatooine",
                                "name": "Luke Skywalker",
                                "id": "1000"
                            }
                        }
                    }"#
            ).expect("Invalid JSON constant in test")
        );
    }

    fn test_simple_post<T: HTTPIntegration>(integration: &T) {
        let response = integration.post("/", r#"{"query": "{hero{name}}"}"#);

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type, "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                .expect("Invalid JSON constant in test")
        );
    }
}
<commit_msg>Derive Clone for GraphQLRequest<commit_after>//! Utilities for building HTTP endpoints in a library-agnostic manner

use serde::ser;
use serde::ser::SerializeMap;

use {GraphQLError, GraphQLType, RootNode, Value, Variables};
use ast::InputValue;
use executor::ExecutionError;

/// The expected structure of the decoded JSON document for either POST or GET requests.
///
/// For POST, you can use Serde to deserialize the incoming JSON data directly
/// into this struct - it derives Deserialize for exactly this reason.
///
/// For GET, you will need to parse the query string and exctract "query",
/// "operationName", and "variables" manually.
#[derive(Deserialize, Clone)]
pub struct GraphQLRequest {
    query: String,
    #[serde(rename = "operationName")]
    operation_name: Option<String>,
    variables: Option<InputValue>,
}

impl GraphQLRequest {
    fn operation_name(&self) -> Option<&str> {
        self.operation_name.as_ref().map(|oper_name| &**oper_name)
    }

    fn variables(&self) -> Variables {
        self.variables
            .as_ref()
            .and_then(|iv| {
                iv.to_object_value().map(|o| {
                    o.into_iter()
                        .map(|(k, v)| (k.to_owned(), v.clone()))
                        .collect()
                })
            })
            .unwrap_or_default()
    }

    /// Construct a new GraphQL request from parts
    pub fn new(
        query: String,
        operation_name: Option<String>,
        variables: Option<InputValue>,
    ) -> GraphQLRequest {
        GraphQLRequest {
            query: query,
            operation_name: operation_name,
            variables: variables,
        }
    }

    /// Execute a GraphQL request using the specified schema and context
    ///
    /// This is a simple wrapper around the `execute` function exposed at the
    /// top level of this crate.
    pub fn execute<'a, CtxT, QueryT, MutationT>(
        &'a self,
        root_node: &RootNode<QueryT, MutationT>,
        context: &CtxT,
    ) -> GraphQLResponse<'a>
    where
        QueryT: GraphQLType<Context = CtxT>,
        MutationT: GraphQLType<Context = CtxT>,
    {
        GraphQLResponse(::execute(
            &self.query,
            self.operation_name(),
            root_node,
            &self.variables(),
            context,
        ))
    }
}

/// Simple wrapper around the result from executing a GraphQL query
///
/// This struct implements Serialize, so you can simply serialize this
/// to JSON and send it over the wire. Use the `is_ok` method to determine
/// whether to send a 200 or 400 HTTP status code.
pub struct GraphQLResponse<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);

impl<'a> GraphQLResponse<'a> {
    /// Was the request successful or not?
    ///
    /// Note that there still might be errors in the response even though it's
    /// considered OK. This is by design in GraphQL.
    pub fn is_ok(&self) -> bool {
        self.0.is_ok()
    }
}

impl<'a> ser::Serialize for GraphQLResponse<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match self.0 {
            Ok((ref res, ref err)) => {
                let mut map = try!(serializer.serialize_map(None));

                try!(map.serialize_key("data"));
                try!(map.serialize_value(res));

                if !err.is_empty() {
                    try!(map.serialize_key("errors"));
                    try!(map.serialize_value(err));
                }

                map.end()
            }
            Err(ref err) => {
                let mut map = try!(serializer.serialize_map(Some(1)));
                try!(map.serialize_key("errors"));
                try!(map.serialize_value(err));
                map.end()
            }
        }
    }
}

#[cfg(any(test, feature = "expose-test-schema"))]
pub mod tests {
    use serde_json::Value as Json;
    use serde_json;

    pub struct TestResponse {
        pub status_code: i32,
        pub body: Option<String>,
        pub content_type: String,
    }

    pub trait HTTPIntegration {
        fn get(&self, url: &str) -> TestResponse;
        fn post(&self, url: &str, body: &str) -> TestResponse;
    }

    pub fn run_http_test_suite<T: HTTPIntegration>(integration: &T) {
        println!("Running HTTP Test suite for integration");

        println!("  - test_simple_get");
        test_simple_get(integration);

        println!("  - test_encoded_get");
        test_encoded_get(integration);

        println!("  - test_get_with_variables");
        test_get_with_variables(integration);

        println!("  - test_simple_post");
        test_simple_post(integration);
    }

    fn unwrap_json_response(response: &TestResponse) -> Json {
        serde_json::from_str::<Json>(
            response
                .body
                .as_ref()
                .expect("No data returned from request"),
        ).expect("Could not parse JSON object")
    }

    fn test_simple_get<T: HTTPIntegration>(integration: &T) {
        let response = integration.get("/?query={hero{name}}");

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type.as_str(), "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                .expect("Invalid JSON constant in test")
        );
    }

    fn test_encoded_get<T: HTTPIntegration>(integration: &T) {
        let response = integration.get(
            "/?query=query%20{%20%20%20human(id:%20\"1000\")%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}");

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type.as_str(), "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(
                r#"{
                    "data": {
                        "human": {
                            "appearsIn": [
                                "NEW_HOPE",
                                "EMPIRE",
                                "JEDI"
                                ],
                                "homePlanet": "Tatooine",
                                "name": "Luke Skywalker",
                                "id": "1000"
                            }
                        }
                    }"#
            ).expect("Invalid JSON constant in test")
        );
    }

    fn test_get_with_variables<T: HTTPIntegration>(integration: &T) {
        let response = integration.get(
            "/?query=query($id:%20String!)%20{%20%20%20human(id:%20$id)%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}&variables={%20%20%20\"id\":%20%20\"1000\"%20}");

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type, "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(
                r#"{
                    "data": {
                        "human": {
                            "appearsIn": [
                                "NEW_HOPE",
                                "EMPIRE",
                                "JEDI"
                                ],
                                "homePlanet": "Tatooine",
                                "name": "Luke Skywalker",
                                "id": "1000"
                            }
                        }
                    }"#
            ).expect("Invalid JSON constant in test")
        );
    }

    fn test_simple_post<T: HTTPIntegration>(integration: &T) {
        let response = integration.post("/", r#"{"query": "{hero{name}}"}"#);

        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type, "application/json");

        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                .expect("Invalid JSON constant in test")
        );
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate app_units;
extern crate euclid;
extern crate malloc_size_of;
extern crate style_traits;
#[macro_use]
extern crate malloc_size_of_derive;
extern crate webrender_api;

use app_units::{Au, MAX_AU, MIN_AU};
use euclid::{Length, Point2D, Rect, Size2D};
use std::f32;
use style_traits::DevicePixel;
use webrender_api::{LayoutPoint, LayoutRect, LayoutSize};

// Units for use with euclid::length and euclid::scale_factor.

pub type DeviceUintLength = Length<u32, DevicePixel>;

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and DeviceIndependentPixel is defined by the OS.  On most low-dpi
/// screens, one DeviceIndependentPixel is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one DeviceIndependentPixel equals
/// two DevicePixels.  On Android "MDPI" displays, one DeviceIndependentPixel equals 1.5 device pixels.
///
/// The ratio between DeviceIndependentPixel and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Clone, Copy, Debug, MallocSizeOf)]
pub enum DeviceIndependentPixel {}

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.

pub trait MaxRect {
    #[inline(always)]
    fn max_rect() -> Self;
}

impl MaxRect for Rect<Au> {
    fn max_rect() -> Rect<Au> {
        Rect::new(
            Point2D::new(MIN_AU / 2, MIN_AU / 2),
            Size2D::new(MAX_AU, MAX_AU),
        )
    }
}

impl MaxRect for LayoutRect {
    fn max_rect() -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(f32::MIN / 2.0, f32::MIN / 2.0),
            LayoutSize::new(f32::MAX, f32::MAX),
        )
    }
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect::new(
        Point2D::new(
            Au::from_f32_px(rect.origin.x),
            Au::from_f32_px(rect.origin.y),
        ),
        Size2D::new(
            Au::from_f32_px(rect.size.width),
            Au::from_f32_px(rect.size.height),
        ),
    )
}

/// A helper function to convert a rect of `Au` pixels to a rect of f32 units.
pub fn au_rect_to_f32_rect(rect: Rect<Au>) -> Rect<f32> {
    Rect::new(
        Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
        Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()),
    )
}
<commit_msg>Move malloc_size_of_derive to proper position<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate app_units;
extern crate euclid;
extern crate malloc_size_of;
#[macro_use]
extern crate malloc_size_of_derive;
extern crate style_traits;
extern crate webrender_api;

use app_units::{Au, MAX_AU, MIN_AU};
use euclid::{Length, Point2D, Rect, Size2D};
use std::f32;
use style_traits::DevicePixel;
use webrender_api::{LayoutPoint, LayoutRect, LayoutSize};

// Units for use with euclid::length and euclid::scale_factor.

pub type DeviceUintLength = Length<u32, DevicePixel>;

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and DeviceIndependentPixel is defined by the OS.  On most low-dpi
/// screens, one DeviceIndependentPixel is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one DeviceIndependentPixel equals
/// two DevicePixels.  On Android "MDPI" displays, one DeviceIndependentPixel equals 1.5 device pixels.
///
/// The ratio between DeviceIndependentPixel and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Clone, Copy, Debug, MallocSizeOf)]
pub enum DeviceIndependentPixel {}

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.

pub trait MaxRect {
    #[inline(always)]
    fn max_rect() -> Self;
}

impl MaxRect for Rect<Au> {
    fn max_rect() -> Rect<Au> {
        Rect::new(
            Point2D::new(MIN_AU / 2, MIN_AU / 2),
            Size2D::new(MAX_AU, MAX_AU),
        )
    }
}

impl MaxRect for LayoutRect {
    fn max_rect() -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(f32::MIN / 2.0, f32::MIN / 2.0),
            LayoutSize::new(f32::MAX, f32::MAX),
        )
    }
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect::new(
        Point2D::new(
            Au::from_f32_px(rect.origin.x),
            Au::from_f32_px(rect.origin.y),
        ),
        Size2D::new(
            Au::from_f32_px(rect.size.width),
            Au::from_f32_px(rect.size.height),
        ),
    )
}

/// A helper function to convert a rect of `Au` pixels to a rect of f32 units.
pub fn au_rect_to_f32_rect(rect: Rect<Au>) -> Rect<f32> {
    Rect::new(
        Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
        Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()),
    )
}
<|endoftext|>


<commit_before>use error::*;
use super::Command;

use constant::*;
use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use std::collections::BTreeSet;
use std::path::Path;

pub struct Ignore {
    pub command: Option<String>,
    pub paths  : Vec<String>,
}

impl Command for Ignore {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Ignore);
    }

    fn main(&self) -> Result<(), CliError> {
        match self.command {
            Some(ref c) => match c.as_ref() {
                "add"     => self.add(),
                "remove"  => self.remove(),
                "current" => Self::ignore_current_files(),
                "clear"   => Self::clear_ignore_file(),
                _         => Err(From::from(self.usage())),
            },
            None => Err(From::from(self.usage())),
        }
    }
}

impl Ignore {
    fn add(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be added to \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_added = paths
            .iter()
            .map(append_prefix_if_need)
            .filter(|p| Path::new(p).is_file())
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_added {
            print_with_tag(1, Tag::Info, format!("\"{}\" will be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .union(&ignores_to_be_added)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn remove(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be removed from \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_removed = paths
            .iter()
            .map(append_prefix_if_need)
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_removed {
            print_with_tag(1, Tag::Info, format!("\"{}\" will not be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .difference(&ignores_to_be_removed)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn ignore_current_files() -> Result<(), CliError> {
        println!("do current command");

        Ok(())
    }

    fn clear_ignore_file() -> Result<(), CliError> {
        println!("do clear command");

        Ok(())
    }
}
<commit_msg>[Feature] Implement "ignore clear"<commit_after>use error::*;
use super::Command;

use constant::*;
use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use std::collections::BTreeSet;
use std::path::Path;

pub struct Ignore {
    pub command: Option<String>,
    pub paths  : Vec<String>,
}

impl Command for Ignore {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Ignore);
    }

    fn main(&self) -> Result<(), CliError> {
        match self.command {
            Some(ref c) => match c.as_ref() {
                "add"     => self.add(),
                "remove"  => self.remove(),
                "current" => Self::ignore_current_files(),
                "clear"   => Self::clear_ignore_file(),
                _         => Err(From::from(self.usage())),
            },
            None => Err(From::from(self.usage())),
        }
    }
}

impl Ignore {
    fn add(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be added to \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_added = paths
            .iter()
            .map(append_prefix_if_need)
            .filter(|p| Path::new(p).is_file())
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_added {
            print_with_tag(1, Tag::Info, format!("\"{}\" will be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .union(&ignores_to_be_added)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn remove(&self) -> Result<(), CliError> {
        let paths = &self.paths;

        if paths.len() == 0 {
            return Err(From::from(self.usage()));
        }

        print_with_tag(0, Tag::Execution, format!("Confirm files to be removed from \"{}\"", IGNORE_FILE_NAME));

        let ignores_to_be_removed = paths
            .iter()
            .map(append_prefix_if_need)
            .collect::<BTreeSet<String>>();

        for file in &ignores_to_be_removed {
            print_with_tag(1, Tag::Info, format!("\"{}\" will not be ignored", file));
        }

        let original_ignores = try!(read_ignore_file());

        let new_ignores = original_ignores
            .difference(&ignores_to_be_removed)
            .fold(String::new(), |c, ref f| c + f + "\n");

        print_with_tag(0, Tag::Execution, format!("Recreate \"{}\" file", IGNORE_FILE_NAME));

        try!(create_ignore_file(new_ignores));

        Ok(())
    }

    fn ignore_current_files() -> Result<(), CliError> {
        println!("do current command");

        Ok(())
    }

    fn clear_ignore_file() -> Result<(), CliError> {
        print_with_tag(0, Tag::Execution, format!("Clear contents of \"{}\"", IGNORE_FILE_NAME));
        try!(create_ignore_file("\n"));

        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::EitherOrBoth::*;

use either::Either;

/// Value that either holds a single A or B, or both.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum EitherOrBoth<A, B> {
    /// Both values are present.
    Both(A, B),
    /// Only the left value of type `A` is present.
    Left(A),
    /// Only the right value of type `B` is present.
    Right(B),
}

impl<A, B> EitherOrBoth<A, B> {
    /// If `Left`, or `Both`, return true, otherwise, return false.
    pub fn has_left(&self) -> bool {
        self.as_ref().left().is_some()
    }

    /// If `Right`, or `Both`, return true, otherwise, return false.
    pub fn has_right(&self) -> bool {
        self.as_ref().right().is_some()
    }

    /// If Left, return true otherwise, return false.
    /// Exclusive version of [`has_left`](Self::has_left).
    pub fn is_left(&self) -> bool {
        match *self {
            Left(_) => true,
            _ => false,
        }
    }

    /// If Right, return true otherwise, return false.
    /// Exclusive version of [`has_right`](Self::has_right).
    pub fn is_right(&self) -> bool {
        match *self {
            Right(_) => true,
            _ => false,
        }
    }

    /// If Right, return true otherwise, return false.
    /// Equivalent to `self.as_ref().both().is_some()`.
    pub fn is_both(&self) -> bool {
        self.as_ref().both().is_some()
    }

    /// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`.
    pub fn left(self) -> Option<A> {
        match self {
            Left(left) | Both(left, _) => Some(left),
            _ => None,
        }
    }

    /// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`.
    pub fn right(self) -> Option<B> {
        match self {
            Right(right) | Both(_, right) => Some(right),
            _ => None,
        }
    }

    /// If Both, return `Some` tuple containing left and right.
    pub fn both(self) -> Option<(A, B)> {
        match self {
            Both(a, b) => Some((a, b)),
            _ => None,
        }
    }

    /// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&A, &B>`.
    pub fn as_ref(&self) -> EitherOrBoth<&A, &B> {
        match *self {
            Left(ref left) => Left(left),
            Right(ref right) => Right(right),
            Both(ref left, ref right) => Both(left, right),
        }
    }

    /// Converts from `&mut EitherOrBoth<A, B>` to `EitherOrBoth<&mut A, &mut B>`.
    pub fn as_mut(&mut self) -> EitherOrBoth<&mut A, &mut B> {
        match *self {
            Left(ref mut left) => Left(left),
            Right(ref mut right) => Right(right),
            Both(ref mut left, ref mut right) => Both(left, right),
        }
    }

    /// Convert `EitherOrBoth<A, B>` to `EitherOrBoth<B, A>`.
    pub fn flip(self) -> EitherOrBoth<B, A> {
        match self {
            Left(a) => Right(a),
            Right(b) => Left(b),
            Both(a, b) => Both(b, a),
        }
    }

    /// Apply the function `f` on the value `a` in `Left(a)` or `Both(a, b)` variants. If it is
    /// present rewrapping the result in `self`'s original variant.
    pub fn map_left<F, M>(self, f: F) -> EitherOrBoth<M, B>
    where
        F: FnOnce(A) -> M,
    {
        match self {
            Both(a, b) => Both(f(a), b),
            Left(a) => Left(f(a)),
            Right(b) => Right(b),
        }
    }

    /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, b)` variants.
    /// If it is present rewrapping the result in `self`'s original variant.
    pub fn map_right<F, M>(self, f: F) -> EitherOrBoth<A, M>
    where
        F: FnOnce(B) -> M,
    {
        match self {
            Left(a) => Left(a),
            Right(b) => Right(f(b)),
            Both(a, b) => Both(a, f(b)),
        }
    }

    /// Apply the functions `f` and `g` on the value `a` and `b` respectively;
    /// found in `Left(a)`, `Right(b)`, or `Both(a, b)` variants.
    /// The Result is rewrapped `self`'s original variant.
    pub fn map_any<F, L, G, R>(self, f: F, g: G) -> EitherOrBoth<L, R>
    where
        F: FnOnce(A) -> L,
        G: FnOnce(B) -> R,
    {
        match self {
            Left(a) => Left(f(a)),
            Right(b) => Right(g(b)),
            Both(a, b) => Both(f(a), g(b)),
        }
    }

    /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, _)` variants if it is
    /// present.
    pub fn left_and_then<F, L>(self, f: F) -> EitherOrBoth<L, B>
    where
        F: FnOnce(A) -> EitherOrBoth<L, B>,
    {
        match self {
            Left(a) | Both(a, _) => f(a),
            Right(b) => Right(b),
        }
    }

    /// Apply the function `f` on the value `a`
    /// in `Left(a)` or `Both(a, _)` variants if it is present.
    pub fn right_and_then<F, R>(self, f: F) -> EitherOrBoth<A, R>
    where
        F: FnOnce(B) -> EitherOrBoth<A, R>,
    {
        match self {
            Left(a) => Left(a),
            Right(b) | Both(_, b) => f(b),
        }
    }
}

impl<T> EitherOrBoth<T, T> {
    /// Return either value of left, right, or the product of `f` applied where `Both` are present.
    pub fn reduce<F>(self, f: F) -> T
    where
        F: FnOnce(T, T) -> T,
    {
        match self {
            Left(a) => a,
            Right(b) => b,
            Both(a, b) => f(a, b),
        }
    }
}

impl<A, B> Into<Option<Either<A, B>>> for EitherOrBoth<A, B> {
    fn into(self) -> Option<Either<A, B>> {
        match self {
            EitherOrBoth::Left(l) => Some(Either::Left(l)),
            EitherOrBoth::Right(r) => Some(Either::Right(r)),
            _ => None,
        }
    }
}
<commit_msg>Added the `or_default`  method to `EitherOrBoth`  See #537 for context.<commit_after>use crate::EitherOrBoth::*;

use either::Either;

/// Value that either holds a single A or B, or both.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum EitherOrBoth<A, B> {
    /// Both values are present.
    Both(A, B),
    /// Only the left value of type `A` is present.
    Left(A),
    /// Only the right value of type `B` is present.
    Right(B),
}

impl<A, B> EitherOrBoth<A, B> {
    /// If `Left`, or `Both`, return true, otherwise, return false.
    pub fn has_left(&self) -> bool {
        self.as_ref().left().is_some()
    }

    /// If `Right`, or `Both`, return true, otherwise, return false.
    pub fn has_right(&self) -> bool {
        self.as_ref().right().is_some()
    }

    /// If Left, return true otherwise, return false.
    /// Exclusive version of [`has_left`](Self::has_left).
    pub fn is_left(&self) -> bool {
        match *self {
            Left(_) => true,
            _ => false,
        }
    }

    /// If Right, return true otherwise, return false.
    /// Exclusive version of [`has_right`](Self::has_right).
    pub fn is_right(&self) -> bool {
        match *self {
            Right(_) => true,
            _ => false,
        }
    }

    /// If Right, return true otherwise, return false.
    /// Equivalent to `self.as_ref().both().is_some()`.
    pub fn is_both(&self) -> bool {
        self.as_ref().both().is_some()
    }

    /// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`.
    pub fn left(self) -> Option<A> {
        match self {
            Left(left) | Both(left, _) => Some(left),
            _ => None,
        }
    }

    /// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`.
    pub fn right(self) -> Option<B> {
        match self {
            Right(right) | Both(_, right) => Some(right),
            _ => None,
        }
    }

    /// If Both, return `Some` tuple containing left and right.
    pub fn both(self) -> Option<(A, B)> {
        match self {
            Both(a, b) => Some((a, b)),
            _ => None,
        }
    }

    /// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&A, &B>`.
    pub fn as_ref(&self) -> EitherOrBoth<&A, &B> {
        match *self {
            Left(ref left) => Left(left),
            Right(ref right) => Right(right),
            Both(ref left, ref right) => Both(left, right),
        }
    }

    /// Converts from `&mut EitherOrBoth<A, B>` to `EitherOrBoth<&mut A, &mut B>`.
    pub fn as_mut(&mut self) -> EitherOrBoth<&mut A, &mut B> {
        match *self {
            Left(ref mut left) => Left(left),
            Right(ref mut right) => Right(right),
            Both(ref mut left, ref mut right) => Both(left, right),
        }
    }

    /// Convert `EitherOrBoth<A, B>` to `EitherOrBoth<B, A>`.
    pub fn flip(self) -> EitherOrBoth<B, A> {
        match self {
            Left(a) => Right(a),
            Right(b) => Left(b),
            Both(a, b) => Both(b, a),
        }
    }

    /// Apply the function `f` on the value `a` in `Left(a)` or `Both(a, b)` variants. If it is
    /// present rewrapping the result in `self`'s original variant.
    pub fn map_left<F, M>(self, f: F) -> EitherOrBoth<M, B>
    where
        F: FnOnce(A) -> M,
    {
        match self {
            Both(a, b) => Both(f(a), b),
            Left(a) => Left(f(a)),
            Right(b) => Right(b),
        }
    }

    /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, b)` variants.
    /// If it is present rewrapping the result in `self`'s original variant.
    pub fn map_right<F, M>(self, f: F) -> EitherOrBoth<A, M>
    where
        F: FnOnce(B) -> M,
    {
        match self {
            Left(a) => Left(a),
            Right(b) => Right(f(b)),
            Both(a, b) => Both(a, f(b)),
        }
    }

    /// Apply the functions `f` and `g` on the value `a` and `b` respectively;
    /// found in `Left(a)`, `Right(b)`, or `Both(a, b)` variants.
    /// The Result is rewrapped `self`'s original variant.
    pub fn map_any<F, L, G, R>(self, f: F, g: G) -> EitherOrBoth<L, R>
    where
        F: FnOnce(A) -> L,
        G: FnOnce(B) -> R,
    {
        match self {
            Left(a) => Left(f(a)),
            Right(b) => Right(g(b)),
            Both(a, b) => Both(f(a), g(b)),
        }
    }

    /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, _)` variants if it is
    /// present.
    pub fn left_and_then<F, L>(self, f: F) -> EitherOrBoth<L, B>
    where
        F: FnOnce(A) -> EitherOrBoth<L, B>,
    {
        match self {
            Left(a) | Both(a, _) => f(a),
            Right(b) => Right(b),
        }
    }

    /// Apply the function `f` on the value `a`
    /// in `Left(a)` or `Both(a, _)` variants if it is present.
    pub fn right_and_then<F, R>(self, f: F) -> EitherOrBoth<A, R>
    where
        F: FnOnce(B) -> EitherOrBoth<A, R>,
    {
        match self {
            Left(a) => Left(a),
            Right(b) | Both(_, b) => f(b),
        }
    }
}

impl<T> EitherOrBoth<T, T> {
    /// Return either value of left, right, or the product of `f` applied where `Both` are present.
    pub fn reduce<F>(self, f: F) -> T
    where
        F: FnOnce(T, T) -> T,
    {
        match self {
            Left(a) => a,
            Right(b) => b,
            Both(a, b) => f(a, b),
        }
    }
}

impl<A, B> Into<Option<Either<A, B>>> for EitherOrBoth<A, B> {
    fn into(self) -> Option<Either<A, B>> {
        match self {
            EitherOrBoth::Left(l) => Some(Either::Left(l)),
            EitherOrBoth::Right(r) => Some(Either::Right(r)),
            _ => None,
        }
    }
}

impl<A: Default, B: Default> EitherOrBoth<A,B> {
    /// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present.
    /// Otherwise, returns the wrapped value for the present element, and the [`default`](Default::default)
    /// for the other.
    pub fn or_default(self) -> (A, B) {
        match self {
            EitherOrBoth::Left(l) => (l, B::default()),
            EitherOrBoth::Right(r) => (A::default(), r),
            EitherOrBoth::Both(l, r) => (l, r),
        }
    }
}<|endoftext|>


<commit_before>//! Single client connection

use std::io;
use std::result::Result as std_Result;
use std::sync::Arc;

use error;
use error::Error;
use result;

use exec::CpuPoolOption;

use solicit::connection::EndStream;
use solicit::frame::settings::*;
use solicit::header::*;
use solicit::StreamId;
use solicit::DEFAULT_SETTINGS;

use service::Service;

use futures::future::Future;
use futures::stream::Stream;
use futures::sync::mpsc::unbounded;
use futures::sync::mpsc::UnboundedSender;
use futures::sync::oneshot;

use tls_api::TlsConnector;

use tokio_core::reactor;
use tokio_io::AsyncRead;
use tokio_io::AsyncWrite;
use tokio_timer::Timer;
use tokio_tls_api;

use solicit_async::*;

use common::*;
use data_or_trailers::*;
use socket::*;

use client_died_error_holder::ClientDiedErrorHolder;
use data_or_headers::DataOrHeaders;
use data_or_headers_with_flag::DataOrHeadersWithFlag;
use headers_place::HeadersPlace;
use req_resp::RequestOrResponse;
use result_or_eof::ResultOrEof;
use std::marker;
use ClientConf;
use ClientTlsOption;
use ErrorCode;

struct ClientTypes<I>(marker::PhantomData<I>);

impl<I> Types for ClientTypes<I>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Io = I;
    type HttpStreamData = ClientStream<I>;
    type HttpStreamSpecific = ClientStreamData;
    type ConnDataSpecific = ClientConnData;
    type ToWriteMessage = ClientToWriteMessage;

    fn out_request_or_response() -> RequestOrResponse {
        RequestOrResponse::Request
    }

    fn first_id() -> StreamId {
        1
    }
}

pub struct ClientStreamData {}

impl HttpStreamDataSpecific for ClientStreamData {}

type ClientStream<I> = HttpStreamCommon<ClientTypes<I>>;

impl<I> HttpStreamData for ClientStream<I>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Types = ClientTypes<I>;
}

pub struct ClientConnData {
    callbacks: Box<ClientConnCallbacks>,
}

impl ConnSpecific for ClientConnData {}

pub struct ClientConn {
    write_tx: UnboundedSender<ClientToWriteMessage>,
}

unsafe impl Sync for ClientConn {}

pub struct StartRequestMessage {
    pub headers: Headers,
    pub body: HttpStreamAfterHeaders,
    pub resp_tx: oneshot::Sender<Response>,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    WaitForHandshake(oneshot::Sender<result::Result<()>>),
    Common(CommonToWriteMessage),
}

impl From<CommonToWriteMessage> for ClientToWriteMessage {
    fn from(m: CommonToWriteMessage) -> Self {
        ClientToWriteMessage::Common(m)
    }
}

impl<I> ConnWriteSideCustom for Conn<ClientTypes<I>>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Types = ClientTypes<I>;

    fn process_message(&mut self, message: ClientToWriteMessage) -> result::Result<()> {
        match message {
            ClientToWriteMessage::Start(start) => self.process_start(start),
            ClientToWriteMessage::Common(common) => self.process_common_message(common),
            ClientToWriteMessage::WaitForHandshake(tx) => {
                // ignore error
                drop(tx.send(Ok(())));
                Ok(())
            }
        }
    }
}

impl<I> Conn<ClientTypes<I>>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    fn process_start(&mut self, start: StartRequestMessage) -> result::Result<()> {
        let StartRequestMessage {
            headers,
            body,
            resp_tx,
        } = start;

        let stream_id = {
            let stream_id = self.next_local_stream_id();

            let out_window = {
                let (mut http_stream, resp_stream, out_window) = self.new_stream_data(
                    stream_id,
                    None,
                    InMessageStage::Initial,
                    ClientStreamData {},
                );

                if let Err(_) = resp_tx.send(Response::from_stream(resp_stream)) {
                    warn!("caller died");
                }

                http_stream
                    .stream()
                    .outgoing
                    .push_back(DataOrHeaders::Headers(headers));

                out_window
            };

            self.pump_stream_to_write_loop(stream_id, body.into_part_stream(), out_window);

            stream_id
        };

        // Also opens latch if necessary
        self.buffer_outg_stream(stream_id)?;
        Ok(())
    }
}

pub trait ClientConnCallbacks: 'static {
    // called at most once
    fn goaway(&self, stream_id: StreamId, raw_error_code: u32);
}

impl ClientConn {
    fn spawn_connected<I, C>(
        lh: reactor::Handle,
        connect: HttpFutureSend<I>,
        conf: ClientConf,
        callbacks: C,
    ) -> Self
    where
        I: AsyncWrite + AsyncRead + Send + 'static,
        C: ClientConnCallbacks,
    {
        let (to_write_tx, to_write_rx) = unbounded();

        let to_write_rx = Box::new(
            to_write_rx
                .map_err(|()| Error::IoError(io::Error::new(io::ErrorKind::Other, "to_write"))),
        );

        let c = ClientConn {
            write_tx: to_write_tx.clone(),
        };

        let settings_frame = SettingsFrame::from_settings(vec![HttpSetting::EnablePush(false)]);
        let mut settings = DEFAULT_SETTINGS;
        settings.apply_from_frame(&settings_frame);

        let handshake = connect.and_then(|conn| client_handshake(conn, settings_frame));

        let conn_died_error_holder = ClientDiedErrorHolder::new();
        let conn_died_error_holder_copy = conn_died_error_holder.clone();

        let lh_copy = lh.clone();

        let future = handshake.and_then(move |conn| {
            debug!("handshake done");

            let (read, write) = conn.split();

            let conn_data = Conn::<ClientTypes<_>>::new(
                lh_copy,
                CpuPoolOption::SingleThread,
                ClientConnData {
                    callbacks: Box::new(callbacks),
                },
                conf.common,
                settings,
                to_write_tx.clone(),
                to_write_rx,
                read,
                write,
                conn_died_error_holder,
            );
            conn_data.run()
        });

        let future = conn_died_error_holder_copy.wrap_future(future);

        lh.spawn(future);

        c
    }

    pub fn spawn<H, C>(
        lh: reactor::Handle,
        addr: Box<ToClientStream>,
        tls: ClientTlsOption<C>,
        conf: ClientConf,
        callbacks: H,
    ) -> Self
    where
        H: ClientConnCallbacks,
        C: TlsConnector + Sync,
    {
        match tls {
            ClientTlsOption::Plain => ClientConn::spawn_plain(lh.clone(), addr, conf, callbacks),
            ClientTlsOption::Tls(domain, connector) => {
                ClientConn::spawn_tls(lh.clone(), &domain, connector, addr, conf, callbacks)
            }
        }
    }

    pub fn spawn_plain<C>(
        lh: reactor::Handle,
        addr: Box<ToClientStream>,
        conf: ClientConf,
        callbacks: C,
    ) -> Self
    where
        C: ClientConnCallbacks,
    {
        let no_delay = conf.no_delay.unwrap_or(true);
        let connect = addr.connect(&lh).map_err(Into::into);
        let map_callback = move |socket: Box<StreamItem>| {
            info!("connected to {}", addr);

            if socket.is_tcp() {
                socket
                    .set_nodelay(no_delay)
                    .expect("failed to set TCP_NODELAY");
            }

            socket
        };

        let connect: Box<Future<Item = _, Error = _> + Send> =
            if let Some(timeout) = conf.connection_timeout {
                let timer = Timer::default();
                Box::new(timer.timeout(connect, timeout).map(map_callback))
            } else {
                Box::new(connect.map(map_callback))
            };

        ClientConn::spawn_connected(lh, connect, conf, callbacks)
    }

    pub fn spawn_tls<H, C>(
        lh: reactor::Handle,
        domain: &str,
        connector: Arc<C>,
        addr: Box<ToClientStream>,
        conf: ClientConf,
        callbacks: H,
    ) -> Self
    where
        H: ClientConnCallbacks,
        C: TlsConnector + Sync,
    {
        let domain = domain.to_owned();

        let connect = addr
            .connect(&lh)
            .map(move |c| {
                info!("connected to {}", addr);
                c
            }).map_err(|e| e.into());

        let tls_conn = connect.and_then(move |conn| {
            tokio_tls_api::connect_async(&*connector, &domain, conn)
                .map_err(|e| Error::IoError(io::Error::new(io::ErrorKind::Other, e)))
        });

        let tls_conn = tls_conn.map_err(Error::from);

        ClientConn::spawn_connected(lh, Box::new(tls_conn), conf, callbacks)
    }

    pub fn start_request_with_resp_sender(
        &self,
        start: StartRequestMessage,
    ) -> Result<(), StartRequestMessage> {
        self.write_tx
            .unbounded_send(ClientToWriteMessage::Start(start))
            .map_err(|send_error| match send_error.into_inner() {
                ClientToWriteMessage::Start(start) => start,
                _ => unreachable!(),
            })
    }

    pub fn dump_state_with_resp_sender(&self, tx: oneshot::Sender<ConnStateSnapshot>) {
        let message = ClientToWriteMessage::Common(CommonToWriteMessage::DumpState(tx));
        // ignore error
        drop(self.write_tx.unbounded_send(message));
    }

    /// For tests
    #[doc(hidden)]
    pub fn _dump_state(&self) -> HttpFutureSend<ConnStateSnapshot> {
        let (tx, rx) = oneshot::channel();

        self.dump_state_with_resp_sender(tx);

        let rx =
            rx.map_err(|_| Error::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx)
    }

    pub fn wait_for_connect_with_resp_sender(
        &self,
        tx: oneshot::Sender<result::Result<()>>,
    ) -> std_Result<(), oneshot::Sender<result::Result<()>>> {
        self.write_tx
            .unbounded_send(ClientToWriteMessage::WaitForHandshake(tx))
            .map_err(|send_error| match send_error.into_inner() {
                ClientToWriteMessage::WaitForHandshake(tx) => tx,
                _ => unreachable!(),
            })
    }
}

impl Service for ClientConn {
    // TODO: copy-paste with Client::start_request
    fn start_request(&self, headers: Headers, body: HttpStreamAfterHeaders) -> Response {
        let (resp_tx, resp_rx) = oneshot::channel();

        let start = StartRequestMessage {
            headers: headers,
            body: body,
            resp_tx: resp_tx,
        };

        if let Err(_) = self.start_request_with_resp_sender(start) {
            return Response::err(error::Error::Other("client died"));
        }

        let resp_rx =
            resp_rx.map_err(|oneshot::Canceled| error::Error::Other("client likely died"));

        let resp_rx = resp_rx.map(|r| r.into_stream_flag());

        let resp_rx = resp_rx.flatten_stream();

        Response::from_stream(resp_rx)
    }
}

impl<I> ConnReadSideCustom for Conn<ClientTypes<I>>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Types = ClientTypes<I>;

    fn process_headers(
        &mut self,
        stream_id: StreamId,
        end_stream: EndStream,
        headers: Headers,
    ) -> result::Result<Option<HttpStreamRef<ClientTypes<I>>>> {
        let existing_stream = self
            .get_stream_for_headers_maybe_send_error(stream_id)?
            .is_some();
        if !existing_stream {
            return Ok(None);
        }

        let in_message_stage = self
            .streams
            .get_mut(stream_id)
            .unwrap()
            .stream()
            .in_message_stage;

        let headers_place = match in_message_stage {
            InMessageStage::Initial => HeadersPlace::Initial,
            InMessageStage::AfterInitialHeaders => HeadersPlace::Trailing,
            InMessageStage::AfterTrailingHeaders => {
                return Err(error::Error::InternalError(format!(
                    "closed stream must be handled before"
                )));
            }
        };

        if let Err(e) = headers.validate(RequestOrResponse::Response, headers_place) {
            warn!("invalid headers: {:?}: {:?}", e, headers);
            self.send_rst_stream(stream_id, ErrorCode::ProtocolError)?;
            return Ok(None);
        }

        let status_1xx = match headers_place {
            HeadersPlace::Initial => {
                let status = headers.status();

                let status_1xx = status >= 100 && status <= 199;
                if status_1xx && end_stream == EndStream::Yes {
                    warn!("1xx headers and end stream: {}", stream_id);
                    self.send_rst_stream(stream_id, ErrorCode::ProtocolError)?;
                    return Ok(None);
                }
                status_1xx
            }
            HeadersPlace::Trailing => {
                if end_stream == EndStream::No {
                    warn!("headers without end stream after data: {}", stream_id);
                    self.send_rst_stream(stream_id, ErrorCode::ProtocolError)?;
                    return Ok(None);
                }
                false
            }
        };

        let mut stream = self.streams.get_mut(stream_id).unwrap();
        if let Some(in_rem_content_length) = headers.content_length() {
            stream.stream().in_rem_content_length = Some(in_rem_content_length);
        }

        stream.stream().in_message_stage = match (headers_place, status_1xx) {
            (HeadersPlace::Initial, false) => InMessageStage::AfterInitialHeaders,
            (HeadersPlace::Initial, true) => InMessageStage::Initial,
            (HeadersPlace::Trailing, _) => InMessageStage::AfterTrailingHeaders,
        };

        // Ignore 1xx headers
        if !status_1xx {
            if let Some(ref mut response_handler) = stream.stream().peer_tx {
                // TODO: reset stream on error
                drop(
                    response_handler.send(ResultOrEof::Item(DataOrHeadersWithFlag {
                        content: DataOrHeaders::Headers(headers),
                        last: end_stream == EndStream::Yes,
                    })),
                );
            } else {
                // TODO: reset stream
            }
        }

        Ok(Some(stream))
    }
}
<commit_msg>Unused code warning<commit_after>//! Single client connection

use std::io;
use std::result::Result as std_Result;
use std::sync::Arc;

use error;
use error::Error;
use result;

use exec::CpuPoolOption;

use solicit::connection::EndStream;
use solicit::frame::settings::*;
use solicit::header::*;
use solicit::StreamId;
use solicit::DEFAULT_SETTINGS;

use service::Service;

use futures::future::Future;
use futures::stream::Stream;
use futures::sync::mpsc::unbounded;
use futures::sync::mpsc::UnboundedSender;
use futures::sync::oneshot;

use tls_api::TlsConnector;

use tokio_core::reactor;
use tokio_io::AsyncRead;
use tokio_io::AsyncWrite;
use tokio_timer::Timer;
use tokio_tls_api;

use solicit_async::*;

use common::*;
use data_or_trailers::*;
use socket::*;

use client_died_error_holder::ClientDiedErrorHolder;
use data_or_headers::DataOrHeaders;
use data_or_headers_with_flag::DataOrHeadersWithFlag;
use headers_place::HeadersPlace;
use req_resp::RequestOrResponse;
use result_or_eof::ResultOrEof;
use std::marker;
use ClientConf;
use ClientTlsOption;
use ErrorCode;

struct ClientTypes<I>(marker::PhantomData<I>);

impl<I> Types for ClientTypes<I>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Io = I;
    type HttpStreamData = ClientStream<I>;
    type HttpStreamSpecific = ClientStreamData;
    type ConnDataSpecific = ClientConnData;
    type ToWriteMessage = ClientToWriteMessage;

    fn out_request_or_response() -> RequestOrResponse {
        RequestOrResponse::Request
    }

    fn first_id() -> StreamId {
        1
    }
}

pub struct ClientStreamData {}

impl HttpStreamDataSpecific for ClientStreamData {}

type ClientStream<I> = HttpStreamCommon<ClientTypes<I>>;

impl<I> HttpStreamData for ClientStream<I>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Types = ClientTypes<I>;
}

pub struct ClientConnData {
    _callbacks: Box<ClientConnCallbacks>,
}

impl ConnSpecific for ClientConnData {}

pub struct ClientConn {
    write_tx: UnboundedSender<ClientToWriteMessage>,
}

unsafe impl Sync for ClientConn {}

pub struct StartRequestMessage {
    pub headers: Headers,
    pub body: HttpStreamAfterHeaders,
    pub resp_tx: oneshot::Sender<Response>,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    WaitForHandshake(oneshot::Sender<result::Result<()>>),
    Common(CommonToWriteMessage),
}

impl From<CommonToWriteMessage> for ClientToWriteMessage {
    fn from(m: CommonToWriteMessage) -> Self {
        ClientToWriteMessage::Common(m)
    }
}

impl<I> ConnWriteSideCustom for Conn<ClientTypes<I>>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Types = ClientTypes<I>;

    fn process_message(&mut self, message: ClientToWriteMessage) -> result::Result<()> {
        match message {
            ClientToWriteMessage::Start(start) => self.process_start(start),
            ClientToWriteMessage::Common(common) => self.process_common_message(common),
            ClientToWriteMessage::WaitForHandshake(tx) => {
                // ignore error
                drop(tx.send(Ok(())));
                Ok(())
            }
        }
    }
}

impl<I> Conn<ClientTypes<I>>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    fn process_start(&mut self, start: StartRequestMessage) -> result::Result<()> {
        let StartRequestMessage {
            headers,
            body,
            resp_tx,
        } = start;

        let stream_id = {
            let stream_id = self.next_local_stream_id();

            let out_window = {
                let (mut http_stream, resp_stream, out_window) = self.new_stream_data(
                    stream_id,
                    None,
                    InMessageStage::Initial,
                    ClientStreamData {},
                );

                if let Err(_) = resp_tx.send(Response::from_stream(resp_stream)) {
                    warn!("caller died");
                }

                http_stream
                    .stream()
                    .outgoing
                    .push_back(DataOrHeaders::Headers(headers));

                out_window
            };

            self.pump_stream_to_write_loop(stream_id, body.into_part_stream(), out_window);

            stream_id
        };

        // Also opens latch if necessary
        self.buffer_outg_stream(stream_id)?;
        Ok(())
    }
}

pub trait ClientConnCallbacks: 'static {
    // called at most once
    fn goaway(&self, stream_id: StreamId, raw_error_code: u32);
}

impl ClientConn {
    fn spawn_connected<I, C>(
        lh: reactor::Handle,
        connect: HttpFutureSend<I>,
        conf: ClientConf,
        callbacks: C,
    ) -> Self
    where
        I: AsyncWrite + AsyncRead + Send + 'static,
        C: ClientConnCallbacks,
    {
        let (to_write_tx, to_write_rx) = unbounded();

        let to_write_rx = Box::new(
            to_write_rx
                .map_err(|()| Error::IoError(io::Error::new(io::ErrorKind::Other, "to_write"))),
        );

        let c = ClientConn {
            write_tx: to_write_tx.clone(),
        };

        let settings_frame = SettingsFrame::from_settings(vec![HttpSetting::EnablePush(false)]);
        let mut settings = DEFAULT_SETTINGS;
        settings.apply_from_frame(&settings_frame);

        let handshake = connect.and_then(|conn| client_handshake(conn, settings_frame));

        let conn_died_error_holder = ClientDiedErrorHolder::new();
        let conn_died_error_holder_copy = conn_died_error_holder.clone();

        let lh_copy = lh.clone();

        let future = handshake.and_then(move |conn| {
            debug!("handshake done");

            let (read, write) = conn.split();

            let conn_data = Conn::<ClientTypes<_>>::new(
                lh_copy,
                CpuPoolOption::SingleThread,
                ClientConnData {
                    _callbacks: Box::new(callbacks),
                },
                conf.common,
                settings,
                to_write_tx.clone(),
                to_write_rx,
                read,
                write,
                conn_died_error_holder,
            );
            conn_data.run()
        });

        let future = conn_died_error_holder_copy.wrap_future(future);

        lh.spawn(future);

        c
    }

    pub fn spawn<H, C>(
        lh: reactor::Handle,
        addr: Box<ToClientStream>,
        tls: ClientTlsOption<C>,
        conf: ClientConf,
        callbacks: H,
    ) -> Self
    where
        H: ClientConnCallbacks,
        C: TlsConnector + Sync,
    {
        match tls {
            ClientTlsOption::Plain => ClientConn::spawn_plain(lh.clone(), addr, conf, callbacks),
            ClientTlsOption::Tls(domain, connector) => {
                ClientConn::spawn_tls(lh.clone(), &domain, connector, addr, conf, callbacks)
            }
        }
    }

    pub fn spawn_plain<C>(
        lh: reactor::Handle,
        addr: Box<ToClientStream>,
        conf: ClientConf,
        callbacks: C,
    ) -> Self
    where
        C: ClientConnCallbacks,
    {
        let no_delay = conf.no_delay.unwrap_or(true);
        let connect = addr.connect(&lh).map_err(Into::into);
        let map_callback = move |socket: Box<StreamItem>| {
            info!("connected to {}", addr);

            if socket.is_tcp() {
                socket
                    .set_nodelay(no_delay)
                    .expect("failed to set TCP_NODELAY");
            }

            socket
        };

        let connect: Box<Future<Item = _, Error = _> + Send> =
            if let Some(timeout) = conf.connection_timeout {
                let timer = Timer::default();
                Box::new(timer.timeout(connect, timeout).map(map_callback))
            } else {
                Box::new(connect.map(map_callback))
            };

        ClientConn::spawn_connected(lh, connect, conf, callbacks)
    }

    pub fn spawn_tls<H, C>(
        lh: reactor::Handle,
        domain: &str,
        connector: Arc<C>,
        addr: Box<ToClientStream>,
        conf: ClientConf,
        callbacks: H,
    ) -> Self
    where
        H: ClientConnCallbacks,
        C: TlsConnector + Sync,
    {
        let domain = domain.to_owned();

        let connect = addr
            .connect(&lh)
            .map(move |c| {
                info!("connected to {}", addr);
                c
            }).map_err(|e| e.into());

        let tls_conn = connect.and_then(move |conn| {
            tokio_tls_api::connect_async(&*connector, &domain, conn)
                .map_err(|e| Error::IoError(io::Error::new(io::ErrorKind::Other, e)))
        });

        let tls_conn = tls_conn.map_err(Error::from);

        ClientConn::spawn_connected(lh, Box::new(tls_conn), conf, callbacks)
    }

    pub fn start_request_with_resp_sender(
        &self,
        start: StartRequestMessage,
    ) -> Result<(), StartRequestMessage> {
        self.write_tx
            .unbounded_send(ClientToWriteMessage::Start(start))
            .map_err(|send_error| match send_error.into_inner() {
                ClientToWriteMessage::Start(start) => start,
                _ => unreachable!(),
            })
    }

    pub fn dump_state_with_resp_sender(&self, tx: oneshot::Sender<ConnStateSnapshot>) {
        let message = ClientToWriteMessage::Common(CommonToWriteMessage::DumpState(tx));
        // ignore error
        drop(self.write_tx.unbounded_send(message));
    }

    /// For tests
    #[doc(hidden)]
    pub fn _dump_state(&self) -> HttpFutureSend<ConnStateSnapshot> {
        let (tx, rx) = oneshot::channel();

        self.dump_state_with_resp_sender(tx);

        let rx =
            rx.map_err(|_| Error::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx)
    }

    pub fn wait_for_connect_with_resp_sender(
        &self,
        tx: oneshot::Sender<result::Result<()>>,
    ) -> std_Result<(), oneshot::Sender<result::Result<()>>> {
        self.write_tx
            .unbounded_send(ClientToWriteMessage::WaitForHandshake(tx))
            .map_err(|send_error| match send_error.into_inner() {
                ClientToWriteMessage::WaitForHandshake(tx) => tx,
                _ => unreachable!(),
            })
    }
}

impl Service for ClientConn {
    // TODO: copy-paste with Client::start_request
    fn start_request(&self, headers: Headers, body: HttpStreamAfterHeaders) -> Response {
        let (resp_tx, resp_rx) = oneshot::channel();

        let start = StartRequestMessage {
            headers: headers,
            body: body,
            resp_tx: resp_tx,
        };

        if let Err(_) = self.start_request_with_resp_sender(start) {
            return Response::err(error::Error::Other("client died"));
        }

        let resp_rx =
            resp_rx.map_err(|oneshot::Canceled| error::Error::Other("client likely died"));

        let resp_rx = resp_rx.map(|r| r.into_stream_flag());

        let resp_rx = resp_rx.flatten_stream();

        Response::from_stream(resp_rx)
    }
}

impl<I> ConnReadSideCustom for Conn<ClientTypes<I>>
where
    I: AsyncWrite + AsyncRead + Send + 'static,
{
    type Types = ClientTypes<I>;

    fn process_headers(
        &mut self,
        stream_id: StreamId,
        end_stream: EndStream,
        headers: Headers,
    ) -> result::Result<Option<HttpStreamRef<ClientTypes<I>>>> {
        let existing_stream = self
            .get_stream_for_headers_maybe_send_error(stream_id)?
            .is_some();
        if !existing_stream {
            return Ok(None);
        }

        let in_message_stage = self
            .streams
            .get_mut(stream_id)
            .unwrap()
            .stream()
            .in_message_stage;

        let headers_place = match in_message_stage {
            InMessageStage::Initial => HeadersPlace::Initial,
            InMessageStage::AfterInitialHeaders => HeadersPlace::Trailing,
            InMessageStage::AfterTrailingHeaders => {
                return Err(error::Error::InternalError(format!(
                    "closed stream must be handled before"
                )));
            }
        };

        if let Err(e) = headers.validate(RequestOrResponse::Response, headers_place) {
            warn!("invalid headers: {:?}: {:?}", e, headers);
            self.send_rst_stream(stream_id, ErrorCode::ProtocolError)?;
            return Ok(None);
        }

        let status_1xx = match headers_place {
            HeadersPlace::Initial => {
                let status = headers.status();

                let status_1xx = status >= 100 && status <= 199;
                if status_1xx && end_stream == EndStream::Yes {
                    warn!("1xx headers and end stream: {}", stream_id);
                    self.send_rst_stream(stream_id, ErrorCode::ProtocolError)?;
                    return Ok(None);
                }
                status_1xx
            }
            HeadersPlace::Trailing => {
                if end_stream == EndStream::No {
                    warn!("headers without end stream after data: {}", stream_id);
                    self.send_rst_stream(stream_id, ErrorCode::ProtocolError)?;
                    return Ok(None);
                }
                false
            }
        };

        let mut stream = self.streams.get_mut(stream_id).unwrap();
        if let Some(in_rem_content_length) = headers.content_length() {
            stream.stream().in_rem_content_length = Some(in_rem_content_length);
        }

        stream.stream().in_message_stage = match (headers_place, status_1xx) {
            (HeadersPlace::Initial, false) => InMessageStage::AfterInitialHeaders,
            (HeadersPlace::Initial, true) => InMessageStage::Initial,
            (HeadersPlace::Trailing, _) => InMessageStage::AfterTrailingHeaders,
        };

        // Ignore 1xx headers
        if !status_1xx {
            if let Some(ref mut response_handler) = stream.stream().peer_tx {
                // TODO: reset stream on error
                drop(
                    response_handler.send(ResultOrEof::Item(DataOrHeadersWithFlag {
                        content: DataOrHeaders::Headers(headers),
                        last: end_stream == EndStream::Yes,
                    })),
                );
            } else {
                // TODO: reset stream
            }
        }

        Ok(Some(stream))
    }
}
<|endoftext|>