<commit_before>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    impl<T> Copy for *mut T {}
    impl<T> Clone for *mut T {
        fn clone(&self) -> *mut T { loop {} }
    }

    impl<T> Copy for *const T {}
    impl<T> Clone for *const T {
        fn clone(&self) -> *const T { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor"]
    pub trait Bitor<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl Bitor for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
            impl Copy for $i {}
            impl Clone for $i {
                fn clone(&self) -> $i { loop {} }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>(_: &T) -> usize { 4 }
    }
}
<commit_msg>Auto merge of #964 - npmccallum:master, r=alexcrichton<commit_after>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    impl<T> Copy for *mut T {}
    impl<T> Clone for *mut T {
        fn clone(&self) -> *mut T { loop {} }
    }

    impl<T> Copy for *const T {}
    impl<T> Clone for *const T {
        fn clone(&self) -> *const T { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS=Self> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS=Self> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor"]
    pub trait Bitor<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl Bitor for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
            impl Copy for $i {}
            impl Clone for $i {
                fn clone(&self) -> $i { loop {} }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>(_: &T) -> usize { 4 }
    }
}
<|endoftext|>


<commit_before>// These are taken from http://en.wikipedia.org/wiki/List_of_HTTP_Status_Codes.
// Last updated on 2013-07-04
// Entries from third-party vendors not standardised upon are not included.
// If not specified otherwise, they are defined in RFC 2616.

// Yes, this is ugly code.
// No, I don't mind.
// That was easy. :-)

use std::collections::hashmap::HashSet;
use std::ascii::StrAsciiExt;
use std::io::IoResult;
use super::get_writer;

enum HeadingOrStatus {
    Heading(&'static str),
    Status(Status),
}

struct Status {
    code: uint,
    reason: &'static str,
    comment: Option<&'static str>,
}

/// Status with comment
fn StatusC(code: uint, reason: &'static str, comment: &'static str) -> HeadingOrStatus {
    Status(Status { code: code, reason: reason, comment: Some(comment) })
}

/// Status without comment
fn StatusN(code: uint, reason: &'static str) -> HeadingOrStatus {
    Status(Status { code: code, reason: reason, comment: None })
}

impl Status {
    fn ident(&self) -> String {
        camel_case(self.reason)
    }

    fn padded_ident(&self) -> String {
        self.ident().append(self.reason_padding_spaces().as_slice())
    }

    fn reason_padding_spaces(&self) -> String {
        " ".repeat(unsafe { longest_reason } - self.reason.len())
    }
}

/// >>> camel_case("I'm a Tea-pot")
/// "ImATeaPot"
fn camel_case(msg: &str) -> String {
    let msg = msg.replace("-", " ").replace("'", "");
    let mut result = String::with_capacity(msg.len());
    let mut capitalise = true;
    for c in msg.as_slice().chars() {
        let c = match capitalise {
            true => c.to_ascii().to_uppercase().to_char(),
            false => c.to_ascii().to_lowercase().to_char(),
        };
        // For a space, capitalise the next char
        capitalise = c == ' ';
        if !capitalise {  // And also, for a space, don't keep it
            result.push_char(c);
        }
    }
    result
}

static mut longest_ident: uint = 0;
static mut longest_reason: uint = 0;

pub fn generate(output_dir: &Path) -> IoResult<()> {
    let mut out = get_writer(output_dir, "status.rs");
    let entries = [
        Heading("1xx Informational"),
        StatusN(100, "Continue"),
        StatusN(101, "Switching Protocols"),
        StatusC(102, "Processing", "WebDAV; RFC 2518"),

        Heading("2xx Success"),
        StatusN(200, "OK"),
        StatusN(201, "Created"),
        StatusN(202, "Accepted"),
        StatusC(203, "Non-Authoritative Information", "since HTTP/1.1"),
        StatusN(204, "No Content"),
        StatusN(205, "Reset Content"),
        StatusN(206, "Partial Content"),
        StatusC(207, "Multi-Status", "WebDAV; RFC 4918"),
        StatusC(208, "Already Reported", "WebDAV; RFC 5842"),
        StatusC(226, "IM Used", "RFC 3229"),

        Heading("3xx Redirection"),
        StatusN(300, "Multiple Choices"),
        StatusN(301, "Moved Permanently"),
        StatusN(302, "Found"),
        StatusC(303, "See Other", "since HTTP/1.1"),
        StatusN(304, "Not Modified"),
        StatusC(305, "Use Proxy", "since HTTP/1.1"),
        StatusN(306, "Switch Proxy"),
        StatusC(307, "Temporary Redirect", "since HTTP/1.1"),
        StatusC(308, "Permanent Redirect", "approved as experimental RFC: http://tools.ietf.org/html/draft-reschke-http-status-308"),

        Heading("4xx Client Error"),
        StatusN(400, "Bad Request"),
        StatusN(401, "Unauthorized"),
        StatusN(402, "Payment Required"),
        StatusN(403, "Forbidden"),
        StatusN(404, "Not Found"),
        StatusN(405, "Method Not Allowed"),
        StatusN(406, "Not Acceptable"),
        StatusN(407, "Proxy Authentication Required"),
        StatusN(408, "Request Timeout"),
        StatusN(409, "Conflict"),
        StatusN(410, "Gone"),
        StatusN(411, "Length Required"),
        StatusN(412, "Precondition Failed"),
        StatusN(413, "Request Entity Too Large"),
        StatusN(414, "Request-URI Too Long"),
        StatusN(415, "Unsupported Media Type"),
        StatusN(416, "Requested Range Not Satisfiable"),
        StatusN(417, "Expectation Failed"),
        StatusC(418, "I'm a teapot", "RFC 2324"),
        StatusN(419, "Authentication Timeout"),
        StatusC(422, "Unprocessable Entity", "WebDAV; RFC 4918"),
        StatusC(423, "Locked", "WebDAV; RFC 4918"),
        StatusC(424, "Failed Dependency", "WebDAV; RFC 4918"),
        StatusC(424, "Method Failure", "WebDAV"),
        StatusC(425, "Unordered Collection", "Internet draft"),
        StatusC(426, "Upgrade Required", "RFC 2817"),
        StatusC(428, "Precondition Required", "RFC 6585"),
        StatusC(429, "Too Many Requests", "RFC 6585"),
        StatusC(431, "Request Header Fields Too Large", "RFC 6585"),
        StatusC(451, "Unavailable For Legal Reasons", "Internet draft"),

        Heading("5xx Server Error"),
        StatusN(500, "Internal Server Error"),
        StatusN(501, "Not Implemented"),
        StatusN(502, "Bad Gateway"),
        StatusN(503, "Service Unavailable"),
        StatusN(504, "Gateway Timeout"),
        StatusN(505, "HTTP Version Not Supported"),
        StatusC(506, "Variant Also Negotiates", "RFC 2295"),
        StatusC(507, "Insufficient Storage", "WebDAV; RFC 4918"),
        StatusC(508, "Loop Detected", "WebDAV; RFC 5842"),
        StatusC(510, "Not Extended", "RFC 2774"),
        StatusC(511, "Network Authentication Required", "RFC 6585"),
        ];
    unsafe {
        longest_ident = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.ident().len(),
        }).max_by(|&i| i).unwrap();
        longest_reason = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.reason.len(),
        }).max_by(|&i| i).unwrap();
    }
    try!(out.write("// This file is automatically generated file is used as http::status.

use std::fmt;
use std::ascii::StrAsciiExt;

/// HTTP status code
#[deriving(Eq, PartialEq, Clone)]
pub enum Status {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n    // {}\n", heading)),
            Status(status) => match status.comment {
                None => try!(write!(out, "    {},\n", status.ident())),
                Some(comment) => try!(write!(out, "    {},  // {}\n", status.ident(), comment)),
            },
        }
    }

    try!(out.write("
    UnregisteredStatus(u16, String),
}

impl Status {

    /// Get the status code
    pub fn code(&self) -> u16 {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => {},\n",
                                                status.padded_ident(), status.code)),
        }
    }
    try!(out.write("
            UnregisteredStatus(code, _)   => code,
        }
    }

    /// Get the reason phrase
    pub fn reason(&self) -> String {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => String::from_str(\"{}\"),\n",
                                                status.padded_ident(), status.reason))
        }
    }
    try!(out.write("
            UnregisteredStatus(_, ref reason) => (*reason).clone(),
        }
    }

    /// Get a status from the code and reason
    pub fn from_code_and_reason(status: u16, reason: String) -> Status {
        let reason_lower = reason.as_slice().to_ascii_lower();
        match (status, reason_lower.as_slice()) {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            ({}, \"{}\"){} => {},\n",
                                                status.code,
                                                status.reason.to_ascii_lower(),
                                                status.reason_padding_spaces(),
                                                status.ident())),
        }
    }
    try!(out.write("
            (_, _) => UnregisteredStatus(status, reason),
        }
    }
}

impl fmt::Show for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, \"{} {}\", self.code(), self.reason())
    }
}

impl fmt::Unsigned for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Unsigned;
        self.code().fmt(f)
    }
}

impl ToPrimitive for Status {

    /// Equivalent to `Some(self.code() as i64)`
    fn to_i64(&self) -> Option<i64> {
        Some(self.code() as i64)
    }

    /// Equivalent to `Some(self.code() as u64)`
    fn to_u64(&self) -> Option<u64> {
        Some(self.code() as u64)
    }
}

