<commit_before>use std::mem;
use std::fmt;
use std::io::{self, Read};
use std::time::Duration;
use std::borrow::Cow;

use encoding_rs::{Encoding, UTF_8};
use futures::{Async, Poll, Stream};
use serde::de::DeserializeOwned;
use serde_json;

use client::KeepCoreThreadAlive;
use header::Headers;
use {async_impl, StatusCode, Url, wait};

/// A Response to a submitted `Request`.
pub struct Response {
    inner: async_impl::Response,
    body: async_impl::ReadableChunks<WaitBody>,
    _thread_handle: KeepCoreThreadAlive,
}

impl fmt::Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.inner, f)
    }
}

impl Response {
    /// Get the final `Url` of this `Response`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let resp = reqwest::get("http://httpbin.org/redirect/1")?;
    /// assert_eq!(resp.url().as_str(), "http://httpbin.org/get");
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn url(&self) -> &Url {
        self.inner.url()
    }

    /// Get the `StatusCode` of this `Response`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let resp = reqwest::get("http://httpbin.org/get")?;
    /// if resp.status().is_success() {
    ///     println!("success!");
    /// } else if resp.status().is_server_error() {
    ///     println!("server error!");
    /// } else {
    ///     println!("Something else happened. Status: {:?}", resp.status());
    /// }
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// ```rust
    /// use reqwest::Client;
    /// use reqwest::StatusCode;
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let client = Client::new();
    /// let resp = client.post("http://httpbin.org/post")
    ///             .body("possibly too large")
    ///             .send()?;
    /// match resp.status() {
    ///     StatusCode::Ok => println!("success!"),
    ///     StatusCode::PayloadTooLarge => {
    ///         println!("Request payload is too large!");
    ///     }
    ///     s => println!("Received response status: {:?}", s),
    /// };
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn status(&self) -> StatusCode {
        self.inner.status()
    }

    /// Get the `Headers` of this `Response`.
    ///
    /// # Example
    ///
    /// Checking the `Content-Length` header before reading the response body.
    ///
    /// ```rust
    /// # use std::io::{Read, Write};
    /// # use reqwest::Client;
    /// # use reqwest::header::ContentLength;
    /// #
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let client = Client::new();
    /// let mut resp = client.head("http://httpbin.org/bytes/3000").send()?;
    /// if resp.status().is_success() {
    ///     let len = resp.headers().get::<ContentLength>()
    ///                 .map(|ct_len| **ct_len)
    ///                 .unwrap_or(0);
    ///     // limit 1mb response
    ///     if len <= 1_000_000 {
    ///         let mut buf = Vec::with_capacity(len as usize);
    ///         let mut resp = reqwest::get("http://httpbin.org/bytes/3000")?;
    ///         if resp.status().is_success() {
    ///             ::std::io::copy(&mut resp, &mut buf)?;
    ///         }
    ///     }
    /// }
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn headers(&self) -> &Headers {
        self.inner.headers()
    }

    /// Try and deserialize the response body as JSON using `serde`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate reqwest;
    /// # #[macro_use] extern crate serde_derive;
    /// #
    /// # use reqwest::Error;
    /// #
    /// #[derive(Deserialize)]
    /// struct Ip {
    ///     origin: String,
    /// }
    ///
    /// # fn run() -> Result<(), Error> {
    /// let json: Ip = reqwest::get("http://httpbin.org/ip")?.json()?;
    /// # Ok(())
    /// # }
    /// #
    /// # fn main() { }
    /// ```
    ///
    /// # Errors
    ///
    /// This method fails whenever the response body is not in JSON format
    /// or it cannot be properly deserialized to target type `T`. For more
    /// details please see [`serde_json::from_reader`].
    /// [`serde_json::from_reader`]: https://docs.serde.rs/serde_json/fn.from_reader.html
    #[inline]
    pub fn json<T: DeserializeOwned>(&mut self) -> ::Result<T> {
        // There's 2 ways we could implement this:
        //
        // 1. Just using from_reader(self), making use of our blocking read adapter
        // 2. Just use self.inner.json().wait()
        //
        // Doing 1 is pretty easy, but it means we have the `serde_json` code
        // in more than one place, doing basically the same thing.
        //
        // Doing 2 would mean `serde_json` is only in one place, but we'd
        // need to update the sync Response to lazily make a blocking read
        // adapter, so that our `inner` could possibly still have the original
        // body.
        //
        // Went for easier for now, just to get it working.
        serde_json::from_reader(self).map_err(::error::from)
    }

    /// Get the response text.
    ///
    /// This method decodes the response body with BOM sniffing
    /// and with malformed sequences replaced with the REPLACEMENT CHARACTER.
    /// Encoding is determinated from the `charset` parameter of `Content-Type` header,
    /// and defaults to `utf-8` if not presented.
    ///
    /// # Example
    ///
    /// ```rust
    /// # extern crate reqwest;
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let content = reqwest::get("http://httpbin.org/range/26")?.text()?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn text(&mut self) -> ::Result<String> {
        let len = self.headers().get::<::header::ContentLength>()
            .map(|ct_len| **ct_len)
            .unwrap_or(0);
        let mut content = Vec::with_capacity(len as usize);
        self.read_to_end(&mut content).map_err(::error::from)?;
        let encoding_name = self.headers().get::<::header::ContentType>()
            .and_then(|content_type| {
                content_type.get_param("charset")
                    .map(|charset| charset.as_str())
            })
            .unwrap_or("utf-8");
        let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
        // a block because of borrow checker
        {
            let (text, _, _) = encoding.decode(&content);
            match text {
                Cow::Owned(s) => return Ok(s),
                _ => (),
            }
        }
        unsafe {
            // decoding returned Cow::Borrowed, meaning these bytes
            // are already valid utf8
            Ok(String::from_utf8_unchecked(content))
        }
    }

    /// Copy the response body into a writer.
    ///
    /// This function internally uses [`std::io::copy`] and hence will continuously read data from
    /// the body and then write it into writer in a streaming fashion until EOF is met.
    ///
    /// On success, the total number of bytes that were copied to `writer` is returned.
    /// [`std::io::copy`]: https://doc.rust-lang.org/std/io/fn.copy.html
    ///
    /// # Example
    ///
    /// ```rust
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let mut resp = reqwest::get("http://httpbin.org/range/5")?;
    /// let mut buf: Vec<u8> = vec![];
    /// resp.copy_to(&mut buf)?;
    /// assert_eq!(b"abcde", buf.as_slice());
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn copy_to<W: ?Sized>(&mut self, w: &mut W) -> ::Result<u64>
        where W: io::Write
    {
        io::copy(self, w).map_err(::error::from)
    }

    /// Turn a response into an error if the server returned an error.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// # extern crate reqwest;
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let res = reqwest::get("http://httpbin.org/status/400")?
    ///     .error_for_status();
    /// if let Err(err) = res {
    ///     assert_eq!(err.status(), Some(reqwest::StatusCode::BadRequest));
    /// }
    /// # Ok(())
    /// # }
    /// # fn main() {}
    /// ```
    #[inline]
    pub fn error_for_status(self) -> ::Result<Self> {
        let Response { body, inner, _thread_handle } = self;
        inner.error_for_status().map(move |inner| {
            Response {
                inner: inner,
                body: body,
                _thread_handle: _thread_handle,
            }
        })
    }
}

impl Read for Response {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.body.read(buf)
    }
}

struct WaitBody {
    inner: wait::WaitStream<async_impl::Decoder>
}

impl Stream for WaitBody {
    type Item = <async_impl::Decoder as Stream>::Item;
    type Error = <async_impl::Decoder as Stream>::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match self.inner.next() {
            Some(Ok(chunk)) => Ok(Async::Ready(Some(chunk))),
            Some(Err(e)) => {
                let req_err = match e {
                    wait::Waited::TimedOut => ::error::timedout(None),
                    wait::Waited::Err(e) => e,
                };

                Err(req_err)
            },
            None => Ok(Async::Ready(None)),
        }
    }
}

// pub(crate)

