<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! A `manticore` "server" and "client" for a PA-RoT.
//!
//! This module provides structures for serving responses to a host making
//! requests to a PA-RoT.

use crate::cert;
use crate::crypto::csrng;
use crate::crypto::hash;
use crate::crypto::hash::EngineExt as _;
use crate::crypto::sig;
use crate::hardware;
use crate::mem::Arena;
use crate::mem::ArenaExt as _;
use crate::net;
use crate::net::CerberusHeader;
use crate::protocol;
use crate::protocol::capabilities;
use crate::protocol::device_id;
use crate::protocol::get_digests::KeyExchangeAlgo;
use crate::protocol::Req;
use crate::protocol::Resp;
use crate::server::Error;
use crate::session::Session;

use crate::server::handler::prelude::*;

/// Options struct for initializing a [`PaRot`].
pub struct Options<'a> {
    /// A handle to the "hardware identity" of the device.
    pub identity: &'a dyn hardware::Identity,
    /// A handle for looking up reset-related information for the current
    /// device.
    pub reset: &'a dyn hardware::Reset,

    /// A handle to a hashing engine.
    pub hasher: &'a mut dyn hash::Engine,
    /// A handle to a signature verification engine,
    pub ciphers: &'a mut dyn sig::Ciphers,
    /// A random number generator for creating nonces and ephemeral keys.
    pub csrng: &'a mut dyn csrng::Csrng,
    /// The trust chain to use for the challenge.
    pub trust_chain: &'a mut dyn cert::TrustChain,

    /// The session manager.
    pub session: &'a mut dyn Session,

    /// The value of PMR0.
    ///
    /// Eventually this should be replaced with a general "PMRs"
    /// trait.
    pub pmr0: &'a [u8],

    /// This device's silicon identifier.
    pub device_id: device_id::DeviceIdentifier,
    /// Integration-provided description of the device's networking
    /// capabilities.
    pub networking: capabilities::Networking,
    /// Integration-provided "acceptable timeout" lengths.
    pub timeouts: capabilities::Timeouts,
}

/// A PA-RoT, or "Platform Root of Trust", server.
///
/// This type implements the request -> response "business logic" of the
/// host <-> PA-RoT interaction. That is, it accepts input and output buffers,
/// and from those, parses incoming requests and processes them into responses.
pub struct PaRot<'a> {
    opts: Options<'a>,
    ok_count: u16,
    err_count: u16,

    /// State from the last `GetDigests`, which records whether the
    /// following `Challenge` will be used to initiate a key exchange.
    /// This prevents the `Challenge` from clobbering session state if
    /// key exchange won't happen.
    key_exchange: Option<KeyExchangeAlgo>,

    /// The most recent certificate slot used for an ECDH-seeding
    /// `Challenge`. This records which certificate's key needs to sign
    /// the ECDH keypair in the key exchange.
    ///
    /// Note that this is *only* changed when the most recent `GetDigests`
    /// indicated a forthcoming key exchange.
    current_cert_slot: Option<u8>,
}

impl<'a> PaRot<'a> {
    /// Create a new `PaRot` with the given `Options`.
    pub fn new(opts: Options<'a>) -> Self {
        Self {
            opts,
            ok_count: 0,
            err_count: 0,
            key_exchange: None,
            current_cert_slot: None,
        }
    }

    /// Process a single incoming request.
    pub fn process_request<'req>(
        &mut self,
        host_port: &mut dyn net::host::HostPort<'req, CerberusHeader>,
        arena: &'req dyn Arena,
    ) -> Result<(), Error<CerberusHeader>> {
        // Style note: when defining a new handler, if it is more than a
        // handful of lines long, define it out-of-line instead.
        let result = Handler::<&mut Self, CerberusHeader>::new()
            .handle::<protocol::FirmwareVersion, _>(|ctx| {
                ctx.server.handle_fw_version(&ctx.req)
            })
            .handle::<protocol::DeviceCapabilities, _>(|ctx| {
                ctx.server.handle_capabilities(&ctx.req)
            })
            .handle::<protocol::DeviceId, _>(|ctx| {
                Ok(Resp::<protocol::DeviceId> {
                    id: ctx.server.opts.device_id,
                })
            })
            .handle::<protocol::DeviceInfo, _>(|ctx| {
                Ok(Resp::<protocol::DeviceInfo> {
                    info: ctx.server.opts.identity.unique_device_identity(),
                })
            })
            .handle::<protocol::GetDigests, _>(|ctx| {
                ctx.server.handle_digests(ctx.arena, &ctx.req)
            })
            .handle::<protocol::GetCert, _>(|ctx| {
                ctx.server.handle_cert(&ctx.req)
            })
            .handle_buffered::<protocol::Challenge, _>(|ctx| {
                ctx.server
                    .handle_challenge(ctx.arena, &ctx.req, ctx.req_buf)
            })
            .handle::<protocol::KeyExchange, _>(|ctx| {
                ctx.server.handle_key_xchg(ctx.arena, &ctx.req)
            })
            .handle::<protocol::ResetCounter, _>(|ctx| {
                use protocol::reset_counter::ResetType;
                // NOTE: Currently, we only handle "local resets" for port 0,
                // the "self" port.
                if ctx.req.reset_type != ResetType::Local
                    || ctx.req.port_id != 0
                {
                    return Err(protocol::error::Error::OutOfRange);
                }

                Ok(Resp::<protocol::ResetCounter> {
                    count: ctx.server.opts.reset.resets_since_power_on() as u16,
                })
            })
            .handle::<protocol::DeviceUptime, _>(|ctx| {
                // NOTE: Currently, we only handle port 0, the "self" port.
                if ctx.req.port_id != 0 {
                    return Err(protocol::error::Error::OutOfRange);
                }

                Ok(Resp::<protocol::DeviceUptime> {
                    uptime: ctx.server.opts.reset.uptime(),
                })
            })
            .handle::<protocol::RequestCounter, _>(|ctx| {
                Ok(Resp::<protocol::RequestCounter> {
                    ok_count: ctx.server.ok_count,
                    err_count: ctx.server.err_count,
                })
            })
            .run(self, host_port, arena);

        match result {
            Ok(_) => self.ok_count += 1,
            Err(_) => self.err_count += 1,
        }
        result
    }

    fn handle_fw_version(
        &mut self,
        req: &Req<protocol::FirmwareVersion>,
    ) -> Result<
        Resp<protocol::FirmwareVersion>,
        protocol::Error<protocol::FirmwareVersion>,
    > {
        if req.index == 0 {
            return Ok(Resp::<protocol::FirmwareVersion> {
                version: self.opts.identity.firmware_version(),
            });
        }

        let version = self
            .opts
            .identity
            .vendor_firmware_version(req.index)
            .ok_or(protocol::error::Error::OutOfRange)?;
        Ok(Resp::<protocol::FirmwareVersion> { version })
    }

    fn handle_capabilities(
        &mut self,
        req: &Req<protocol::DeviceCapabilities>,
    ) -> Result<
        Resp<protocol::DeviceCapabilities>,
        protocol::Error<protocol::DeviceCapabilities>,
    > {
        use enumflags2::BitFlags;
        use protocol::capabilities::*;
        let mut crypto = req.capabilities.crypto;

        self.opts.ciphers.negotiate(&mut crypto);
        crypto.has_aes = false;
        crypto.aes_strength = BitFlags::<AesKeyStrength>::empty();

        let capabilities = Capabilities {
            networking: self.opts.networking,
            security: BitFlags::<Security>::empty(),

            has_pfm_support: false,
            has_policy_support: false,
            has_firmware_protection: false,

            crypto,
        };

        Ok(Resp::<protocol::DeviceCapabilities> {
            capabilities,
            timeouts: self.opts.timeouts,
        })
    }

    fn handle_digests<'req>(
        &mut self,
        arena: &'req dyn Arena,
        req: &Req<protocol::GetDigests>,
    ) -> Result<
        Resp<'req, protocol::GetDigests>,
        protocol::Error<protocol::GetDigests>,
    > {
        let digests_len = self
            .opts
            .trust_chain
            .chain_len(req.slot)
            .ok_or(protocol::error::ChallengeError::UnknownChain)?
            .get();
        let digests = arena
            .alloc_slice::<[u8; hash::Algo::Sha256.bytes()]>(digests_len)?;
        for (i, digest) in digests.iter_mut().enumerate() {
            let cert = self
                .opts
                .trust_chain
                .cert(req.slot, i)
                .ok_or(protocol::error::ChallengeError::UnknownChain)?;
            self.opts.hasher.contiguous_hash(
                hash::Algo::Sha256,
                cert.raw(),
                digest,
            )?;
        }

        self.key_exchange = Some(req.key_exchange);
        Ok(Resp::<protocol::GetDigests> { digests })
    }

    fn handle_cert(
        &mut self,
        req: &Req<protocol::GetCert>,
    ) -> Result<Resp<protocol::GetCert>, protocol::Error<protocol::GetCert>>
    {
        let cert = self
            .opts
            .trust_chain
            .cert(req.slot, req.cert_number as usize)
            .ok_or(protocol::error::ChallengeError::UnknownChain)?;

        let start = cert.raw().len().min(req.offset as usize);
        let end = cert
            .raw()
            .len()
            .min((req.len as usize).saturating_add(start));
        Ok(Resp::<protocol::GetCert> {
            slot: req.slot,
            cert_number: req.cert_number,
            data: &cert.raw()[start..end],
        })
    }

    fn handle_challenge<'req>(
        &'req mut self,
        arena: &'req dyn Arena,
        req: &Req<protocol::Challenge>,
        req_buf: &[u8],
    ) -> Result<
        Resp<'req, protocol::Challenge>,
        protocol::Error<protocol::Challenge>,
    > {
        use protocol::challenge::ChallengeResponseTbs;
        let signer = self
            .opts
            .trust_chain
            .signer(req.slot)
            .ok_or(protocol::error::ChallengeError::UnknownChain)?;
        let nonce = arena.alloc::<[u8; 32]>()?;
        self.opts.csrng.fill(nonce)?;

        let tbs = ChallengeResponseTbs {
            slot: req.slot,
            slot_mask: 0, // Currently unspecified?
            protocol_range: (0, 0),
            nonce,
            pmr0_components: 0,
            pmr0: self.opts.pmr0,
        };

        let signature = arena.alloc_slice::<u8>(signer.sig_bytes())?;
        let sig_len = tbs.as_iovec_with(|[a, b, c, d]| {
            signer.sign(&[req_buf, a, b, c, d], signature)
        })?;
        let signature = &signature[..sig_len];

        if let Some(KeyExchangeAlgo::Ecdh) = self.key_exchange {
            self.opts.session.create_session(req.nonce, tbs.nonce)?;
            self.current_cert_slot = Some(tbs.slot);
        }

        Ok(Resp::<protocol::Challenge> { tbs, signature })
    }

    fn handle_key_xchg<'req>(
        &mut self,
        arena: &'req dyn Arena,
        req: &Req<protocol::KeyExchange>,
    ) -> Result<
        Resp<'req, protocol::KeyExchange>,
        protocol::Error<protocol::KeyExchange>,
    > {
        use protocol::key_exchange::*;
        match req {
            Req::<KeyExchange>::SessionKey {
                hmac_algorithm,
                pk_req,
            } => {
                let slot = self
                    .current_cert_slot
                    .ok_or(protocol::error::Error::OutOfRange)?;
                let signer = self
                    .opts
                    .trust_chain
                    .signer(slot)
                    .ok_or(protocol::error::ChallengeError::UnknownChain)?;

                let pk_resp =
                    arena.alloc_slice(self.opts.session.ephemeral_bytes())?;
                let key_len = self.opts.session.begin_ecdh(pk_resp)?;
                let pk_resp = &pk_resp[..key_len];
                self.opts.session.finish_ecdh(*hmac_algorithm, pk_req)?;

                let signature = arena.alloc_slice(signer.sig_bytes())?;
                signer.sign(&[pk_req, pk_resp], signature)?;

                let chain_len = self
                    .opts
                    .trust_chain
                    .chain_len(slot)
                    .ok_or(protocol::error::Error::OutOfRange)?
                    .get();
                let alias_cert = self
                    .opts
                    .trust_chain
                    .cert(slot, chain_len - 1)
                    .ok_or(protocol::error::Error::OutOfRange)?;

                let alias_cert_hmac = hmac_algorithm.alloc(arena)?;
                let (_, hmac_key) = self
                    .opts
                    .session
                    .hmac_key()
                    .ok_or(protocol::error::Error::Internal)?;
                self.opts.hasher.contiguous_hmac(
                    *hmac_algorithm,
                    hmac_key,
                    alias_cert.raw(),
                    alias_cert_hmac,
                )?;

                Ok(Resp::<KeyExchange>::SessionKey {
                    pk_resp,
                    signature,
                    alias_cert_hmac,
                })
            }
            _ => Err(protocol::error::Error::Internal),
        }
    }
}
<commit_msg>[server] Implement a couple of SPDM commands<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! A `manticore` "server" and "client" for a PA-RoT.
//!
//! This module provides structures for serving responses to a host making
//! requests to a PA-RoT.