impl FromPrimitive for Status {
    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown (or negative, which are invalid) code is passed.
    ///
    /// For example, `from_i64(200)` will return `OK`.
    fn from_i64(n: i64) -> Option<Status> {
        if n < 0 {
            None
        } else {
            FromPrimitive::from_u64(n as u64)
        }
    }

    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown code is passed.
    ///
    /// For example, `from_u64(200)` will return `OK`.
    fn from_u64(n: u64) -> Option<Status> {
        Some(match n {
".as_bytes()));
    let mut matched_numbers = HashSet::new();
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => {
                if !matched_numbers.contains(&status.code) {
                    // Purpose: FailedDependency and MethodFailure both use 424,
                    // but clearly they mustn't both go in here
                    try!(write!(out, "            {:u} => {},\n", status.code, status.ident()));
                    matched_numbers.insert(status.code);
                }
            },
        }
    }
    out.write("
            _   => { return None }
        })
    }
}".as_bytes())
}
<commit_msg>Changed StatusC and StatusN to snake case<commit_after>// These are taken from http://en.wikipedia.org/wiki/List_of_HTTP_Status_Codes.
// Last updated on 2013-07-04
// Entries from third-party vendors not standardised upon are not included.
// If not specified otherwise, they are defined in RFC 2616.

// Yes, this is ugly code.
// No, I don't mind.
// That was easy. :-)

use std::collections::hashmap::HashSet;
use std::ascii::StrAsciiExt;
use std::io::IoResult;
use super::get_writer;

enum HeadingOrStatus {
    Heading(&'static str),
    Status(Status),
}

struct Status {
    code: uint,
    reason: &'static str,
    comment: Option<&'static str>,
}

/// Status with comment
fn status_c(code: uint, reason: &'static str, comment: &'static str) -> HeadingOrStatus {
    Status(Status { code: code, reason: reason, comment: Some(comment) })
}

/// Status without comment
fn status_n(code: uint, reason: &'static str) -> HeadingOrStatus {
    Status(Status { code: code, reason: reason, comment: None })
}

impl Status {
    fn ident(&self) -> String {
        camel_case(self.reason)
    }

    fn padded_ident(&self) -> String {
        self.ident().append(self.reason_padding_spaces().as_slice())
    }

    fn reason_padding_spaces(&self) -> String {
        " ".repeat(unsafe { longest_reason } - self.reason.len())
    }
}

/// >>> camel_case("I'm a Tea-pot")
/// "ImATeaPot"
fn camel_case(msg: &str) -> String {
    let msg = msg.replace("-", " ").replace("'", "");
    let mut result = String::with_capacity(msg.len());
    let mut capitalise = true;
    for c in msg.as_slice().chars() {
        let c = match capitalise {
            true => c.to_ascii().to_uppercase().to_char(),
            false => c.to_ascii().to_lowercase().to_char(),
        };
        // For a space, capitalise the next char
        capitalise = c == ' ';
        if !capitalise {  // And also, for a space, don't keep it
            result.push_char(c);
        }
    }
    result
}

static mut longest_ident: uint = 0;
static mut longest_reason: uint = 0;

pub fn generate(output_dir: &Path) -> IoResult<()> {
    let mut out = get_writer(output_dir, "status.rs");
    let entries = [
        Heading("1xx Informational"),
        status_n(100, "Continue"),
        status_n(101, "Switching Protocols"),
        status_c(102, "Processing", "WebDAV; RFC 2518"),

        Heading("2xx Success"),
        status_n(200, "OK"),
        status_n(201, "Created"),
        status_n(202, "Accepted"),
        status_c(203, "Non-Authoritative Information", "since HTTP/1.1"),
        status_n(204, "No Content"),
        status_n(205, "Reset Content"),
        status_n(206, "Partial Content"),
        status_c(207, "Multi-Status", "WebDAV; RFC 4918"),
        status_c(208, "Already Reported", "WebDAV; RFC 5842"),
        status_c(226, "IM Used", "RFC 3229"),

        Heading("3xx Redirection"),
        status_n(300, "Multiple Choices"),
        status_n(301, "Moved Permanently"),
        status_n(302, "Found"),
        status_c(303, "See Other", "since HTTP/1.1"),
        status_n(304, "Not Modified"),
        status_c(305, "Use Proxy", "since HTTP/1.1"),
        status_n(306, "Switch Proxy"),
        status_c(307, "Temporary Redirect", "since HTTP/1.1"),
        status_c(308, "Permanent Redirect", "approved as experimental RFC: http://tools.ietf.org/html/draft-reschke-http-status-308"),

        Heading("4xx Client Error"),
        status_n(400, "Bad Request"),
        status_n(401, "Unauthorized"),
        status_n(402, "Payment Required"),
        status_n(403, "Forbidden"),
        status_n(404, "Not Found"),
        status_n(405, "Method Not Allowed"),
        status_n(406, "Not Acceptable"),
        status_n(407, "Proxy Authentication Required"),
        status_n(408, "Request Timeout"),
        status_n(409, "Conflict"),
        status_n(410, "Gone"),
        status_n(411, "Length Required"),
        status_n(412, "Precondition Failed"),
        status_n(413, "Request Entity Too Large"),
        status_n(414, "Request-URI Too Long"),
        status_n(415, "Unsupported Media Type"),
        status_n(416, "Requested Range Not Satisfiable"),
        status_n(417, "Expectation Failed"),
        status_c(418, "I'm a teapot", "RFC 2324"),
        status_n(419, "Authentication Timeout"),
        status_c(422, "Unprocessable Entity", "WebDAV; RFC 4918"),
        status_c(423, "Locked", "WebDAV; RFC 4918"),
        status_c(424, "Failed Dependency", "WebDAV; RFC 4918"),
        status_c(424, "Method Failure", "WebDAV"),
        status_c(425, "Unordered Collection", "Internet draft"),
        status_c(426, "Upgrade Required", "RFC 2817"),
        status_c(428, "Precondition Required", "RFC 6585"),
        status_c(429, "Too Many Requests", "RFC 6585"),
        status_c(431, "Request Header Fields Too Large", "RFC 6585"),
        status_c(451, "Unavailable For Legal Reasons", "Internet draft"),

        Heading("5xx Server Error"),
        status_n(500, "Internal Server Error"),
        status_n(501, "Not Implemented"),
        status_n(502, "Bad Gateway"),
        status_n(503, "Service Unavailable"),
        status_n(504, "Gateway Timeout"),
        status_n(505, "HTTP Version Not Supported"),
        status_c(506, "Variant Also Negotiates", "RFC 2295"),
        status_c(507, "Insufficient Storage", "WebDAV; RFC 4918"),
        status_c(508, "Loop Detected", "WebDAV; RFC 5842"),
        status_c(510, "Not Extended", "RFC 2774"),
        status_c(511, "Network Authentication Required", "RFC 6585"),
        ];
    unsafe {
        longest_ident = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.ident().len(),
        }).max_by(|&i| i).unwrap();
        longest_reason = entries.iter().map(|&e| match e {
            Heading(_heading) => 0,
            Status(status) => status.reason.len(),
        }).max_by(|&i| i).unwrap();
    }
    try!(out.write("// This file is automatically generated file is used as http::status.

use std::fmt;
use std::ascii::StrAsciiExt;

/// HTTP status code
#[deriving(Eq, PartialEq, Clone)]
pub enum Status {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n    // {}\n", heading)),
            Status(status) => match status.comment {
                None => try!(write!(out, "    {},\n", status.ident())),
                Some(comment) => try!(write!(out, "    {},  // {}\n", status.ident(), comment)),
            },
        }
    }

    try!(out.write("
    UnregisteredStatus(u16, String),
}

impl Status {

    /// Get the status code
    pub fn code(&self) -> u16 {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => {},\n",
                                                status.padded_ident(), status.code)),
        }
    }
    try!(out.write("
            UnregisteredStatus(code, _)   => code,
        }
    }

    /// Get the reason phrase
    pub fn reason(&self) -> String {
        match *self {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            {} => String::from_str(\"{}\"),\n",
                                                status.padded_ident(), status.reason))
        }
    }
    try!(out.write("
            UnregisteredStatus(_, ref reason) => (*reason).clone(),
        }
    }

    /// Get a status from the code and reason
    pub fn from_code_and_reason(status: u16, reason: String) -> Status {
        let reason_lower = reason.as_slice().to_ascii_lower();
        match (status, reason_lower.as_slice()) {
".as_bytes()));
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => try!(write!(out, "            ({}, \"{}\"){} => {},\n",
                                                status.code,
                                                status.reason.to_ascii_lower(),
                                                status.reason_padding_spaces(),
                                                status.ident())),
        }
    }
    try!(out.write("
            (_, _) => UnregisteredStatus(status, reason),
        }
    }
}

impl fmt::Show for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, \"{} {}\", self.code(), self.reason())
    }
}

impl fmt::Unsigned for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Unsigned;
        self.code().fmt(f)
    }
}

impl ToPrimitive for Status {

    /// Equivalent to `Some(self.code() as i64)`
    fn to_i64(&self) -> Option<i64> {
        Some(self.code() as i64)
    }

    /// Equivalent to `Some(self.code() as u64)`
    fn to_u64(&self) -> Option<u64> {
        Some(self.code() as u64)
    }
}