pub fn new(mut res: async_impl::Response, timeout: Option<Duration>, thread: KeepCoreThreadAlive) -> Response {
    let body = mem::replace(res.body_mut(), async_impl::Decoder::empty());
    let body = async_impl::ReadableChunks::new(WaitBody {
        inner: wait::stream(body, timeout)
    });

    Response {
        inner: res,
        body: body,
        _thread_handle: thread,
    }
}
<commit_msg>document that Response::text consumes the body<commit_after>use std::mem;
use std::fmt;
use std::io::{self, Read};
use std::time::Duration;
use std::borrow::Cow;

use encoding_rs::{Encoding, UTF_8};
use futures::{Async, Poll, Stream};
use serde::de::DeserializeOwned;
use serde_json;

use client::KeepCoreThreadAlive;
use header::Headers;
use {async_impl, StatusCode, Url, wait};

/// A Response to a submitted `Request`.
pub struct Response {
    inner: async_impl::Response,
    body: async_impl::ReadableChunks<WaitBody>,
    _thread_handle: KeepCoreThreadAlive,
}

impl fmt::Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.inner, f)
    }
}

impl Response {
    /// Get the final `Url` of this `Response`.
    ///
    /// # Example
    ///
    /// ```rust
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let resp = reqwest::get("http://httpbin.org/redirect/1")?;
    /// assert_eq!(resp.url().as_str(), "http://httpbin.org/get");
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn url(&self) -> &Url {
        self.inner.url()
    }

    /// Get the `StatusCode` of this `Response`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let resp = reqwest::get("http://httpbin.org/get")?;
    /// if resp.status().is_success() {
    ///     println!("success!");
    /// } else if resp.status().is_server_error() {
    ///     println!("server error!");
    /// } else {
    ///     println!("Something else happened. Status: {:?}", resp.status());
    /// }
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// ```rust
    /// use reqwest::Client;
    /// use reqwest::StatusCode;
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let client = Client::new();
    /// let resp = client.post("http://httpbin.org/post")
    ///             .body("possibly too large")
    ///             .send()?;
    /// match resp.status() {
    ///     StatusCode::Ok => println!("success!"),
    ///     StatusCode::PayloadTooLarge => {
    ///         println!("Request payload is too large!");
    ///     }
    ///     s => println!("Received response status: {:?}", s),
    /// };
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn status(&self) -> StatusCode {
        self.inner.status()
    }

    /// Get the `Headers` of this `Response`.
    ///
    /// # Example
    ///
    /// Checking the `Content-Length` header before reading the response body.
    ///
    /// ```rust
    /// # use std::io::{Read, Write};
    /// # use reqwest::Client;
    /// # use reqwest::header::ContentLength;
    /// #
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let client = Client::new();
    /// let mut resp = client.head("http://httpbin.org/bytes/3000").send()?;
    /// if resp.status().is_success() {
    ///     let len = resp.headers().get::<ContentLength>()
    ///                 .map(|ct_len| **ct_len)
    ///                 .unwrap_or(0);
    ///     // limit 1mb response
    ///     if len <= 1_000_000 {
    ///         let mut buf = Vec::with_capacity(len as usize);
    ///         let mut resp = reqwest::get("http://httpbin.org/bytes/3000")?;
    ///         if resp.status().is_success() {
    ///             ::std::io::copy(&mut resp, &mut buf)?;
    ///         }
    ///     }
    /// }
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn headers(&self) -> &Headers {
        self.inner.headers()
    }

    /// Try and deserialize the response body as JSON using `serde`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate reqwest;
    /// # #[macro_use] extern crate serde_derive;
    /// #
    /// # use reqwest::Error;
    /// #
    /// #[derive(Deserialize)]
    /// struct Ip {
    ///     origin: String,
    /// }
    ///
    /// # fn run() -> Result<(), Error> {
    /// let json: Ip = reqwest::get("http://httpbin.org/ip")?.json()?;
    /// # Ok(())
    /// # }
    /// #
    /// # fn main() { }
    /// ```
    ///
    /// # Errors
    ///
    /// This method fails whenever the response body is not in JSON format
    /// or it cannot be properly deserialized to target type `T`. For more
    /// details please see [`serde_json::from_reader`].
    /// [`serde_json::from_reader`]: https://docs.serde.rs/serde_json/fn.from_reader.html
    #[inline]
    pub fn json<T: DeserializeOwned>(&mut self) -> ::Result<T> {
        // There's 2 ways we could implement this:
        //
        // 1. Just using from_reader(self), making use of our blocking read adapter
        // 2. Just use self.inner.json().wait()
        //
        // Doing 1 is pretty easy, but it means we have the `serde_json` code
        // in more than one place, doing basically the same thing.
        //
        // Doing 2 would mean `serde_json` is only in one place, but we'd
        // need to update the sync Response to lazily make a blocking read
        // adapter, so that our `inner` could possibly still have the original
        // body.
        //
        // Went for easier for now, just to get it working.
        serde_json::from_reader(self).map_err(::error::from)
    }

    /// Get the response text.
    ///
    /// This method decodes the response body with BOM sniffing
    /// and with malformed sequences replaced with the REPLACEMENT CHARACTER.
    /// Encoding is determinated from the `charset` parameter of `Content-Type` header,
    /// and defaults to `utf-8` if not presented.
    ///
    /// # Example
    ///
    /// ```rust
    /// # extern crate reqwest;
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let content = reqwest::get("http://httpbin.org/range/26")?.text()?;
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Note
    ///
    /// This consumes the body. Trying to read more, or use of `response.json()`
    /// will return empty values.
    pub fn text(&mut self) -> ::Result<String> {
        let len = self.headers().get::<::header::ContentLength>()
            .map(|ct_len| **ct_len)
            .unwrap_or(0);
        let mut content = Vec::with_capacity(len as usize);
        self.read_to_end(&mut content).map_err(::error::from)?;
        let encoding_name = self.headers().get::<::header::ContentType>()
            .and_then(|content_type| {
                content_type.get_param("charset")
                    .map(|charset| charset.as_str())
            })
            .unwrap_or("utf-8");
        let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
        // a block because of borrow checker
        {
            let (text, _, _) = encoding.decode(&content);
            match text {
                Cow::Owned(s) => return Ok(s),
                _ => (),
            }
        }
        unsafe {
            // decoding returned Cow::Borrowed, meaning these bytes
            // are already valid utf8
            Ok(String::from_utf8_unchecked(content))
        }
    }

    /// Copy the response body into a writer.
    ///
    /// This function internally uses [`std::io::copy`] and hence will continuously read data from
    /// the body and then write it into writer in a streaming fashion until EOF is met.
    ///
    /// On success, the total number of bytes that were copied to `writer` is returned.
    /// [`std::io::copy`]: https://doc.rust-lang.org/std/io/fn.copy.html
    ///
    /// # Example
    ///
    /// ```rust
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let mut resp = reqwest::get("http://httpbin.org/range/5")?;
    /// let mut buf: Vec<u8> = vec![];
    /// resp.copy_to(&mut buf)?;
    /// assert_eq!(b"abcde", buf.as_slice());
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn copy_to<W: ?Sized>(&mut self, w: &mut W) -> ::Result<u64>
        where W: io::Write
    {
        io::copy(self, w).map_err(::error::from)
    }

    /// Turn a response into an error if the server returned an error.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// # extern crate reqwest;
    /// # fn run() -> Result<(), Box<::std::error::Error>> {
    /// let res = reqwest::get("http://httpbin.org/status/400")?
    ///     .error_for_status();
    /// if let Err(err) = res {
    ///     assert_eq!(err.status(), Some(reqwest::StatusCode::BadRequest));
    /// }
    /// # Ok(())
    /// # }
    /// # fn main() {}
    /// ```
    #[inline]
    pub fn error_for_status(self) -> ::Result<Self> {
        let Response { body, inner, _thread_handle } = self;
        inner.error_for_status().map(move |inner| {
            Response {
                inner: inner,
                body: body,
                _thread_handle: _thread_handle,
            }
        })
    }
}

impl Read for Response {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.body.read(buf)
    }
}

struct WaitBody {
    inner: wait::WaitStream<async_impl::Decoder>
}