use crate::cert;
use crate::crypto::csrng;
use crate::crypto::hash;
use crate::crypto::hash::EngineExt as _;
use crate::crypto::sig;
use crate::hardware;
use crate::mem::Arena;
use crate::mem::ArenaExt as _;
use crate::net;
use crate::net::CerberusHeader;
use crate::net::SpdmHeader;
use crate::protocol;
use crate::protocol::capabilities;
use crate::protocol::device_id;
use crate::protocol::get_digests::KeyExchangeAlgo;
use crate::protocol::spdm;
use crate::protocol::Req;
use crate::protocol::Resp;
use crate::server::Error;
use crate::session::Session;

use crate::server::handler::prelude::*;

/// Options struct for initializing a [`PaRot`].
pub struct Options<'a> {
    /// A handle to the "hardware identity" of the device.
    pub identity: &'a dyn hardware::Identity,
    /// A handle for looking up reset-related information for the current
    /// device.
    pub reset: &'a dyn hardware::Reset,

    /// A handle to a hashing engine.
    pub hasher: &'a mut dyn hash::Engine,
    /// A handle to a signature verification engine,
    pub ciphers: &'a mut dyn sig::Ciphers,
    /// A random number generator for creating nonces and ephemeral keys.
    pub csrng: &'a mut dyn csrng::Csrng,
    /// The trust chain to use for the challenge.
    pub trust_chain: &'a mut dyn cert::TrustChain,

    /// The session manager.
    pub session: &'a mut dyn Session,

    /// The value of PMR0.
    ///
    /// Eventually this should be replaced with a general "PMRs"
    /// trait.
    pub pmr0: &'a [u8],

    /// This device's silicon identifier.
    pub device_id: device_id::DeviceIdentifier,
    /// Integration-provided description of the device's networking
    /// capabilities.
    pub networking: capabilities::Networking,
    /// Integration-provided "acceptable timeout" lengths.
    pub timeouts: capabilities::Timeouts,
}

/// A PA-RoT, or "Platform Root of Trust", server.
///
/// This type implements the request -> response "business logic" of the
/// host <-> PA-RoT interaction. That is, it accepts input and output buffers,
/// and from those, parses incoming requests and processes them into responses.
pub struct PaRot<'a> {
    opts: Options<'a>,
    ok_count: u16,
    err_count: u16,

    /// State from the last `GetDigests`, which records whether the
    /// following `Challenge` will be used to initiate a key exchange.
    /// This prevents the `Challenge` from clobbering session state if
    /// key exchange won't happen.
    key_exchange: Option<KeyExchangeAlgo>,

    /// The most recent certificate slot used for an ECDH-seeding
    /// `Challenge`. This records which certificate's key needs to sign
    /// the ECDH keypair in the key exchange.
    ///
    /// Note that this is *only* changed when the most recent `GetDigests`
    /// indicated a forthcoming key exchange.
    current_cert_slot: Option<u8>,
}

impl<'a> PaRot<'a> {
    /// Create a new `PaRot` with the given `Options`.
    pub fn new(opts: Options<'a>) -> Self {
        Self {
            opts,
            ok_count: 0,
            err_count: 0,
            key_exchange: None,
            current_cert_slot: None,
        }
    }