impl FromPrimitive for Status {
    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown (or negative, which are invalid) code is passed.
    ///
    /// For example, `from_i64(200)` will return `OK`.
    fn from_i64(n: i64) -> Option<Status> {
        if n < 0 {
            None
        } else {
            FromPrimitive::from_u64(n as u64)
        }
    }

    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will return None if an unknown code is passed.
    ///
    /// For example, `from_u64(200)` will return `OK`.
    fn from_u64(n: u64) -> Option<Status> {
        Some(match n {
".as_bytes()));
    let mut matched_numbers = HashSet::new();
    for &entry in entries.iter() {
        match entry {
            Heading(heading) => try!(write!(out, "\n            // {}\n", heading)),
            Status(status) => {
                if !matched_numbers.contains(&status.code) {
                    // Purpose: FailedDependency and MethodFailure both use 424,
                    // but clearly they mustn't both go in here
                    try!(write!(out, "            {:u} => {},\n", status.code, status.ident()));
                    matched_numbers.insert(status.code);
                }
            },
        }
    }
    out.write("
            _   => { return None }
        })
    }
}".as_bytes())
}
<|endoftext|>


<commit_before>/// Copyright (c) 2000, 2001, 2008, 2011, David E. O'Brien
/// Copyright (c) 1998 John D. Polstra.
/// Copyright (c) 2016 Nemanja Boric
/// All rights reserved
///
/// Redistribution and use in source and binary forms, with or without
/// modification, are permitted provided that the following conditions
/// are met:
/// 1. Redistributions of source code must retain the above copyright
///    notice, this list of conditions and the following disclaimer.
/// 2. Redistributions in binary form must reproduce the above copyright
///    notice, this list of conditions and the following disclaimer in the
///    documentation and/or other materials provided with the distribution.
///
/// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
/// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
/// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
/// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
/// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
/// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
/// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
/// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
/// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
/// SUCH DAMAGE.
///
///	Source:
/// $FreeBSD: head/sys/sys/elf_common.h 294844 2016-01-26 18:20:25Z emaste $
///

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}

/// Elf32 section header
#[repr(C)]
pub struct Elf32_Shrdr {
    sh_name: Elf32_Word,
    sh_type: Elf32_Word,
    sh_flags: Elf32_Word,
    sh_addr: Elf32_Addr,
    sh_offset: Elf32_Off,
    sh_size: Elf32_Word,
    sh_link: Elf32_Word,
    sh_info: Elf32_Word,
    sh_addalign: Elf32_Word,
    sh_entsize: Elf32_Word,
}

/// Elf32 symbol table
#[repr(C)]
pub struct Elf32_Sym {
    st_name: Elf32_Word,
    st_value: Elf32_Addr,
    st_size: Elf32_Word,
    st_info: u8,
    st_other: u8,
    st_shndx: Elf32_Half,
}

/// Elf32 relocation structure that doesn't need an addend
#[repr(C)]
pub struct Elf32_Rel {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
}

/// Elf32 relocation structure that needs an addend
#[repr(C)]
pub struct Elf32_Rela {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
    r_addent: Elf32_Sword
}

/// Magic number; byte 0
const EI_MAG0: usize = 0;
/// Magic number; byte 1
const EI_MAG1: usize = 1;
/// Magic number; byte 2
const EI_MAG2: usize = 2;
/// Magic number; byte 3
const EI_MAG3: usize = 3;
/// Class of machine
const EI_CLASS: usize = 4;
/// Data format
const EI_DATA: usize = 5;
/// ELF format version
const EI_VERSION: usize = 6;
/// Operating system / ABI ident
const EI_OSABI: usize = 7;
/// ABI version
const EI_ABIVERSION: usize = 8;
/// Start of architecture definition
const OLD_EI_BRAND: usize = 8;
/// Start of padding (per SV4 ABI)
const EI_PAD: usize = 9;
/// Size of e_ident array
const EI_NIDENT: usize = 16;
<commit_msg>Add values for the magic bytes<commit_after>/// Copyright (c) 2000, 2001, 2008, 2011, David E. O'Brien
/// Copyright (c) 1998 John D. Polstra.
/// Copyright (c) 2016 Nemanja Boric
/// All rights reserved
///
/// Redistribution and use in source and binary forms, with or without
/// modification, are permitted provided that the following conditions
/// are met:
/// 1. Redistributions of source code must retain the above copyright
///    notice, this list of conditions and the following disclaimer.
/// 2. Redistributions in binary form must reproduce the above copyright
///    notice, this list of conditions and the following disclaimer in the
///    documentation and/or other materials provided with the distribution.
///
/// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
/// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
/// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
/// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
/// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
/// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
/// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
/// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
/// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
/// SUCH DAMAGE.
///
///	Source:
/// $FreeBSD: head/sys/sys/elf_common.h 294844 2016-01-26 18:20:25Z emaste $
///

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}

/// Elf32 section header
#[repr(C)]
pub struct Elf32_Shrdr {
    sh_name: Elf32_Word,
    sh_type: Elf32_Word,
    sh_flags: Elf32_Word,
    sh_addr: Elf32_Addr,
    sh_offset: Elf32_Off,
    sh_size: Elf32_Word,
    sh_link: Elf32_Word,
    sh_info: Elf32_Word,
    sh_addalign: Elf32_Word,
    sh_entsize: Elf32_Word,
}

/// Elf32 symbol table
#[repr(C)]
pub struct Elf32_Sym {
    st_name: Elf32_Word,
    st_value: Elf32_Addr,
    st_size: Elf32_Word,
    st_info: u8,
    st_other: u8,
    st_shndx: Elf32_Half,
}

/// Elf32 relocation structure that doesn't need an addend
#[repr(C)]
pub struct Elf32_Rel {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
}

/// Elf32 relocation structure that needs an addend
#[repr(C)]
pub struct Elf32_Rela {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
    r_addent: Elf32_Sword
}

/// Magic number; byte 0
const EI_MAG0: usize = 0;
/// Magic number; byte 1
const EI_MAG1: usize = 1;
/// Magic number; byte 2
const EI_MAG2: usize = 2;
/// Magic number; byte 3
const EI_MAG3: usize = 3;
/// Class of machine
const EI_CLASS: usize = 4;
/// Data format
const EI_DATA: usize = 5;
/// ELF format version
const EI_VERSION: usize = 6;
/// Operating system / ABI ident
const EI_OSABI: usize = 7;
/// ABI version
const EI_ABIVERSION: usize = 8;
/// Start of architecture definition
const OLD_EI_BRAND: usize = 8;
/// Start of padding (per SV4 ABI)
const EI_PAD: usize = 9;
/// Size of e_ident array
const EI_NIDENT: usize = 16;

/// Values for the magic number bytes
const ELFMAG0: u8 = 0x7f;
const ELFMAG1: u8 = 'E' as u8;
const ELFMAG2: u8 = 'L' as u8;
const ELFMAG3: u8 = 'F' as u8;
const ELFMAG: &'static str = "\u{177}ELF";
const SELFMAG: usize = 4;
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::connection::Connection;
use crate::deserialize::QueryableByName;
use crate::query_builder::{AstPass, QueryFragment, QueryId};
use crate::query_dsl::{LoadQuery, RunQueryDsl};
use crate::result::QueryResult;
use crate::serialize::ToSql;
use crate::sql_types::HasSqlType;

#[derive(Debug, Clone)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
/// The return value of `sql_query`.
///
/// Unlike most queries in Diesel, `SqlQuery` loads its data by column name,
/// rather than by index. This means that you cannot deserialize this query into
/// a tuple, and any structs used must implement `QueryableByName`.
///
/// See [`sql_query`](../fn.sql_query.html) for examples.
pub struct SqlQuery<Inner = ()> {
    inner: Inner,
    query: String,
}

impl<Inner> SqlQuery<Inner> {
    pub(crate) fn new(inner: Inner, query: String) -> Self {
        SqlQuery { inner, query }
    }

    /// Bind a value for use with this SQL query.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Example
    ///
    /// ```
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # use schema::users;
    /// #
    /// # #[derive(QueryableByName, Debug, PartialEq)]
    /// # #[table_name="users"]
    /// # struct User {
    /// #     id: i32,
    /// #     name: String,
    /// # }
    /// #
    /// # fn main() {
    /// #     use diesel::sql_query;
    /// #     use diesel::sql_types::{Integer, Text};
    /// #
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users::table)
    /// #         .values(users::name.eq("Jim"))
    /// #         .execute(&connection).unwrap();
    /// # #[cfg(feature = "postgres")]
    /// # let users = sql_query("SELECT * FROM users WHERE id > $1 AND name != $2");
    /// # #[cfg(not(feature = "postgres"))]
    /// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?")
    /// # ;
    /// # let users = users
    ///     .bind::<Integer, _>(1)
    ///     .bind::<Text, _>("Tess")
    ///     .get_results(&connection);
    /// let expected_users = vec![
    ///     User { id: 3, name: "Jim".into() },
    /// ];
    /// assert_eq!(Ok(expected_users), users);
    /// # }
    /// ```
    pub fn bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST> {
        UncheckedBind::new(self, value)
    }

    /// Internally boxes future calls on `bind` and `sql` so that they don't
    /// change the type.
    ///
    /// This allows doing things you otherwise couldn't do, e.g. `bind`ing in a
    /// loop.
    pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
        BoxedSqlQuery::new(self)
    }

    /// Appends a piece of SQL code at the end.
    pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
        self.query += sql.as_ref();
        self
    }
}

impl<DB, Inner> QueryFragment<DB> for SqlQuery<Inner>
where
    DB: Backend,
    Inner: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.inner.walk_ast(out.reborrow())?;
        out.push_sql(&self.query);
        Ok(())
    }
}

impl<Inner> QueryId for SqlQuery<Inner> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<Inner, Conn, T> LoadQuery<Conn, T> for SqlQuery<Inner>
where
    Conn: Connection,
    T: QueryableByName<Conn::Backend>,
    Self: QueryFragment<Conn::Backend>,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
        conn.query_by_name(&self)
    }
}

impl<Inner, Conn> RunQueryDsl<Conn> for SqlQuery<Inner> {}