impl Stream for WaitBody {
    type Item = <async_impl::Decoder as Stream>::Item;
    type Error = <async_impl::Decoder as Stream>::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match self.inner.next() {
            Some(Ok(chunk)) => Ok(Async::Ready(Some(chunk))),
            Some(Err(e)) => {
                let req_err = match e {
                    wait::Waited::TimedOut => ::error::timedout(None),
                    wait::Waited::Err(e) => e,
                };

                Err(req_err)
            },
            None => Ok(Async::Ready(None)),
        }
    }
}

// pub(crate)

pub fn new(mut res: async_impl::Response, timeout: Option<Duration>, thread: KeepCoreThreadAlive) -> Response {
    let body = mem::replace(res.body_mut(), async_impl::Decoder::empty());
    let body = async_impl::ReadableChunks::new(WaitBody {
        inner: wait::stream(body, timeout)
    });

    Response {
        inner: res,
        body: body,
        _thread_handle: thread,
    }
}
<|endoftext|>


<commit_before>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

libc_bitflags!{
    pub flags ProtFlags: libc::c_int {
        PROT_NONE,
        PROT_READ,
        PROT_WRITE,
        PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_ANONYMOUS,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            MAP_32BIT,
            MAP_GROWSDOWN,
            MAP_DENYWRITE,
            MAP_EXECUTABLE,
            MAP_LOCKED,
            MAP_NORESERVE,
            MAP_POPULATE,
            MAP_NONBLOCK,
            MAP_STACK,
            MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC,
            MS_INVALIDATE,
            MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_NOCACHE,
            MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC, /* [MF|SIO] return immediately */
            MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            MS_KILLPAGES, /* invalidate pages, leave mapped */
            MS_DEACTIVATE, /* deactivate pages, leave mapped */
            MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_RENAME,
            MAP_NORESERVE,
            MAP_HASSEMAPHORE,
            #[cfg(not(any(target_os = "openbsd", target_os = "netbsd")))]
            MAP_STACK,
            #[cfg(target_os = "netbsd")]
            MAP_WIRED,
            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
            MAP_NOSYNC,
            MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        pub struct MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004, /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::munlock(addr, length)).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(ffi::munmap(addr, len)).map(drop)
}

pub unsafe fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(ffi::madvise(addr, length, advise)).map(drop)
}

pub unsafe fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(ffi::msync(addr, length, flags.bits())).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<commit_msg>Fix BSD error<commit_after>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

libc_bitflags!{
    pub flags ProtFlags: libc::c_int {
        PROT_NONE,
        PROT_READ,
        PROT_WRITE,
        PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_ANONYMOUS,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            MAP_32BIT,
            MAP_GROWSDOWN,
            MAP_DENYWRITE,
            MAP_EXECUTABLE,
            MAP_LOCKED,
            MAP_NORESERVE,
            MAP_POPULATE,
            MAP_NONBLOCK,
            MAP_STACK,
            MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC,
            MS_INVALIDATE,
            MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_NOCACHE,
            MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC, /* [MF|SIO] return immediately */
            MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            MS_KILLPAGES, /* invalidate pages, leave mapped */
            MS_DEACTIVATE, /* deactivate pages, leave mapped */
            MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_RENAME,
            MAP_NORESERVE,
            MAP_HASSEMAPHORE,
            #[cfg(not(any(target_os = "openbsd", target_os = "netbsd")))]
            MAP_STACK,
            #[cfg(target_os = "netbsd")]
            MAP_WIRED,
            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
            MAP_NOSYNC,
            MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        pub struct MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC; /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE; /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004; /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004; /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC; /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::munlock(addr, length)).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(ffi::munmap(addr, len)).map(drop)
}

pub unsafe fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(ffi::madvise(addr, length, advise)).map(drop)
}

pub unsafe fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(ffi::msync(addr, length, flags.bits())).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<|endoftext|>


<commit_before>// unix/ctl.rs

use super::funcs::*;
use ctl_error::SysctlError;
use ctl_flags::CtlFlags;
use ctl_info::CtlInfo;
use ctl_type::CtlType;
use ctl_value::CtlValue;
use std::str::FromStr;
use traits::Sysctl;

/// This struct represents a system control.
#[derive(Debug, Clone, PartialEq)]
pub struct Ctl {
    pub oid: Vec<libc::c_int>,
}

impl std::str::FromStr for Ctl {
    type Err = SysctlError;

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::redundant_field_names))]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let oid = name2oid(s)?;

        Ok(Ctl { oid: oid })
    }
}

impl Sysctl for Ctl {
    fn new(name: &str) -> Result<Self, SysctlError> {
        Ctl::from_str(name)
    }

    fn name(&self) -> Result<String, SysctlError> {
        oid2name(&self.oid)
    }

    fn value_type(&self) -> Result<CtlType, SysctlError> {
        let info = oidfmt(&self.oid)?;
        Ok(info.ctl_type)
    }

    #[cfg(not(target_os = "macos"))]
    fn description(&self) -> Result<String, SysctlError> {
        oid2description(&self.oid)
    }

    #[cfg(target_os = "macos")]
    fn description(&self) -> Result<String, SysctlError> {
        Ok("[N/A]".to_string())
    }

    #[cfg(not(target_os = "macos"))]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        value_oid(&self.oid)
    }

    #[cfg(target_os = "macos")]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        let mut oid = self.oid.clone();
        value_oid(&mut oid)
    }

    #[cfg(not(target_os = "macos"))]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        value_oid_as::<T>(&self.oid)
    }

    fn value_string(&self) -> Result<String, SysctlError> {
        self.value().map(|v| format!("{}", v))
    }

    #[cfg(target_os = "macos")]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        let mut oid = self.oid.clone();
        value_oid_as::<T>(&mut oid)
    }

    #[cfg(not(target_os = "macos"))]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        set_oid_value(&self.oid, value)
    }

    #[cfg(target_os = "macos")]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        let mut oid = self.oid.clone();
        set_oid_value(&mut oid, value)
    }

    #[cfg(not(target_os = "macos"))]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let ctl_type = self.value_type()?;
        println!("type {:?}", ctl_type);
        let _ = match ctl_type {
            CtlType::String => set_oid_value(&self.oid, CtlValue::String(value.to_owned())),
            CtlType::Uint => set_oid_value(
                &self.oid,
                CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Int => set_oid_value(
                &self.oid,
                CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Ulong => set_oid_value(
                &self.oid,
                CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::U8 => set_oid_value(
                &self.oid,
                CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
            ),
            _ => Err(SysctlError::MissingImplementation),
        }?;
        self.value_string()
    }

    #[cfg(target_os = "macos")]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let ctl_type = self.value_type()?;
        let mut oid = self.oid.clone();
        let _ = match ctl_type {
            CtlType::String => set_oid_value(&mut oid, CtlValue::String(value.to_owned())),
            CtlType::Uint => set_oid_value(
                &mut oid,
                CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Int => set_oid_value(
                &mut oid,
                CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Ulong => set_oid_value(
                &mut oid,
                CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::U8 => set_oid_value(
                &mut oid,
                CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
            ),
            _ => Err(SysctlError::MissingImplementation),
        }?;
        self.value_string()
    }

    fn flags(&self) -> Result<CtlFlags, SysctlError> {
        Ok(self.info()?.flags())
    }

    fn info(&self) -> Result<CtlInfo, SysctlError> {
        oidfmt(&self.oid)
    }
}

#[cfg(test)]
mod tests {
    use crate::Sysctl;

    #[test]
    fn ctl_new() {
        let _ = super::Ctl::new("kern.ostype").expect("Ctl::new");
    }

    #[test]
    fn ctl_description() {
        let ctl = super::Ctl::new("kern.ostype").expect("Ctl::new");

        let descp = ctl.description();
        assert!(descp.is_ok());

        let descp = descp.unwrap();

        #[cfg(target_os = "freebsd")]
        assert_eq!(descp, "Operating system type");

        #[cfg(any(target_os = "macos", target_os = "linux"))]
        assert_eq!(descp, "[N/A]");
    }
}

#[cfg(all(test, target_os = "freebsd"))]
mod tests_freebsd {}
<commit_msg>Remove debugging println that is visible on FreeBSD<commit_after>// unix/ctl.rs

use super::funcs::*;
use ctl_error::SysctlError;
use ctl_flags::CtlFlags;
use ctl_info::CtlInfo;
use ctl_type::CtlType;
use ctl_value::CtlValue;
use std::str::FromStr;
use traits::Sysctl;

/// This struct represents a system control.
#[derive(Debug, Clone, PartialEq)]
pub struct Ctl {
    pub oid: Vec<libc::c_int>,
}

impl std::str::FromStr for Ctl {
    type Err = SysctlError;

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::redundant_field_names))]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let oid = name2oid(s)?;

        Ok(Ctl { oid: oid })
    }
}