    /// Process a single incoming request.
    pub fn process_request<'req>(
        &mut self,
        host_port: &mut dyn net::host::HostPort<'req, CerberusHeader>,
        arena: &'req dyn Arena,
    ) -> Result<(), Error<CerberusHeader>> {
        // Style note: when defining a new handler, if it is more than a
        // handful of lines long, define it out-of-line instead.
        let result = Handler::<&mut Self, CerberusHeader>::new()
            .handle::<protocol::FirmwareVersion, _>(|ctx| {
                ctx.server.handle_fw_version(&ctx.req)
            })
            .handle::<protocol::DeviceCapabilities, _>(|ctx| {
                ctx.server.handle_capabilities(&ctx.req)
            })
            .handle::<protocol::DeviceId, _>(|ctx| {
                Ok(Resp::<protocol::DeviceId> {
                    id: ctx.server.opts.device_id,
                })
            })
            .handle::<protocol::DeviceInfo, _>(|ctx| {
                Ok(Resp::<protocol::DeviceInfo> {
                    info: ctx.server.opts.identity.unique_device_identity(),
                })
            })
            .handle::<protocol::GetDigests, _>(|ctx| {
                ctx.server.handle_digests(ctx.arena, &ctx.req)
            })
            .handle::<protocol::GetCert, _>(|ctx| {
                ctx.server.handle_cert(&ctx.req)
            })
            .handle_buffered::<protocol::Challenge, _>(|ctx| {
                ctx.server
                    .handle_challenge(ctx.arena, &ctx.req, ctx.req_buf)
            })
            .handle::<protocol::KeyExchange, _>(|ctx| {
                ctx.server.handle_key_xchg(ctx.arena, &ctx.req)
            })
            .handle::<protocol::ResetCounter, _>(|ctx| {
                use protocol::reset_counter::ResetType;
                // NOTE: Currently, we only handle "local resets" for port 0,
                // the "self" port.
                if ctx.req.reset_type != ResetType::Local
                    || ctx.req.port_id != 0
                {
                    return Err(protocol::error::Error::OutOfRange);
                }

                Ok(Resp::<protocol::ResetCounter> {
                    count: ctx.server.opts.reset.resets_since_power_on() as u16,
                })
            })
            .handle::<protocol::DeviceUptime, _>(|ctx| {
                // NOTE: Currently, we only handle port 0, the "self" port.
                if ctx.req.port_id != 0 {
                    return Err(protocol::error::Error::OutOfRange);
                }

                Ok(Resp::<protocol::DeviceUptime> {
                    uptime: ctx.server.opts.reset.uptime(),
                })
            })
            .handle::<protocol::RequestCounter, _>(|ctx| {
                Ok(Resp::<protocol::RequestCounter> {
                    ok_count: ctx.server.ok_count,
                    err_count: ctx.server.err_count,
                })
            })
            .run(self, host_port, arena);

        match result {
            Ok(_) => self.ok_count += 1,
            Err(_) => self.err_count += 1,
        }
        result
    }

    fn handle_fw_version(
        &mut self,
        req: &Req<protocol::FirmwareVersion>,
    ) -> Result<
        Resp<protocol::FirmwareVersion>,
        protocol::Error<protocol::FirmwareVersion>,
    > {
        if req.index == 0 {
            return Ok(Resp::<protocol::FirmwareVersion> {
                version: self.opts.identity.firmware_version(),
            });
        }

        let version = self
            .opts
            .identity
            .vendor_firmware_version(req.index)
            .ok_or(protocol::error::Error::OutOfRange)?;
        Ok(Resp::<protocol::FirmwareVersion> { version })
    }

    fn handle_capabilities(
        &mut self,
        req: &Req<protocol::DeviceCapabilities>,
    ) -> Result<
        Resp<protocol::DeviceCapabilities>,
        protocol::Error<protocol::DeviceCapabilities>,
    > {
        use enumflags2::BitFlags;
        use protocol::capabilities::*;
        let mut crypto = req.capabilities.crypto;

        self.opts.ciphers.negotiate(&mut crypto);
        crypto.has_aes = false;
        crypto.aes_strength = BitFlags::<AesKeyStrength>::empty();

        let capabilities = Capabilities {
            networking: self.opts.networking,
            security: BitFlags::<Security>::empty(),

            has_pfm_support: false,
            has_policy_support: false,
            has_firmware_protection: false,

            crypto,
        };

        Ok(Resp::<protocol::DeviceCapabilities> {
            capabilities,
            timeouts: self.opts.timeouts,
        })
    }

    fn handle_digests<'req>(
        &mut self,
        arena: &'req dyn Arena,
        req: &Req<protocol::GetDigests>,
    ) -> Result<
        Resp<'req, protocol::GetDigests>,
        protocol::Error<protocol::GetDigests>,
    > {
        let digests_len = self
            .opts
            .trust_chain
            .chain_len(req.slot)
            .ok_or(protocol::error::ChallengeError::UnknownChain)?
            .get();
        let digests = arena
            .alloc_slice::<[u8; hash::Algo::Sha256.bytes()]>(digests_len)?;
        for (i, digest) in digests.iter_mut().enumerate() {
            let cert = self
                .opts
                .trust_chain
                .cert(req.slot, i)
                .ok_or(protocol::error::ChallengeError::UnknownChain)?;
            self.opts.hasher.contiguous_hash(
                hash::Algo::Sha256,
                cert.raw(),
                digest,
            )?;
        }

        self.key_exchange = Some(req.key_exchange);
        Ok(Resp::<protocol::GetDigests> { digests })
    }

    fn handle_cert(
        &mut self,
        req: &Req<protocol::GetCert>,
    ) -> Result<Resp<protocol::GetCert>, protocol::Error<protocol::GetCert>>
    {
        let cert = self
            .opts
            .trust_chain
            .cert(req.slot, req.cert_number as usize)
            .ok_or(protocol::error::ChallengeError::UnknownChain)?;

        let start = cert.raw().len().min(req.offset as usize);
        let end = cert
            .raw()
            .len()
            .min((req.len as usize).saturating_add(start));
        Ok(Resp::<protocol::GetCert> {
            slot: req.slot,
            cert_number: req.cert_number,
            data: &cert.raw()[start..end],
        })
    }

    fn handle_challenge<'req>(
        &'req mut self,
        arena: &'req dyn Arena,
        req: &Req<protocol::Challenge>,
        req_buf: &[u8],
    ) -> Result<
        Resp<'req, protocol::Challenge>,
        protocol::Error<protocol::Challenge>,
    > {
        use protocol::challenge::ChallengeResponseTbs;
        let signer = self
            .opts
            .trust_chain
            .signer(req.slot)
            .ok_or(protocol::error::ChallengeError::UnknownChain)?;
        let nonce = arena.alloc::<[u8; 32]>()?;
        self.opts.csrng.fill(nonce)?;

        let tbs = ChallengeResponseTbs {
            slot: req.slot,
            slot_mask: 0, // Currently unspecified?
            protocol_range: (0, 0),
            nonce,
            pmr0_components: 0,
            pmr0: self.opts.pmr0,
        };

        let signature = arena.alloc_slice::<u8>(signer.sig_bytes())?;
        let sig_len = tbs.as_iovec_with(|[a, b, c, d]| {
            signer.sign(&[req_buf, a, b, c, d], signature)
        })?;
        let signature = &signature[..sig_len];

        if let Some(KeyExchangeAlgo::Ecdh) = self.key_exchange {
            self.opts.session.create_session(req.nonce, tbs.nonce)?;
            self.current_cert_slot = Some(tbs.slot);
        }

        Ok(Resp::<protocol::Challenge> { tbs, signature })
    }

    fn handle_key_xchg<'req>(
        &mut self,
        arena: &'req dyn Arena,
        req: &Req<protocol::KeyExchange>,
    ) -> Result<
        Resp<'req, protocol::KeyExchange>,
        protocol::Error<protocol::KeyExchange>,
    > {
        use protocol::key_exchange::*;
        match req {
            Req::<KeyExchange>::SessionKey {
                hmac_algorithm,
                pk_req,
            } => {
                let slot = self
                    .current_cert_slot
                    .ok_or(protocol::error::Error::OutOfRange)?;
                let signer = self
                    .opts
                    .trust_chain
                    .signer(slot)
                    .ok_or(protocol::error::ChallengeError::UnknownChain)?;

                let pk_resp =
                    arena.alloc_slice(self.opts.session.ephemeral_bytes())?;
                let key_len = self.opts.session.begin_ecdh(pk_resp)?;
                let pk_resp = &pk_resp[..key_len];
                self.opts.session.finish_ecdh(*hmac_algorithm, pk_req)?;

                let signature = arena.alloc_slice(signer.sig_bytes())?;
                signer.sign(&[pk_req, pk_resp], signature)?;

                let chain_len = self
                    .opts
                    .trust_chain
                    .chain_len(slot)
                    .ok_or(protocol::error::Error::OutOfRange)?
                    .get();
                let alias_cert = self
                    .opts
                    .trust_chain
                    .cert(slot, chain_len - 1)
                    .ok_or(protocol::error::Error::OutOfRange)?;

                let alias_cert_hmac = hmac_algorithm.alloc(arena)?;
                let (_, hmac_key) = self
                    .opts
                    .session
                    .hmac_key()
                    .ok_or(protocol::error::Error::Internal)?;
                self.opts.hasher.contiguous_hmac(
                    *hmac_algorithm,
                    hmac_key,
                    alias_cert.raw(),
                    alias_cert_hmac,
                )?;

                Ok(Resp::<KeyExchange>::SessionKey {
                    pk_resp,
                    signature,
                    alias_cert_hmac,
                })
            }
            _ => Err(protocol::error::Error::Internal),
        }
    }

    /// Process a single incoming SPDM request.
    pub fn process_spdm_request<'req>(
        &mut self,
        host_port: &mut dyn net::host::HostPort<'req, SpdmHeader>,
        arena: &'req dyn Arena,
    ) -> Result<(), Error<SpdmHeader>> {
        // Style note: when defining a new handler, if it is more than a
        // handful of lines long, define it out-of-line instead.
        let result = Handler::<&mut Self, SpdmHeader>::new()
            .handle::<spdm::GetVersion, _>(|_| {
                Ok(Resp::<spdm::GetVersion> {
                    versions: &[spdm::ExtendedVersion::MANTICORE],
                })
            })
            .handle::<spdm::GetCaps, _>(|ctx| {
                Ok(Resp::<spdm::GetCaps> {
                    crypto_timeout: ctx.server.opts.timeouts.crypto,
                    caps: spdm::get_caps::Caps::manticore(),
                    max_packet_size: ctx.server.opts.networking.max_packet_size as u32,
                    max_message_size: ctx.server.opts.networking.max_message_size as u32,
                })
            })
            .run(self, host_port, arena);

        match result {
            Ok(_) => self.ok_count += 1,
            Err(_) => self.err_count += 1,
        }
        result
    }
}
<|endoftext|>


<commit_before>//! Local server that accepts SOCKS 5 protocol

use std::{io, net::SocketAddr, sync::Arc};

use futures::{self, stream::Stream, Future};

use log::{debug, error, info, trace, warn};
use tokio::{
    self,
    net::{TcpListener, TcpStream},
};
use tokio_io::{
    io::{flush, ReadHalf, WriteHalf},
    AsyncRead,
};

use crate::{config::ServerConfig, context::SharedContext};

use crate::relay::{
    boxed_future,
    loadbalancing::server::{LoadBalancer, RoundRobin},
    socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
    tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
};

use super::{ignore_until_end, try_timeout, tunnel};

#[derive(Debug, Clone)]
struct UdpConfig {
    enable_udp: bool,
    client_addr: SocketAddr,
}