#[derive(Debug, Clone, Copy)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
pub struct UncheckedBind<Query, Value, ST> {
    query: Query,
    value: Value,
    _marker: PhantomData<ST>,
}

impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
    pub fn new(query: Query, value: Value) -> Self {
        UncheckedBind {
            query,
            value,
            _marker: PhantomData,
        }
    }

    pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
        UncheckedBind::new(self, value)
    }

    pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
        BoxedSqlQuery::new(self)
    }

    pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
        SqlQuery::new(self, sql.into())
    }
}

impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
where
    Query: QueryId,
    ST: QueryId,
{
    type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;

    const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
}

impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
where
    DB: Backend + HasSqlType<ST>,
    Query: QueryFragment<DB>,
    Value: ToSql<ST, DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        self.query.walk_ast(out.reborrow())?;
        out.push_bind_param_value_only(&self.value)?;
        Ok(())
    }
}

impl<Conn, Query, Value, ST, T> LoadQuery<Conn, T> for UncheckedBind<Query, Value, ST>
where
    Conn: Connection,
    T: QueryableByName<Conn::Backend>,
    Self: QueryFragment<Conn::Backend> + QueryId,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
        conn.query_by_name(&self)
    }
}

impl<Conn, Query, Value, ST> RunQueryDsl<Conn> for UncheckedBind<Query, Value, ST> {}

#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// See [`SqlQuery::into_boxed`].
///
/// [`SqlQuery::into_boxed`]: ./struct.SqlQuery.html#method.into_boxed
#[allow(missing_debug_implementations)]
pub struct BoxedSqlQuery<'f, DB: Backend, Query> {
    query: Query,
    sql: String,
    binds: Vec<Box<dyn Fn(AstPass<DB>) -> QueryResult<()> + 'f>>,
}

impl<'f, DB: Backend, Query> BoxedSqlQuery<'f, DB, Query> {
    pub(crate) fn new(query: Query) -> Self {
        BoxedSqlQuery {
            query,
            sql: "".to_string(),
            binds: vec![],
        }
    }

    /// See [`SqlQuery::bind`].
    ///
    /// [`SqlQuery::bind`]: ./struct.SqlQuery.html#method.bind
    pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
    where
        DB: HasSqlType<BindSt>,
        Value: ToSql<BindSt, DB> + 'f,
    {
        self.binds
            .push(Box::new(move |mut out| out.push_bind_param_value_only(&b)));
        self
    }

    /// See [`SqlQuery::sql`].
    ///
    /// [`SqlQuery::sql`]: ./struct.SqlQuery.html#method.sql
    pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
        self.sql += sql.as_ref();
        self
    }
}

impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
where
    DB: Backend,
    Query: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.query.walk_ast(out.reborrow())?;
        out.push_sql(&self.sql);

        for b in &self.binds {
            b(out.reborrow())?;
        }
        Ok(())
    }
}

impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<Conn, T, Query> LoadQuery<Conn, T> for BoxedSqlQuery<'_, Conn::Backend, Query>
where
    Conn: Connection,
    T: QueryableByName<Conn::Backend>,
    Self: QueryFragment<Conn::Backend> + QueryId,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
        conn.query_by_name(&self)
    }
}

impl<Conn: Connection, Query> RunQueryDsl<Conn> for BoxedSqlQuery<'_, Conn::Backend, Query> {}
<commit_msg>Add note clarifying that placeholder syntax is engine-dependent<commit_after>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::connection::Connection;
use crate::deserialize::QueryableByName;
use crate::query_builder::{AstPass, QueryFragment, QueryId};
use crate::query_dsl::{LoadQuery, RunQueryDsl};
use crate::result::QueryResult;
use crate::serialize::ToSql;
use crate::sql_types::HasSqlType;

#[derive(Debug, Clone)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
/// The return value of `sql_query`.
///
/// Unlike most queries in Diesel, `SqlQuery` loads its data by column name,
/// rather than by index. This means that you cannot deserialize this query into
/// a tuple, and any structs used must implement `QueryableByName`.
///
/// See [`sql_query`](../fn.sql_query.html) for examples.
pub struct SqlQuery<Inner = ()> {
    inner: Inner,
    query: String,
}

impl<Inner> SqlQuery<Inner> {
    pub(crate) fn new(inner: Inner, query: String) -> Self {
        SqlQuery { inner, query }
    }

    /// Bind a value for use with this SQL query. The given query should have
    /// placeholders that vary based on the database type,
    /// like [SQLite Parameters](https://sqlite.org/lang_expr.html#varparam) or
    /// the [PostgreSQL PREPARE syntax](https://www.postgresql.org/docs/current/sql-prepare.html).
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Example
    ///
    /// ```
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # use schema::users;
    /// #
    /// # #[derive(QueryableByName, Debug, PartialEq)]
    /// # #[table_name="users"]
    /// # struct User {
    /// #     id: i32,
    /// #     name: String,
    /// # }
    /// #
    /// # fn main() {
    /// #     use diesel::sql_query;
    /// #     use diesel::sql_types::{Integer, Text};
    /// #
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users::table)
    /// #         .values(users::name.eq("Jim"))
    /// #         .execute(&connection).unwrap();
    /// # #[cfg(feature = "postgres")]
    /// # let users = sql_query("SELECT * FROM users WHERE id > $1 AND name != $2");
    /// # #[cfg(not(feature = "postgres"))]
    /// let users = sql_query("SELECT * FROM users WHERE id > ? AND name <> ?")
    /// # ;
    /// # let users = users
    ///     .bind::<Integer, _>(1)
    ///     .bind::<Text, _>("Tess")
    ///     .get_results(&connection);
    /// let expected_users = vec![
    ///     User { id: 3, name: "Jim".into() },
    /// ];
    /// assert_eq!(Ok(expected_users), users);
    /// # }
    /// ```
    pub fn bind<ST, Value>(self, value: Value) -> UncheckedBind<Self, Value, ST> {
        UncheckedBind::new(self, value)
    }

    /// Internally boxes future calls on `bind` and `sql` so that they don't
    /// change the type.
    ///
    /// This allows doing things you otherwise couldn't do, e.g. `bind`ing in a
    /// loop.
    pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
        BoxedSqlQuery::new(self)
    }

    /// Appends a piece of SQL code at the end.
    pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
        self.query += sql.as_ref();
        self
    }
}

impl<DB, Inner> QueryFragment<DB> for SqlQuery<Inner>
where
    DB: Backend,
    Inner: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.inner.walk_ast(out.reborrow())?;
        out.push_sql(&self.query);
        Ok(())
    }
}

impl<Inner> QueryId for SqlQuery<Inner> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<Inner, Conn, T> LoadQuery<Conn, T> for SqlQuery<Inner>
where
    Conn: Connection,
    T: QueryableByName<Conn::Backend>,
    Self: QueryFragment<Conn::Backend>,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
        conn.query_by_name(&self)
    }
}

impl<Inner, Conn> RunQueryDsl<Conn> for SqlQuery<Inner> {}

#[derive(Debug, Clone, Copy)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
pub struct UncheckedBind<Query, Value, ST> {
    query: Query,
    value: Value,
    _marker: PhantomData<ST>,
}

impl<Query, Value, ST> UncheckedBind<Query, Value, ST> {
    pub fn new(query: Query, value: Value) -> Self {
        UncheckedBind {
            query,
            value,
            _marker: PhantomData,
        }
    }

    pub fn bind<ST2, Value2>(self, value: Value2) -> UncheckedBind<Self, Value2, ST2> {
        UncheckedBind::new(self, value)
    }

    pub fn into_boxed<'f, DB: Backend>(self) -> BoxedSqlQuery<'f, DB, Self> {
        BoxedSqlQuery::new(self)
    }

    pub fn sql<T: Into<String>>(self, sql: T) -> SqlQuery<Self> {
        SqlQuery::new(self, sql.into())
    }
}

impl<Query, Value, ST> QueryId for UncheckedBind<Query, Value, ST>
where
    Query: QueryId,
    ST: QueryId,
{
    type QueryId = UncheckedBind<Query::QueryId, (), ST::QueryId>;

    const HAS_STATIC_QUERY_ID: bool = Query::HAS_STATIC_QUERY_ID && ST::HAS_STATIC_QUERY_ID;
}

impl<Query, Value, ST, DB> QueryFragment<DB> for UncheckedBind<Query, Value, ST>
where
    DB: Backend + HasSqlType<ST>,
    Query: QueryFragment<DB>,
    Value: ToSql<ST, DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        self.query.walk_ast(out.reborrow())?;
        out.push_bind_param_value_only(&self.value)?;
        Ok(())
    }
}

impl<Conn, Query, Value, ST, T> LoadQuery<Conn, T> for UncheckedBind<Query, Value, ST>
where
    Conn: Connection,
    T: QueryableByName<Conn::Backend>,
    Self: QueryFragment<Conn::Backend> + QueryId,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
        conn.query_by_name(&self)
    }
}

impl<Conn, Query, Value, ST> RunQueryDsl<Conn> for UncheckedBind<Query, Value, ST> {}

#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// See [`SqlQuery::into_boxed`].
///
/// [`SqlQuery::into_boxed`]: ./struct.SqlQuery.html#method.into_boxed
#[allow(missing_debug_implementations)]
pub struct BoxedSqlQuery<'f, DB: Backend, Query> {
    query: Query,
    sql: String,
    binds: Vec<Box<dyn Fn(AstPass<DB>) -> QueryResult<()> + 'f>>,
}

impl<'f, DB: Backend, Query> BoxedSqlQuery<'f, DB, Query> {
    pub(crate) fn new(query: Query) -> Self {
        BoxedSqlQuery {
            query,
            sql: "".to_string(),
            binds: vec![],
        }
    }