impl Sysctl for Ctl {
    fn new(name: &str) -> Result<Self, SysctlError> {
        Ctl::from_str(name)
    }

    fn name(&self) -> Result<String, SysctlError> {
        oid2name(&self.oid)
    }

    fn value_type(&self) -> Result<CtlType, SysctlError> {
        let info = oidfmt(&self.oid)?;
        Ok(info.ctl_type)
    }

    #[cfg(not(target_os = "macos"))]
    fn description(&self) -> Result<String, SysctlError> {
        oid2description(&self.oid)
    }

    #[cfg(target_os = "macos")]
    fn description(&self) -> Result<String, SysctlError> {
        Ok("[N/A]".to_string())
    }

    #[cfg(not(target_os = "macos"))]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        value_oid(&self.oid)
    }

    #[cfg(target_os = "macos")]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        let mut oid = self.oid.clone();
        value_oid(&mut oid)
    }

    #[cfg(not(target_os = "macos"))]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        value_oid_as::<T>(&self.oid)
    }

    fn value_string(&self) -> Result<String, SysctlError> {
        self.value().map(|v| format!("{}", v))
    }

    #[cfg(target_os = "macos")]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        let mut oid = self.oid.clone();
        value_oid_as::<T>(&mut oid)
    }

    #[cfg(not(target_os = "macos"))]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        set_oid_value(&self.oid, value)
    }

    #[cfg(target_os = "macos")]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        let mut oid = self.oid.clone();
        set_oid_value(&mut oid, value)
    }

    #[cfg(not(target_os = "macos"))]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let ctl_type = self.value_type()?;
        let _ = match ctl_type {
            CtlType::String => set_oid_value(&self.oid, CtlValue::String(value.to_owned())),
            CtlType::Uint => set_oid_value(
                &self.oid,
                CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Int => set_oid_value(
                &self.oid,
                CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Ulong => set_oid_value(
                &self.oid,
                CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::U8 => set_oid_value(
                &self.oid,
                CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
            ),
            _ => Err(SysctlError::MissingImplementation),
        }?;
        self.value_string()
    }

    #[cfg(target_os = "macos")]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let ctl_type = self.value_type()?;
        let mut oid = self.oid.clone();
        let _ = match ctl_type {
            CtlType::String => set_oid_value(&mut oid, CtlValue::String(value.to_owned())),
            CtlType::Uint => set_oid_value(
                &mut oid,
                CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Int => set_oid_value(
                &mut oid,
                CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Ulong => set_oid_value(
                &mut oid,
                CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::U8 => set_oid_value(
                &mut oid,
                CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
            ),
            _ => Err(SysctlError::MissingImplementation),
        }?;
        self.value_string()
    }

    fn flags(&self) -> Result<CtlFlags, SysctlError> {
        Ok(self.info()?.flags())
    }

    fn info(&self) -> Result<CtlInfo, SysctlError> {
        oidfmt(&self.oid)
    }
}

#[cfg(test)]
mod tests {
    use crate::Sysctl;

    #[test]
    fn ctl_new() {
        let _ = super::Ctl::new("kern.ostype").expect("Ctl::new");
    }

    #[test]
    fn ctl_description() {
        let ctl = super::Ctl::new("kern.ostype").expect("Ctl::new");

        let descp = ctl.description();
        assert!(descp.is_ok());

        let descp = descp.unwrap();

        #[cfg(target_os = "freebsd")]
        assert_eq!(descp, "Operating system type");

        #[cfg(any(target_os = "macos", target_os = "linux"))]
        assert_eq!(descp, "[N/A]");
    }
}

#[cfg(all(test, target_os = "freebsd"))]
mod tests_freebsd {}
<|endoftext|>


<commit_before>use std::any::AnyRefExt;
use std::rand::{task_rng, Rng};
use std::str;
use serialize::json;

use conduit::{Request, Response};
use conduit_cookie::{RequestSession};
use curl::http;
use oauth2::Authorization;
use pg::PostgresRow;
use pg::types::ToSql;

use Model;
use app::RequestApp;
use db::{Connection, RequestTransaction};
use krate::{Crate, EncodableCrate};
use util::{RequestUtils, CargoResult, internal, Require, ChainError, human};
use util::errors::NotFound;

pub use self::middleware::{Middleware, RequestUser};

mod middleware;

#[deriving(Clone, Show, PartialEq, Eq)]
pub struct User {
    pub id: i32,
    pub gh_login: String,
    pub name: Option<String>,
    pub email: Option<String>,
    pub avatar: Option<String>,
    pub gh_access_token: String,
    pub api_token: String,
}

#[deriving(Decodable, Encodable)]
pub struct EncodableUser {
    pub id: i32,
    pub login: String,
    pub email: Option<String>,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

impl User {
    pub fn find(conn: &Connection, id: i32) -> CargoResult<User> {
        let stmt = try!(conn.prepare("SELECT * FROM users WHERE id = $1 LIMIT 1"));
        return try!(stmt.query(&[&id])).next().map(User::from_row).require(|| {
            NotFound
        })
    }

    pub fn find_by_api_token(conn: &Connection, token: &str) -> CargoResult<User> {
        let stmt = try!(conn.prepare("SELECT * FROM users \
                                      WHERE api_token = $1 LIMIT 1"));
        return try!(stmt.query(&[&token as &ToSql])).next()
                        .map(User::from_row).require(|| {
            NotFound
        })
    }

    pub fn find_or_insert(conn: &Connection,
                          login: &str,
                          email: Option<&str>,
                          name: Option<&str>,
                          avatar: Option<&str>,
                          access_token: &str,
                          api_token: &str) -> CargoResult<User> {
        // TODO: this is racy, but it looks like any other solution is...
        //       interesting! For now just do the racy thing which will report
        //       more errors than it needs to.

        let stmt = try!(conn.prepare("UPDATE users
                                      SET gh_access_token = $1,
                                          email = $2,
                                          name = $3,
                                          gh_avatar = $4
                                      WHERE gh_login = $5
                                      RETURNING *"));
        let mut rows = try!(stmt.query(&[&access_token as &ToSql,
                                         &email, &name, &avatar,
                                         &login as &ToSql]));
        match rows.next() {
            Some(row) => return Ok(User::from_row(row)),
            None => {}
        }
        let stmt = try!(conn.prepare("INSERT INTO users
                                      (email, gh_access_token, api_token,
                                       gh_login, name, gh_avatar)
                                      VALUES ($1, $2, $3, $4, $5, $6)
                                      RETURNING *"));
        let mut rows = try!(stmt.query(&[&email as &ToSql,
                                         &access_token as &ToSql,
                                         &api_token as &ToSql,
                                         &login as &ToSql,
                                         &name, &avatar]));
        Ok(User::from_row(try!(rows.next().require(|| {
            internal("no user with email we just found")
        }))))
    }

    fn from_row(row: PostgresRow) -> User {
        User {
            id: row.get("id"),
            email: row.get("email"),
            gh_access_token: row.get("gh_access_token"),
            api_token: row.get("api_token"),
            gh_login: row.get("gh_login"),
            name: row.get("name"),
            avatar: row.get("gh_avatar"),
        }
    }

    pub fn new_api_token() -> String {
        task_rng().gen_ascii_chars().take(32).collect()
    }

    pub fn encodable(self) -> EncodableUser {
        let User { id, email, api_token: _, gh_access_token: _,
                   name, gh_login, avatar } = self;
        EncodableUser {
            id: id,
            email: email,
            avatar: avatar,
            login: gh_login,
            name: name,
        }
    }
}

pub fn github_authorize(req: &mut Request) -> CargoResult<Response> {
    let state: String = task_rng().gen_ascii_chars().take(16).collect();
    req.session().insert("github_oauth_state".to_string(), state.clone());

    let url = req.app().github.authorize_url(state.clone());

    #[deriving(Encodable)]
    struct R { url: String, state: String }
    Ok(req.json(&R { url: url.to_string(), state: state }))
}

pub fn github_access_token(req: &mut Request) -> CargoResult<Response> {
    // Parse the url query
    let mut query = req.query();
    let code = query.pop_equiv(&"code").unwrap_or(String::new());
    let state = query.pop_equiv(&"state").unwrap_or(String::new());

    // Make sure that the state we just got matches the session state that we
    // should have issued earlier.
    {
        let session_state = req.session().pop(&"github_oauth_state".to_string());
        let session_state = session_state.as_ref().map(|a| a.as_slice());
        if Some(state.as_slice()) != session_state {
            return Err(human("invalid state parameter"))
        }
    }

    // Fetch the access token from github using the code we just got
    let token = match req.app().github.exchange(code.clone()) {
        Ok(token) => token,
        Err(s) => return Err(human(s)),
    };

    let resp = try!(http::handle().get("https://api.github.com/user")
                         .header("Accept", "application/vnd.github.v3+json")
                         .header("User-Agent", "hello!")
                         .auth_with(&token)
                         .exec());
    if resp.get_code() != 200 {
        return Err(internal(format!("didn't get a 200 result from github: {}",
                                    resp)))
    }

    #[deriving(Decodable)]
    struct GithubUser {
        email: Option<String>,
        name: Option<String>,
        login: String,
        avatar_url: Option<String>,
    }
    let json = try!(str::from_utf8(resp.get_body()).require(||{
        internal("github didn't send a utf8-response")
    }));
    let ghuser: GithubUser = try!(json::decode(json).chain_error(|| {
        internal("github didn't send a valid json response")
    }));

    // Into the database!
    let api_token = User::new_api_token();
    let user = try!(User::find_or_insert(try!(req.tx()),
                                         ghuser.login.as_slice(),
                                         ghuser.email.as_ref()
                                               .map(|s| s.as_slice()),
                                         ghuser.name.as_ref()
                                               .map(|s| s.as_slice()),
                                         ghuser.avatar_url.as_ref()
                                               .map(|s| s.as_slice()),
                                         token.access_token.as_slice(),
                                         api_token.as_slice()));
    req.session().insert("user_id".to_string(), user.id.to_string());

    #[deriving(Encodable)]
    struct R { user: EncodableUser }
    Ok(req.json(&R { user: user.encodable() }))
}

pub fn logout(req: &mut Request) -> CargoResult<Response> {
    req.session().remove(&"user_id".to_string());
    Ok(req.json(&true))
}

pub fn reset_token(req: &mut Request) -> CargoResult<Response> {
    let user = try!(req.user());

    let token = User::new_api_token();
    let conn = try!(req.tx());
    try!(conn.execute("UPDATE users SET api_token = $1 WHERE id = $2",
                      &[&token, &user.id]));

    #[deriving(Encodable)]
    struct R { api_token: String }
    Ok(req.json(&R { api_token: token }))
}

pub fn me(req: &mut Request) -> CargoResult<Response> {
    let user = try!(req.user());

    #[deriving(Encodable)]
    struct R { user: EncodableUser, api_token: String }
    let token = user.api_token.clone();
    Ok(req.json(&R{ user: user.clone().encodable(), api_token: token }))
}

pub fn my_crates(req: &mut Request) -> CargoResult<Response> {
    let user = try!(req.user());
    let (offset, limit) = try!(req.pagination(10, 100));

    let tx = try!(req.tx());
    let stmt = try!(tx.prepare("SELECT * FROM crates WHERE user_id = $1
                                OFFSET $2 LIMIT $3"));
    let mut crates = Vec::new();
    for row in try!(stmt.query(&[&user.id, &offset, &limit])) {
        crates.push(Model::from_row(&row));
    }

    #[deriving(Encodable)]
    struct R { crates: Vec<EncodableCrate> }
    Ok(req.json(&R{ crates: try!(Crate::encode_many(tx, crates)) }))
}
<commit_msg>Send the auth token on an authorization<commit_after>use std::any::AnyRefExt;
use std::rand::{task_rng, Rng};
use std::str;
use serialize::json;

use conduit::{Request, Response};
use conduit_cookie::{RequestSession};
use curl::http;
use oauth2::Authorization;
use pg::PostgresRow;
use pg::types::ToSql;

use Model;
use app::RequestApp;
use db::{Connection, RequestTransaction};
use krate::{Crate, EncodableCrate};
use util::{RequestUtils, CargoResult, internal, Require, ChainError, human};
use util::errors::NotFound;

pub use self::middleware::{Middleware, RequestUser};

mod middleware;

#[deriving(Clone, Show, PartialEq, Eq)]
pub struct User {
    pub id: i32,
    pub gh_login: String,
    pub name: Option<String>,
    pub email: Option<String>,
    pub avatar: Option<String>,
    pub gh_access_token: String,
    pub api_token: String,
}

#[deriving(Decodable, Encodable)]
pub struct EncodableUser {
    pub id: i32,
    pub login: String,
    pub email: Option<String>,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

impl User {
    pub fn find(conn: &Connection, id: i32) -> CargoResult<User> {
        let stmt = try!(conn.prepare("SELECT * FROM users WHERE id = $1 LIMIT 1"));
        return try!(stmt.query(&[&id])).next().map(User::from_row).require(|| {
            NotFound
        })
    }

    pub fn find_by_api_token(conn: &Connection, token: &str) -> CargoResult<User> {
        let stmt = try!(conn.prepare("SELECT * FROM users \
                                      WHERE api_token = $1 LIMIT 1"));
        return try!(stmt.query(&[&token as &ToSql])).next()
                        .map(User::from_row).require(|| {
            NotFound
        })
    }

    pub fn find_or_insert(conn: &Connection,
                          login: &str,
                          email: Option<&str>,
                          name: Option<&str>,
                          avatar: Option<&str>,
                          access_token: &str,
                          api_token: &str) -> CargoResult<User> {
        // TODO: this is racy, but it looks like any other solution is...
        //       interesting! For now just do the racy thing which will report
        //       more errors than it needs to.

        let stmt = try!(conn.prepare("UPDATE users
                                      SET gh_access_token = $1,
                                          email = $2,
                                          name = $3,
                                          gh_avatar = $4
                                      WHERE gh_login = $5
                                      RETURNING *"));
        let mut rows = try!(stmt.query(&[&access_token as &ToSql,
                                         &email, &name, &avatar,
                                         &login as &ToSql]));
        match rows.next() {
            Some(row) => return Ok(User::from_row(row)),
            None => {}
        }
        let stmt = try!(conn.prepare("INSERT INTO users
                                      (email, gh_access_token, api_token,
                                       gh_login, name, gh_avatar)
                                      VALUES ($1, $2, $3, $4, $5, $6)
                                      RETURNING *"));
        let mut rows = try!(stmt.query(&[&email as &ToSql,
                                         &access_token as &ToSql,
                                         &api_token as &ToSql,
                                         &login as &ToSql,
                                         &name, &avatar]));
        Ok(User::from_row(try!(rows.next().require(|| {
            internal("no user with email we just found")
        }))))
    }

    fn from_row(row: PostgresRow) -> User {
        User {
            id: row.get("id"),
            email: row.get("email"),
            gh_access_token: row.get("gh_access_token"),
            api_token: row.get("api_token"),
            gh_login: row.get("gh_login"),
            name: row.get("name"),
            avatar: row.get("gh_avatar"),
        }
    }

    pub fn new_api_token() -> String {
        task_rng().gen_ascii_chars().take(32).collect()
    }

    pub fn encodable(self) -> EncodableUser {
        let User { id, email, api_token: _, gh_access_token: _,
                   name, gh_login, avatar } = self;
        EncodableUser {
            id: id,
            email: email,
            avatar: avatar,
            login: gh_login,
            name: name,
        }
    }
}

pub fn github_authorize(req: &mut Request) -> CargoResult<Response> {
    let state: String = task_rng().gen_ascii_chars().take(16).collect();
    req.session().insert("github_oauth_state".to_string(), state.clone());

    let url = req.app().github.authorize_url(state.clone());

    #[deriving(Encodable)]
    struct R { url: String, state: String }
    Ok(req.json(&R { url: url.to_string(), state: state }))
}

pub fn github_access_token(req: &mut Request) -> CargoResult<Response> {
    // Parse the url query
    let mut query = req.query();
    let code = query.pop_equiv(&"code").unwrap_or(String::new());
    let state = query.pop_equiv(&"state").unwrap_or(String::new());

    // Make sure that the state we just got matches the session state that we
    // should have issued earlier.
    {
        let session_state = req.session().pop(&"github_oauth_state".to_string());
        let session_state = session_state.as_ref().map(|a| a.as_slice());
        if Some(state.as_slice()) != session_state {
            return Err(human("invalid state parameter"))
        }
    }

    // Fetch the access token from github using the code we just got
    let token = match req.app().github.exchange(code.clone()) {
        Ok(token) => token,
        Err(s) => return Err(human(s)),
    };

    let resp = try!(http::handle().get("https://api.github.com/user")
                         .header("Accept", "application/vnd.github.v3+json")
                         .header("User-Agent", "hello!")
                         .auth_with(&token)
                         .exec());
    if resp.get_code() != 200 {
        return Err(internal(format!("didn't get a 200 result from github: {}",
                                    resp)))
    }

    #[deriving(Decodable)]
    struct GithubUser {
        email: Option<String>,
        name: Option<String>,
        login: String,
        avatar_url: Option<String>,
    }
    let json = try!(str::from_utf8(resp.get_body()).require(||{
        internal("github didn't send a utf8-response")
    }));
    let ghuser: GithubUser = try!(json::decode(json).chain_error(|| {
        internal("github didn't send a valid json response")
    }));

    // Into the database!
    let api_token = User::new_api_token();
    let user = try!(User::find_or_insert(try!(req.tx()),
                                         ghuser.login.as_slice(),
                                         ghuser.email.as_ref()
                                               .map(|s| s.as_slice()),
                                         ghuser.name.as_ref()
                                               .map(|s| s.as_slice()),
                                         ghuser.avatar_url.as_ref()
                                               .map(|s| s.as_slice()),
                                         token.access_token.as_slice(),
                                         api_token.as_slice()));
    req.session().insert("user_id".to_string(), user.id.to_string());
    req.mut_extensions().insert(user);
    me(req)
}

pub fn logout(req: &mut Request) -> CargoResult<Response> {
    req.session().remove(&"user_id".to_string());
    Ok(req.json(&true))
}

pub fn reset_token(req: &mut Request) -> CargoResult<Response> {
    let user = try!(req.user());

    let token = User::new_api_token();
    let conn = try!(req.tx());
    try!(conn.execute("UPDATE users SET api_token = $1 WHERE id = $2",
                      &[&token, &user.id]));

    #[deriving(Encodable)]
    struct R { api_token: String }
    Ok(req.json(&R { api_token: token }))
}

pub fn me(req: &mut Request) -> CargoResult<Response> {
    let user = try!(req.user());

    #[deriving(Encodable)]
    struct R { user: EncodableUser, api_token: String }
    let token = user.api_token.clone();
    Ok(req.json(&R{ user: user.clone().encodable(), api_token: token }))
}

pub fn my_crates(req: &mut Request) -> CargoResult<Response> {
    let user = try!(req.user());
    let (offset, limit) = try!(req.pagination(10, 100));

    let tx = try!(req.tx());
    let stmt = try!(tx.prepare("SELECT * FROM crates WHERE user_id = $1
                                OFFSET $2 LIMIT $3"));
    let mut crates = Vec::new();
    for row in try!(stmt.query(&[&user.id, &offset, &limit])) {
        crates.push(Model::from_row(&row));
    }

    #[deriving(Encodable)]
    struct R { crates: Vec<EncodableCrate> }
    Ok(req.json(&R{ crates: try!(Crate::encode_many(tx, crates)) }))
}
<|endoftext|>


<commit_before>use super::parse_timestamp;
use super::stringly_int;
use super::Timestamp;
use super::WatchState;

#[derive(Debug, Clone, Deserialize)]
pub struct Login {
	#[serde(deserialize_with = "stringly_int")]
	pub uid: i64,
	pub avatar: String,
	pub token: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Logout {}

#[derive(Debug, Clone, Deserialize)]
pub struct GetList {
	#[serde(deserialize_with = "stringly_int")]
	pub id: i64,
	pub name: String,
	#[serde(deserialize_with = "stringly_int")]
	pub count: i64,
	pub medium: String,
	pub estate: String,
	#[serde(deserialize_with = "stringly_int")]
	pub cid: i64,
	pub comment: String,
	pub state: String,
	#[serde(deserialize_with = "stringly_int")]
	pub episode: i64,
	pub data: String,
	#[serde(deserialize_with = "stringly_int")]
	pub rating: i64,
	#[serde(deserialize_with = "parse_timestamp")]
	pub timestamp: Timestamp,
}

#[derive(Deserialize, Debug, Clone)]
pub struct Userinfo {
	#[serde(deserialize_with = "stringly_int")]
	pub uid: i64,
	pub username: String,
	pub avatar: String,
	pub status: String,
	#[serde(deserialize_with = "parse_timestamp")]
	pub status_time: Timestamp,
	#[serde(deserialize_with = "stringly_int")]
	pub points_uploads: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_anime: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_manga: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_info: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_forum: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_misc: i64,
}

#[derive(Deserialize, Debug, Clone)]
pub struct TopTen {
	#[serde(deserialize_with = "stringly_int")]
	pub eid: i64,
	pub name: String,
	pub kat: String,
	pub medium: String,
}
<commit_msg>update response types<commit_after>use super::parse_timestamp;
use super::stringly_int;
use super::Timestamp;
use super::WatchState;
use super::Medium;

#[derive(Debug, Clone, Deserialize)]
pub struct Login {
	#[serde(deserialize_with = "stringly_int")]
	pub uid: i64,
	pub avatar: String,
	pub token: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Logout {}

#[derive(Debug, Clone, Deserialize)]
pub struct GetList {
	#[serde(deserialize_with = "stringly_int")]
	pub id: i64,
	pub name: String,
	#[serde(deserialize_with = "stringly_int")]
	pub count: i64,
	pub medium: Medium,
	pub estate: WatchState,
	#[serde(deserialize_with = "stringly_int")]
	pub cid: i64,
	pub comment: String,
	pub state: String,
	#[serde(deserialize_with = "stringly_int")]
	pub episode: i64,
	pub data: String,
	#[serde(deserialize_with = "stringly_int")]
	pub rating: i64,
	#[serde(deserialize_with = "parse_timestamp")]
	pub timestamp: Timestamp,
}

#[derive(Deserialize, Debug, Clone)]
pub struct Userinfo {
	#[serde(deserialize_with = "stringly_int")]
	pub uid: i64,
	pub username: String,
	pub avatar: String,
	pub status: String,
	#[serde(deserialize_with = "parse_timestamp")]
	pub status_time: Timestamp,
	#[serde(deserialize_with = "stringly_int")]
	pub points_uploads: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_anime: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_manga: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_info: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_forum: i64,
	#[serde(deserialize_with = "stringly_int")]
	pub points_misc: i64,
}

#[derive(Deserialize, Debug, Clone)]
pub struct TopTen {
	#[serde(deserialize_with = "stringly_int")]
	pub eid: i64,
	pub name: String,
	pub kat: String,
	pub medium: String,
}
<|endoftext|>


<commit_before>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]

use std::collections::VecDeque;
use std::sync::Arc;
use std::env;

use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
use libc;

use self::x11::XConnection;
use self::x11::XError;
use self::x11::XNotSupported;
use self::x11::ffi::XVisualInfo;

mod dlopen;
pub mod wayland;
pub mod x11;

/// Environment variable that indicates the X11 backend should be used
/// even if Wayland is available. In this case XWayland will be used.
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_PREFER_UNIX_BACKEND";

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub visual_infos: Option<XVisualInfo>,
    pub screen_id: Option<i32>,
}

pub enum UnixBackend {
    X(Arc<XConnection>),
    Wayland(Arc<wayland::WaylandContext>),
    Error(XNotSupported),
}

lazy_static!(
    pub static ref UNIX_BACKEND: UnixBackend = {
        #[inline]
        fn x_backend() -> UnixBackend {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => UnixBackend::X(Arc::new(x)),
                Err(e) => UnixBackend::Error(e),
            }
        }
        match env::var(BACKEND_PREFERENCE_ENV_VAR) {
            Ok(ref s) if s == "x11" => {
                println!("{}: using x11 backend", BACKEND_PREFERENCE_ENV_VAR);
                x_backend()
            },
            _ => {
                if let Some(ctxt) = wayland::WaylandContext::init() {
                    UnixBackend::Wayland(Arc::new(ctxt))
                } else {
                    x_backend()
                }
            },
        }
    };
);

pub enum Window2 {
    #[doc(hidden)]
    X(x11::Window2),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowId {
    #[doc(hidden)]
    X(x11::WindowId),
    #[doc(hidden)]
    Wayland(wayland::WindowId)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DeviceId {
    #[doc(hidden)]
    X(x11::DeviceId),
    #[doc(hidden)]
    Wayland(wayland::DeviceId)
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt)
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        UnixBackend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        UnixBackend::Error(_) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)),
        UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        UnixBackend::Error(_) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

impl Window2 {
    #[inline]
    pub fn new(events_loop: &EventsLoop,
               window: &::WindowAttributes,
               pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Self, CreationError>
    {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                if let EventsLoop::Wayland(ref evlp) = *events_loop {
                    wayland::Window::new(evlp, ctxt.clone(), window).map(Window2::Wayland)
                } else {
                    // It is not possible to instanciate an EventsLoop not matching its backend
                    unreachable!()
                }
            },

            UnixBackend::X(_) => {
                x11::Window2::new(events_loop, window, pl_attribs).map(Window2::X)
            },
            UnixBackend::Error(_) => {
                // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
                // thus this function cannot be called!
                unreachable!()
            }
        }
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        match self {
            &Window2::X(ref w) => WindowId::X(w.id()),
            &Window2::Wayland(ref w) => WindowId::Wayland(w.id())
        }
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window2::X(ref w) => w.set_title(title),
            &Window2::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window2::X(ref w) => w.show(),
            &Window2::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window2::X(ref w) => w.hide(),
            &Window2::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window2::X(ref w) => w.get_position(),
            &Window2::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window2::X(ref w) => w.set_position(x, y),
            &Window2::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_inner_size(),
            &Window2::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_outer_size(),
            &Window2::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window2::X(ref w) => w.set_inner_size(x, y),
            &Window2::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window2::X(ref w) => w.set_cursor(cursor),
            &Window2::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window2::X(ref w) => w.set_cursor_state(state),
            &Window2::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window2::X(ref w) => w.hidpi_factor(),
            &Window2::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window2::X(ref w) => w.set_cursor_position(x, y),
            &Window2::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_display(),
            &Window2::Wayland(ref w) => w.get_display().ptr() as *mut _
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_window(),
            &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let UnixBackend::X(ref x) = *UNIX_BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut libc::c_char, buff.capacity() as i32);
        let description = CStr::from_ptr(buff.as_mut_ptr() as *const libc::c_char).to_string_lossy();

        let error = XError {
            description: description.into_owned(),
            error_code: (*event).error_code,
            request_code: (*event).request_code,
            minor_code: (*event).minor_code,
        };

        *x.latest_error.lock().unwrap() = Some(error);
    }

    0
}

pub enum EventsLoop {
    #[doc(hidden)]
    Wayland(wayland::EventsLoop),
    #[doc(hidden)]
    X(x11::EventsLoop)
}

pub enum EventsLoopProxy {
    X(x11::EventsLoopProxy),
    Wayland(wayland::EventsLoopProxy),
}

impl EventsLoop {
    pub fn new() -> EventsLoop {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                EventsLoop::Wayland(wayland::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::X(ref ctxt) => {
                EventsLoop::X(x11::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::Error(_) => {
                panic!("Attempted to create an EventsLoop while no backend was available.")
            }
        }
    }

    pub fn create_proxy(&self) -> EventsLoopProxy {
        match *self {
            EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()),
            EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()),
        }
    }

    pub fn poll_events<F>(&mut self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback),
            EventsLoop::X(ref mut evlp) => evlp.poll_events(callback)
        }
    }

    pub fn run_forever<F>(&mut self, callback: F)
        where F: FnMut(::Event) -> ControlFlow
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.run_forever(callback),
            EventsLoop::X(ref mut evlp) => evlp.run_forever(callback)
        }
    }
}

impl EventsLoopProxy {
    pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
        match *self {
            EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(),
            EventsLoopProxy::X(ref proxy) => proxy.wakeup(),
        }
    }
}
<commit_msg>Make usage of env vars strict<commit_after>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]

use std::collections::VecDeque;
use std::sync::Arc;
use std::env;

use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
use libc;

use self::x11::XConnection;
use self::x11::XError;
use self::x11::XNotSupported;
use self::x11::ffi::XVisualInfo;

mod dlopen;
pub mod wayland;
pub mod x11;

/// Environment variable that indicates the X11 backend should be used
/// even if Wayland is available. In this case XWayland will be used.
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_PREFER_UNIX_BACKEND";

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub visual_infos: Option<XVisualInfo>,
    pub screen_id: Option<i32>,
}

pub enum UnixBackend {
    X(Arc<XConnection>),
    Wayland(Arc<wayland::WaylandContext>),
    Error(Option<XNotSupported>, Option<String>),
}

lazy_static!(
    pub static ref UNIX_BACKEND: UnixBackend = {
        #[inline]
        fn x_backend() -> Result<UnixBackend, XNotSupported> {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => Ok(UnixBackend::X(Arc::new(x))),
                Err(e) => Err(e),
            }
        }
        #[inline]
        fn wayland_backend() -> Result<UnixBackend, ()> {
             wayland::WaylandContext::init()
                .map(|ctx| UnixBackend::Wayland(Arc::new(ctx)))
                .ok_or(())
        }
        match env::var(BACKEND_PREFERENCE_ENV_VAR) {
            Ok(s) => match s.as_str() {
                "x11" => x_backend().unwrap_or_else(|e| UnixBackend::Error(Some(e), None)),
                "wayland" => wayland_backend().unwrap_or_else(|_| {
                    UnixBackend::Error(None, Some("Wayland not available".into()))
                }),
                _ => panic!("Unknown environment variable value for {}, try one of `x11`,`wayland`",
                            BACKEND_PREFERENCE_ENV_VAR),
            },
            Err(_) => {
                // Try wayland, fallback to X11
                wayland_backend().unwrap_or_else(|_| {
                    x_backend().unwrap_or_else(|x_err| {
                        UnixBackend::Error(Some(x_err), Some("Wayland not available".into()))
                    })
                })
            },
        }
    };
);

pub enum Window2 {
    #[doc(hidden)]
    X(x11::Window2),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowId {
    #[doc(hidden)]
    X(x11::WindowId),
    #[doc(hidden)]
    Wayland(wayland::WindowId)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DeviceId {
    #[doc(hidden)]
    X(x11::DeviceId),
    #[doc(hidden)]
    Wayland(wayland::DeviceId)
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt)
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        UnixBackend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        UnixBackend::Error(..) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)),
        UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        UnixBackend::Error(..) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

impl Window2 {
    #[inline]
    pub fn new(events_loop: &EventsLoop,
               window: &::WindowAttributes,
               pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Self, CreationError>
    {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                if let EventsLoop::Wayland(ref evlp) = *events_loop {
                    wayland::Window::new(evlp, ctxt.clone(), window).map(Window2::Wayland)
                } else {
                    // It is not possible to instanciate an EventsLoop not matching its backend
                    unreachable!()
                }
            },

            UnixBackend::X(_) => {
                x11::Window2::new(events_loop, window, pl_attribs).map(Window2::X)
            },
            UnixBackend::Error(..) => {
                // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
                // thus this function cannot be called!
                unreachable!()
            }
        }
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        match self {
            &Window2::X(ref w) => WindowId::X(w.id()),
            &Window2::Wayland(ref w) => WindowId::Wayland(w.id())
        }
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window2::X(ref w) => w.set_title(title),
            &Window2::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window2::X(ref w) => w.show(),
            &Window2::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window2::X(ref w) => w.hide(),
            &Window2::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window2::X(ref w) => w.get_position(),
            &Window2::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window2::X(ref w) => w.set_position(x, y),
            &Window2::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_inner_size(),
            &Window2::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_outer_size(),
            &Window2::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window2::X(ref w) => w.set_inner_size(x, y),
            &Window2::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window2::X(ref w) => w.set_cursor(cursor),
            &Window2::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window2::X(ref w) => w.set_cursor_state(state),
            &Window2::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window2::X(ref w) => w.hidpi_factor(),
            &Window2::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window2::X(ref w) => w.set_cursor_position(x, y),
            &Window2::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_display(),
            &Window2::Wayland(ref w) => w.get_display().ptr() as *mut _
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_window(),
            &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let UnixBackend::X(ref x) = *UNIX_BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut libc::c_char, buff.capacity() as i32);
        let description = CStr::from_ptr(buff.as_mut_ptr() as *const libc::c_char).to_string_lossy();

        let error = XError {
            description: description.into_owned(),
            error_code: (*event).error_code,
            request_code: (*event).request_code,
            minor_code: (*event).minor_code,
        };

        *x.latest_error.lock().unwrap() = Some(error);
    }

    0
}

pub enum EventsLoop {
    #[doc(hidden)]
    Wayland(wayland::EventsLoop),
    #[doc(hidden)]
    X(x11::EventsLoop)
}

pub enum EventsLoopProxy {
    X(x11::EventsLoopProxy),
    Wayland(wayland::EventsLoopProxy),
}

impl EventsLoop {
    pub fn new() -> EventsLoop {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                EventsLoop::Wayland(wayland::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::X(ref ctxt) => {
                EventsLoop::X(x11::EventsLoop::new(ctxt.clone()))
            },

            UnixBackend::Error(..) => {
                panic!("Attempted to create an EventsLoop while no backend was available.")
            }
        }
    }

    pub fn create_proxy(&self) -> EventsLoopProxy {
        match *self {
            EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()),
            EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()),
        }
    }

    pub fn poll_events<F>(&mut self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback),
            EventsLoop::X(ref mut evlp) => evlp.poll_events(callback)
        }
    }

    pub fn run_forever<F>(&mut self, callback: F)
        where F: FnMut(::Event) -> ControlFlow
    {
        match *self {
            EventsLoop::Wayland(ref mut evlp) => evlp.run_forever(callback),
            EventsLoop::X(ref mut evlp) => evlp.run_forever(callback)
        }
    }
}