fn handle_socks5_connect(
    context: SharedContext,
    (r, w): (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
    client_addr: SocketAddr,
    addr: Address,
    svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = (), Error = io::Error> + Send {
    let timeout = svr_cfg.timeout();
    super::connect_proxy_server(context, svr_cfg.clone())
        .then(move |res| {
            let (header, r) = match res {
                Ok(svr_s) => {
                    trace!("Proxy server connected");

                    // Tell the client that we are ready
                    let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(client_addr));

                    (header, Ok(svr_s))
                }
                Err(err) => {
                    use crate::relay::socks5::Reply;
                    use std::io::ErrorKind;

                    error!("Failed to connect remote server, err: {}", err);

                    let reply = match err.kind() {
                        ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
                        ErrorKind::ConnectionAborted => Reply::HostUnreachable,
                        _ => Reply::NetworkUnreachable,
                    };

                    let header = TcpResponseHeader::new(reply, Address::SocketAddress(client_addr));

                    (header, Err(err))
                }
            };

            trace!("Sent header: {:?}", header);
            try_timeout(header.write_to(w).and_then(flush), timeout).and_then(|w| match r {
                Ok(svr_s) => Ok((svr_s, w)),
                Err(err) => Err(err),
            })
        })
        .and_then(move |(svr_s, w)| {
            let timeout = svr_cfg.timeout();
            super::proxy_server_handshake(svr_s, svr_cfg, addr).and_then(move |(svr_r, svr_w)| {
                let rhalf = svr_r.and_then(move |svr_r| svr_r.copy_timeout_opt(w, timeout));
                let whalf = svr_w.and_then(move |svr_w| svr_w.copy_timeout_opt(r, timeout));
                tunnel(whalf, rhalf)
            })
        })
}

fn handle_socks5_client(
    context: SharedContext,
    s: TcpStream,
    conf: Arc<ServerConfig>,
    udp_conf: UdpConfig,
) -> io::Result<()> {
    if let Err(err) = s.set_keepalive(conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if context.config().no_delay {
        if let Err(err) = s.set_nodelay(true) {
            error!("Failed to set no delay: {:?}", err);
        }
    }

    let client_addr = s.peer_addr()?;
    let cloned_client_addr = client_addr;
    let fut = futures::lazy(|| Ok(s.split()))
        .and_then(|(r, w)| {
            // Socks5 handshakes
            HandshakeRequest::read_from(r).and_then(move |(r, req)| {
                trace!("Socks5 {:?}", req);

                let (resp, res) = if !req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
                    warn!("Currently shadowsocks-rust does not support authentication");
                    (
                        resp,
                        Err(io::Error::new(
                            io::ErrorKind::Other,
                            "Currently shadowsocks-rust does not support authentication",
                        )),
                    )
                } else {
                    // Reply to client
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
                    trace!("Reply handshake {:?}", resp);
                    (resp, Ok(()))
                };

                resp.write_to(w).and_then(flush).and_then(move |w| match res {
                    Ok(..) => Ok((r, w)),
                    Err(err) => Err(err),
                })
            })
        })
        .and_then(move |(r, w)| {
            // Fetch headers
            TcpRequestHeader::read_from(r).then(move |res| match res {
                Ok((r, h)) => boxed_future(futures::finished((r, w, h))),
                Err(err) => {
                    error!("Failed to get TcpRequestHeader: {}", err);
                    let fut = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr))
                        .write_to(w)
                        .then(|_| Err(From::from(err)));
                    boxed_future(fut)
                }
            })
        })
        .and_then(move |(r, w, header)| {
            trace!("Socks5 {:?}", header);

            let addr = header.address;
            match header.command {
                socks5::Command::TcpConnect => {
                    let enable_tcp = context.config().mode.enable_tcp();
                    if enable_tcp {
                        debug!("CONNECT {}", addr);
                        let fut = handle_socks5_connect(context, (r, w), cloned_client_addr, addr.clone(), conf)
                            .map_err(move |err| {
                                io::Error::new(err.kind(), format!("CONNECT {} failed with error \"{}\"", addr, err))
                            });
                        boxed_future(fut)
                    } else {
                        warn!("CONNECT is not enabled");
                        let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                            .write_to(w)
                            .map(|_| ());
                        boxed_future(fut)
                    }
                }
                socks5::Command::TcpBind => {
                    warn!("BIND is not supported");
                    let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                        .write_to(w)
                        .map(|_| ());
                    boxed_future(fut)
                }
                socks5::Command::UdpAssociate => {
                    if udp_conf.enable_udp {
                        debug!("UDP ASSOCIATE {}", addr);
                        let fut = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr))
                            .write_to(w)
                            .and_then(flush)
                            .and_then(|_| {
                                // Hold the connection until it ends by its own
                                ignore_until_end(r).map(|_| ())
                            });

                        boxed_future(fut)
                    } else {
                        warn!("UDP ASSOCIATE is not enabled");
                        let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                            .write_to(w)
                            .map(|_| ());
                        boxed_future(fut)
                    }
                }
            }
        });

    tokio::spawn(fut.then(|res| match res {
        Ok(..) => Ok(()),
        Err(err) => {
            if err.kind() != io::ErrorKind::BrokenPipe {
                error!("Socks5 client: {}", err);
            }
            Err(())
        }
    }));

    Ok(())
}

/// Starts a TCP local server with Socks5 proxy protocol
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
    let local_addr = *context.config().local.as_ref().expect("Missing local config");

    let listener =
        TcpListener::bind(&local_addr).unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));

    info!("ShadowSocks TCP Listening on {}", local_addr);

    let udp_conf = UdpConfig {
        enable_udp: context.config().mode.enable_udp(),
        client_addr: local_addr,
    };

    let mut servers = RoundRobin::new(context.config());
    listener.incoming().for_each(move |socket| {
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", socket.peer_addr()?);
        trace!("Picked proxy server: {:?}", server_cfg);

        handle_socks5_client(context.clone(), socket, server_cfg, udp_conf.clone())
    })
}
<commit_msg>Properly display the port bound to (#148)<commit_after>//! Local server that accepts SOCKS 5 protocol

use std::{io, net::SocketAddr, sync::Arc};

use futures::{self, stream::Stream, Future};

use log::{debug, error, info, trace, warn};
use tokio::{
    self,
    net::{TcpListener, TcpStream},
};
use tokio_io::{
    io::{flush, ReadHalf, WriteHalf},
    AsyncRead,
};

use crate::{config::ServerConfig, context::SharedContext};

use crate::relay::{
    boxed_future,
    loadbalancing::server::{LoadBalancer, RoundRobin},
    socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
    tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
};

use super::{ignore_until_end, try_timeout, tunnel};

#[derive(Debug, Clone)]
struct UdpConfig {
    enable_udp: bool,
    client_addr: SocketAddr,
}

fn handle_socks5_connect(
    context: SharedContext,
    (r, w): (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
    client_addr: SocketAddr,
    addr: Address,
    svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = (), Error = io::Error> + Send {
    let timeout = svr_cfg.timeout();
    super::connect_proxy_server(context, svr_cfg.clone())
        .then(move |res| {
            let (header, r) = match res {
                Ok(svr_s) => {
                    trace!("Proxy server connected");

                    // Tell the client that we are ready
                    let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(client_addr));

                    (header, Ok(svr_s))
                }
                Err(err) => {
                    use crate::relay::socks5::Reply;
                    use std::io::ErrorKind;

                    error!("Failed to connect remote server, err: {}", err);

                    let reply = match err.kind() {
                        ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
                        ErrorKind::ConnectionAborted => Reply::HostUnreachable,
                        _ => Reply::NetworkUnreachable,
                    };

                    let header = TcpResponseHeader::new(reply, Address::SocketAddress(client_addr));

                    (header, Err(err))
                }
            };

            trace!("Sent header: {:?}", header);
            try_timeout(header.write_to(w).and_then(flush), timeout).and_then(|w| match r {
                Ok(svr_s) => Ok((svr_s, w)),
                Err(err) => Err(err),
            })
        })
        .and_then(move |(svr_s, w)| {
            let timeout = svr_cfg.timeout();
            super::proxy_server_handshake(svr_s, svr_cfg, addr).and_then(move |(svr_r, svr_w)| {
                let rhalf = svr_r.and_then(move |svr_r| svr_r.copy_timeout_opt(w, timeout));
                let whalf = svr_w.and_then(move |svr_w| svr_w.copy_timeout_opt(r, timeout));
                tunnel(whalf, rhalf)
            })
        })
}

fn handle_socks5_client(
    context: SharedContext,
    s: TcpStream,
    conf: Arc<ServerConfig>,
    udp_conf: UdpConfig,
) -> io::Result<()> {
    if let Err(err) = s.set_keepalive(conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if context.config().no_delay {
        if let Err(err) = s.set_nodelay(true) {
            error!("Failed to set no delay: {:?}", err);
        }
    }

    let client_addr = s.peer_addr()?;
    let cloned_client_addr = client_addr;
    let fut = futures::lazy(|| Ok(s.split()))
        .and_then(|(r, w)| {
            // Socks5 handshakes
            HandshakeRequest::read_from(r).and_then(move |(r, req)| {
                trace!("Socks5 {:?}", req);

                let (resp, res) = if !req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
                    warn!("Currently shadowsocks-rust does not support authentication");
                    (
                        resp,
                        Err(io::Error::new(
                            io::ErrorKind::Other,
                            "Currently shadowsocks-rust does not support authentication",
                        )),
                    )
                } else {
                    // Reply to client
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
                    trace!("Reply handshake {:?}", resp);
                    (resp, Ok(()))
                };

                resp.write_to(w).and_then(flush).and_then(move |w| match res {
                    Ok(..) => Ok((r, w)),
                    Err(err) => Err(err),
                })
            })
        })
        .and_then(move |(r, w)| {
            // Fetch headers
            TcpRequestHeader::read_from(r).then(move |res| match res {
                Ok((r, h)) => boxed_future(futures::finished((r, w, h))),
                Err(err) => {
                    error!("Failed to get TcpRequestHeader: {}", err);
                    let fut = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr))
                        .write_to(w)
                        .then(|_| Err(From::from(err)));
                    boxed_future(fut)
                }
            })
        })
        .and_then(move |(r, w, header)| {
            trace!("Socks5 {:?}", header);

            let addr = header.address;
            match header.command {
                socks5::Command::TcpConnect => {
                    let enable_tcp = context.config().mode.enable_tcp();
                    if enable_tcp {
                        debug!("CONNECT {}", addr);
                        let fut = handle_socks5_connect(context, (r, w), cloned_client_addr, addr.clone(), conf)
                            .map_err(move |err| {
                                io::Error::new(err.kind(), format!("CONNECT {} failed with error \"{}\"", addr, err))
                            });
                        boxed_future(fut)
                    } else {
                        warn!("CONNECT is not enabled");
                        let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                            .write_to(w)
                            .map(|_| ());
                        boxed_future(fut)
                    }
                }
                socks5::Command::TcpBind => {
                    warn!("BIND is not supported");
                    let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                        .write_to(w)
                        .map(|_| ());
                    boxed_future(fut)
                }
                socks5::Command::UdpAssociate => {
                    if udp_conf.enable_udp {
                        debug!("UDP ASSOCIATE {}", addr);
                        let fut = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr))
                            .write_to(w)
                            .and_then(flush)
                            .and_then(|_| {
                                // Hold the connection until it ends by its own
                                ignore_until_end(r).map(|_| ())
                            });

                        boxed_future(fut)
                    } else {
                        warn!("UDP ASSOCIATE is not enabled");
                        let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                            .write_to(w)
                            .map(|_| ());
                        boxed_future(fut)
                    }
                }
            }
        });

    tokio::spawn(fut.then(|res| match res {
        Ok(..) => Ok(()),
        Err(err) => {
            if err.kind() != io::ErrorKind::BrokenPipe {
                error!("Socks5 client: {}", err);
            }
            Err(())
        }
    }));

    Ok(())
}