    /// See [`SqlQuery::bind`].
    ///
    /// [`SqlQuery::bind`]: ./struct.SqlQuery.html#method.bind
    pub fn bind<BindSt, Value>(mut self, b: Value) -> Self
    where
        DB: HasSqlType<BindSt>,
        Value: ToSql<BindSt, DB> + 'f,
    {
        self.binds
            .push(Box::new(move |mut out| out.push_bind_param_value_only(&b)));
        self
    }

    /// See [`SqlQuery::sql`].
    ///
    /// [`SqlQuery::sql`]: ./struct.SqlQuery.html#method.sql
    pub fn sql<T: AsRef<str>>(mut self, sql: T) -> Self {
        self.sql += sql.as_ref();
        self
    }
}

impl<DB, Query> QueryFragment<DB> for BoxedSqlQuery<'_, DB, Query>
where
    DB: Backend,
    Query: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.query.walk_ast(out.reborrow())?;
        out.push_sql(&self.sql);

        for b in &self.binds {
            b(out.reborrow())?;
        }
        Ok(())
    }
}

impl<DB: Backend, Query> QueryId for BoxedSqlQuery<'_, DB, Query> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<Conn, T, Query> LoadQuery<Conn, T> for BoxedSqlQuery<'_, Conn::Backend, Query>
where
    Conn: Connection,
    T: QueryableByName<Conn::Backend>,
    Self: QueryFragment<Conn::Backend> + QueryId,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<T>> {
        conn.query_by_name(&self)
    }
}

impl<Conn: Connection, Query> RunQueryDsl<Conn> for BoxedSqlQuery<'_, Conn::Backend, Query> {}
<|endoftext|>


<commit_before>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

trait ToResponse {
    fn status(&self) -> StatusCode {
        StatusCode::Ok
    }

    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(0)
    }

    fn content(&self) -> &[u8] {
        &[]
    }

    fn make_response(&self, mut response: Response) {
        response.headers_mut().set(self.content_type());
        response.headers_mut().set(self.content_length());
        response.start().unwrap().write(self.content()).unwrap();
    }
}

impl ToResponse for StatusCode {
    fn status(&self) -> StatusCode {
        *self
    }
}

impl ToResponse for String {
    fn content_type(&self) -> ContentType {
        ContentType::html()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.as_bytes()
    }
}

pub fn get(request: Request, response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request).make_response(response),
            path == "/ip" => origin(&request).make_response(response),
            path.starts_with("/status/") => status(path).make_response(response),
            path.starts_with("/test") => test(&request).make_response(response),
            true => notfound404().make_response(response),
        ];
    }
}

struct Text(String);

impl ToResponse for Text {
    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.0.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

fn notfound404() -> String {
    String::from("<!DOCTYPE html>

            <title>404 Not Found</title>

Not Found

The requested URL was not found on the server.
        If you entered the URL manually please check your spelling and try again.

    ")
}

fn index(request: &Request) -> String {
    String::from("<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ")
}

fn status(path: &str) -> StatusCode {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    }
}

fn origin(request: &Request) -> Text {
    Text(format!("origin: {}", request.remote_addr))
}

fn test(request: &Request) -> String {
    format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
            request.remote_addr,
            request.method,
            request.version,
            request.headers,
            request.uri)
}
<commit_msg>ToResponse -> MakeResponse<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

trait MakeResponse {
    fn status(&self) -> StatusCode {
        StatusCode::Ok
    }

    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(0)
    }

    fn content(&self) -> &[u8] {
        &[]
    }

    fn make_response(&self, mut response: Response) {
        response.headers_mut().set(self.content_type());
        response.headers_mut().set(self.content_length());
        response.start().unwrap().write(self.content()).unwrap();
    }
}

impl MakeResponse for StatusCode {
    fn status(&self) -> StatusCode {
        *self
    }
}

impl MakeResponse for String {
    fn content_type(&self) -> ContentType {
        ContentType::html()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.as_bytes()
    }
}

pub fn get(request: Request, response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request).make_response(response),
            path == "/ip" => origin(&request).make_response(response),
            path.starts_with("/status/") => status(path).make_response(response),
            path.starts_with("/test") => test(&request).make_response(response),
            true => notfound404().make_response(response),
        ];
    }
}

struct Text(String);

impl MakeResponse for Text {
    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.0.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

fn notfound404() -> String {
    String::from("<!DOCTYPE html>

            <title>404 Not Found</title>

Not Found

The requested URL was not found on the server.
        If you entered the URL manually please check your spelling and try again.

    ")
}

fn index(request: &Request) -> String {
    String::from("<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ")
}

fn status(path: &str) -> StatusCode {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    }
}

fn origin(request: &Request) -> Text {
    Text(format!("origin: {}", request.remote_addr))
}

fn test(request: &Request) -> String {
    format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
            request.remote_addr,
            request.method,
            request.version,
            request.headers,
            request.uri)
}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use std::io::{Read, Write, ErrorKind};
use std::result::Result;
use std::net::TcpStream;
use std::time::Duration;
use rand::{thread_rng, Rng};

use super::command::ControlCommandResponse;
use super::command::ControlCommand;
use super::command::COMMAND_SIZE;
use APP_CONF;
use LINE_FEED;
use cache::route::CacheRoute;
use cache::route::ROUTE_HASH_SIZE;

pub struct ControlHandle;

enum ControlHandleError {
    Closed,
    IncompatibleHasher,
    NotRecognized,
    TimedOut,
    ConnectionAborted,
    Interrupted,
    Unknown,
}

#[derive(PartialEq)]
enum ControlHandleMessageResult {
    Continue,
    Close,
}

const LINE_END_GAP: usize = 1;
const MAX_LINE_SIZE: usize = COMMAND_SIZE + ROUTE_HASH_SIZE + LINE_END_GAP + 1;
const HASH_VALUE_SIZE: usize = 10;
const HASH_RESULT_SIZE: usize = 7 + ROUTE_HASH_SIZE + LINE_END_GAP + 1;
const SHARD_DEFAULT: ControlShard = 0;
const TCP_TIMEOUT_NON_ESTABLISHED: u64 = 20;

static BUFFER_LINE_SEPARATOR: u8 = '\n' as u8;

pub type ControlShard = u8;

lazy_static! {
    static ref CONNECTED_BANNER: String = format!("CONNECTED <{} v{}>",
        env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}

impl ControlHandleError {
    pub fn to_str(&self) -> &'static str {
        match *self {
            ControlHandleError::Closed => "closed",
            ControlHandleError::IncompatibleHasher => "incompatible_hasher",
            ControlHandleError::NotRecognized => "not_recognized",
            ControlHandleError::TimedOut => "timed_out",
            ControlHandleError::ConnectionAborted => "connection_aborted",
            ControlHandleError::Interrupted => "interrupted",
            ControlHandleError::Unknown => "unknown",
        }
    }
}

