<commit_before>use crate::task::{self, Poll};
use core::fmt;
use std::marker::{PhantomData,Unpin};
use core::mem::PinMut;

use crate::stream::Stream;

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitrary self types for more
///   information #44874)
pub struct LocalStreamObj<'a, T> {
    ptr: *mut (),
    poll_next_fn: unsafe fn(*mut (), &mut task::Context) -> Poll<Option<T>>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> Unpin for LocalStreamObj<'a, T> {}

impl<'a, T> LocalStreamObj<'a, T> {
    /// Create a `LocalStreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + 'a>(f: F) -> LocalStreamObj<'a, T> {
        LocalStreamObj {
            ptr: f.into_raw(),
            poll_next_fn: F::poll_next,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalStreamObj` into a `StreamObj`
    /// To make this operation safe one has to ensure that the `UnsafeStreamObj`
    /// instance from which this `LocalStreamObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_stream_obj(self) -> StreamObj<'a, T> {
        StreamObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalStreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalStreamObj")
            .finish()
    }
}

impl<'a, T> From<StreamObj<'a, T>> for LocalStreamObj<'a, T> {
    #[inline]
    fn from(f: StreamObj<'a, T>) -> LocalStreamObj<'a, T> {
        f.0
    }
}

impl<'a, T> Stream for LocalStreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        unsafe {
            (self.poll_next_fn)(self.ptr, cx)
        }
    }
}

impl<'a, T> Drop for LocalStreamObj<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.ptr)
        }
    }
}

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct StreamObj<'a, T>(LocalStreamObj<'a, T>);

impl<'a, T> Unpin for StreamObj<'a, T> {}
unsafe impl<'a, T> Send for StreamObj<'a, T> {}

impl<'a, T> StreamObj<'a, T> {
    /// Create a `StreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + Send>(f: F) -> StreamObj<'a, T> {
        StreamObj(LocalStreamObj::new(f))
    }
}

impl<'a, T> fmt::Debug for StreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("StreamObj")
            .finish()
    }
}

impl<'a, T> Stream for StreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
        pinned_field.poll_next(cx)
    }
}

/// A custom implementation of a future trait object for `StreamObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called.
pub unsafe trait UnsafeStreamObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll` with the result of `into_raw` until `drop` is called; such calls
    /// are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>>;

    /// Drops the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for &'a mut F
    where F: Stream<Item = T> + Unpin + 'a
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll_next(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for PinMut<'a, F>
    where F: Stream<Item = T> + 'a
{
    fn into_raw(self) -> *mut () {
        unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () }
    }

    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll_next(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

if_std! {
    use std::boxed::{Box,PinBox};

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Box<F>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(self) -> *mut () {
            Box::into_raw(self) as *mut ()
        }

        unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
            pin.poll_next(cx)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(Box::from_raw(ptr as *mut F))
        }
    }

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for PinBox<F>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(self) -> *mut () {
            PinBox::into_raw(self) as *mut ()
        }

        unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
            pin.poll_next(cx)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(PinBox::from_raw(ptr as *mut F))
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<PinBox<F>> for StreamObj<'a, ()> {
        fn from(boxed: PinBox<F>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<Box<F>> for StreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<PinBox<F>> for LocalStreamObj<'a, ()> {
        fn from(boxed: PinBox<F>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<Box<F>> for LocalStreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }
}<commit_msg>Switch marker over to core<commit_after>use crate::task::{self, Poll};
use core::fmt;
use core::marker::{PhantomData,Unpin};
use core::mem::PinMut;

use crate::stream::Stream;

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitrary self types for more
///   information #44874)
pub struct LocalStreamObj<'a, T> {
    ptr: *mut (),
    poll_next_fn: unsafe fn(*mut (), &mut task::Context) -> Poll<Option<T>>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> Unpin for LocalStreamObj<'a, T> {}

impl<'a, T> LocalStreamObj<'a, T> {
    /// Create a `LocalStreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + 'a>(f: F) -> LocalStreamObj<'a, T> {
        LocalStreamObj {
            ptr: f.into_raw(),
            poll_next_fn: F::poll_next,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalStreamObj` into a `StreamObj`
    /// To make this operation safe one has to ensure that the `UnsafeStreamObj`
    /// instance from which this `LocalStreamObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_stream_obj(self) -> StreamObj<'a, T> {
        StreamObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalStreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalStreamObj")
            .finish()
    }
}

impl<'a, T> From<StreamObj<'a, T>> for LocalStreamObj<'a, T> {
    #[inline]
    fn from(f: StreamObj<'a, T>) -> LocalStreamObj<'a, T> {
        f.0
    }
}

impl<'a, T> Stream for LocalStreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        unsafe {
            (self.poll_next_fn)(self.ptr, cx)
        }
    }
}

impl<'a, T> Drop for LocalStreamObj<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.ptr)
        }
    }
}

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Stream<Item = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct StreamObj<'a, T>(LocalStreamObj<'a, T>);

impl<'a, T> Unpin for StreamObj<'a, T> {}
unsafe impl<'a, T> Send for StreamObj<'a, T> {}

impl<'a, T> StreamObj<'a, T> {
    /// Create a `StreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + Send>(f: F) -> StreamObj<'a, T> {
        StreamObj(LocalStreamObj::new(f))
    }
}

impl<'a, T> fmt::Debug for StreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("StreamObj")
            .finish()
    }
}

impl<'a, T> Stream for StreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Option<T>> {
        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
        pinned_field.poll_next(cx)
    }
}