impl EventsLoopProxy {
    pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
        match *self {
            EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(),
            EventsLoopProxy::X(ref proxy) => proxy.wakeup(),
        }
    }
}
<|endoftext|>


<commit_before>use crate::auth::auth_filter;
use crate::endpoints;
use crate::prelude::*;
use futures::{FutureExt, TryFutureExt};
use warp::{
    filters::{
        body::json,
        method::{get2, head, post2},
        path::{end, path},
        BoxedFilter,
    },
    Filter,
};

fn config_filter(config: Arc<Config>) -> impl Fn() -> BoxedFilter<(Arc<Config>,)> {
    move || {
        let config = Arc::clone(&config);
        warp::any().map(move || config.clone()).boxed()
    }
}

/// Create a [warp BoxedFilter](warp::filters::BoxedFilter) based on the provided configuration.
pub fn app(config: Arc<Config>) -> BoxedFilter<(impl warp::Reply,)> {
    // Authentication if enabled.
    let auth_filter = config.auth.clone().map(auth_filter);
    let with_config = config_filter(config);

    let base = if let Some(filter) = auth_filter {
        warp::any().and(filter).boxed()
    } else {
        warp::any().boxed()
    };

    // GET /healthz
    // HEAD /healthz
    let healthz = path("healthz")
        .and(end())
        .and(head().or(get2()).unify())
        .map(|| "OK");

    // POST /merge
    let merge = path("merge")
        .and(end())
        .and(post2())
        .and(json())
        .and(with_config())
        .and_then(|merge_spec, config| {
            endpoints::merge(merge_spec, config)
                .map_err(EndpointError::into_rejection)
                .boxed()
                .compat()
        });

    // POST /submit
    let submit = path("submit")
        .and(end())
        .and(post2())
        .and(json())
        .and(with_config())
        .and_then(|document_spec, config| {
            endpoints::submit(document_spec, config)
                .map_err(EndpointError::into_rejection)
                .boxed()
                .compat()
        });

    // POST /preview
    let preview = path("preview")
        .and(end())
        .and(post2())
        .and(json())
        .and(with_config())
        .and_then(|document_spec, config| {
            endpoints::preview(document_spec, config)
                .map_err(EndpointError::into_rejection)
                .boxed()
                .compat()
        });

    let routes = healthz.or(merge).or(submit).or(preview);

    base.and(routes).recover(recover).boxed()
}