impl ControlHandle {
    pub fn client(mut stream: TcpStream) {
        // Configure stream (non-established)
        ControlHandle::configure_stream(&stream, false);

        // Send connected banner
        write!(stream, "{}{}", *CONNECTED_BANNER, LINE_FEED).expect("write failed");

        // Ensure client hasher is compatible
        match Self::ensure_hasher(&stream) {
            Ok(_) => {
                // Configure stream (established)
                ControlHandle::configure_stream(&stream, true);

                // Send started acknowledgement
                write!(stream, "STARTED{}", LINE_FEED).expect("write failed");

                // Select default shard
                let mut shard = SHARD_DEFAULT;

                // Initialize packet buffer
                let mut buffer = Vec::new();

                // Wait for incoming messages
                'handler: loop {
                    let mut read = [0; MAX_LINE_SIZE];

                    match stream.read(&mut read) {
                        Ok(n) => {
                            // Should close?
                            if n == 0 {
                                break;
                            }

                            // Buffer chunk
                            buffer.extend_from_slice(&read[0..n]);

                            // Should handle this chunk? (terminated)
                            if buffer[buffer.len() - 1] == BUFFER_LINE_SEPARATOR {
                                {
                                    // Handle all buffered chunks as lines
                                    let buffer_split =
                                        buffer.split(|value| value == &BUFFER_LINE_SEPARATOR);

                                    for line in buffer_split {
                                        if line.len() > 0 {
                                            if Self::on_message(&mut shard, &stream, line) ==
                                                ControlHandleMessageResult::Close
                                            {
                                                // Should close?
                                                break 'handler;
                                            }
                                        }
                                    }
                                }

                                // Reset buffer
                                buffer.clear();
                            }
                        }
                        Err(err) => {
                            info!("closing control thread with traceback: {}", err);

                            panic!("closing control channel");
                        }
                    }
                }
            }
            Err(err) => {
                write!(stream, "ENDED {}{}", err.to_str(), LINE_FEED).expect("write failed");
            }
        }
    }

    fn configure_stream(stream: &TcpStream, is_established: bool) {
        let tcp_timeout = if is_established == true {
            APP_CONF.control.tcp_timeout
        } else {
            TCP_TIMEOUT_NON_ESTABLISHED
        };

        assert!(stream.set_nodelay(true).is_ok());

        assert!(
            stream
                .set_read_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
        assert!(
            stream
                .set_write_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
    }

    fn ensure_hasher(mut stream: &TcpStream) -> Result<Option<()>, ControlHandleError> {
        let test_value: String = thread_rng()
            .gen_ascii_chars()
            .take(HASH_VALUE_SIZE)
            .collect();
        let test_hash = CacheRoute::hash(test_value.as_str());

        write!(stream, "HASHREQ {}{}", test_value, LINE_FEED).expect("write failed");

        debug!(
            "sent hasher request: {} and expecting hash: {}",
            test_value,
            test_hash
        );

        loop {
            let mut read = [0; HASH_RESULT_SIZE];

            match stream.read(&mut read) {
                Ok(n) => {
                    if n == 0 {
                        return Err(ControlHandleError::Closed);
                    }

                    let mut parts = str::from_utf8(&read[0..n]).unwrap_or("").split_whitespace();

                    if parts.next().unwrap_or("") == "HASHRES" {
                        let res_hash = parts.next().unwrap_or("");

                        debug!(
                            "got hasher response: {} and expecting: {}",
                            res_hash,
                            test_hash
                        );

                        // Validate hash
                        if res_hash.is_empty() == false && res_hash == test_hash {
                            return Ok(None);
                        }

                        return Err(ControlHandleError::IncompatibleHasher);
                    }

                    return Err(ControlHandleError::NotRecognized);
                }
                Err(err) => {
                    let err_reason = match err.kind() {
                        ErrorKind::TimedOut => ControlHandleError::TimedOut,
                        ErrorKind::ConnectionAborted => ControlHandleError::ConnectionAborted,
                        ErrorKind::Interrupted => ControlHandleError::Interrupted,
                        _ => ControlHandleError::Unknown,
                    };

                    return Err(err_reason);
                }
            }
        }
    }

    fn on_message(
        shard: &mut ControlShard,
        mut stream: &TcpStream,
        message_slice: &[u8],
    ) -> ControlHandleMessageResult {
        let message = str::from_utf8(message_slice).unwrap_or("");

        debug!("got control message on shard {}: {}", shard, message);

        let mut result = ControlHandleMessageResult::Continue;

        let response = match Self::handle_message(shard, &message) {
            Ok(resp) => {
                match resp {
                    ControlCommandResponse::Ok |
                    ControlCommandResponse::Pong |
                    ControlCommandResponse::Ended |
                    ControlCommandResponse::Nil |
                    ControlCommandResponse::Void => {
                        if resp == ControlCommandResponse::Ended {
                            result = ControlHandleMessageResult::Close;
                        }
                        resp.to_str()
                    }
                    _ => ControlCommandResponse::Err.to_str(),
                }
            }
            _ => ControlCommandResponse::Err.to_str(),
        };

        if response.is_empty() == false {
            write!(stream, "{}{}", response, LINE_FEED).expect("write failed");
        }

        return result;
    }

    fn handle_message(
        shard: &mut ControlShard,
        message: &str,
    ) -> Result<ControlCommandResponse, Option<()>> {
        let mut parts = message.split_whitespace();
        let command = parts.next().unwrap_or("");

        debug!("will dispatch command: {}", command);

        match command {
            "" => Ok(ControlCommandResponse::Void),
            "FLUSHB" => ControlCommand::dispatch_flush_bucket(shard, parts),
            "FLUSHA" => ControlCommand::dispatch_flush_auth(shard, parts),
            "PING" => ControlCommand::dispatch_ping(),
            "SHARD" => ControlCommand::dispatch_shard(shard, parts),
            "QUIT" => ControlCommand::dispatch_quit(),
            _ => Ok(ControlCommandResponse::Nil),
        }
    }
}
<commit_msg>Log written resp.<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use std::io::{Read, Write, ErrorKind};
use std::result::Result;
use std::net::TcpStream;
use std::time::Duration;
use rand::{thread_rng, Rng};

use super::command::ControlCommandResponse;
use super::command::ControlCommand;
use super::command::COMMAND_SIZE;
use APP_CONF;
use LINE_FEED;
use cache::route::CacheRoute;
use cache::route::ROUTE_HASH_SIZE;

pub struct ControlHandle;

enum ControlHandleError {
    Closed,
    IncompatibleHasher,
    NotRecognized,
    TimedOut,
    ConnectionAborted,
    Interrupted,
    Unknown,
}

#[derive(PartialEq)]
enum ControlHandleMessageResult {
    Continue,
    Close,
}

const LINE_END_GAP: usize = 1;
const MAX_LINE_SIZE: usize = COMMAND_SIZE + ROUTE_HASH_SIZE + LINE_END_GAP + 1;
const HASH_VALUE_SIZE: usize = 10;
const HASH_RESULT_SIZE: usize = 7 + ROUTE_HASH_SIZE + LINE_END_GAP + 1;
const SHARD_DEFAULT: ControlShard = 0;
const TCP_TIMEOUT_NON_ESTABLISHED: u64 = 20;

static BUFFER_LINE_SEPARATOR: u8 = '\n' as u8;

pub type ControlShard = u8;

lazy_static! {
    static ref CONNECTED_BANNER: String = format!("CONNECTED <{} v{}>",
        env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}

impl ControlHandleError {
    pub fn to_str(&self) -> &'static str {
        match *self {
            ControlHandleError::Closed => "closed",
            ControlHandleError::IncompatibleHasher => "incompatible_hasher",
            ControlHandleError::NotRecognized => "not_recognized",
            ControlHandleError::TimedOut => "timed_out",
            ControlHandleError::ConnectionAborted => "connection_aborted",
            ControlHandleError::Interrupted => "interrupted",
            ControlHandleError::Unknown => "unknown",
        }
    }
}

impl ControlHandle {
    pub fn client(mut stream: TcpStream) {
        // Configure stream (non-established)
        ControlHandle::configure_stream(&stream, false);

        // Send connected banner
        write!(stream, "{}{}", *CONNECTED_BANNER, LINE_FEED).expect("write failed");

        // Ensure client hasher is compatible
        match Self::ensure_hasher(&stream) {
            Ok(_) => {
                // Configure stream (established)
                ControlHandle::configure_stream(&stream, true);

                // Send started acknowledgement
                write!(stream, "STARTED{}", LINE_FEED).expect("write failed");

                // Select default shard
                let mut shard = SHARD_DEFAULT;

                // Initialize packet buffer
                let mut buffer = Vec::new();

                // Wait for incoming messages
                'handler: loop {
                    let mut read = [0; MAX_LINE_SIZE];

                    match stream.read(&mut read) {
                        Ok(n) => {
                            // Should close?
                            if n == 0 {
                                break;
                            }

                            // Buffer chunk
                            buffer.extend_from_slice(&read[0..n]);

                            // Should handle this chunk? (terminated)
                            if buffer[buffer.len() - 1] == BUFFER_LINE_SEPARATOR {
                                {
                                    // Handle all buffered chunks as lines
                                    let buffer_split =
                                        buffer.split(|value| value == &BUFFER_LINE_SEPARATOR);

                                    for line in buffer_split {
                                        if line.len() > 0 {
                                            if Self::on_message(&mut shard, &stream, line) ==
                                                ControlHandleMessageResult::Close
                                            {
                                                // Should close?
                                                break 'handler;
                                            }
                                        }
                                    }
                                }

                                // Reset buffer
                                buffer.clear();
                            }
                        }
                        Err(err) => {
                            info!("closing control thread with traceback: {}", err);

                            panic!("closing control channel");
                        }
                    }
                }
            }
            Err(err) => {
                write!(stream, "ENDED {}{}", err.to_str(), LINE_FEED).expect("write failed");
            }
        }
    }

    fn configure_stream(stream: &TcpStream, is_established: bool) {
        let tcp_timeout = if is_established == true {
            APP_CONF.control.tcp_timeout
        } else {
            TCP_TIMEOUT_NON_ESTABLISHED
        };

        assert!(stream.set_nodelay(true).is_ok());

        assert!(
            stream
                .set_read_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
        assert!(
            stream
                .set_write_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
    }

    fn ensure_hasher(mut stream: &TcpStream) -> Result<Option<()>, ControlHandleError> {
        let test_value: String = thread_rng()
            .gen_ascii_chars()
            .take(HASH_VALUE_SIZE)
            .collect();
        let test_hash = CacheRoute::hash(test_value.as_str());

        write!(stream, "HASHREQ {}{}", test_value, LINE_FEED).expect("write failed");

        debug!(
            "sent hasher request: {} and expecting hash: {}",
            test_value,
            test_hash
        );

        loop {
            let mut read = [0; HASH_RESULT_SIZE];

            match stream.read(&mut read) {
                Ok(n) => {
                    if n == 0 {
                        return Err(ControlHandleError::Closed);
                    }

                    let mut parts = str::from_utf8(&read[0..n]).unwrap_or("").split_whitespace();

                    if parts.next().unwrap_or("") == "HASHRES" {
                        let res_hash = parts.next().unwrap_or("");

                        debug!(
                            "got hasher response: {} and expecting: {}",
                            res_hash,
                            test_hash
                        );

                        // Validate hash
                        if res_hash.is_empty() == false && res_hash == test_hash {
                            return Ok(None);
                        }

                        return Err(ControlHandleError::IncompatibleHasher);
                    }

                    return Err(ControlHandleError::NotRecognized);
                }
                Err(err) => {
                    let err_reason = match err.kind() {
                        ErrorKind::TimedOut => ControlHandleError::TimedOut,
                        ErrorKind::ConnectionAborted => ControlHandleError::ConnectionAborted,
                        ErrorKind::Interrupted => ControlHandleError::Interrupted,
                        _ => ControlHandleError::Unknown,
                    };

                    return Err(err_reason);
                }
            }
        }
    }

    fn on_message(
        shard: &mut ControlShard,
        mut stream: &TcpStream,
        message_slice: &[u8],
    ) -> ControlHandleMessageResult {
        let message = str::from_utf8(message_slice).unwrap_or("");

        debug!("got control message on shard {}: {}", shard, message);

        let mut result = ControlHandleMessageResult::Continue;

        let response = match Self::handle_message(shard, &message) {
            Ok(resp) => {
                match resp {
                    ControlCommandResponse::Ok |
                    ControlCommandResponse::Pong |
                    ControlCommandResponse::Ended |
                    ControlCommandResponse::Nil |
                    ControlCommandResponse::Void => {
                        if resp == ControlCommandResponse::Ended {
                            result = ControlHandleMessageResult::Close;
                        }
                        resp.to_str()
                    }
                    _ => ControlCommandResponse::Err.to_str(),
                }
            }
            _ => ControlCommandResponse::Err.to_str(),
        };

        if response.is_empty() == false {
            write!(stream, "{}{}", response, LINE_FEED).expect("write failed");

            debug!("wrote response: {}", response);
        }

        return result;
    }

    fn handle_message(
        shard: &mut ControlShard,
        message: &str,
    ) -> Result<ControlCommandResponse, Option<()>> {
        let mut parts = message.split_whitespace();
        let command = parts.next().unwrap_or("");

        debug!("will dispatch command: {}", command);

        match command {
            "" => Ok(ControlCommandResponse::Void),
            "FLUSHB" => ControlCommand::dispatch_flush_bucket(shard, parts),
            "FLUSHA" => ControlCommand::dispatch_flush_auth(shard, parts),
            "PING" => ControlCommand::dispatch_ping(),
            "SHARD" => ControlCommand::dispatch_shard(shard, parts),
            "QUIT" => ControlCommand::dispatch_quit(),
            _ => Ok(ControlCommandResponse::Nil),
        }
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::collections::hashmap::{HashMap, Occupied, Vacant};
use std::io::fs::PathExtensions;
use std::io::util;
use std::io::{Command, BufferedReader, Process, IoResult, File, fs};
use std::io;
use std::os;

use semver;
use flate2::reader::GzDecoder;
use git2;
use serialize::json;

use conduit::{Request, Response};

use app::{App, RequestApp};
use util::{CargoResult, internal};

#[deriving(Encodable, Decodable)]
pub struct Crate {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: Option<bool>,
}

#[deriving(Encodable, Decodable)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
}

pub fn serve_index(req: &mut Request) -> CargoResult<Response> {
    let mut cmd = Command::new("git");
    cmd.arg("http-backend");

    // Required environment variables
    cmd.env("REQUEST_METHOD",
            req.method().to_string().as_slice().to_ascii_upper());
    cmd.env("GIT_PROJECT_ROOT", &req.app().git_repo_checkout);
    cmd.env("PATH_INFO", req.path().replace("/git/index", ""));
    cmd.env("REMOTE_USER", "");
    cmd.env("REMOTE_ADDR", req.remote_ip().to_string());
    cmd.env("QUERY_STRING", req.query_string().unwrap_or(""));
    cmd.env("CONTENT_TYPE", header(req, "Content-Type"));
    cmd.stderr(::std::io::process::InheritFd(2));
    let mut p = try!(cmd.spawn());

    // Pass in the body of the request (if any)
    //
    // As part of the CGI interface we're required to take care of gzip'd
    // requests. I'm not totally sure that this sequential copy is the best
    // thing to do or actually correct...
    if header(req, "Content-Encoding") == "gzip" {
        let mut body = GzDecoder::new(req.body());
        try!(util::copy(&mut body, &mut p.stdin.take().unwrap()));
    } else {
        try!(util::copy(&mut req.body(), &mut p.stdin.take().unwrap()));
    }

    // Parse the headers coming out, and the pass through the rest of the
    // process back down the stack.
    //
    // Note that we have to be careful to not drop the process which will wait
    // for the process to exit (and we haven't read stdout)
    let mut rdr = BufferedReader::new(p.stdout.take().unwrap());

    let mut headers = HashMap::new();
    for line in rdr.lines() {
        let line = try!(line);
        if line.as_slice() == "\r\n" { break }

        let mut parts = line.as_slice().splitn(2, ':');
        let key = parts.next().unwrap();
        let value = parts.next().unwrap();
        let value = value.slice(1, value.len() - 2);
        match headers.entry(key.to_string()) {
            Occupied(e) => e.into_mut(),
            Vacant(e) => e.set(Vec::new()),
        }.push(value.to_string());
    }

    let (status_code, status_desc) = {
        let line = headers.pop_equiv(&"Status").unwrap_or(Vec::new());
        let line = line.into_iter().next().unwrap_or(String::new());
        let mut parts = line.as_slice().splitn(1, ' ');
        (from_str(parts.next().unwrap_or("")).unwrap_or(200),
         match parts.next() {
             Some("Not Found") => "Not Found",
             _ => "Ok",
         })
    };

    struct ProcessAndBuffer<R> { _p: Process, buf: BufferedReader<R> }
    impl<R: Reader> Reader for ProcessAndBuffer<R> {
        fn read(&mut self, b: &mut [u8]) -> IoResult<uint> { self.buf.read(b) }
    }
    return Ok(Response {
        status: (status_code, status_desc),
        headers: headers,
        body: box ProcessAndBuffer { _p: p, buf: rdr },
    });

    fn header<'a>(req: &'a Request, name: &str) -> &'a str {
        let h = req.headers().find(name).unwrap_or(Vec::new());
        h.as_slice().get(0).map(|s| *s).unwrap_or("")
    }
}

fn index_file(base: &Path, name: &str) -> Path {
    match name.len() {
        1 => base.join("1").join(name),
        2 => base.join("2").join(name),
        3 => base.join("3").join(name.slice_to(1)).join(name),
        _ => base.join(name.slice(0, 2))
                 .join(name.slice(2, 4))
                 .join(name),
    }
}

pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> {
    let repo = app.git_repo.lock();
    let repo = &*repo;
    let repo_path = repo.path().dir_path();
    let dst = index_file(&repo_path, krate.name.as_slice());

    commit_and_push(repo, || {
        // Add the crate to its relevant file
        try!(fs::mkdir_recursive(&dst.dir_path(), io::USER_RWX));
        let prev = if dst.exists() {
            try!(File::open(&dst).read_to_string())
        } else {
            String::new()
        };
        let s = json::encode(krate);
        let new = if prev.len() == 0 {s} else {prev + "\n" + s};
        try!(File::create(&dst).write(new.as_bytes()));

        Ok((format!("Updating crate `{}#{}`", krate.name, krate.vers),
            dst.clone()))
    })
}

pub fn yank(app: &App, krate: &str, version: &semver::Version,
            yanked: bool) -> CargoResult<()> {
    let repo = app.git_repo.lock();
    let repo = &*repo;
    let repo_path = repo.path().dir_path();
    let dst = index_file(&repo_path, krate);

    commit_and_push(repo, || {
        let prev = try!(File::open(&dst).read_to_string());
        let new = prev.as_slice().lines().map(|line| {
            let mut git_crate = try!(json::decode::<Crate>(line).map_err(|_| {
                internal(format!("couldn't decode: `{}`", line))
            }));
            if git_crate.name.as_slice() != krate ||
               git_crate.vers.to_string() != version.to_string() {
                return Ok(line.to_string())
            }
            git_crate.yanked = Some(yanked);
            Ok(json::encode(&git_crate))
        }).collect::<CargoResult<Vec<String>>>();
        let new = try!(new).as_slice().connect("\n");
        try!(File::create(&dst).write_line(new.as_slice()));

        Ok((format!("{} crate `{}#{}`",
                    if yanked {"Yanking"} else {"Unyanking"},
                    krate, version),
            dst.clone()))
    })
}

fn commit_and_push(repo: &git2::Repository,
                   f: || -> CargoResult<(String, Path)>)
                   -> CargoResult<()> {
    let repo_path = repo.path().dir_path();

    // Attempt to commit in a loop. It's possible that we're going to need to
    // rebase our repository, and after that it's possible that we're going to
    // race to commit the changes. For now we just cap out the maximum number of
    // retries at a fixed number.
    for _ in range(0i, 20) {
        let (msg, dst) = try!(f());

        // git add $file
        let mut index = try!(repo.index());
        try!(index.add_path(&dst.path_relative_from(&repo_path).unwrap()));
        try!(index.write());
        let tree_id = try!(index.write_tree());
        let tree = try!(repo.find_tree(tree_id));

        // git commit -m "..."
        let head = try!(repo.head());
        let parent = try!(repo.find_commit(head.target().unwrap()));
        let sig = try!(repo.signature());
        try!(repo.commit(Some("HEAD"), &sig, &sig, msg.as_slice(),
                         &tree, &[&parent]));

        // git push
        let mut origin = try!(repo.find_remote("origin"));
        let cfg = try!(repo.config());
        let ok = try!(with_authentication(origin.url().unwrap(), &cfg, |f| {
            let mut origin = try!(repo.find_remote("origin"));
            let mut callbacks = git2::RemoteCallbacks::new().credentials(f);
            origin.set_callbacks(&mut callbacks);

            let mut push = try!(origin.push());
            try!(push.add_refspec("refs/heads/master"));

            match push.finish() {
                Ok(()) => {}
                Err(..) => return Ok(false)
            }

            if !push.unpack_ok() {
                return Err(internal("failed to push some remote refspecs"))
            }
            try!(push.update_tips(None, None));

            Ok(true)
        }));
        if ok { return Ok(()) }

        // Ok, we need to update, so fetch and reset --hard
        try!(origin.add_fetch("refs/heads/*:refs/heads/*"));
        try!(origin.fetch(None, None));
        let head = try!(repo.head()).target().unwrap();
        let obj = try!(repo.find_object(head, None));
        try!(repo.reset(&obj, git2::Hard, None, None));
    }

    Err(internal("Too many rebase failures"))
}

pub fn with_authentication<T>(url: &str,
                              cfg: &git2::Config,
                              f: |git2::Credentials| -> T)
                              -> T {
    let mut cred_helper = git2::CredentialHelper::new(url);
    cred_helper.config(cfg);
    // TODO: read username/pass from the environment
    f(|_url, _username, _allowed| {
        match (os::getenv("GIT_HTTP_USER"), os::getenv("GIT_HTTP_PWD")) {
            (Some(u), Some(p)) => {
                git2::Cred::userpass_plaintext(u.as_slice(), p.as_slice())
            }
            _ => Err(git2::Error::from_str("no authentication set"))
        }
    })
}
<commit_msg>Be sure to terminate all files with a newline<commit_after>use std::ascii::AsciiExt;
use std::collections::hashmap::{HashMap, Occupied, Vacant};
use std::io::fs::PathExtensions;
use std::io::util;
use std::io::{Command, BufferedReader, Process, IoResult, File, fs};
use std::io;
use std::os;

use semver;
use flate2::reader::GzDecoder;
use git2;
use serialize::json;

use conduit::{Request, Response};

use app::{App, RequestApp};
use util::{CargoResult, internal};

#[deriving(Encodable, Decodable)]
pub struct Crate {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: Option<bool>,
}

#[deriving(Encodable, Decodable)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
}