/// Starts a TCP local server with Socks5 proxy protocol
pub fn run(context: SharedContext) -> impl Future<Item = (), Error = io::Error> + Send {
    let local_addr = *context.config().local.as_ref().expect("Missing local config");

    let listener =
        TcpListener::bind(&local_addr).unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));

    let actual_local_addr = listener.local_addr().expect("Could not determine port bound to");

    info!("ShadowSocks TCP Listening on {}", actual_local_addr);

    let udp_conf = UdpConfig {
        enable_udp: context.config().mode.enable_udp(),
        client_addr: actual_local_addr,
    };

    let mut servers = RoundRobin::new(context.config());
    listener.incoming().for_each(move |socket| {
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", socket.peer_addr()?);
        trace!("Picked proxy server: {:?}", server_cfg);

        handle_socks5_client(context.clone(), socket, server_cfg, udp_conf.clone())
    })
}
<|endoftext|>


<commit_before>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct MediaType {
    type_: ~str,
    subtype: ~str,
    parameters: ~[(~str, ~str)],
}

pub fn MediaType(type_: ~str, subtype: ~str, parameters: ~[(~str, ~str)]) -> MediaType {
    MediaType {
        type_: type_,
        subtype: subtype,
        parameters: parameters,
    }
}

impl ToStr for MediaType {
    fn to_str(&self) -> ~str {
        // Idea:
        //let s = ~"";
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = format!("{}/{}", self.type_, self.subtype);
        push_parameters(s, self.parameters)
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                reader.some_if_consumed(MediaType {
                    type_: type_,
                    subtype: subtype,
                    parameters: parameters,
                })
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        writer.write_token(self.type_);
        writer.write(['/' as u8]);
        writer.write_token(self.subtype);
        writer.write_parameters(self.parameters);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}

#[test]
fn test_content_type() {
    ::headers::test_utils::assert_conversion_correct("type/subtype", MediaType(~"type", ~"subtype", ~[]));
    ::headers::test_utils::assert_conversion_correct("type/subtype;key=value",
                              MediaType(~"type", ~"subtype", ~[(~"key", ~"value")]));
}

#[test]
#[ignore(reason="lws collapse bug")]  // FIXME: triggers infinite loop.
fn test_content_type_BROKEN() {
    ::headers::test_utils::assert_conversion_correct("type/subtype;key=value;q=0.1",
            MediaType(~"type", ~"subtype", ~[(~"key", ~"value"), (~"q", ~"0.1")]));
}

#[test]
#[ignore(reason="lws collapse bug")]  // FIXME: assertion failure
fn test_content_type_BROKEN_2() {
    ::headers::test_utils::assert_interpretation_correct("type/subtype ; key = value ; q = 0.1",
            MediaType(~"type", ~"subtype", ~[(~"key", ~"value"), (~"q", ~"0.1")]));
}

#[test]
fn test_invalid_content_type() {
    ::headers::test_utils::assert_invalid::<MediaType>("");
    ::headers::test_utils::assert_invalid::<MediaType>("/");
    ::headers::test_utils::assert_invalid::<MediaType>("type/subtype,foo=bar");
}

#[test]
#[ignore(reason="lws collapse bug")]  // FIXME: assertion failure
fn test_invalid_content_type_BROKEN() {
    ::headers::test_utils::assert_invalid::<MediaType>("type /subtype");
    ::headers::test_utils::assert_invalid::<MediaType>("type/ subtype");
}

#[test]
#[ignore(reason="lws collapse bug")]  // FIXME: triggers infinite loop.
fn test_invalid_content_type_BROKEN_2() {
    ::headers::test_utils::assert_invalid::<MediaType>("type/subtype;foo=bar,foo=bar");
}
<commit_msg>Remove ignored tests.<commit_after>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct MediaType {
    type_: ~str,
    subtype: ~str,
    parameters: ~[(~str, ~str)],
}

pub fn MediaType(type_: ~str, subtype: ~str, parameters: ~[(~str, ~str)]) -> MediaType {
    MediaType {
        type_: type_,
        subtype: subtype,
        parameters: parameters,
    }
}

impl ToStr for MediaType {
    fn to_str(&self) -> ~str {
        // Idea:
        //let s = ~"";
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = format!("{}/{}", self.type_, self.subtype);
        push_parameters(s, self.parameters)
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                reader.some_if_consumed(MediaType {
                    type_: type_,
                    subtype: subtype,
                    parameters: parameters,
                })
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        writer.write_token(self.type_);
        writer.write(['/' as u8]);
        writer.write_token(self.subtype);
        writer.write_parameters(self.parameters);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}

#[test]
fn test_content_type() {
    ::headers::test_utils::assert_conversion_correct("type/subtype", MediaType(~"type", ~"subtype", ~[]));
    ::headers::test_utils::assert_conversion_correct("type/subtype;key=value",
                              MediaType(~"type", ~"subtype", ~[(~"key", ~"value")]));
}

#[test]
fn test_content_type_BROKEN() {
    ::headers::test_utils::assert_conversion_correct("type/subtype;key=value;q=0.1",
            MediaType(~"type", ~"subtype", ~[(~"key", ~"value"), (~"q", ~"0.1")]));
}

#[test]
fn test_content_type_BROKEN_2() {
    ::headers::test_utils::assert_interpretation_correct("type/subtype ; key = value ; q = 0.1",
            MediaType(~"type", ~"subtype", ~[(~"key", ~"value"), (~"q", ~"0.1")]));
}

#[test]
fn test_invalid_content_type() {
    ::headers::test_utils::assert_invalid::<MediaType>("");
    ::headers::test_utils::assert_invalid::<MediaType>("/");
    ::headers::test_utils::assert_invalid::<MediaType>("type/subtype,foo=bar");
}

#[test]
fn test_invalid_content_type_BROKEN() {
    ::headers::test_utils::assert_invalid::<MediaType>("type /subtype");
    ::headers::test_utils::assert_invalid::<MediaType>("type/ subtype");
}

#[test]
fn test_invalid_content_type_BROKEN_2() {
    ::headers::test_utils::assert_invalid::<MediaType>("type/subtype;foo=bar,foo=bar");
}
<|endoftext|>


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

use check::regionck::{self, Rcx};

use middle::infer;
use middle::region;
use middle::ty::{self, Ty};
use util::ppaux::{Repr};

use syntax::codemap::Span;

pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                                                     typ: ty::Ty<'tcx>,
                                                     span: Span,
                                                     scope: region::CodeExtent) {
    debug!("check_safety_of_destructor_if_necessary typ: {} scope: {:?}",
           typ.repr(rcx.tcx()), scope);

    // types that have been traversed so far by `traverse_type_if_unseen`
    let mut breadcrumbs: Vec<Ty<'tcx>> = Vec::new();

    iterate_over_potentially_unsafe_regions_in_type(
        rcx,
        &mut breadcrumbs,
        typ,
        span,
        scope,
        0);
}

fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
    rcx: &mut Rcx<'a, 'tcx>,
    breadcrumbs: &mut Vec<Ty<'tcx>>,
    ty_root: ty::Ty<'tcx>,
    span: Span,
    scope: region::CodeExtent,
    depth: uint)
{
    let origin = |&:| infer::SubregionOrigin::SafeDestructor(span);
    let mut walker = ty_root.walk();
    while let Some(typ) = walker.next() {
        // Avoid recursing forever.
        if breadcrumbs.contains(&typ) {
            continue;
        }
        breadcrumbs.push(typ);

        let has_dtor = match typ.sty {
            ty::ty_struct(struct_did, _) => ty::has_dtor(rcx.tcx(), struct_did),
            ty::ty_enum(enum_did, _) => ty::has_dtor(rcx.tcx(), enum_did),
            _ => false,
        };

        debug!("iterate_over_potentially_unsafe_regions_in_type \
                {}typ: {} scope: {:?} has_dtor: {}",
               (0..depth).map(|_| ' ').collect::<String>(),
               typ.repr(rcx.tcx()), scope, has_dtor);

        if has_dtor {
            // If `typ` has a destructor, then we must ensure that all
            // borrowed data reachable via `typ` must outlive the
            // parent of `scope`. (It does not suffice for it to
            // outlive `scope` because that could imply that the
            // borrowed data is torn down in between the end of
            // `scope` and when the destructor itself actually runs.

            let parent_region =
                match rcx.tcx().region_maps.opt_encl_scope(scope) {
                    Some(parent_scope) => ty::ReScope(parent_scope),
                    None => rcx.tcx().sess.span_bug(
                        span, format!("no enclosing scope found for scope: {:?}",
                                      scope).as_slice()),
                };

            regionck::type_must_outlive(rcx, origin(), typ, parent_region);

        } else {
            // Okay, `typ` itself is itself not reachable by a
            // destructor; but it may contain substructure that has a
            // destructor.

            match typ.sty {
                ty::ty_struct(struct_did, substs) => {
                    // Don't recurse; we extract type's substructure,
                    // so do not process subparts of type expression.
                    walker.skip_current_subtree();

                    let fields =
                        ty::lookup_struct_fields(rcx.tcx(), struct_did);
                    for field in fields.iter() {
                        let field_type =
                            ty::lookup_field_type(rcx.tcx(),
                                                  struct_did,
                                                  field.id,
                                                  substs);
                        iterate_over_potentially_unsafe_regions_in_type(
                            rcx,
                            breadcrumbs,
                            field_type,
                            span,
                            scope,
                            depth+1)
                    }
                }

                ty::ty_enum(enum_did, substs) => {
                    // Don't recurse; we extract type's substructure,
                    // so do not process subparts of type expression.
                    walker.skip_current_subtree();

                    let all_variant_info =
                        ty::substd_enum_variants(rcx.tcx(),
                                                 enum_did,
                                                 substs);
                    for variant_info in all_variant_info.iter() {
                        for argument_type in variant_info.args.iter() {
                            iterate_over_potentially_unsafe_regions_in_type(
                                rcx,
                                breadcrumbs,
                                *argument_type,
                                span,
                                scope,
                                depth+1)
                        }
                    }
                }

                ty::ty_rptr(..) | ty::ty_ptr(_) | ty::ty_bare_fn(..) => {
                    // Don't recurse, since references, pointers,
                    // boxes, and bare functions don't own instances
                    // of the types appearing within them.
                    walker.skip_current_subtree();
                }
                _ => {}
            };

            // You might be tempted to pop breadcrumbs here after
            // processing type's internals above, but then you hit
            // exponential time blowup e.g. on
            // compile-fail/huge-struct.rs. Instead, we do not remove
            // anything from the breadcrumbs vector during any particular
            // traversal, and instead clear it after the whole traversal
            // is done.
        }
    }
}
<commit_msg>dropck: treat parametric types as safe for dropping.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use check::regionck::{self, Rcx};