/// A custom implementation of a future trait object for `StreamObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called.
pub unsafe trait UnsafeStreamObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll` with the result of `into_raw` until `drop` is called; such calls
    /// are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>>;

    /// Drops the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for &'a mut F
    where F: Stream<Item = T> + Unpin + 'a
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll_next(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for PinMut<'a, F>
    where F: Stream<Item = T> + 'a
{
    fn into_raw(self) -> *mut () {
        unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () }
    }

    unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll_next(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

if_std! {
    use std::boxed::{Box,PinBox};

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Box<F>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(self) -> *mut () {
            Box::into_raw(self) as *mut ()
        }

        unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
            pin.poll_next(cx)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(Box::from_raw(ptr as *mut F))
        }
    }

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for PinBox<F>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(self) -> *mut () {
            PinBox::into_raw(self) as *mut ()
        }

        unsafe fn poll_next(ptr: *mut (), cx: &mut task::Context) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
            pin.poll_next(cx)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(PinBox::from_raw(ptr as *mut F))
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<PinBox<F>> for StreamObj<'a, ()> {
        fn from(boxed: PinBox<F>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<Box<F>> for StreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<PinBox<F>> for LocalStreamObj<'a, ()> {
        fn from(boxed: PinBox<F>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<Box<F>> for LocalStreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }
}<|endoftext|>


<commit_before>use extra::url::Url;
use method::{Method, Options};
use status;
use std::rt::io::{Stream, Reader};
use std::rt::io::net::ip::SocketAddr;
use std::rt::io::net::tcp::TcpStream;
use rfc2616::{CR, LF, SP};
use headers;
use buffer::BufferedStream;
use common::read_http_version;

use headers::{HeaderLineErr, EndOfFile, EndOfHeaders, MalformedHeaderSyntax, MalformedHeaderValue};

/// Line/header can't be more than 4KB long (note that with the compacting of LWS the actual source
/// data could be longer than 4KB)
static MAX_LINE_LEN: uint = 0x1000;

static MAX_REQUEST_URI_LEN: uint = 1024;
pub static MAX_METHOD_LEN: uint = 64;
static MAX_HTTP_VERSION_LEN: uint = 1024;

/// Moderately arbitrary figure: read in 64KB chunks. GET requests should never be this large.
static BUF_SIZE: uint = 0x10000;  // Let's try 64KB chunks

pub struct RequestBuffer<'self, S> {
    /// The socket connection to read from
    stream: &'self mut BufferedStream<S>,

    /// A working space for
    line_bytes: ~[u8],
}

impl<'self, S: Stream> RequestBuffer<'self, S> {
    pub fn new<'a>(stream: &'a mut BufferedStream<S>) -> RequestBuffer<'a, S> {
        RequestBuffer {
            stream: stream,
            line_bytes: ~[0u8, ..MAX_LINE_LEN],
        }
    }

    pub fn read_request_line(&mut self) -> Result<(Method, RequestUri, (uint, uint)),
                                                  status::Status> {
        let method = match self.read_method() {
            Some(m) => m,
            // TODO: this is a very common case, if a connection is kept open but then closed or
            // timed out. We should handle that case specially if we can improve perf—check if the
            // peer is still there and just drop the request if it is not
            None => return Err(status::BadRequest),
        };

        let request_uri = match self.read_request_uri() {
            Ok(m) => m,
            Err(e) => return Err(e),
        };

        match (read_http_version(self.stream, CR), self.stream.read_byte()) {
            (Some(vv), Some(b)) if b == LF => Ok((method, request_uri, vv)),
            _ => return Err(status::BadRequest),
        }
    }

    #[inline]
    fn read_method(&mut self) -> Option<Method> {
        include!("../generated/read_method.rs");
    }

    #[inline]
    fn read_request_uri(&mut self) -> Result<RequestUri, status::Status> {
        // Got that, including consuming the SP; now get the request_uri
        let mut request_uri = ~"";
        loop {
            match self.stream.read_byte() {
                None => return Err(status::BadRequest),
                Some(b) if b == SP => break,
                Some(b) => {
                    if request_uri.len() == MAX_REQUEST_URI_LEN {
                        return Err(status::RequestUriTooLong)
                    }
                    request_uri.push_char(b as char);
                }
            }
        }
        match FromStr::from_str(request_uri) {
            Some(r) => Ok(r),
            None => Err(status::BadRequest),
        }
    }

    /// Read a header (name, value) pair.
    ///
    /// This is not necessarily just a line ending with CRLF; there are much fancier rules at work.
    /// Where appropriate (TODO, it's everywhere at present) linear whitespace is collapsed into a
    /// single space.
    ///
    /// # Error values
    ///
    /// - `EndOfHeaders`: I have no more headers to give; go forth and conquer on the body!
    /// - `EndOfFile`: socket was closed unexpectedly; probable best behavour is to drop the request
    /// - `MalformedHeaderValue`: header's value is invalid; normally, ignore it.
    /// - `MalformedHeaderSyntax`: bad request; you could drop it or try returning 400 Bad Request
    pub fn read_header<T: headers::HeaderEnum>(&mut self) -> Result<T, HeaderLineErr> {
        match headers::header_enum_from_stream(self.stream) {
        //match headers::HeaderEnum::from_stream(self.stream) {
            (Err(m), None) => Err(m),
            (Err(m), Some(b)) => {
                self.stream.poke_byte(b);
                Err(m)
            },
            (Ok(header), Some(b)) => {
                self.stream.poke_byte(b);
                Ok(header)
            }
            (Ok(header), None) => {
                // This should have read an extra byte, on account of the CR LF SP possibility
                error!("header with no next byte, did reading go wrong?");
                Ok(header)
            }
        }
    }
}

/// An HTTP request sent to the server.
pub struct Request {
    /// The originating IP address of the request.
    remote_addr: Option<SocketAddr>,

    /// The host name and IP address that the request was sent to; this must always be specified for
    /// HTTP/1.1 requests (or the request will be rejected), but for HTTP/1.0 requests the Host
    /// header was not defined, and so this field will probably be None in such cases.
    //host: Option<Host>,  // Now in headers.host

    /// The headers sent with the request.
    headers: ~headers::request::HeaderCollection,

    /// The body of the request; empty for such methods as GET.
    body: ~str,

    /// The HTTP method for the request.
    method: Method,

    /// The URI that was requested, as found in the Request-URI of the Request-Line.
    /// You will almost never need to use this; you should prefer the `url` field instead.
    request_uri: RequestUri,

    /// Whether to close the TCP connection when the request has been served.
    /// The alternative is keeping the connection open and waiting for another request.
    close_connection: bool,

    /// The HTTP version number; typically `(1, 1)` or, less commonly, `(1, 0)`.
    version: (uint, uint)
}

/// The URI (Request-URI in RFC 2616) as specified in the Status-Line of an HTTP request
#[deriving(Eq)]
pub enum RequestUri {
    /// 'The asterisk "*" means that the request does not apply to a particular resource, but to the
    /// server itself, and is only allowed when the method used does not necessarily apply to a
    /// resource. One example would be "OPTIONS * HTTP/1.1" '
    Star,

    /// 'The absoluteURI form is REQUIRED when the request is being made to a proxy. The proxy is
    /// requested to forward the request or service it from a valid cache, and return the response.
    /// Note that the proxy MAY forward the request on to another proxy or directly to the server
    /// specified by the absoluteURI. In order to avoid request loops, a proxy MUST be able to
    /// recognize all of its server names, including any aliases, local variations, and the numeric
    /// IP address. An example Request-Line would be:
    /// "GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1"'
    AbsoluteUri(Url),

    /// 'To allow for transition to absoluteURIs in all requests in future versions of HTTP, all
    /// HTTP/1.1 servers MUST accept the absoluteURI form in requests, even though HTTP/1.1 clients
    /// will only generate them in requests to proxies.'
    ///
    /// TODO: this shouldn't be a string; it should be further parsed. `extra::net::url` has some
    /// stuff which might help, but isn't public.
    AbsolutePath(~str),

    /// 'The authority form is only used by the CONNECT method (CONNECT).'
    ///
    /// TODO: this shouldn't be a string; it should be further parsed. `extra::net::url` has some
    /// stuff which might help, but isn't public.
    Authority(~str),
}

impl FromStr for RequestUri {
    /// Interpret a RFC2616 Request-URI
    fn from_str(request_uri: &str) -> Option<RequestUri> {
        if request_uri == "*" {
            Some(Star)
        } else if request_uri.starts_with("/") {
            Some(AbsolutePath(request_uri.to_owned()))
        } else if request_uri.contains("/") {
            // An authority can't have a slash in it
            match FromStr::from_str(request_uri) {
                Some(url) => Some(AbsoluteUri(url)),
                None => None,
            }
        } else {
            // TODO: parse authority with extra::net::url
            Some(Authority(request_uri.to_owned()))
        }
    }
}

impl Request {

    /// Get a response from an open socket.
    pub fn load(stream: &mut BufferedStream<TcpStream>) -> (~Request, Result<(), status::Status>) {
        let mut buffer = RequestBuffer::new(stream);

        // Start out with dummy values
        let mut request = ~Request {
            remote_addr: buffer.stream.wrapped.peer_name(),
            headers: ~headers::request::HeaderCollection::new(),
            body: ~"",
            method: Options,
            request_uri: Star,
            close_connection: true,
            version: (0, 0),
        };

        let (method, request_uri, version) = match buffer.read_request_line() {
            Ok(vals) => vals,
            Err(err) => return (request, Err(err)),
        };
        request.method = method;
        request.request_uri = request_uri;
        request.version = version;

        // request.close_connection is deliberately left set to true so that in case of a bad
        // request we can close the connection
        let close_connection = match version {
            (1, 0) => true,
            (1, 1) => false,
            _ => return (request, Err(status::HttpVersionNotSupported)),
        };

        loop {
            match buffer.read_header() {
                Err(EndOfFile) => fail!("client disconnected, nowhere to send response"),
                Err(EndOfHeaders) => break,
                Err(MalformedHeaderSyntax) => {
                    println("BAD REQUEST: malformed header (TODO: is this right?)");
                    return (request, Err(status::BadRequest));
                },
                Err(MalformedHeaderValue) => {
                    println("Bad header encountered. TODO: handle this better.");
                    // Now just ignore the header
                },
                Ok(header) => {
                    request.headers.insert(header);
                },
            }
        }

        // HTTP/1.0 doesn't have Host, but HTTP/1.1 requires it
        if request.version == (1, 1) && request.headers.host.is_none() {
            println("BAD REQUEST: host is none for HTTP/1.1 request");
            return (request, Err(status::BadRequest));
        }

        request.close_connection = close_connection;
        match request.headers.connection {
            Some(ref h) => for v in h.iter() {
                match *v {
                    headers::connection::Close => {
                        request.close_connection = true;
                        break;
                    },
                    headers::connection::Token(ref s) if s.as_slice() == "keep-alive" => {
                        request.close_connection = false;
                        // No break; let it be overridden by close should some weird person do that
                    },
                    headers::connection::Token(_) => (),
                }
            },
            None => (),
        }

        (request, Ok(()))
    }
}

/* What follows is most of Go's net/http module's definition of Request.

pub struct Request {
    // GET, POST, etc.
    method: ~Method,

    // The URL requested, constructed from the request line and (if available)
    // the Host header.
    url: ~Url,

    // The HTTP protocol version used; typically (1, 1)
    protocol: (uint, uint),

    // Request headers, all nicely and correctly parsed.
    headers: ~Headers,

    // The message body.
    body: Reader,

    // ContentLength records the length of the associated content.
    // The value -1 indicates that the length is unknown.
    // Values >= 0 indicate that the given number of bytes may
    // be read from Body.
    // For outgoing requests, a value of 0 means unknown if Body is not nil.
    content_length: i64,

    // TransferEncoding lists the transfer encodings from outermost to
    // innermost. An empty list denotes the "identity" encoding.
    // TransferEncoding can usually be ignored; chunked encoding is
    // automatically added and removed as necessary when sending and
    // receiving requests.
    transfer_encoding: ~[~str],

    // Close indicates whether to close the connection after
    // replying to this request.
    close: bool,

    // The host on which the URL is sought.
    // Per RFC 2616, this is either the value of the Host: header
    // or the host name given in the URL itself.
    // It may be of the form "host:port".
    host: ~str,

    // Form contains the parsed form data, including both the URL
    // field's query parameters and the POST or PUT form data.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores Form and uses Body instead.
    form: url.Values,

    // PostForm contains the parsed form data from POST or PUT
    // body parameters.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores PostForm and uses Body instead.
    post_form: url.Values,

    // MultipartForm is the parsed multipart form, including file uploads.
    // This field is only available after ParseMultipartForm is called.
    // The HTTP client ignores MultipartForm and uses Body instead.
    multipart_form: *multipart.Form,

    // Trailer maps trailer keys to values.  Like for Header, if the
    // response has multiple trailer lines with the same key, they will be
    // concatenated, delimited by commas.
    // For server requests, Trailer is only populated after Body has been
    // closed or fully consumed.
    // Trailer support is only partially complete.
    trailer: ~Headers,

    // RemoteAddr allows HTTP servers and other software to record
    // the network address that sent the request, usually for
    // logging. This field is not filled in by ReadRequest and
    // has no defined format. The HTTP server in this package
    // sets RemoteAddr to an "IP:port" address before invoking a
    // handler.
    // This field is ignored by the HTTP client.
    remote_addr: string,

    // RequestURI is the unmodified Request-URI of the
    // Request-Line (RFC 2616, Section 5.1) as sent by the client
    // to a server. Usually the URL field should be used instead.
    // It is an error to set this field in an HTTP client request.
    request_uri: string,

    // TLS allows HTTP servers and other software to record
    // information about the TLS connection on which the request
    // was received. This field is not filled in by ReadRequest.
    // The HTTP server in this package sets the field for
    // TLS-enabled connections before invoking a handler;
    // otherwise it leaves the field nil.
    // This field is ignored by the HTTP client.
    tls: *tls.ConnectionState,
}*/
<commit_msg>Improve and test server request line reading.<commit_after>use extra::url::Url;
use method::{Method, Options};
use status;
use std::rt::io::{Stream, Reader};
use std::rt::io::net::ip::SocketAddr;
use std::rt::io::net::tcp::TcpStream;
use rfc2616::{CR, LF, SP};
use headers;
use buffer::BufferedStream;
use common::read_http_version;

use headers::{HeaderLineErr, EndOfFile, EndOfHeaders, MalformedHeaderSyntax, MalformedHeaderValue};

/// Line/header can't be more than 4KB long (note that with the compacting of LWS the actual source
/// data could be longer than 4KB)
static MAX_LINE_LEN: uint = 0x1000;

static MAX_REQUEST_URI_LEN: uint = 1024;
pub static MAX_METHOD_LEN: uint = 64;
static MAX_HTTP_VERSION_LEN: uint = 1024;

/// Moderately arbitrary figure: read in 64KB chunks. GET requests should never be this large.
static BUF_SIZE: uint = 0x10000;  // Let's try 64KB chunks

pub struct RequestBuffer<'self, S> {
    /// The socket connection to read from
    stream: &'self mut BufferedStream<S>,

    /// A working space for
    line_bytes: ~[u8],
}

impl<'self, S: Stream> RequestBuffer<'self, S> {
    pub fn new<'a>(stream: &'a mut BufferedStream<S>) -> RequestBuffer<'a, S> {
        RequestBuffer {
            stream: stream,
            line_bytes: ~[0u8, ..MAX_LINE_LEN],
        }
    }

    pub fn read_request_line(&mut self) -> Result<(Method, RequestUri, (uint, uint)),
                                                  status::Status> {
        let method = match self.read_method() {
            Some(m) => m,
            // TODO: this is a very common case, if a connection is kept open but then closed or
            // timed out. We should handle that case specially if we can improve perf—check if the
            // peer is still there and just drop the request if it is not
            None => return Err(status::BadRequest),
        };

        // Finished reading the method, including consuming a single SP.
        // Before we read the Request-URI, we should consume *SP (it's invalid,
        // but the spec recommends supporting it anyway).
        let mut next_byte;
        loop {
            match self.stream.read_byte() {
                Some(_b@SP) => continue,
                Some(b) => {
                    next_byte = b;
                    break;
                },
                None => return Err(status::BadRequest),
            };
        }

        // Good, we're now into the Request-URI. Bear in mind that as well as
        // ending in SP, it can for HTTP/0.9 end in CR LF or LF.
        let mut raw_request_uri = ~"";
        loop {
            if next_byte == CR {
                // For CR, we must have an LF immediately afterwards.
                if self.stream.read_byte() != Some(LF) {
                    return Err(status::BadRequest);
                } else {
                    // Simplify it by just dealing with the LF possibility
                    next_byte = LF;
                    break;
                }
            } else if next_byte == SP || next_byte == LF {
                break;
            }

            if raw_request_uri.len() == MAX_REQUEST_URI_LEN {
                return Err(status::RequestUriTooLong)
            }
            raw_request_uri.push_char(next_byte as char);

            next_byte = match self.stream.read_byte() {
                Some(b) => b,
                None => return Err(status::BadRequest),
            }
        }

        // Now parse it into a RequestUri.
        let request_uri = match FromStr::from_str(raw_request_uri) {
            Some(r) => r,
            None => return Err(status::BadRequest),
        };

        // At this point, we need to consider what came immediately after the
        // Request-URI. If it was a SP, then we expect (again after allowing for
        // possible *SP, though illegal) to get an HTTP-Version. If it was CR LF
        // or LF, we consider it to be HTTP/0.9.
        if next_byte == LF {
            // Good, we got CR LF or LF; HTTP/0.9 it is.
            return Ok((method, request_uri, (0, 9)));
        }

        // By this point, next_byte can only be SP. Now we want an HTTP-Version.

        // FIXME: we have a couple of inconsistencies here:
        // (a) this isn't trimming *SP
        // (b) this is requiring CR LF, rather than allowing just LF,
        //      which is what RFC 2616 recommends
        match (read_http_version(self.stream, CR), self.stream.read_byte()) {
            (Some(vv), Some(b)) if b == LF => Ok((method, request_uri, vv)),
            _ => return Err(status::BadRequest),
        }
    }

    #[inline]
    fn read_method(&mut self) -> Option<Method> {
        include!("../generated/read_method.rs");
    }

    /// Read a header (name, value) pair.
    ///
    /// This is not necessarily just a line ending with CRLF; there are much fancier rules at work.
    /// Where appropriate (TODO, it's everywhere at present) linear whitespace is collapsed into a
    /// single space.
    ///
    /// # Error values
    ///
    /// - `EndOfHeaders`: I have no more headers to give; go forth and conquer on the body!
    /// - `EndOfFile`: socket was closed unexpectedly; probable best behavour is to drop the request
    /// - `MalformedHeaderValue`: header's value is invalid; normally, ignore it.
    /// - `MalformedHeaderSyntax`: bad request; you could drop it or try returning 400 Bad Request
    pub fn read_header<T: headers::HeaderEnum>(&mut self) -> Result<T, HeaderLineErr> {
        match headers::header_enum_from_stream(self.stream) {
        //match headers::HeaderEnum::from_stream(self.stream) {
            (Err(m), None) => Err(m),
            (Err(m), Some(b)) => {
                self.stream.poke_byte(b);
                Err(m)
            },
            (Ok(header), Some(b)) => {
                self.stream.poke_byte(b);
                Ok(header)
            }
            (Ok(header), None) => {
                // This should have read an extra byte, on account of the CR LF SP possibility
                error!("header with no next byte, did reading go wrong?");
                Ok(header)
            }
        }
    }
}

#[test]
fn test_read_request_line() {
    use method::{Get, Options, Connect, ExtensionMethod};
    use buffer::BufferedStream;
    use memstream::MemReaderFakeStream;

    macro_rules! tt(
        ($value:expr => $expected:expr) => {{
            let expected = $expected;
            let mut stream = BufferedStream::new(
                MemReaderFakeStream::new($value.as_bytes().to_owned()));
            assert_eq!(RequestBuffer::new(&mut stream).read_request_line(), expected);
            if expected.is_ok() {
                assert!(stream.eof());
            }
        }}
    )

    // TODO: support just \n on ones with an HTTP-Version (would currently fail)
    //tt!("GET / HTTP/1.1\n" => Ok((Get, AbsolutePath(~"/"), (1, 1))));
    tt!("GET / HTTP/1.1\r\n" => Ok((Get, AbsolutePath(~"/"), (1, 1))));
    tt!("OPTIONS /foo/bar HTTP/1.1\r\n" => Ok((Options, AbsolutePath(~"/foo/bar"), (1, 1))));
    tt!("OPTIONS * HTTP/1.1\r\n" => Ok((Options, Star, (1, 1))));
    tt!("CONNECT example.com HTTP/1.1\r\n" => Ok((Connect,
                                                Authority(~"example.com"),
                                                (1, 1))));
    tt!("FOO /\r\n" => Ok((ExtensionMethod(~"FOO"), AbsolutePath(~"/"), (0, 9))));
    tt!("FOO /\n" => Ok((ExtensionMethod(~"FOO"), AbsolutePath(~"/"), (0, 9))));
    tt!("get    http://example.com/ HTTP/42.17\r\n"
            => Ok((ExtensionMethod(~"get"),
                    AbsoluteUri(from_str("http://example.com/").unwrap()),
                    (42, 17))));

    // Now for some failing cases.

    // method name is not a token
    tt!("GE,T / HTTP/1.1\r\n" => Err(status::BadRequest));

    // Request-URI is missing ("HTTP/1.1" isn't a valid Request-URI; I confirmed this by tracing the
    // rule through RFC 2396: the "/" prevents it from being a reg_name authority, and it doesn't
    // satisfy any of the other possibilities for Request-URI either)
    tt!("GET  HTTP/1.1\r\n" => Err(status::BadRequest));

    // Invalid HTTP-Version
    tt!("GET / HTTX/1.1\r\n" => Err(status::BadRequest));
}

/// An HTTP request sent to the server.
pub struct Request {
    /// The originating IP address of the request.
    remote_addr: Option<SocketAddr>,

    /// The host name and IP address that the request was sent to; this must always be specified for
    /// HTTP/1.1 requests (or the request will be rejected), but for HTTP/1.0 requests the Host
    /// header was not defined, and so this field will probably be None in such cases.
    //host: Option<Host>,  // Now in headers.host

    /// The headers sent with the request.
    headers: ~headers::request::HeaderCollection,

    /// The body of the request; empty for such methods as GET.
    body: ~str,

    /// The HTTP method for the request.
    method: Method,

    /// The URI that was requested, as found in the Request-URI of the Request-Line.
    /// You will almost never need to use this; you should prefer the `url` field instead.
    request_uri: RequestUri,

    /// Whether to close the TCP connection when the request has been served.
    /// The alternative is keeping the connection open and waiting for another request.
    close_connection: bool,

    /// The HTTP version number; typically `(1, 1)` or, less commonly, `(1, 0)`.
    version: (uint, uint)
}

/// The URI (Request-URI in RFC 2616) as specified in the Status-Line of an HTTP request
#[deriving(Eq)]
pub enum RequestUri {
    /// 'The asterisk "*" means that the request does not apply to a particular resource, but to the
    /// server itself, and is only allowed when the method used does not necessarily apply to a
    /// resource. One example would be "OPTIONS * HTTP/1.1" '
    Star,

    /// 'The absoluteURI form is REQUIRED when the request is being made to a proxy. The proxy is
    /// requested to forward the request or service it from a valid cache, and return the response.
    /// Note that the proxy MAY forward the request on to another proxy or directly to the server
    /// specified by the absoluteURI. In order to avoid request loops, a proxy MUST be able to
    /// recognize all of its server names, including any aliases, local variations, and the numeric
    /// IP address. An example Request-Line would be:
    /// "GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1"'
    AbsoluteUri(Url),

    /// 'To allow for transition to absoluteURIs in all requests in future versions of HTTP, all
    /// HTTP/1.1 servers MUST accept the absoluteURI form in requests, even though HTTP/1.1 clients
    /// will only generate them in requests to proxies.'
    ///
    /// TODO: this shouldn't be a string; it should be further parsed. `extra::net::url` has some
    /// stuff which might help, but isn't public.
    AbsolutePath(~str),

    /// 'The authority form is only used by the CONNECT method (CONNECT).'
    ///
    /// TODO: this shouldn't be a string; it should be further parsed. `extra::net::url` has some
    /// stuff which might help, but isn't public.
    Authority(~str),
}

impl FromStr for RequestUri {
    /// Interpret a RFC2616 Request-URI
    fn from_str(request_uri: &str) -> Option<RequestUri> {
        if request_uri == "*" {
            Some(Star)
        } else if request_uri.starts_with("/") {
            Some(AbsolutePath(request_uri.to_owned()))
        } else if request_uri.contains("/") {
            // An authority can't have a slash in it
            match FromStr::from_str(request_uri) {
                Some(url) => Some(AbsoluteUri(url)),
                None => None,
            }
        } else {
            // TODO: parse authority with extra::net::url
            Some(Authority(request_uri.to_owned()))
        }
    }
}

impl Request {

    /// Get a response from an open socket.
    pub fn load(stream: &mut BufferedStream<TcpStream>) -> (~Request, Result<(), status::Status>) {
        let mut buffer = RequestBuffer::new(stream);

        // Start out with dummy values
        let mut request = ~Request {
            remote_addr: buffer.stream.wrapped.peer_name(),
            headers: ~headers::request::HeaderCollection::new(),
            body: ~"",
            method: Options,
            request_uri: Star,
            close_connection: true,
            version: (0, 0),
        };

        let (method, request_uri, version) = match buffer.read_request_line() {
            Ok(vals) => vals,
            Err(err) => return (request, Err(err)),
        };
        request.method = method;
        request.request_uri = request_uri;
        request.version = version;

        // request.close_connection is deliberately left set to true so that in case of a bad
        // request we can close the connection
        let close_connection = match version {
            (1, 0) => true,
            (1, 1) => false,
            _ => return (request, Err(status::HttpVersionNotSupported)),
        };

        loop {
            match buffer.read_header() {
                Err(EndOfFile) => fail!("client disconnected, nowhere to send response"),
                Err(EndOfHeaders) => break,
                Err(MalformedHeaderSyntax) => {
                    println("BAD REQUEST: malformed header (TODO: is this right?)");
                    return (request, Err(status::BadRequest));
                },
                Err(MalformedHeaderValue) => {
                    println("Bad header encountered. TODO: handle this better.");
                    // Now just ignore the header
                },
                Ok(header) => {
                    request.headers.insert(header);
                },
            }
        }

        // HTTP/1.0 doesn't have Host, but HTTP/1.1 requires it
        if request.version == (1, 1) && request.headers.host.is_none() {
            println("BAD REQUEST: host is none for HTTP/1.1 request");
            return (request, Err(status::BadRequest));
        }

        request.close_connection = close_connection;
        match request.headers.connection {
            Some(ref h) => for v in h.iter() {
                match *v {
                    headers::connection::Close => {
                        request.close_connection = true;
                        break;
                    },
                    headers::connection::Token(ref s) if s.as_slice() == "keep-alive" => {
                        request.close_connection = false;
                        // No break; let it be overridden by close should some weird person do that
                    },
                    headers::connection::Token(_) => (),
                }
            },
            None => (),
        }

        (request, Ok(()))
    }
}

/* What follows is most of Go's net/http module's definition of Request.

pub struct Request {
    // GET, POST, etc.
    method: ~Method,

    // The URL requested, constructed from the request line and (if available)
    // the Host header.
    url: ~Url,

    // The HTTP protocol version used; typically (1, 1)
    protocol: (uint, uint),

    // Request headers, all nicely and correctly parsed.
    headers: ~Headers,

    // The message body.
    body: Reader,

    // ContentLength records the length of the associated content.
    // The value -1 indicates that the length is unknown.
    // Values >= 0 indicate that the given number of bytes may
    // be read from Body.
    // For outgoing requests, a value of 0 means unknown if Body is not nil.
    content_length: i64,

    // TransferEncoding lists the transfer encodings from outermost to
    // innermost. An empty list denotes the "identity" encoding.
    // TransferEncoding can usually be ignored; chunked encoding is
    // automatically added and removed as necessary when sending and
    // receiving requests.
    transfer_encoding: ~[~str],

    // Close indicates whether to close the connection after
    // replying to this request.
    close: bool,

    // The host on which the URL is sought.
    // Per RFC 2616, this is either the value of the Host: header
    // or the host name given in the URL itself.
    // It may be of the form "host:port".
    host: ~str,

    // Form contains the parsed form data, including both the URL
    // field's query parameters and the POST or PUT form data.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores Form and uses Body instead.
    form: url.Values,

    // PostForm contains the parsed form data from POST or PUT
    // body parameters.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores PostForm and uses Body instead.
    post_form: url.Values,

    // MultipartForm is the parsed multipart form, including file uploads.
    // This field is only available after ParseMultipartForm is called.
    // The HTTP client ignores MultipartForm and uses Body instead.
    multipart_form: *multipart.Form,

    // Trailer maps trailer keys to values.  Like for Header, if the
    // response has multiple trailer lines with the same key, they will be
    // concatenated, delimited by commas.
    // For server requests, Trailer is only populated after Body has been
    // closed or fully consumed.
    // Trailer support is only partially complete.
    trailer: ~Headers,

    // RemoteAddr allows HTTP servers and other software to record
    // the network address that sent the request, usually for
    // logging. This field is not filled in by ReadRequest and
    // has no defined format. The HTTP server in this package
    // sets RemoteAddr to an "IP:port" address before invoking a
    // handler.
    // This field is ignored by the HTTP client.
    remote_addr: string,

    // RequestURI is the unmodified Request-URI of the
    // Request-Line (RFC 2616, Section 5.1) as sent by the client
    // to a server. Usually the URL field should be used instead.
    // It is an error to set this field in an HTTP client request.
    request_uri: string,

    // TLS allows HTTP servers and other software to record
    // information about the TLS connection on which the request
    // was received. This field is not filled in by ReadRequest.
    // The HTTP server in this package sets the field for
    // TLS-enabled connections before invoking a handler;
    // otherwise it leaves the field nil.
    // This field is ignored by the HTTP client.
    tls: *tls.ConnectionState,
}*/
<|endoftext|>


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

use std::fmt;
use std::io;
use std::path::PathBuf;

use externalfiles::ExternalHtml;

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub css_class: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str,
    pub resource_suffix: &'a str,
}

pub fn render<T: fmt::Display, S: fmt::Display>(
    dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
    css_file_extension: bool, themes: &[PathBuf])
    -> io::Result<()>
{
    write!(dst,
r##"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <meta name="description" content="{description}">
    <meta name="keywords" content="{keywords}">

    <title>{title}</title>

    <link rel="stylesheet" type="text/css" href="{root_path}normalize{suffix}.css">
    <link rel="stylesheet" type="text/css" href="{root_path}rustdoc{suffix}.css"
          id="mainThemeStyle">
    {themes}
    <link rel="stylesheet" type="text/css" href="{root_path}dark{suffix}.css">
    <link rel="stylesheet" type="text/css" href="{root_path}light{suffix}.css" id="themeStyle">

    {css_extension}

    {favicon}
    {in_header}

    {before_content}

☰

        {logo}
        {sidebar}

        <button id="theme-picker" aria-label="Pick another theme!">

        </button>

        <form class="search-form js-only">

                <input class="search-input" name="search"
                       autocomplete="off"
                       placeholder="Click or press ‘S’ to search, ‘?’ for more options…"
                       type="search">

        </form>

{content}

Help

Keyboard Shortcuts

?

Show this help dialog

S

Focus the search field

↑

Move up in search results

↓

Move down in search results

↹

Switch tab

⏎

Go to active search result

+

Expand all sections

-

Collapse all sections

Search Tricks

                    Prefix searches with a type followed by a colon (e.g.
                    fn:) to restrict the search to a given type.

                    Accepted types are: fn, mod,
                    struct, enum,
                    trait, type, macro,
                    and const.

                    Search functions by type signature (e.g.
                    vec -> usize or * -> vec)

    {after_content}

"##,
    css_extension = if css_file_extension {
        format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">",
                root_path = page.root_path,
                suffix=page.resource_suffix)
    } else {
        "".to_owned()
    },
    content   = *t,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = if layout.logo.is_empty() {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    themes = themes.iter()
                   .filter_map(|t| t.file_stem())
                   .filter_map(|t| t.to_str())
                   .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}">"#,
                                    page.root_path,
                                    t.replace(".css", &format!("{}.css", page.resource_suffix))))
                   .collect::<String>(),
    suffix=page.resource_suffix,
    )
}

pub fn redirect(dst: &mut io::Write, url: &str) -> io::Result<()> {
    //

"##,
    url = url,
    )
}
<commit_msg>Small size reduction<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io;
use std::path::PathBuf;

use externalfiles::ExternalHtml;

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub css_class: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str,
    pub resource_suffix: &'a str,
}

pub fn render<T: fmt::Display, S: fmt::Display>(
    dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
    css_file_extension: bool, themes: &[PathBuf])
    -> io::Result<()>
{
    write!(dst,
"<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {themes}\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}dark{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
          id=\"themeStyle\">\
    \
    {css_extension}\
    {favicon}\
    {in_header}\
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
            \
        </button>\

\

\
    \
    \
        <form class=\"search-form js-only\">\

\
                <input class=\"search-input\" name=\"search\" \
                       autocomplete=\"off\" \
                       placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                       type=\"search\">\

\
        </form>\
    \

{content}
\

\

\
    \

\

Help
\

\

Keyboard Shortcuts
\

\

?
\

Show this help dialog
\

S
\

Focus the search field
\

↑
\

Move up in search results
\

↓
\

Move down in search results
\

↹
\

Switch tab
\

⏎
\

Go to active search result
\

+
\

Expand all sections
\

-
\

Collapse all sections
\

\

\

\

Search Tricks
\

\
                    Prefix searches with a type followed by a colon (e.g. \
                    fn:) to restrict the search to a given type.\

\

\
                    Accepted types are: fn, mod, \
                    struct, enum, \
                    trait, type, macro, \
                    and const.\

\

\
                    Search functions by type signature (e.g. \
                    vec -> usize or * -> vec)\

\

\

\
    \
    {after_content}\
    \
    \
    \
\
",
    css_extension = if css_file_extension {
        format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">",
                root_path = page.root_path,
                suffix=page.resource_suffix)
    } else {
        "".to_owned()
    },
    content   = *t,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = if layout.logo.is_empty() {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    themes = themes.iter()
                   .filter_map(|t| t.file_stem())
                   .filter_map(|t| t.to_str())
                   .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}">"#,
                                    page.root_path,
                                    t.replace(".css", &format!("{}.css", page.resource_suffix))))
                   .collect::<String>(),
    suffix=page.resource_suffix,
    )
}

pub fn redirect(dst: &mut io::Write, url: &str) -> io::Result<()> {
    //

"##,
    url = url,
    )
}
<|endoftext|>


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

use prelude::v1::*;

use alloc::boxed::FnBox;
use cmp;
#[cfg(not(any(target_env = "newlib", target_os = "solaris")))]
use ffi::CString;
use io;
use libc;
use mem;
use ptr;
use sys::os;
use time::Duration;

use sys_common::thread::*;

pub struct Thread {
    id: libc::pthread_t,
}

// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;
        let mut native: libc::pthread_t = mem::zeroed();
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);

        let stack_size = cmp::max(stack, min_stack_size(&attr));
        match libc::pthread_attr_setstacksize(&mut attr,
                                              stack_size as libc::size_t) {
            0 => {}
            n => {
                assert_eq!(n, libc::EINVAL);
                // EINVAL means |stack_size| is either too small or not a
                // multiple of the system page size.  Because it's definitely
                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                // Round up to the nearest page and try again.
                let page_size = os::page_size();
                let stack_size = (stack_size + page_size - 1) &
                                 (-(page_size as isize - 1) as usize - 1);
                let stack_size = stack_size as libc::size_t;
                assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
                                                           stack_size), 0);
            }
        };

        let ret = libc::pthread_create(&mut native, &attr, thread_start,
                                       &*p as *const _ as *mut _);
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);

        return if ret != 0 {
            Err(io::Error::from_raw_os_error(ret))
        } else {
            mem::forget(p); // ownership passed to pthread_create
            Ok(Thread { id: native })
        };

        extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
            unsafe { start_thread(main); }
            ptr::null_mut()
        }
    }

    pub fn yield_now() {
        let ret = unsafe { libc::sched_yield() };
        debug_assert_eq!(ret, 0);
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    pub fn set_name(name: &str) {
        const PR_SET_NAME: libc::c_int = 15;
        let cname = CString::new(name).unwrap_or_else(|_| {
            panic!("thread name may not contain interior null bytes")
        });
        // pthread wrapper only appeared in glibc 2.12, so we use syscall
        // directly.
        unsafe {
            libc::prctl(PR_SET_NAME, cname.as_ptr() as libc::c_ulong, 0, 0, 0);
        }
    }

    #[cfg(any(target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    pub fn set_name(name: &str) {
        let cname = CString::new(name).unwrap();
        unsafe {
            libc::pthread_set_name_np(libc::pthread_self(), cname.as_ptr());
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn set_name(name: &str) {
        let cname = CString::new(name).unwrap();
        unsafe {
            libc::pthread_setname_np(cname.as_ptr());
        }
    }

    #[cfg(target_os = "netbsd")]
    pub fn set_name(name: &str) {
        let cname = CString::new(&b"%s"[..]).unwrap();
        let carg = CString::new(name).unwrap();
        unsafe {
            libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
                                     carg.as_ptr() as *mut libc::c_void);
        }
    }
    #[cfg(any(target_env = "newlib", target_os = "solaris"))]
    pub fn set_name(_name: &str) {
        // Newlib and Illumos has no way to set a thread name.
    }

    pub fn sleep(dur: Duration) {
        let mut ts = libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long,
        };

        // If we're awoken with a signal then the return value will be -1 and
        // nanosleep will fill in `ts` with the remaining time.
        unsafe {
            while libc::nanosleep(&ts, &mut ts) == -1 {
                assert_eq!(os::errno(), libc::EINTR);
            }
        }
    }

    pub fn join(self) {
        unsafe {
            let ret = libc::pthread_join(self.id, ptr::null_mut());
            mem::forget(self);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn id(&self) -> libc::pthread_t { self.id }

    pub fn into_id(self) -> libc::pthread_t {
        let id = self.id;
        mem::forget(self);
        id
    }
}

impl Drop for Thread {
    fn drop(&mut self) {
        let ret = unsafe { libc::pthread_detach(self.id) };
        debug_assert_eq!(ret, 0);
    }
}

#[cfg(all(not(target_os = "linux"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
          not(target_os = "openbsd"),
          not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}

#[cfg(any(target_os = "linux",
          target_os = "macos",
          target_os = "bitrig",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd",
          target_os = "solaris"))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    use prelude::v1::*;

    use libc;
    use libc::mmap;
    use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
    use sys::os;

    #[cfg(any(target_os = "macos",
              target_os = "bitrig",
              target_os = "openbsd",
              target_os = "solaris"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        current().map(|s| s as *mut libc::c_void)
    }

    #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        if libc::pthread_getattr_np(libc::pthread_self(), &mut attr) == 0 {
            let mut stackaddr = ::ptr::null_mut();
            let mut stacksize = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut stacksize), 0);
            ret = Some(stackaddr);
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }

    pub unsafe fn init() -> Option<usize> {
        let psize = os::page_size();
        let mut stackaddr = match get_stack_start() {
            Some(addr) => addr,
            None => return None,
        };

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % psize;
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + psize - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          psize as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(target_os = "linux") {2} else {1};

        Some(stackaddr as usize + offset * psize)
    }

    #[cfg(target_os = "solaris")]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = mem::zeroed();
        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
        Some(current_stack.ss_sp as usize)
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> Option<usize> {
        Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t -
              libc::pthread_get_stacksize_np(libc::pthread_self())) as usize)
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
                                             &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        Some(if libc::pthread_main_np() == 1 {
            // main thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
        } else {
            // new thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize
        })
    }

    #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
    pub unsafe fn current() -> Option<usize> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        if libc::pthread_getattr_np(libc::pthread_self(), &mut attr) == 0 {
            let mut guardsize = 0;
            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
            if guardsize == 0 {
                panic!("there is no guard page");
            }
            let mut stackaddr = ::ptr::null_mut();
            let mut size = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut size), 0);

            ret = if cfg!(target_os = "netbsd") {
                Some(stackaddr as usize)
            } else {
                Some(stackaddr as usize + guardsize as usize)
            };
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }
}

// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
//
// Use dlsym to get the symbol value at runtime, both for
// compatibility with older versions of glibc, and to avoid creating
// dependencies on GLIBC_PRIVATE symbols.  Assumes that we've been
// dynamically linked to libpthread but that is currently always the
// case.  We previously used weak linkage (under the same assumption),
// but that caused Debian to detect an unnecessarily strict versioned
// dependency on libc6 (#23628).
#[cfg(target_os = "linux")]
#[allow(deprecated)]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
    use dynamic_lib::DynamicLibrary;
    use sync::Once;

    type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
    static INIT: Once = Once::new();
    static mut __pthread_get_minstack: Option<F> = None;

    INIT.call_once(|| {
        let lib = match DynamicLibrary::open(None) {
            Ok(l) => l,
            Err(..) => return,
        };
        unsafe {
            if let Ok(f) = lib.symbol("__pthread_get_minstack") {
                __pthread_get_minstack = Some(mem::transmute::<*const (), F>(f));
            }
        }
    });

    match unsafe { __pthread_get_minstack } {
        None => libc::PTHREAD_STACK_MIN as usize,
        Some(f) => unsafe { f(attr) as usize },
    }
}

// No point in looking up __pthread_get_minstack() on non-glibc
// platforms.
#[cfg(all(not(target_os = "linux"),
          not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    libc::PTHREAD_STACK_MIN as usize
}

#[cfg(target_os = "netbsd")]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    2048 // just a guess
}
<commit_msg>Fix unresolved name in libstd/sys/unix/thread<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use prelude::v1::*;

use alloc::boxed::FnBox;
use cmp;
#[cfg(not(any(target_env = "newlib", target_os = "solaris")))]
use ffi::CString;
use io;
use libc;
use mem;
use ptr;
use sys::os;
use time::Duration;

use sys_common::thread::*;

pub struct Thread {
    id: libc::pthread_t,
}

// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;
        let mut native: libc::pthread_t = mem::zeroed();
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);

        let stack_size = cmp::max(stack, min_stack_size(&attr));
        match libc::pthread_attr_setstacksize(&mut attr,
                                              stack_size as libc::size_t) {
            0 => {}
            n => {
                assert_eq!(n, libc::EINVAL);
                // EINVAL means |stack_size| is either too small or not a
                // multiple of the system page size.  Because it's definitely
                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                // Round up to the nearest page and try again.
                let page_size = os::page_size();
                let stack_size = (stack_size + page_size - 1) &
                                 (-(page_size as isize - 1) as usize - 1);
                let stack_size = stack_size as libc::size_t;
                assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
                                                           stack_size), 0);
            }
        };

        let ret = libc::pthread_create(&mut native, &attr, thread_start,
                                       &*p as *const _ as *mut _);
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);

        return if ret != 0 {
            Err(io::Error::from_raw_os_error(ret))
        } else {
            mem::forget(p); // ownership passed to pthread_create
            Ok(Thread { id: native })
        };

        extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
            unsafe { start_thread(main); }
            ptr::null_mut()
        }
    }

    pub fn yield_now() {
        let ret = unsafe { libc::sched_yield() };
        debug_assert_eq!(ret, 0);
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    pub fn set_name(name: &str) {
        const PR_SET_NAME: libc::c_int = 15;
        let cname = CString::new(name).unwrap_or_else(|_| {
            panic!("thread name may not contain interior null bytes")
        });
        // pthread wrapper only appeared in glibc 2.12, so we use syscall
        // directly.
        unsafe {
            libc::prctl(PR_SET_NAME, cname.as_ptr() as libc::c_ulong, 0, 0, 0);
        }
    }

    #[cfg(any(target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    pub fn set_name(name: &str) {
        let cname = CString::new(name).unwrap();
        unsafe {
            libc::pthread_set_name_np(libc::pthread_self(), cname.as_ptr());
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn set_name(name: &str) {
        let cname = CString::new(name).unwrap();
        unsafe {
            libc::pthread_setname_np(cname.as_ptr());
        }
    }

    #[cfg(target_os = "netbsd")]
    pub fn set_name(name: &str) {
        let cname = CString::new(&b"%s"[..]).unwrap();
        let carg = CString::new(name).unwrap();
        unsafe {
            libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
                                     carg.as_ptr() as *mut libc::c_void);
        }
    }
    #[cfg(any(target_env = "newlib", target_os = "solaris"))]
    pub fn set_name(_name: &str) {
        // Newlib and Illumos has no way to set a thread name.
    }

    pub fn sleep(dur: Duration) {
        let mut ts = libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long,
        };

        // If we're awoken with a signal then the return value will be -1 and
        // nanosleep will fill in `ts` with the remaining time.
        unsafe {
            while libc::nanosleep(&ts, &mut ts) == -1 {
                assert_eq!(os::errno(), libc::EINTR);
            }
        }
    }

    pub fn join(self) {
        unsafe {
            let ret = libc::pthread_join(self.id, ptr::null_mut());
            mem::forget(self);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn id(&self) -> libc::pthread_t { self.id }

    pub fn into_id(self) -> libc::pthread_t {
        let id = self.id;
        mem::forget(self);
        id
    }
}

impl Drop for Thread {
    fn drop(&mut self) {
        let ret = unsafe { libc::pthread_detach(self.id) };
        debug_assert_eq!(ret, 0);
    }
}

#[cfg(all(not(target_os = "linux"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
          not(target_os = "openbsd"),
          not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}

#[cfg(any(target_os = "linux",
          target_os = "macos",
          target_os = "bitrig",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd",
          target_os = "solaris"))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    use prelude::v1::*;

    use libc;
    use libc::mmap;
    use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
    use sys::os;

    #[cfg(any(target_os = "macos",
              target_os = "bitrig",
              target_os = "openbsd",
              target_os = "solaris"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        current().map(|s| s as *mut libc::c_void)
    }

    #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        if libc::pthread_getattr_np(libc::pthread_self(), &mut attr) == 0 {
            let mut stackaddr = ::ptr::null_mut();
            let mut stacksize = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut stacksize), 0);
            ret = Some(stackaddr);
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }

    pub unsafe fn init() -> Option<usize> {
        let psize = os::page_size();
        let mut stackaddr = match get_stack_start() {
            Some(addr) => addr,
            None => return None,
        };

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % psize;
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + psize - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          psize as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(target_os = "linux") {2} else {1};

        Some(stackaddr as usize + offset * psize)
    }

    #[cfg(target_os = "solaris")]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
        Some(current_stack.ss_sp as usize)
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> Option<usize> {
        Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t -
              libc::pthread_get_stacksize_np(libc::pthread_self())) as usize)
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
                                             &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        Some(if libc::pthread_main_np() == 1 {
            // main thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
        } else {
            // new thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize
        })
    }

    #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
    pub unsafe fn current() -> Option<usize> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        if libc::pthread_getattr_np(libc::pthread_self(), &mut attr) == 0 {
            let mut guardsize = 0;
            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
            if guardsize == 0 {
                panic!("there is no guard page");
            }
            let mut stackaddr = ::ptr::null_mut();
            let mut size = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut size), 0);

            ret = if cfg!(target_os = "netbsd") {
                Some(stackaddr as usize)
            } else {
                Some(stackaddr as usize + guardsize as usize)
            };
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }
}

// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
//
// Use dlsym to get the symbol value at runtime, both for
// compatibility with older versions of glibc, and to avoid creating
// dependencies on GLIBC_PRIVATE symbols.  Assumes that we've been
// dynamically linked to libpthread but that is currently always the
// case.  We previously used weak linkage (under the same assumption),
// but that caused Debian to detect an unnecessarily strict versioned
// dependency on libc6 (#23628).
#[cfg(target_os = "linux")]
#[allow(deprecated)]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
    use dynamic_lib::DynamicLibrary;
    use sync::Once;

    type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
    static INIT: Once = Once::new();
    static mut __pthread_get_minstack: Option<F> = None;

    INIT.call_once(|| {
        let lib = match DynamicLibrary::open(None) {
            Ok(l) => l,
            Err(..) => return,
        };
        unsafe {
            if let Ok(f) = lib.symbol("__pthread_get_minstack") {
                __pthread_get_minstack = Some(mem::transmute::<*const (), F>(f));
            }
        }
    });

    match unsafe { __pthread_get_minstack } {
        None => libc::PTHREAD_STACK_MIN as usize,
        Some(f) => unsafe { f(attr) as usize },
    }
}

// No point in looking up __pthread_get_minstack() on non-glibc
// platforms.
#[cfg(all(not(target_os = "linux"),
          not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    libc::PTHREAD_STACK_MIN as usize
}

#[cfg(target_os = "netbsd")]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    2048 // just a guess
}
<|endoftext|>


<commit_before>use cargo_test_support::compare::assert_ui;
use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;
use cargo_test_support::TestEnv;

use crate::cargo_remove::init_registry;

#[cargo_test]
fn case() {
    init_registry();
    let project = Project::from_template(curr_dir!().join("in"));
    let project_root = project.root();
    let cwd = &project_root;

    // run the metadata command to populate the cache
    let cargo = std::env::var_os("CARGO").unwrap();
    snapbox::cmd::Command::new(cargo)
        .test_env()
        .arg("metadata")
        .current_dir(cwd)
        .assert()
        .success();

    snapbox::cmd::Command::cargo_ui()
        .arg("remove")
        .args(["docopt", "--offline"])
        .current_dir(cwd)
        .assert()
        .success()
        .stdout_matches_path(curr_dir!().join("stdout.log"))
        .stderr_matches_path(curr_dir!().join("stderr.log"));

    assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
}
<commit_msg>Auto merge of #11193 - cassaundra:wrong-cargo-test, r=ehuss<commit_after>use cargo_test_support::compare::assert_ui;
use cargo_test_support::curr_dir;
use cargo_test_support::CargoCommand;
use cargo_test_support::Project;

use crate::cargo_remove::init_registry;

#[cargo_test]
fn case() {
    init_registry();
    let project = Project::from_template(curr_dir!().join("in"));
    let project_root = project.root();
    let cwd = &project_root;

    // run the metadata command to populate the cache
    snapbox::cmd::Command::cargo_ui()
        .arg("metadata")
        .current_dir(cwd)
        .assert()
        .success();

    snapbox::cmd::Command::cargo_ui()
        .arg("remove")
        .args(["docopt", "--offline"])
        .current_dir(cwd)
        .assert()
        .success()
        .stdout_matches_path(curr_dir!().join("stdout.log"))
        .stderr_matches_path(curr_dir!().join("stderr.log"));

    assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
}
<|endoftext|>


<commit_before>use std::collections::{HashSet, VecDeque};

use super::*;

#[derive(Default, Debug)]
pub(super) struct SegmentAccountant {
    pub tip: LogID,
    pub segments: Vec<Segment>,
    pub to_clean: HashSet<LogID>,
    pub pending_clean: HashSet<PageID>,
    pub free: VecDeque<LogID>,
    pub config: Config,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Segment {
    pids: HashSet<PageID>,
    original_len: usize,
    lsn: Lsn,
}

// concurrency properties:
//  the pagecache will ask this (maybe through the log) about what it should rewrite
//
//  open questions:
//  * how do we avoid contention
//      * pending zone?
//  * how do we maximize rewrite effectiveness?
//      * tell them to rewrite pages present in a large number of segments?
//      * tell them to rewrite small pages?
//      * just focus on lowest one
//  * how often do we rewrite pages?
//      * if we read a page that is in a segment that is being cleaned!
//
//
//  pagecache: set
//      we replaced this page, used to be at these spots, now it's here, the set's lsn is _
//
//  pagecache: merge
//      we added a frag for this page at this log, with this lsn
//
//  log: write_to_log
//      we need the next log offset, which gets this lsn

impl SegmentAccountant {
    pub fn set(&mut self, pid: PageID, old_lids: Vec<LogID>, new_lid: LogID, lsn: Lsn) {
        let new_idx = new_lid as usize / self.config.get_io_buf_size();

        for old_lid in old_lids.into_iter() {
            let idx = old_lid as usize / self.config.get_io_buf_size();

            if new_idx == idx {
                // we probably haven't flushed this segment yet, so don't
                // mark the pid as being removed from it
                continue;
            }

            let mut segment = &mut self.segments[idx];

            if segment.lsn > lsn {
                // has been replaced after this call already,
                // quite a big race happened
                continue;
            }

            if segment.original_len == 0 {
                // mark the length before decrementing it
                segment.original_len = segment.pids.len();
            }

            segment.pids.remove(&pid);

            let segment_start = (idx * self.config.get_io_buf_size()) as LogID;

            if segment.pids.is_empty() {
                // can be reused immediately
                self.to_clean.remove(&segment_start);
                self.free.push_back(segment_start);
            } else if segment.pids.len() as f64 / segment.original_len as f64 <=
                       self.config.get_segment_cleanup_threshold()
            {
                // can be cleaned
                self.to_clean.insert(segment_start);
            }
        }

        self.merged(pid, new_lid, lsn);
    }

    pub fn merged(&mut self, pid: PageID, lid: LogID, lsn: Lsn) {
        let idx = lid as usize / self.config.get_io_buf_size();

        let mut segment = &mut self.segments[idx];

        if segment.lsn > lsn {
            // a race happened, and our Lsn does not apply anymore
            return;
        }

        assert_ne!(segment.lsn, 0);

        assert_eq!(segment.lsn as usize / self.config.get_io_buf_size(), idx);

        segment.pids.insert(pid);
    }

    pub fn next(&mut self, lsn: Lsn) -> LogID {
        // pop free or add to end
        let lid = if let Some(lid) = self.free.pop_front() {
            lid
        } else {
            let lid = self.tip;
            self.tip += self.config.get_io_buf_size() as LogID;
            lid
        };

        let idx = lid as usize / self.config.get_io_buf_size();

        if self.segments.len() <= idx {
            self.segments.resize(idx + 1, Segment::default());
        }

        self.segments[idx].lsn = lsn;

        lid
    }
}
<commit_msg>add simple test for segment accountant<commit_after>use std::collections::{HashSet, VecDeque};

use super::*;

#[derive(Default, Debug)]
pub(super) struct SegmentAccountant {
    pub tip: LogID,
    pub segments: Vec<Segment>,
    pub to_clean: HashSet<LogID>,
    pub pending_clean: HashSet<PageID>,
    pub free: VecDeque<LogID>,
    pub config: Config,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Segment {
    pids: HashSet<PageID>,
    pids_len: usize,
    lsn: Lsn,
}

// concurrency properties:
//  the pagecache will ask this (maybe through the log) about what it should rewrite
//
//  open questions:
//  * how do we avoid contention
//      * pending zone?
//  * how do we maximize rewrite effectiveness?
//      * tell them to rewrite pages present in a large number of segments?
//      * tell them to rewrite small pages?
//      * just focus on lowest one
//  * how often do we rewrite pages?
//      * if we read a page that is in a segment that is being cleaned!
//
//
//  pagecache: set
//      we replaced this page, used to be at these spots, now it's here, the set's lsn is _
//
//  pagecache: merge
//      we added a frag for this page at this log, with this lsn
//
//  log: write_to_log
//      we need the next log offset, which gets this lsn

impl SegmentAccountant {
    pub fn new(config: Config, tip: LogID) -> SegmentAccountant {
        let mut ret = SegmentAccountant::default();
        ret.config = config;
        ret.tip = tip;
        ret
    }

    pub fn set(&mut self, pid: PageID, old_lids: Vec<LogID>, new_lid: LogID, lsn: Lsn) {
        self.pending_clean.remove(&pid);

        let new_idx = new_lid as usize / self.config.get_io_buf_size();

        for old_lid in old_lids.into_iter() {
            let idx = old_lid as usize / self.config.get_io_buf_size();

            if new_idx == idx {
                // we probably haven't flushed this segment yet, so don't
                // mark the pid as being removed from it
                continue;
            }

            let mut segment = &mut self.segments[idx];

            if segment.lsn > lsn {
                // has been replaced after this call already,
                // quite a big race happened
                continue;
            }

            if segment.pids_len == 0 {
                segment.pids_len = segment.pids.len();
            }

            segment.pids.remove(&pid);

            let segment_start = (idx * self.config.get_io_buf_size()) as LogID;

            if segment.pids.is_empty() {
                // can be reused immediately
                self.to_clean.remove(&segment_start);
                self.free.push_back(segment_start);
            } else if segment.pids.len() as f64 / segment.pids_len as f64 <=
                       self.config.get_segment_cleanup_threshold()
            {
                // can be cleaned
                self.to_clean.insert(segment_start);
            }
        }

        self.merged(pid, new_lid, lsn);
    }

    pub fn merged(&mut self, pid: PageID, lid: LogID, lsn: Lsn) {
        self.pending_clean.remove(&pid);

        let idx = lid as usize / self.config.get_io_buf_size();

        let mut segment = &mut self.segments[idx];

        if segment.lsn > lsn {
            // a race happened, and our Lsn does not apply anymore
            return;
        }

        assert_ne!(segment.lsn, 0);

        segment.pids.insert(pid);
    }

    pub fn next(&mut self, lsn: Lsn) -> LogID {
        // pop free or add to end
        let lid = if let Some(lid) = self.free.pop_front() {
            lid
        } else {
            let lid = self.tip;
            self.tip += self.config.get_io_buf_size() as LogID;
            lid
        };

        let idx = lid as usize / self.config.get_io_buf_size();

        if self.segments.len() <= idx {
            self.segments.resize(idx + 1, Segment::default());
        }

        self.segments[idx].lsn = lsn;

        lid
    }

    pub fn clean(&mut self) -> Option<PageID> {
        if self.free.len() > self.config.get_min_free_segments() || self.to_clean.is_empty() {
            return None;
        }

        for lid in &self.to_clean {
            let idx = *lid as usize / self.config.get_io_buf_size();
            let segment = &self.segments[idx];
            for pid in &segment.pids {
                if self.pending_clean.contains(&pid) {
                    continue;
                }
                self.pending_clean.insert(*pid);
                return Some(*pid);
            }
        }

        None
    }
}

#[test]
fn basic_workflow() {
    // empty clean is None
    let conf = Config::default();
    let mut sa = SegmentAccountant::new(conf, 0);

    let mut highest = 0;
    let mut lsn = || {
        highest += 1;
        highest
    };

    let first = sa.next(lsn());
    let second = sa.next(lsn());
    let third = sa.next(lsn());

    sa.merged(0, first, lsn());

    // assert that sets for the same pid don't yield anything to clean yet
    sa.set(0, vec![first], first, lsn());
    assert_eq!(sa.clean(), None);
    sa.set(0, vec![first], first, lsn());
    assert_eq!(sa.clean(), None);
    sa.set(0, vec![first], first, lsn());
    assert_eq!(sa.clean(), None);
    sa.set(0, vec![first], first, lsn());
    assert_eq!(sa.clean(), None);

    // assert that when we roll over to the next log, we can immediately reuse first
    let fourth = sa.next(lsn());
    sa.set(0, vec![first], second, lsn());
    assert_eq!(sa.clean(), None);
    let fifth = sa.next(lsn());
    assert_eq!(fifth, first);
    sa.merged(1, second, lsn());
    sa.merged(2, second, lsn());
    sa.merged(3, second, lsn());
    sa.merged(4, second, lsn());
    sa.merged(5, second, lsn());

    // now move a page from second to third, and assert pid 1 can be cleaned
    sa.set(0, vec![second], third, lsn());
    sa.set(2, vec![second], third, lsn());
    sa.set(3, vec![second], third, lsn());
    sa.set(4, vec![second], third, lsn());
    sa.set(5, vec![second], third, lsn());
    assert_eq!(sa.clean(), Some(1));
    assert_eq!(sa.clean(), None);
}
<|endoftext|>