pub fn serve_index(req: &mut Request) -> CargoResult<Response> {
    let mut cmd = Command::new("git");
    cmd.arg("http-backend");

    // Required environment variables
    cmd.env("REQUEST_METHOD",
            req.method().to_string().as_slice().to_ascii_upper());
    cmd.env("GIT_PROJECT_ROOT", &req.app().git_repo_checkout);
    cmd.env("PATH_INFO", req.path().replace("/git/index", ""));
    cmd.env("REMOTE_USER", "");
    cmd.env("REMOTE_ADDR", req.remote_ip().to_string());
    cmd.env("QUERY_STRING", req.query_string().unwrap_or(""));
    cmd.env("CONTENT_TYPE", header(req, "Content-Type"));
    cmd.stderr(::std::io::process::InheritFd(2));
    let mut p = try!(cmd.spawn());

    // Pass in the body of the request (if any)
    //
    // As part of the CGI interface we're required to take care of gzip'd
    // requests. I'm not totally sure that this sequential copy is the best
    // thing to do or actually correct...
    if header(req, "Content-Encoding") == "gzip" {
        let mut body = GzDecoder::new(req.body());
        try!(util::copy(&mut body, &mut p.stdin.take().unwrap()));
    } else {
        try!(util::copy(&mut req.body(), &mut p.stdin.take().unwrap()));
    }

    // Parse the headers coming out, and the pass through the rest of the
    // process back down the stack.
    //
    // Note that we have to be careful to not drop the process which will wait
    // for the process to exit (and we haven't read stdout)
    let mut rdr = BufferedReader::new(p.stdout.take().unwrap());

    let mut headers = HashMap::new();
    for line in rdr.lines() {
        let line = try!(line);
        if line.as_slice() == "\r\n" { break }

        let mut parts = line.as_slice().splitn(2, ':');
        let key = parts.next().unwrap();
        let value = parts.next().unwrap();
        let value = value.slice(1, value.len() - 2);
        match headers.entry(key.to_string()) {
            Occupied(e) => e.into_mut(),
            Vacant(e) => e.set(Vec::new()),
        }.push(value.to_string());
    }

    let (status_code, status_desc) = {
        let line = headers.pop_equiv(&"Status").unwrap_or(Vec::new());
        let line = line.into_iter().next().unwrap_or(String::new());
        let mut parts = line.as_slice().splitn(1, ' ');
        (from_str(parts.next().unwrap_or("")).unwrap_or(200),
         match parts.next() {
             Some("Not Found") => "Not Found",
             _ => "Ok",
         })
    };

    struct ProcessAndBuffer<R> { _p: Process, buf: BufferedReader<R> }
    impl<R: Reader> Reader for ProcessAndBuffer<R> {
        fn read(&mut self, b: &mut [u8]) -> IoResult<uint> { self.buf.read(b) }
    }
    return Ok(Response {
        status: (status_code, status_desc),
        headers: headers,
        body: box ProcessAndBuffer { _p: p, buf: rdr },
    });

    fn header<'a>(req: &'a Request, name: &str) -> &'a str {
        let h = req.headers().find(name).unwrap_or(Vec::new());
        h.as_slice().get(0).map(|s| *s).unwrap_or("")
    }
}