use middle::infer;
use middle::region;
use middle::subst;
use middle::ty::{self, Ty};
use util::ppaux::{Repr};

use syntax::codemap::Span;

pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                                                     typ: ty::Ty<'tcx>,
                                                     span: Span,
                                                     scope: region::CodeExtent) {
    debug!("check_safety_of_destructor_if_necessary typ: {} scope: {:?}",
           typ.repr(rcx.tcx()), scope);

    // types that have been traversed so far by `traverse_type_if_unseen`
    let mut breadcrumbs: Vec<Ty<'tcx>> = Vec::new();

    iterate_over_potentially_unsafe_regions_in_type(
        rcx,
        &mut breadcrumbs,
        typ,
        span,
        scope,
        0);
}

fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
    rcx: &mut Rcx<'a, 'tcx>,
    breadcrumbs: &mut Vec<Ty<'tcx>>,
    ty_root: ty::Ty<'tcx>,
    span: Span,
    scope: region::CodeExtent,
    depth: uint)
{
    let origin = |&:| infer::SubregionOrigin::SafeDestructor(span);
    let mut walker = ty_root.walk();
    let opt_phantom_data_def_id = rcx.tcx().lang_items.phantom_data();

    let destructor_for_type = rcx.tcx().destructor_for_type.borrow();

    while let Some(typ) = walker.next() {
        // Avoid recursing forever.
        if breadcrumbs.contains(&typ) {
            continue;
        }
        breadcrumbs.push(typ);

        // If we encounter `PhantomData<T>`, then we should replace it
        // with `T`, the type it represents as owned by the
        // surrounding context, before doing further analysis.
        let typ = if let ty::ty_struct(struct_did, substs) = typ.sty {
            if opt_phantom_data_def_id == Some(struct_did) {
                let item_type = ty::lookup_item_type(rcx.tcx(), struct_did);
                let tp_def = item_type.generics.types
                    .opt_get(subst::TypeSpace, 0).unwrap();
                let new_typ = substs.type_for_def(tp_def);
                debug!("replacing phantom {} with {}",
                       typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
                new_typ
            } else {
                typ
            }
        } else {
            typ
        };

        let opt_type_did = match typ.sty {
            ty::ty_struct(struct_did, _) => Some(struct_did),
            ty::ty_enum(enum_did, _) => Some(enum_did),
            _ => None,
        };

        let opt_dtor =
            opt_type_did.and_then(|did| destructor_for_type.get(&did));

        debug!("iterate_over_potentially_unsafe_regions_in_type \
                {}typ: {} scope: {:?} opt_dtor: {:?}",
               (0..depth).map(|_| ' ').collect::<String>(),
               typ.repr(rcx.tcx()), scope, opt_dtor);

        // If `typ` has a destructor, then we must ensure that all
        // borrowed data reachable via `typ` must outlive the parent
        // of `scope`. This is handled below.
        //
        // However, there is an important special case: by
        // parametricity, any generic type parameters have *no* trait
        // bounds in the Drop impl can not be used in any way (apart
        // from being dropped), and thus we can treat data borrowed
        // via such type parameters remains unreachable.
        //
        // For example, consider `impl<T> Drop for Vec<T> { ... }`,
        // which does have to be able to drop instances of `T`, but
        // otherwise cannot read data from `T`.
        //
        // Of course, for the type expression passed in for any such
        // unbounded type parameter `T`, we must resume the recursive
        // analysis on `T` (since it would be ignored by
        // type_must_outlive).
        //
        // FIXME (pnkfelix): Long term, we could be smart and actually
        // feed which generic parameters can be ignored *into* `fn
        // type_must_outlive` (or some generalization thereof). But
        // for the short term, it probably covers most cases of
        // interest to just special case Drop impls where: (1.) there
        // are no generic lifetime parameters and (2.)  *all* generic
        // type parameters are unbounded.  If both conditions hold, we
        // simply skip the `type_must_outlive` call entirely (but
        // resume the recursive checking of the type-substructure).

        let has_dtor_of_interest;

        if let Some(&dtor_method_did) = opt_dtor {
            let impl_did = ty::impl_of_method(rcx.tcx(), dtor_method_did)
                .unwrap_or_else(|| {
                    rcx.tcx().sess.span_bug(
                        span, "no Drop impl found for drop method")
                });

            let dtor_typescheme = ty::lookup_item_type(rcx.tcx(), impl_did);
            let dtor_generics = dtor_typescheme.generics;

            let has_pred_of_interest = dtor_generics.predicates.iter().any(|pred| {
                // In `impl<T> Drop where ...`, we automatically
                // assume some predicate will be meaningful and thus
                // represents a type through which we could reach
                // borrowed data. However, there can be implicit
                // predicates (namely for Sized), and so we still need
                // to walk through and filter out those cases.

                let result = match *pred {
                    ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
                        let def_id = t_pred.trait_ref.def_id;
                        match rcx.tcx().lang_items.to_builtin_kind(def_id) {
                            Some(ty::BoundSend) |
                            Some(ty::BoundSized) |
                            Some(ty::BoundCopy) |
                            Some(ty::BoundSync) => false,
                            _ => true,
                        }
                    }
                    ty::Predicate::Equate(..) |
                    ty::Predicate::RegionOutlives(..) |
                    ty::Predicate::TypeOutlives(..) |
                    ty::Predicate::Projection(..) => {
                        // we assume all of these where-clauses may
                        // give the drop implementation the capabilty
                        // to access borrowed data.
                        true
                    }
                };

                if result {
                    debug!("typ: {} has interesting dtor due to generic preds, e.g. {}",
                           typ.repr(rcx.tcx()), pred.repr(rcx.tcx()));
                }

                result
            });

            let has_type_param_of_interest = dtor_generics.types.iter().any(|t| {
                let &ty::ParamBounds {
                    ref region_bounds, builtin_bounds, ref trait_bounds,
                    ref projection_bounds,
                } = &t.bounds;

                // Belt-and-suspenders: The current set of builtin
                // bounds {Send, Sized, Copy, Sync} do not introduce
                // any new capability to access borrowed data hidden
                // behind a type parameter.
                //
                // In case new builtin bounds get added that do not
                // satisfy that property, ensure `builtin_bounds \
                // {Send,Sized,Copy,Sync}` is empty.

                let mut builtin_bounds = builtin_bounds;
                builtin_bounds.remove(&ty::BoundSend);
                builtin_bounds.remove(&ty::BoundSized);
                builtin_bounds.remove(&ty::BoundCopy);
                builtin_bounds.remove(&ty::BoundSync);

                let has_bounds =
                    !region_bounds.is_empty() ||
                    !builtin_bounds.is_empty() ||
                    !trait_bounds.is_empty() ||
                    !projection_bounds.is_empty();

                if has_bounds {
                    debug!("typ: {} has interesting dtor due to \
                            bounds on param {}",
                           typ.repr(rcx.tcx()), t.name);
                }

                has_bounds

            });

            // In `impl<'a> Drop ...`, we automatically assume
            // `'a` is meaningful and thus represents a bound
            // through which we could reach borrowed data.
            //
            // FIXME (pnkfelix): In the future it would be good to
            // extend the language to allow the user to express,
            // in the impl signature, that a lifetime is not
            // actually used (something like `where 'a: ?Live`).
            let has_region_param_of_interest =
                dtor_generics.has_region_params(subst::TypeSpace);

            has_dtor_of_interest =
                has_region_param_of_interest ||
                has_type_param_of_interest ||
                has_pred_of_interest;

            if has_dtor_of_interest {
                debug!("typ: {} has interesting dtor, due to \
                        region params: {} type params: {} or pred: {}",
                       typ.repr(rcx.tcx()),
                       has_region_param_of_interest,
                       has_type_param_of_interest,
                       has_pred_of_interest);
            } else {
                debug!("typ: {} has dtor, but it is uninteresting",
                       typ.repr(rcx.tcx()));
            }

        } else {
            debug!("typ: {} has no dtor, and thus is uninteresting",
                   typ.repr(rcx.tcx()));
            has_dtor_of_interest = false;
        }

        if has_dtor_of_interest {
            // If `typ` has a destructor, then we must ensure that all
            // borrowed data reachable via `typ` must outlive the
            // parent of `scope`. (It does not suffice for it to
            // outlive `scope` because that could imply that the
            // borrowed data is torn down in between the end of
            // `scope` and when the destructor itself actually runs.)

            let parent_region =
                match rcx.tcx().region_maps.opt_encl_scope(scope) {
                    Some(parent_scope) => ty::ReScope(parent_scope),
                    None => rcx.tcx().sess.span_bug(
                        span, format!("no enclosing scope found for scope: {:?}",
                                      scope).as_slice()),
                };

            regionck::type_must_outlive(rcx, origin(), typ, parent_region);

        } else {
            // Okay, `typ` itself is itself not reachable by a
            // destructor; but it may contain substructure that has a
            // destructor.

            match typ.sty {
                ty::ty_struct(struct_did, substs) => {
                    // Don't recurse; we extract type's substructure,
                    // so do not process subparts of type expression.
                    walker.skip_current_subtree();

                    let fields =
                        ty::lookup_struct_fields(rcx.tcx(), struct_did);
                    for field in fields.iter() {
                        let field_type =
                            ty::lookup_field_type(rcx.tcx(),
                                                  struct_did,
                                                  field.id,
                                                  substs);
                        iterate_over_potentially_unsafe_regions_in_type(
                            rcx,
                            breadcrumbs,
                            field_type,
                            span,
                            scope,
                            depth+1)
                    }
                }

                ty::ty_enum(enum_did, substs) => {
                    // Don't recurse; we extract type's substructure,
                    // so do not process subparts of type expression.
                    walker.skip_current_subtree();

                    let all_variant_info =
                        ty::substd_enum_variants(rcx.tcx(),
                                                 enum_did,
                                                 substs);
                    for variant_info in all_variant_info.iter() {
                        for argument_type in variant_info.args.iter() {
                            iterate_over_potentially_unsafe_regions_in_type(
                                rcx,
                                breadcrumbs,
                                *argument_type,
                                span,
                                scope,
                                depth+1)
                        }
                    }
                }

                ty::ty_rptr(..) | ty::ty_ptr(_) | ty::ty_bare_fn(..) => {
                    // Don't recurse, since references, pointers,
                    // boxes, and bare functions don't own instances
                    // of the types appearing within them.
                    walker.skip_current_subtree();
                }
                _ => {}
            };

            // You might be tempted to pop breadcrumbs here after
            // processing type's internals above, but then you hit
            // exponential time blowup e.g. on
            // compile-fail/huge-struct.rs. Instead, we do not remove
            // anything from the breadcrumbs vector during any particular
            // traversal, and instead clear it after the whole traversal
            // is done.
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::single_match_else,
  clippy::unseparated_literal_suffix,
  clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]
pub mod logger;

pub type Logger = logger::Logger;

use num_enum::CustomTryInto;

// This is a hard-coding of constants in the standard logging python package.
// TODO: Switch from CustomTryInto to TryFromPrimitive when try_from is stable.
#[derive(Debug, Eq, PartialEq, CustomTryInto, Clone, Copy)]
#[repr(u64)]
enum PythonLogLevel {
  NotSet = 0,
  // Trace doesn't exist in a Python world, so set it to "a bit lower than Debug".
  Trace = 5,
  Debug = 10,
  Info = 20,
  Warn = 30,
  Error = 40,
  Critical = 50,
}

impl From<log::Level> for PythonLogLevel {
  fn from(level: log::Level) -> Self {
    match level {
      log::Level::Error => PythonLogLevel::Error,
      log::Level::Warn => PythonLogLevel::Warn,
      log::Level::Info => PythonLogLevel::Info,
      log::Level::Debug => PythonLogLevel::Debug,
      log::Level::Trace => PythonLogLevel::Trace,
    }
  }
}

impl From<PythonLogLevel> for log::LevelFilter {
  fn from(level: PythonLogLevel) -> Self {
    match level {
      PythonLogLevel::NotSet => log::LevelFilter::Off,
      PythonLogLevel::Trace => log::LevelFilter::Trace,
      PythonLogLevel::Debug => log::LevelFilter::Debug,
      PythonLogLevel::Info => log::LevelFilter::Info,
      PythonLogLevel::Warn => log::LevelFilter::Warn,
      PythonLogLevel::Error => log::LevelFilter::Error,
      // Rust doesn't have a Critical, so treat them like Errors.
      PythonLogLevel::Critical => log::LevelFilter::Error,
    }
  }
}

impl From<PythonLogLevel> for log::Level {
  fn from(level: PythonLogLevel) -> Self {
    match level {
      PythonLogLevel::NotSet => {
        panic!("PythonLogLevel::NotSet doesn't have a translation to Level")
      }
      PythonLogLevel::Trace => log::Level::Trace,
      PythonLogLevel::Debug => log::Level::Debug,
      PythonLogLevel::Info => log::Level::Info,
      PythonLogLevel::Warn => log::Level::Warn,
      PythonLogLevel::Error => log::Level::Error,
      // Rust doesn't have a Critical, so treat them like Errors.
      PythonLogLevel::Critical => log::Level::Error,
    }
  }
}
<commit_msg>Add debug_log macro for one-off debugging (#7566)<commit_after>// Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::single_match_else,
  clippy::unseparated_literal_suffix,
  clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

///
/// Macro to allow debug logging to a file which bypasses the standard logging systems.
/// This is useful for one-off debugging, and is code that several developers have found they're
/// writing a lot as one-offs when working in the rust code (particularly when working on logging),
/// so this is a useful macro to exist for one-off use.
///
/// This should not be used for actual production logging; use the log crate's macros
/// (info!, debug!, trace!) for that.
///
#[macro_export]
macro_rules! debug_log {
    ($path:expr, $($arg:tt)+) => {
      {
        use ::std::io::Write;
        let mut f = ::std::fs::OpenOptions::new().create(true).append(true).open($path).unwrap();
        writeln!(f, $($arg)+).unwrap()
      }
    };
}

pub mod logger;

pub type Logger = logger::Logger;

use num_enum::CustomTryInto;

// This is a hard-coding of constants in the standard logging python package.
// TODO: Switch from CustomTryInto to TryFromPrimitive when try_from is stable.
#[derive(Debug, Eq, PartialEq, CustomTryInto, Clone, Copy)]
#[repr(u64)]
enum PythonLogLevel {
  NotSet = 0,
  // Trace doesn't exist in a Python world, so set it to "a bit lower than Debug".
  Trace = 5,
  Debug = 10,
  Info = 20,
  Warn = 30,
  Error = 40,
  Critical = 50,
}

impl From<log::Level> for PythonLogLevel {
  fn from(level: log::Level) -> Self {
    match level {
      log::Level::Error => PythonLogLevel::Error,
      log::Level::Warn => PythonLogLevel::Warn,
      log::Level::Info => PythonLogLevel::Info,
      log::Level::Debug => PythonLogLevel::Debug,
      log::Level::Trace => PythonLogLevel::Trace,
    }
  }
}

impl From<PythonLogLevel> for log::LevelFilter {
  fn from(level: PythonLogLevel) -> Self {
    match level {
      PythonLogLevel::NotSet => log::LevelFilter::Off,
      PythonLogLevel::Trace => log::LevelFilter::Trace,
      PythonLogLevel::Debug => log::LevelFilter::Debug,
      PythonLogLevel::Info => log::LevelFilter::Info,
      PythonLogLevel::Warn => log::LevelFilter::Warn,
      PythonLogLevel::Error => log::LevelFilter::Error,
      // Rust doesn't have a Critical, so treat them like Errors.
      PythonLogLevel::Critical => log::LevelFilter::Error,
    }
  }
}

impl From<PythonLogLevel> for log::Level {
  fn from(level: PythonLogLevel) -> Self {
    match level {
      PythonLogLevel::NotSet => {
        panic!("PythonLogLevel::NotSet doesn't have a translation to Level")
      }
      PythonLogLevel::Trace => log::Level::Trace,
      PythonLogLevel::Debug => log::Level::Debug,
      PythonLogLevel::Info => log::Level::Info,
      PythonLogLevel::Warn => log::Level::Warn,
      PythonLogLevel::Error => log::Level::Error,
      // Rust doesn't have a Critical, so treat them like Errors.
      PythonLogLevel::Critical => log::Level::Error,
    }
  }
}
<|endoftext|>


<commit_before>extern crate translator;

#[test]
fn empty()
{
	let translator = translator::Translator::new();

	assert_eq!("", translator.translate(""));
	assert_eq!(" ", translator.translate(" "));
	assert_eq!("  ", translator.translate("  "));
	assert_eq!("   ", translator.translate("   "));
}

#[test]
fn letters()
{
	let translator = translator::Translator::new();

	assert_eq!("а", translator.translate("a"));
	assert_eq!("б", translator.translate("b"));
	assert_eq!("в", translator.translate("v"));
	assert_eq!("г", translator.translate("g"));
	assert_eq!("д", translator.translate("d"));
	assert_eq!("е", translator.translate("e"));
	assert_eq!("ё", translator.translate("jo"));
	assert_eq!("ж", translator.translate("zh"));
	assert_eq!("з", translator.translate("z"));
	assert_eq!("и", translator.translate("i"));
	assert_eq!("й", translator.translate("j"));
	assert_eq!("к", translator.translate("k"));
	assert_eq!("л", translator.translate("l"));
	assert_eq!("м", translator.translate("m"));
	assert_eq!("н", translator.translate("n"));
	assert_eq!("о", translator.translate("o"));
	assert_eq!("п", translator.translate("p"));
	assert_eq!("р", translator.translate("r"));
	assert_eq!("с", translator.translate("s"));
	assert_eq!("т", translator.translate("t"));
	assert_eq!("у", translator.translate("u"));
	assert_eq!("ф", translator.translate("f"));
	assert_eq!("х", translator.translate("h"));
	assert_eq!("ц", translator.translate("c"));
	assert_eq!("ч", translator.translate("ch"));
	assert_eq!("ш", translator.translate("sh"));
	assert_eq!("щ", translator.translate("shh"));
	assert_eq!("ъ", translator.translate("#"));
	assert_eq!("ы", translator.translate("y"));
	assert_eq!("ь", translator.translate("'"));
	assert_eq!("э", translator.translate("je"));
	assert_eq!("ю", translator.translate("ju"));
	assert_eq!("я", translator.translate("ja"));
}

#[test]
fn capital_letters()
{
	let translator = translator::Translator::new();

	assert_eq!("А", translator.translate("A"));
	assert_eq!("Б", translator.translate("B"));
	assert_eq!("В", translator.translate("V"));
	assert_eq!("Г", translator.translate("G"));
	assert_eq!("Д", translator.translate("D"));
	assert_eq!("Е", translator.translate("E"));
	assert_eq!("Ё", translator.translate("JO"));
	assert_eq!("Ж", translator.translate("ZH"));
	assert_eq!("З", translator.translate("Z"));
	assert_eq!("И", translator.translate("I"));
	assert_eq!("Й", translator.translate("J"));
	assert_eq!("К", translator.translate("K"));
	assert_eq!("Л", translator.translate("L"));
	assert_eq!("М", translator.translate("M"));
	assert_eq!("Н", translator.translate("N"));
	assert_eq!("О", translator.translate("O"));
	assert_eq!("П", translator.translate("P"));
	assert_eq!("Р", translator.translate("R"));
	assert_eq!("С", translator.translate("S"));
	assert_eq!("Т", translator.translate("T"));
	assert_eq!("У", translator.translate("U"));
	assert_eq!("Ф", translator.translate("F"));
	assert_eq!("Х", translator.translate("X"));
	assert_eq!("Х", translator.translate("H"));
	assert_eq!("Ц", translator.translate("C"));
	assert_eq!("Ч", translator.translate("CH"));
	assert_eq!("Ш", translator.translate("SH"));
	assert_eq!("Щ", translator.translate("SHH"));
	assert_eq!("Ъ", translator.translate("##"));
	assert_eq!("Ы", translator.translate("Y"));
	assert_eq!("Ь", translator.translate("''"));
	assert_eq!("Э", translator.translate("JE"));
	assert_eq!("Ю", translator.translate("JU"));
	assert_eq!("Я", translator.translate("JA"));
}

#[test]
fn words()
{
	let translator = translator::Translator::new();

	assert_eq!("Привет", translator.translate("Privet"));
}
<commit_msg>'sentences' test has been added<commit_after>extern crate translator;

#[test]
fn empty()
{
	let translator = translator::Translator::new();

	assert_eq!("", translator.translate(""));
	assert_eq!(" ", translator.translate(" "));
	assert_eq!("  ", translator.translate("  "));
	assert_eq!("   ", translator.translate("   "));
}

#[test]
fn letters()
{
	let translator = translator::Translator::new();

	assert_eq!("а", translator.translate("a"));
	assert_eq!("б", translator.translate("b"));
	assert_eq!("в", translator.translate("v"));
	assert_eq!("г", translator.translate("g"));
	assert_eq!("д", translator.translate("d"));
	assert_eq!("е", translator.translate("e"));
	assert_eq!("ё", translator.translate("jo"));
	assert_eq!("ж", translator.translate("zh"));
	assert_eq!("з", translator.translate("z"));
	assert_eq!("и", translator.translate("i"));
	assert_eq!("й", translator.translate("j"));
	assert_eq!("к", translator.translate("k"));
	assert_eq!("л", translator.translate("l"));
	assert_eq!("м", translator.translate("m"));
	assert_eq!("н", translator.translate("n"));
	assert_eq!("о", translator.translate("o"));
	assert_eq!("п", translator.translate("p"));
	assert_eq!("р", translator.translate("r"));
	assert_eq!("с", translator.translate("s"));
	assert_eq!("т", translator.translate("t"));
	assert_eq!("у", translator.translate("u"));
	assert_eq!("ф", translator.translate("f"));
	assert_eq!("х", translator.translate("h"));
	assert_eq!("ц", translator.translate("c"));
	assert_eq!("ч", translator.translate("ch"));
	assert_eq!("ш", translator.translate("sh"));
	assert_eq!("щ", translator.translate("shh"));
	assert_eq!("ъ", translator.translate("#"));
	assert_eq!("ы", translator.translate("y"));
	assert_eq!("ь", translator.translate("'"));
	assert_eq!("э", translator.translate("je"));
	assert_eq!("ю", translator.translate("ju"));
	assert_eq!("я", translator.translate("ja"));
}

#[test]
fn capital_letters()
{
	let translator = translator::Translator::new();

	assert_eq!("А", translator.translate("A"));
	assert_eq!("Б", translator.translate("B"));
	assert_eq!("В", translator.translate("V"));
	assert_eq!("Г", translator.translate("G"));
	assert_eq!("Д", translator.translate("D"));
	assert_eq!("Е", translator.translate("E"));
	assert_eq!("Ё", translator.translate("JO"));
	assert_eq!("Ж", translator.translate("ZH"));
	assert_eq!("З", translator.translate("Z"));
	assert_eq!("И", translator.translate("I"));
	assert_eq!("Й", translator.translate("J"));
	assert_eq!("К", translator.translate("K"));
	assert_eq!("Л", translator.translate("L"));
	assert_eq!("М", translator.translate("M"));
	assert_eq!("Н", translator.translate("N"));
	assert_eq!("О", translator.translate("O"));
	assert_eq!("П", translator.translate("P"));
	assert_eq!("Р", translator.translate("R"));
	assert_eq!("С", translator.translate("S"));
	assert_eq!("Т", translator.translate("T"));
	assert_eq!("У", translator.translate("U"));
	assert_eq!("Ф", translator.translate("F"));
	assert_eq!("Х", translator.translate("X"));
	assert_eq!("Х", translator.translate("H"));
	assert_eq!("Ц", translator.translate("C"));
	assert_eq!("Ч", translator.translate("CH"));
	assert_eq!("Ш", translator.translate("SH"));
	assert_eq!("Щ", translator.translate("SHH"));
	assert_eq!("Ъ", translator.translate("##"));
	assert_eq!("Ы", translator.translate("Y"));
	assert_eq!("Ь", translator.translate("''"));
	assert_eq!("Э", translator.translate("JE"));
	assert_eq!("Ю", translator.translate("JU"));
	assert_eq!("Я", translator.translate("JA"));
}

#[test]
fn words()
{
	let translator = translator::Translator::new();

	assert_eq!("Привет", translator.translate("Privet"));
}

#[test]
fn sentences()
{
	let translator = translator::Translator::new();

	assert_eq!("Привет нуб", translator.translate("Privet nub"));
}
<|endoftext|>


<commit_before>#[feature(globs)];
#[feature(macro_rules)];
#[feature(managed_boxes)];

#[link_args="-lwxc"];

extern mod wx;

use std::libc::c_void;

use wx::_unsafe::*;
use wx::defs::*;
use wx::base::*;
use wx::core::*;

mod macros;

wxApp!(wx_main)

extern "C"
fn wx_main() {
    let frame = MyFrame::new();
    frame.show();
    frame.raise();
}

struct MyFrame(@wxFrame);
impl MyFrame {
    #[fixed_stack_segment]
    #[inline(never)]
    fn new() -> MyFrame {
        let frame = wxFrame::new(wxWindow::null(), wxID_ANY, "Hello, wxRust!", -1, -1, -1, -1, wxDEFAULT_FRAME_STYLE);
        let menubar = MyMenuBar::new();
        frame.setMenuBar(menubar.asMenuBar());

        MyButton::new(frame);

        MyFrame(frame)
    }
}

struct MyMenuBar(@wxMenuBar);
impl MyMenuBar {
    #[fixed_stack_segment]
    #[inline(never)]
    fn new() -> MyMenuBar {
        let menubar = wxMenuBar::new(0);

        let fileMenu = wxMenu::new("", 0);
        let fileNew = wxMenuItem::newEx(wxID_ANY, "New", "Create a new file.", 0, wxMenu::null());
        fileMenu.appendItem(fileNew);

        menubar.append(fileMenu, "File");
        MyMenuBar(menubar)
    }
    fn asMenuBar(&self) -> @wxMenuBar {
        return **self;
    }
}

struct MyButton(@wxButton);
impl MyButton {
    #[fixed_stack_segment]
    #[inline(never)]
    fn new<T: _wxWindow>(parent: &T) -> MyButton {
        let button = wxButton::new(parent, wxID_ANY, "Push me!", 10, 10, 50, 30, 0);
        let closure = wxClosure::new(MyButton::clicked as *mut c_void, parent.handle());
        unsafe {
            button.connect(wxID_ANY, wxID_ANY, expEVT_COMMAND_BUTTON_CLICKED(), closure.handle());
        }

        MyButton(button)
    }
    #[fixed_stack_segment]
    #[inline(never)]
    fn clicked(fun: *mut c_void, data: *mut c_void, evt: *mut c_void) {
        println("hello!");
        let parent = wxWindow::from(data);
        let msgDlg = wxMessageDialog::new(parent, "Pushed!!", "The Button", 0);
        msgDlg.showModal();
    }
}
<commit_msg>Convert button clicked event handler from member function to extern "C" free standing function to try to fix linux segfault(#21).<commit_after>#[feature(globs)];
#[feature(macro_rules)];
#[feature(managed_boxes)];

#[link_args="-lwxc"];

extern mod wx;

use std::libc::c_void;

use wx::_unsafe::*;
use wx::defs::*;
use wx::base::*;
use wx::core::*;

mod macros;

wxApp!(wx_main)

extern "C"
fn wx_main() {
    let frame = MyFrame::new();
    frame.show();
    frame.raise();
}

struct MyFrame(@wxFrame);
impl MyFrame {
    #[fixed_stack_segment]
    #[inline(never)]
    fn new() -> MyFrame {
        let frame = wxFrame::new(wxWindow::null(), wxID_ANY, "Hello, wxRust!", -1, -1, -1, -1, wxDEFAULT_FRAME_STYLE);
        let menubar = MyMenuBar::new();
        frame.setMenuBar(menubar.asMenuBar());

        MyButton::new(frame);

        MyFrame(frame)
    }
}

struct MyMenuBar(@wxMenuBar);
impl MyMenuBar {
    #[fixed_stack_segment]
    #[inline(never)]
    fn new() -> MyMenuBar {
        let menubar = wxMenuBar::new(0);

        let fileMenu = wxMenu::new("", 0);
        let fileNew = wxMenuItem::newEx(wxID_ANY, "New", "Create a new file.", 0, wxMenu::null());
        fileMenu.appendItem(fileNew);

        menubar.append(fileMenu, "File");
        MyMenuBar(menubar)
    }
    fn asMenuBar(&self) -> @wxMenuBar {
        return **self;
    }
}

extern "C"
fn MyButton_clicked(fun: *mut c_void, data: *mut c_void, evt: *mut c_void) {
    println("hello!");
    let parent = wxWindow::from(data);
    let msgDlg = wxMessageDialog::new(parent, "Pushed!!", "The Button", 0);
    msgDlg.showModal();
}

struct MyButton(@wxButton);
impl MyButton {
    #[fixed_stack_segment]
    #[inline(never)]
    fn new<T: _wxWindow>(parent: &T) -> MyButton {
        let button = wxButton::new(parent, wxID_ANY, "Push me!", 10, 10, 50, 30, 0);
        let closure = wxClosure::new(MyButton_clicked as *mut c_void, parent.handle());
        unsafe {
            button.connect(wxID_ANY, wxID_ANY, expEVT_COMMAND_BUTTON_CLICKED(), closure.handle());
        }

        MyButton(button)
    }
}
<|endoftext|>