fn recover(rejection: warp::Rejection) -> Result<Response, warp::Rejection> {
    use failure::Compat;

    if let Some(endpoint_err) = rejection.find_cause::<Compat<EndpointError>>() {
        return Ok(endpoint_err.get_ref().to_response());
    }

    Err(rejection)
}
<commit_msg>🐛 Do not try to authenticate requests on /healthz<commit_after>use crate::auth::auth_filter;
use crate::endpoints;
use crate::prelude::*;
use futures::{FutureExt, TryFutureExt};
use warp::{
    filters::{
        body::json,
        method::{get2, head, post2},
        path::{end, path},
        BoxedFilter,
    },
    Filter,
};

fn config_filter(config: Arc<Config>) -> impl Fn() -> BoxedFilter<(Arc<Config>,)> {
    move || {
        let config = Arc::clone(&config);
        warp::any().map(move || config.clone()).boxed()
    }
}

/// Create a [warp BoxedFilter](warp::filters::BoxedFilter) based on the provided configuration.
pub fn app(config: Arc<Config>) -> BoxedFilter<(impl warp::Reply,)> {
    // Authentication if enabled.
    let auth_filter = config.auth.clone().map(auth_filter);
    let with_config = config_filter(config);

    let base = if let Some(filter) = auth_filter {
        warp::any().and(filter).boxed()
    } else {
        warp::any().boxed()
    };

    // GET /healthz
    // HEAD /healthz
    let healthz = path("healthz")
        .and(end())
        .and(head().or(get2()).unify())
        .map(|| "OK");

    // POST /merge
    let merge = path("merge")
        .and(end())
        .and(post2())
        .and(json())
        .and(with_config())
        .and_then(|merge_spec, config| {
            endpoints::merge(merge_spec, config)
                .map_err(EndpointError::into_rejection)
                .boxed()
                .compat()
        });

    // POST /submit
    let submit = path("submit")
        .and(end())
        .and(post2())
        .and(json())
        .and(with_config())
        .and_then(|document_spec, config| {
            endpoints::submit(document_spec, config)
                .map_err(EndpointError::into_rejection)
                .boxed()
                .compat()
        });

    // POST /preview
    let preview = path("preview")
        .and(end())
        .and(post2())
        .and(json())
        .and(with_config())
        .and_then(|document_spec, config| {
            endpoints::preview(document_spec, config)
                .map_err(EndpointError::into_rejection)
                .boxed()
                .compat()
        });

    let routes = merge.or(submit).or(preview);

    healthz.or(base.and(routes)).recover(recover).boxed()
}

fn recover(rejection: warp::Rejection) -> Result<Response, warp::Rejection> {
    use failure::Compat;

    if let Some(endpoint_err) = rejection.find_cause::<Compat<EndpointError>>() {
        return Ok(endpoint_err.get_ref().to_response());
    }

    Err(rejection)
}
<|endoftext|>