fn index_file(base: &Path, name: &str) -> Path {
    match name.len() {
        1 => base.join("1").join(name),
        2 => base.join("2").join(name),
        3 => base.join("3").join(name.slice_to(1)).join(name),
        _ => base.join(name.slice(0, 2))
                 .join(name.slice(2, 4))
                 .join(name),
    }
}

pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> {
    let repo = app.git_repo.lock();
    let repo = &*repo;
    let repo_path = repo.path().dir_path();
    let dst = index_file(&repo_path, krate.name.as_slice());

    commit_and_push(repo, || {
        // Add the crate to its relevant file
        try!(fs::mkdir_recursive(&dst.dir_path(), io::USER_RWX));
        let prev = if dst.exists() {
            try!(File::open(&dst).read_to_string())
        } else {
            String::new()
        };
        let s = json::encode(krate);
        let new = if prev.len() == 0 {s} else {prev + "\n" + s};
        try!(File::create(&dst).write_line(new.as_slice()));

        Ok((format!("Updating crate `{}#{}`", krate.name, krate.vers),
            dst.clone()))
    })
}

pub fn yank(app: &App, krate: &str, version: &semver::Version,
            yanked: bool) -> CargoResult<()> {
    let repo = app.git_repo.lock();
    let repo = &*repo;
    let repo_path = repo.path().dir_path();
    let dst = index_file(&repo_path, krate);

    commit_and_push(repo, || {
        let prev = try!(File::open(&dst).read_to_string());
        let new = prev.as_slice().lines().map(|line| {
            let mut git_crate = try!(json::decode::<Crate>(line).map_err(|_| {
                internal(format!("couldn't decode: `{}`", line))
            }));
            if git_crate.name.as_slice() != krate ||
               git_crate.vers.to_string() != version.to_string() {
                return Ok(line.to_string())
            }
            git_crate.yanked = Some(yanked);
            Ok(json::encode(&git_crate))
        }).collect::<CargoResult<Vec<String>>>();
        let new = try!(new).as_slice().connect("\n");
        try!(File::create(&dst).write_line(new.as_slice()));

        Ok((format!("{} crate `{}#{}`",
                    if yanked {"Yanking"} else {"Unyanking"},
                    krate, version),
            dst.clone()))
    })
}

fn commit_and_push(repo: &git2::Repository,
                   f: || -> CargoResult<(String, Path)>)
                   -> CargoResult<()> {
    let repo_path = repo.path().dir_path();

    // Attempt to commit in a loop. It's possible that we're going to need to
    // rebase our repository, and after that it's possible that we're going to
    // race to commit the changes. For now we just cap out the maximum number of
    // retries at a fixed number.
    for _ in range(0i, 20) {
        let (msg, dst) = try!(f());

        // git add $file
        let mut index = try!(repo.index());
        try!(index.add_path(&dst.path_relative_from(&repo_path).unwrap()));
        try!(index.write());
        let tree_id = try!(index.write_tree());
        let tree = try!(repo.find_tree(tree_id));

        // git commit -m "..."
        let head = try!(repo.head());
        let parent = try!(repo.find_commit(head.target().unwrap()));
        let sig = try!(repo.signature());
        try!(repo.commit(Some("HEAD"), &sig, &sig, msg.as_slice(),
                         &tree, &[&parent]));

        // git push
        let mut origin = try!(repo.find_remote("origin"));
        let cfg = try!(repo.config());
        let ok = try!(with_authentication(origin.url().unwrap(), &cfg, |f| {
            let mut origin = try!(repo.find_remote("origin"));
            let mut callbacks = git2::RemoteCallbacks::new().credentials(f);
            origin.set_callbacks(&mut callbacks);

            let mut push = try!(origin.push());
            try!(push.add_refspec("refs/heads/master"));

            match push.finish() {
                Ok(()) => {}
                Err(..) => return Ok(false)
            }

            if !push.unpack_ok() {
                return Err(internal("failed to push some remote refspecs"))
            }
            try!(push.update_tips(None, None));

            Ok(true)
        }));
        if ok { return Ok(()) }

        // Ok, we need to update, so fetch and reset --hard
        try!(origin.add_fetch("refs/heads/*:refs/heads/*"));
        try!(origin.fetch(None, None));
        let head = try!(repo.head()).target().unwrap();
        let obj = try!(repo.find_object(head, None));
        try!(repo.reset(&obj, git2::Hard, None, None));
    }

    Err(internal("Too many rebase failures"))
}

pub fn with_authentication<T>(url: &str,
                              cfg: &git2::Config,
                              f: |git2::Credentials| -> T)
                              -> T {
    let mut cred_helper = git2::CredentialHelper::new(url);
    cred_helper.config(cfg);
    // TODO: read username/pass from the environment
    f(|_url, _username, _allowed| {
        match (os::getenv("GIT_HTTP_USER"), os::getenv("GIT_HTTP_PWD")) {
            (Some(u), Some(p)) => {
                git2::Cred::userpass_plaintext(u.as_slice(), p.as_slice())
            }
            _ => Err(git2::Error::from_str("no authentication set"))
        }
    })
}
<|endoftext|>