<commit_before>pub mod ffi;

use std::result;

use libc::c_long;

pub enum HttpStatus {
   Continue,
   SwitchingProtocols,
   Processing,
   Ok,
   Created,
   Accepted,
   NoContent,
   PartialContent,
   SpecialResponse,
   MovedPermanently,
   MovedTemporarily,
   SeeOther,
   NotModified,
   TemporaryRedirect,
   BadRequest,
   Unauthorized,
   Forbidden,
   NotFound,
   NotAllowed,
   RequestTimeOut,
   Conflict,
   LengthRequired,
   PreconditionFailed,
   RequestUriTooLarge,
   RequestEntityTooLarge,
   UnsupportedMediaType,
   RangeNotSatisfiable,
   Close,
   RequestHeaderTooLarge,
   CertError,
   NoCert,
   ToHttps,
   ClientClosedRequest,
   InternalServerError,
   NotImplement,
   BadGateway,
   ServiceUnavailable,
   GatewayTimeOut,
   InsufficientStorage,
}

impl HttpStatus {
   pub fn new(rc: ffi::ngx_int_t) -> Self {
      match rc {
         ffi::NGX_HTTP_CONTINUE => {
            HttpStatus::Continue }
         ffi::NGX_HTTP_SWITCHING_PROTOCOLS => {
            HttpStatus::SwitchingProtocols }
         ffi::NGX_HTTP_PROCESSING => {
            HttpStatus::Processing }
         ffi::NGX_HTTP_OK => {
            HttpStatus::Ok }
         ffi::NGX_HTTP_CREATED => {
            HttpStatus::Created }
         ffi::NGX_HTTP_ACCEPTED => {
            HttpStatus::Accepted }
         ffi::NGX_HTTP_NO_CONTENT => {
            HttpStatus::NoContent }
         ffi::NGX_HTTP_PARTIAL_CONTENT => {
            HttpStatus::PartialContent }
         ffi::NGX_HTTP_SPECIAL_RESPONSE => {
            HttpStatus::SpecialResponse }
         ffi::NGX_HTTP_MOVED_PERMANENTLY => {
            HttpStatus::MovedPermanently }
         ffi::NGX_HTTP_MOVED_TEMPORARILY => {
            HttpStatus::MovedTemporarily }
         ffi::NGX_HTTP_SEE_OTHER => {
            HttpStatus::SeeOther }
         ffi::NGX_HTTP_NOT_MODIFIED => {
            HttpStatus::NotModified }
         ffi::NGX_HTTP_TEMPORARY_REDIRECT => {
            HttpStatus::TemporaryRedirect }
         ffi::NGX_HTTP_BAD_REQUEST => {
            HttpStatus::BadRequest }
         ffi::NGX_HTTP_UNAUTHORIZED => {
            HttpStatus::Unauthorized }
         ffi::NGX_HTTP_FORBIDDEN => {
            HttpStatus::Forbidden }
         ffi::NGX_HTTP_NOT_FOUND => {
            HttpStatus::NotFound }
         ffi::NGX_HTTP_NOT_ALLOWED => {
            HttpStatus::NotAllowed }
         ffi::NGX_HTTP_REQUEST_TIME_OUT => {
            HttpStatus::RequestTimeOut }
         ffi::NGX_HTTP_CONFLICT => {
            HttpStatus::Conflict }
         ffi::NGX_HTTP_LENGTH_REQUIRED => {
            HttpStatus::LengthRequired }
         ffi::NGX_HTTP_PRECONDITION_FAILED => {
            HttpStatus::PreconditionFailed }
         ffi::NGX_HTTP_REQUEST_URI_TOO_LARGE => {
            HttpStatus::RequestUriTooLarge }
         ffi::NGX_HTTP_REQUEST_ENTITY_TOO_LARGE => {
            HttpStatus::RequestEntityTooLarge }
         ffi::NGX_HTTP_UNSUPPORTED_MEDIA_TYPE => {
            HttpStatus::UnsupportedMediaType }
         ffi::NGX_HTTP_RANGE_NOT_SATISFIABLE => {
            HttpStatus::RangeNotSatisfiable }
         ffi::NGX_HTTP_CLOSE => {
            HttpStatus::Close }
         ffi::NGX_HTTP_REQUEST_HEADER_TOO_LARGE => {
            HttpStatus::RequestHeaderTooLarge }
         ffi::NGX_HTTPS_CERT_ERROR => {
            HttpStatus::CertError }
         ffi::NGX_HTTPS_NO_CERT => {
            HttpStatus::NoCert }
         ffi::NGX_HTTP_TO_HTTPS => {
            HttpStatus::ToHttps }
         ffi::NGX_HTTP_CLIENT_CLOSED_REQUEST => {
            HttpStatus::ClientClosedRequest }
         ffi::NGX_HTTP_INTERNAL_SERVER_ERROR => {
            HttpStatus::InternalServerError }
         ffi::NGX_HTTP_NOT_IMPLEMENTED => {
            HttpStatus::NotImplement }
         ffi::NGX_HTTP_BAD_GATEWAY => {
            HttpStatus::BadGateway }
         ffi::NGX_HTTP_SERVICE_UNAVAILABLE => {
            HttpStatus::ServiceUnavailable }
         ffi::NGX_HTTP_GATEWAY_TIME_OUT => {
            HttpStatus::GatewayTimeOut }
         ffi::NGX_HTTP_INSUFFICIENT_STORAGE => {
            HttpStatus::InsufficientStorage }
         _ => {
            HttpStatus::InternalServerError }
      }
   }

   pub fn rc(&self) -> ffi::ngx_int_t {
      match *self {
         HttpStatus::Continue => {
            ffi::NGX_HTTP_CONTINUE }
         HttpStatus::SwitchingProtocols => {
            ffi::NGX_HTTP_SWITCHING_PROTOCOLS }
         HttpStatus::Processing => {
            ffi::NGX_HTTP_PROCESSING }
         HttpStatus::Ok => {
            ffi::NGX_HTTP_OK }
         HttpStatus::Created => {
            ffi::NGX_HTTP_CREATED }
         HttpStatus::Accepted => {
            ffi::NGX_HTTP_ACCEPTED }
         HttpStatus::NoContent => {
            ffi::NGX_HTTP_NO_CONTENT }
         HttpStatus::PartialContent => {
            ffi::NGX_HTTP_PARTIAL_CONTENT }
         HttpStatus::SpecialResponse => {
            ffi::NGX_HTTP_SPECIAL_RESPONSE }
         HttpStatus::MovedPermanently => {
            ffi::NGX_HTTP_MOVED_PERMANENTLY }
         HttpStatus::MovedTemporarily => {
            ffi::NGX_HTTP_MOVED_TEMPORARILY }
         HttpStatus::SeeOther => {
            ffi::NGX_HTTP_SEE_OTHER }
         HttpStatus::NotModified => {
            ffi::NGX_HTTP_NOT_MODIFIED }
         HttpStatus::TemporaryRedirect => {
            ffi::NGX_HTTP_TEMPORARY_REDIRECT }
         HttpStatus::BadRequest => {
            ffi::NGX_HTTP_BAD_REQUEST }
         HttpStatus::Unauthorized => {
            ffi::NGX_HTTP_UNAUTHORIZED }
         HttpStatus::Forbidden => {
            ffi::NGX_HTTP_FORBIDDEN }
         HttpStatus::NotFound => {
            ffi::NGX_HTTP_NOT_FOUND }
         HttpStatus::NotAllowed => {
            ffi::NGX_HTTP_NOT_ALLOWED }
         HttpStatus::RequestTimeOut => {
            ffi::NGX_HTTP_REQUEST_TIME_OUT }
         HttpStatus::InternalServerError => {
            ffi::NGX_HTTP_INTERNAL_SERVER_ERROR }
         HttpStatus::Conflict => {
            ffi::NGX_HTTP_CONFLICT }
         HttpStatus::LengthRequired => {
            ffi::NGX_HTTP_LENGTH_REQUIRED }
         HttpStatus::PreconditionFailed => {
            ffi::NGX_HTTP_PRECONDITION_FAILED }
         HttpStatus::RequestUriTooLarge => {
            ffi::NGX_HTTP_REQUEST_URI_TOO_LARGE }
         HttpStatus::RequestEntityTooLarge => {
            ffi::NGX_HTTP_REQUEST_ENTITY_TOO_LARGE }
         HttpStatus::UnsupportedMediaType => {
            ffi::NGX_HTTP_UNSUPPORTED_MEDIA_TYPE }
         HttpStatus::RangeNotSatisfiable => {
            ffi::NGX_HTTP_RANGE_NOT_SATISFIABLE }
         HttpStatus::Close => {
            ffi::NGX_HTTP_CLOSE }
         HttpStatus::RequestHeaderTooLarge => {
            ffi::NGX_HTTP_REQUEST_HEADER_TOO_LARGE }
         HttpStatus::CertError => {
            ffi::NGX_HTTPS_CERT_ERROR }
         HttpStatus::NoCert => {
            ffi::NGX_HTTPS_NO_CERT }
         HttpStatus::ToHttps => {
            ffi::NGX_HTTP_TO_HTTPS }
         HttpStatus::ClientClosedRequest => {
            ffi::NGX_HTTP_CLIENT_CLOSED_REQUEST }
         HttpStatus::NotImplement => {
            ffi::NGX_HTTP_NOT_IMPLEMENTED }
         HttpStatus::BadGateway => {
            ffi::NGX_HTTP_BAD_GATEWAY }
         HttpStatus::ServiceUnavailable => {
            ffi::NGX_HTTP_SERVICE_UNAVAILABLE }
         HttpStatus::GatewayTimeOut => {
            ffi::NGX_HTTP_GATEWAY_TIME_OUT }
         HttpStatus::InsufficientStorage => {
            ffi::NGX_HTTP_INSUFFICIENT_STORAGE }
      }
   }
}

pub enum Status {
   Ok,
   Error,
   Again,
   Busy,
   Done,
   Declined,
   Abort,
   Http(HttpStatus),
}

impl Status {
   pub fn new(rc: ffi::ngx_int_t) -> Self {
      match rc {
         ffi::NGX_OK => {
            Status::Ok }
         ffi::NGX_ERROR => {
            Status::Error }
         ffi::NGX_AGAIN => {
            Status::Again }
         ffi::NGX_BUSY => {
            Status::Busy }
         ffi::NGX_DONE => {
            Status::Done }
         ffi::NGX_DECLINED => {
            Status::Declined }
         ffi::NGX_ABORT => {
            Status::Abort }
         http_rc if rc > 0 => {
            Status::Http(HttpStatus::new(http_rc)) }
         _ => {
            Status::Error }
      }
   }

   pub fn rc(&self) -> ffi::ngx_int_t {
      match *self {
         Status::Ok => {
            ffi::NGX_OK }
         Status::Error => {
            ffi::NGX_ERROR }
         Status::Again => {
            ffi::NGX_AGAIN }
         Status::Busy => {
            ffi::NGX_BUSY }
         Status::Done => {
            ffi::NGX_DONE }
         Status::Declined => {
            ffi::NGX_DECLINED }
         Status::Abort => {
            ffi::NGX_ABORT }
         Status::Http(ref http_status) => {
            http_status.rc() }
      }
   }
}

pub struct Connection {
   raw: *mut ffi::ngx_connection_t,
}

impl Connection {
   pub fn new(raw: *mut ffi::ngx_connection_t) -> Self {
      Connection {
         raw: raw
      }
   }

   pub fn log(&self) -> Option<Log> {
      let raw = unsafe { (*self.raw).log };

      if raw.is_null() {
         None
      } else {
         Some(
            Log::new(raw)
         )
      }
   }
}

pub struct Log {
   pub raw: *mut ffi::ngx_log_t,
}

impl Log {
   pub fn new(raw: *mut ffi::ngx_log_t) -> Self {
      Log {
         raw: raw
      }
   }
}

pub struct HttpRequest {
   raw: *mut ffi::ngx_http_request_t,
}

impl HttpRequest {
   pub fn new(raw: *mut ffi::ngx_http_request_t) -> Self {
      HttpRequest {
         raw: raw
      }
   }

   pub fn connection(&self) -> Option<Connection> {
      let raw = unsafe { (*self.raw).connection };

      if raw.is_null() {
         None
      } else {
         Some(
            Connection::new(raw)
         )
      }
   }

   pub fn headers_out(&self) -> HttpHeadersOut {
      let raw: *mut ffi::ngx_http_headers_out_t = unsafe { &mut (*self.raw).headers_out };

      HttpHeadersOut::new(raw)
   }

   pub fn http_send_header(&self) -> Status {
      let rc = unsafe { ffi::ngx_http_send_header(self.raw) };
      Status::new(rc)
   }
}

pub struct HttpHeadersOut {
   raw: *mut ffi::ngx_http_headers_out_t,
}

impl HttpHeadersOut {
   pub fn new(raw: *mut ffi::ngx_http_headers_out_t) -> Self {
      HttpHeadersOut {
         raw: raw
      }
   }

   pub fn set_status(&mut self, status: ffi::ngx_uint_t) {
      unsafe {
         (*self.raw).status = status;
      };
   }

   pub fn set_content_length_n(&mut self, content_length_n: ffi::off_t) {
      unsafe {
         (*self.raw).content_length_n = content_length_n;
      };
   }
}
<commit_msg>Starting a pool wrapper.<commit_after>pub mod ffi;

use std::result;
use std::mem;

use libc::c_long;

pub enum HttpStatus {
   Continue,
   SwitchingProtocols,
   Processing,
   Ok,
   Created,
   Accepted,
   NoContent,
   PartialContent,
   SpecialResponse,
   MovedPermanently,
   MovedTemporarily,
   SeeOther,
   NotModified,
   TemporaryRedirect,
   BadRequest,
   Unauthorized,
   Forbidden,
   NotFound,
   NotAllowed,
   RequestTimeOut,
   Conflict,
   LengthRequired,
   PreconditionFailed,
   RequestUriTooLarge,
   RequestEntityTooLarge,
   UnsupportedMediaType,
   RangeNotSatisfiable,
   Close,
   RequestHeaderTooLarge,
   CertError,
   NoCert,
   ToHttps,
   ClientClosedRequest,
   InternalServerError,
   NotImplement,
   BadGateway,
   ServiceUnavailable,
   GatewayTimeOut,
   InsufficientStorage,
}

impl HttpStatus {
   pub fn new(rc: ffi::ngx_int_t) -> Self {
      match rc {
         ffi::NGX_HTTP_CONTINUE => {
            HttpStatus::Continue }
         ffi::NGX_HTTP_SWITCHING_PROTOCOLS => {
            HttpStatus::SwitchingProtocols }
         ffi::NGX_HTTP_PROCESSING => {
            HttpStatus::Processing }
         ffi::NGX_HTTP_OK => {
            HttpStatus::Ok }
         ffi::NGX_HTTP_CREATED => {
            HttpStatus::Created }
         ffi::NGX_HTTP_ACCEPTED => {
            HttpStatus::Accepted }
         ffi::NGX_HTTP_NO_CONTENT => {
            HttpStatus::NoContent }
         ffi::NGX_HTTP_PARTIAL_CONTENT => {
            HttpStatus::PartialContent }
         ffi::NGX_HTTP_SPECIAL_RESPONSE => {
            HttpStatus::SpecialResponse }
         ffi::NGX_HTTP_MOVED_PERMANENTLY => {
            HttpStatus::MovedPermanently }
         ffi::NGX_HTTP_MOVED_TEMPORARILY => {
            HttpStatus::MovedTemporarily }
         ffi::NGX_HTTP_SEE_OTHER => {
            HttpStatus::SeeOther }
         ffi::NGX_HTTP_NOT_MODIFIED => {
            HttpStatus::NotModified }
         ffi::NGX_HTTP_TEMPORARY_REDIRECT => {
            HttpStatus::TemporaryRedirect }
         ffi::NGX_HTTP_BAD_REQUEST => {
            HttpStatus::BadRequest }
         ffi::NGX_HTTP_UNAUTHORIZED => {
            HttpStatus::Unauthorized }
         ffi::NGX_HTTP_FORBIDDEN => {
            HttpStatus::Forbidden }
         ffi::NGX_HTTP_NOT_FOUND => {
            HttpStatus::NotFound }
         ffi::NGX_HTTP_NOT_ALLOWED => {
            HttpStatus::NotAllowed }
         ffi::NGX_HTTP_REQUEST_TIME_OUT => {
            HttpStatus::RequestTimeOut }
         ffi::NGX_HTTP_CONFLICT => {
            HttpStatus::Conflict }
         ffi::NGX_HTTP_LENGTH_REQUIRED => {
            HttpStatus::LengthRequired }
         ffi::NGX_HTTP_PRECONDITION_FAILED => {
            HttpStatus::PreconditionFailed }
         ffi::NGX_HTTP_REQUEST_URI_TOO_LARGE => {
            HttpStatus::RequestUriTooLarge }
         ffi::NGX_HTTP_REQUEST_ENTITY_TOO_LARGE => {
            HttpStatus::RequestEntityTooLarge }
         ffi::NGX_HTTP_UNSUPPORTED_MEDIA_TYPE => {
            HttpStatus::UnsupportedMediaType }
         ffi::NGX_HTTP_RANGE_NOT_SATISFIABLE => {
            HttpStatus::RangeNotSatisfiable }
         ffi::NGX_HTTP_CLOSE => {
            HttpStatus::Close }
         ffi::NGX_HTTP_REQUEST_HEADER_TOO_LARGE => {
            HttpStatus::RequestHeaderTooLarge }
         ffi::NGX_HTTPS_CERT_ERROR => {
            HttpStatus::CertError }
         ffi::NGX_HTTPS_NO_CERT => {
            HttpStatus::NoCert }
         ffi::NGX_HTTP_TO_HTTPS => {
            HttpStatus::ToHttps }
         ffi::NGX_HTTP_CLIENT_CLOSED_REQUEST => {
            HttpStatus::ClientClosedRequest }
         ffi::NGX_HTTP_INTERNAL_SERVER_ERROR => {
            HttpStatus::InternalServerError }
         ffi::NGX_HTTP_NOT_IMPLEMENTED => {
            HttpStatus::NotImplement }
         ffi::NGX_HTTP_BAD_GATEWAY => {
            HttpStatus::BadGateway }
         ffi::NGX_HTTP_SERVICE_UNAVAILABLE => {
            HttpStatus::ServiceUnavailable }
         ffi::NGX_HTTP_GATEWAY_TIME_OUT => {
            HttpStatus::GatewayTimeOut }
         ffi::NGX_HTTP_INSUFFICIENT_STORAGE => {
            HttpStatus::InsufficientStorage }
         _ => {
            HttpStatus::InternalServerError }
      }
   }

   pub fn rc(&self) -> ffi::ngx_int_t {
      match *self {
         HttpStatus::Continue => {
            ffi::NGX_HTTP_CONTINUE }
         HttpStatus::SwitchingProtocols => {
            ffi::NGX_HTTP_SWITCHING_PROTOCOLS }
         HttpStatus::Processing => {
            ffi::NGX_HTTP_PROCESSING }
         HttpStatus::Ok => {
            ffi::NGX_HTTP_OK }
         HttpStatus::Created => {
            ffi::NGX_HTTP_CREATED }
         HttpStatus::Accepted => {
            ffi::NGX_HTTP_ACCEPTED }
         HttpStatus::NoContent => {
            ffi::NGX_HTTP_NO_CONTENT }
         HttpStatus::PartialContent => {
            ffi::NGX_HTTP_PARTIAL_CONTENT }
         HttpStatus::SpecialResponse => {
            ffi::NGX_HTTP_SPECIAL_RESPONSE }
         HttpStatus::MovedPermanently => {
            ffi::NGX_HTTP_MOVED_PERMANENTLY }
         HttpStatus::MovedTemporarily => {
            ffi::NGX_HTTP_MOVED_TEMPORARILY }
         HttpStatus::SeeOther => {
            ffi::NGX_HTTP_SEE_OTHER }
         HttpStatus::NotModified => {
            ffi::NGX_HTTP_NOT_MODIFIED }
         HttpStatus::TemporaryRedirect => {
            ffi::NGX_HTTP_TEMPORARY_REDIRECT }
         HttpStatus::BadRequest => {
            ffi::NGX_HTTP_BAD_REQUEST }
         HttpStatus::Unauthorized => {
            ffi::NGX_HTTP_UNAUTHORIZED }
         HttpStatus::Forbidden => {
            ffi::NGX_HTTP_FORBIDDEN }
         HttpStatus::NotFound => {
            ffi::NGX_HTTP_NOT_FOUND }
         HttpStatus::NotAllowed => {
            ffi::NGX_HTTP_NOT_ALLOWED }
         HttpStatus::RequestTimeOut => {
            ffi::NGX_HTTP_REQUEST_TIME_OUT }
         HttpStatus::InternalServerError => {
            ffi::NGX_HTTP_INTERNAL_SERVER_ERROR }
         HttpStatus::Conflict => {
            ffi::NGX_HTTP_CONFLICT }
         HttpStatus::LengthRequired => {
            ffi::NGX_HTTP_LENGTH_REQUIRED }
         HttpStatus::PreconditionFailed => {
            ffi::NGX_HTTP_PRECONDITION_FAILED }
         HttpStatus::RequestUriTooLarge => {
            ffi::NGX_HTTP_REQUEST_URI_TOO_LARGE }
         HttpStatus::RequestEntityTooLarge => {
            ffi::NGX_HTTP_REQUEST_ENTITY_TOO_LARGE }
         HttpStatus::UnsupportedMediaType => {
            ffi::NGX_HTTP_UNSUPPORTED_MEDIA_TYPE }
         HttpStatus::RangeNotSatisfiable => {
            ffi::NGX_HTTP_RANGE_NOT_SATISFIABLE }
         HttpStatus::Close => {
            ffi::NGX_HTTP_CLOSE }
         HttpStatus::RequestHeaderTooLarge => {
            ffi::NGX_HTTP_REQUEST_HEADER_TOO_LARGE }
         HttpStatus::CertError => {
            ffi::NGX_HTTPS_CERT_ERROR }
         HttpStatus::NoCert => {
            ffi::NGX_HTTPS_NO_CERT }
         HttpStatus::ToHttps => {
            ffi::NGX_HTTP_TO_HTTPS }
         HttpStatus::ClientClosedRequest => {
            ffi::NGX_HTTP_CLIENT_CLOSED_REQUEST }
         HttpStatus::NotImplement => {
            ffi::NGX_HTTP_NOT_IMPLEMENTED }
         HttpStatus::BadGateway => {
            ffi::NGX_HTTP_BAD_GATEWAY }
         HttpStatus::ServiceUnavailable => {
            ffi::NGX_HTTP_SERVICE_UNAVAILABLE }
         HttpStatus::GatewayTimeOut => {
            ffi::NGX_HTTP_GATEWAY_TIME_OUT }
         HttpStatus::InsufficientStorage => {
            ffi::NGX_HTTP_INSUFFICIENT_STORAGE }
      }
   }
}

pub enum Status {
   Ok,
   Error,
   Again,
   Busy,
   Done,
   Declined,
   Abort,
   Http(HttpStatus),
}

impl Status {
   pub fn new(rc: ffi::ngx_int_t) -> Self {
      match rc {
         ffi::NGX_OK => {
            Status::Ok }
         ffi::NGX_ERROR => {
            Status::Error }
         ffi::NGX_AGAIN => {
            Status::Again }
         ffi::NGX_BUSY => {
            Status::Busy }
         ffi::NGX_DONE => {
            Status::Done }
         ffi::NGX_DECLINED => {
            Status::Declined }
         ffi::NGX_ABORT => {
            Status::Abort }
         http_rc if rc > 0 => {
            Status::Http(HttpStatus::new(http_rc)) }
         _ => {
            Status::Error }
      }
   }

   pub fn rc(&self) -> ffi::ngx_int_t {
      match *self {
         Status::Ok => {
            ffi::NGX_OK }
         Status::Error => {
            ffi::NGX_ERROR }
         Status::Again => {
            ffi::NGX_AGAIN }
         Status::Busy => {
            ffi::NGX_BUSY }
         Status::Done => {
            ffi::NGX_DONE }
         Status::Declined => {
            ffi::NGX_DECLINED }
         Status::Abort => {
            ffi::NGX_ABORT }
         Status::Http(ref http_status) => {
            http_status.rc() }
      }
   }
}

pub struct Connection {
   raw: *mut ffi::ngx_connection_t,
}

impl Connection {
   pub fn new(raw: *mut ffi::ngx_connection_t) -> Self {
      Connection {
         raw: raw
      }
   }

   pub fn log(&self) -> Option<Log> {
      let raw = unsafe { (*self.raw).log };

      if raw.is_null() {
         None
      } else {
         Some(
            Log::new(raw)
         )
      }
   }
}

pub struct Log {
   pub raw: *mut ffi::ngx_log_t,
}

impl Log {
   pub fn new(raw: *mut ffi::ngx_log_t) -> Self {
      Log {
         raw: raw
      }
   }
}

pub struct HttpRequest {
   raw: *mut ffi::ngx_http_request_t,
}

impl HttpRequest {
   pub fn new(raw: *mut ffi::ngx_http_request_t) -> Self {
      HttpRequest {
         raw: raw
      }
   }

   pub fn connection(&self) -> Option<Connection> {
      let raw = unsafe { (*self.raw).connection };

      if raw.is_null() {
         None
      } else {
         Some(
            Connection::new(raw)
         )
      }
   }

   pub fn headers_out(&self) -> HttpHeadersOut {
      let raw: *mut ffi::ngx_http_headers_out_t = unsafe { &mut (*self.raw).headers_out };

      HttpHeadersOut::new(raw)
   }

   pub fn http_send_header(&self) -> Status {
      let rc = unsafe { ffi::ngx_http_send_header(self.raw) };
      Status::new(rc)
   }

   pub fn pool(&self) -> Option<Pool> {
      let raw = unsafe { (*self.raw).pool };

      if raw.is_null() {
         None
      } else {
         Some(
            Pool::new(raw)
         )
      }
   }
}

pub struct HttpHeadersOut {
   raw: *mut ffi::ngx_http_headers_out_t,
}

impl HttpHeadersOut {
   pub fn new(raw: *mut ffi::ngx_http_headers_out_t) -> Self {
      HttpHeadersOut {
         raw: raw
      }
   }

   pub fn set_status(&mut self, status: ffi::ngx_uint_t) {
      unsafe {
         (*self.raw).status = status;
      };
   }

   pub fn set_content_length_n(&mut self, content_length_n: ffi::off_t) {
      unsafe {
         (*self.raw).content_length_n = content_length_n;
      };
   }
}

pub struct Pool {
   raw: *mut ffi::ngx_pool_t,
}

impl Pool {
   pub fn new(raw: *mut ffi::ngx_pool_t) -> Self {
      Pool {
         raw: raw
      }
   }

   #[inline]
   pub fn palloc<T>(&self) -> *mut T {
      unsafe {
         ffi::ngx_palloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      }
   }

   #[inline]
   pub fn pnalloc<T>(&self) -> *mut T {
      unsafe {
         ffi::ngx_pnalloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      }
   }

   #[inline]
   pub fn pcalloc<T>(&self) -> *mut T {
      unsafe {
         ffi::ngx_pcalloc(self.raw, mem::size_of::<T>() as ffi::size_t) as *mut T
      }
   }

}
<|endoftext|>


<commit_before>//! Headers container, and common header fields.
//!
//! hyper has the opinion that Headers should be strongly-typed, because that's
//! why we're using Rust in the first place. To set or get any header, an object
//! must implement the `Header` trait from this module. Several common headers
//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
use std::ascii::{AsciiExt, ASCII_LOWER_MAP};
use std::fmt::{mod, Show};
use std::hash;
use std::intrinsics::TypeId;
use std::mem::{transmute, transmute_copy};
use std::raw::TraitObject;
use std::str::{from_utf8, SendStr, Slice, Owned};
use std::string::raw;
use std::collections::hashmap::{HashMap, Entries, Occupied, Vacant};
use std::sync::RWLock;

use uany::UncheckedAnyDowncast;
use typeable::Typeable;

use http::read_header;
use {HttpResult};

/// Common Headers
pub mod common;

/// A trait for any object that will represent a header field and value.
pub trait Header: Typeable + Send + Sync {
    /// Returns the name of the header field this belongs to.
    ///
    /// The market `Option` is to hint to the type system which implementation
    /// to call. This can be done away with once UFCS arrives.
    fn header_name(marker: Option<Self>) -> &'static str;
    /// Parse a header from a raw stream of bytes.
    ///
    /// It's possible that a request can include a header field more than once,
    /// and in that case, the slice will have a length greater than 1. However,
    /// it's not necessarily the case that a Header is *allowed* to have more
    /// than one field value. If that's the case, you **should** return `None`
    /// if `raw.len() > 1`.
    fn parse_header(raw: &[Vec<u8>]) -> Option<Self>;
    /// Format a header to be output into a TcpStream.
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result;
}

#[doc(hidden)]
trait Is {
    fn is<T: 'static>(self) -> bool;
}

impl<'a> Is for &'a Header {
    fn is<T: 'static>(self) -> bool {
        self.get_type() == TypeId::of::<T>()
    }
}

impl<'a> UncheckedAnyDowncast<'a> for &'a Header {
    #[inline]
    unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
        let to: TraitObject = transmute_copy(&self);
        transmute(to.data)
    }
}

fn header_name<T: Header>() -> &'static str {
    let name = Header::header_name(None::<T>);
    name
}

/// A map of header fields on requests and responses.
pub struct Headers {
    data: HashMap<CaseInsensitive, RWLock<Item>>
}

impl Headers {

    /// Creates a new, empty headers map.
    pub fn new() -> Headers {
        Headers {
            data: HashMap::new()
        }
    }

    #[doc(hidden)]
    pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> {
        let mut headers = Headers::new();
        loop {
            match try!(read_header(rdr)) {
                Some((name, value)) => {
                    // read_header already checks that name is a token, which
                    // means its safe utf8
                    let name = unsafe {
                        raw::from_utf8(name)
                    };

                    let name = CaseInsensitive(Owned(name));
                    let item = match headers.data.entry(name) {
                        Vacant(entry) => entry.set(RWLock::new(Raw(vec![]))),
                        Occupied(entry) => entry.into_mut()
                    };

                    match &mut *item.write() {
                        &Raw(ref mut raw) => raw.push(value),
                        // Unreachable
                        _ => {}
                    };
                },
                None => break,
            }
        }
        Ok(headers)
    }

    /// Set a header field to the corresponding value.
    ///
    /// The field is determined by the type of the value being set.
    pub fn set<H: Header>(&mut self, value: H) {
        self.data.insert(CaseInsensitive(Slice(header_name::<H>())), RWLock::new(Typed(box value as Box<Header + Send + Sync>)));
    }

    /// Get a clone of the header field's value, if it exists.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let content_type = headers.get::<ContentType>();
    /// ```
    pub fn get<H: Header + Clone>(&self) -> Option<H> {
        self.get_ref().map(|v: &H| v.clone())
    }

    /// Access the raw value of a header, if it exists and has not
    /// been already parsed.
    ///
    /// If the header field has already been parsed into a typed header,
    /// then you *must* access it through that representation.
    ///
    /// This operation is unsafe because the raw representation can be
    /// invalidated by lasting too long or by the header being parsed
    /// while you still have a reference to the data.
    ///
    /// Example:
    /// ```
    /// # use hyper::header::Headers;
    /// # let mut headers = Headers::new();
    /// let raw_content_type = unsafe { headers.get_raw("content-type") };
    /// ```
    pub unsafe fn get_raw(&self, name: &'static str) -> Option<*const [Vec<u8>]> {
        self.data.find(&CaseInsensitive(Slice(name))).and_then(|item| {
            match *item.read() {
                Raw(ref raw) => Some(raw.as_slice() as *const [Vec<u8>]),
                _ => None
            }
        })
    }

    /// Get a reference to the header field's value, if it exists.
    pub fn get_ref<H: Header>(&self) -> Option<&H> {
        self.data.find(&CaseInsensitive(Slice(header_name::<H>()))).and_then(|item| {
            let header = match *item.read() {
                // Huge borrowck hack here, should be refactored to just return here.
                Typed(ref typed) if typed.is::<H>() => None,
                // Typed, wrong type
                Typed(_) => return None,
                Raw(ref raw) => match Header::parse_header(raw.as_slice()) {
                    Some::<H>(h) => {
                        Some(h)
                    },
                    None => return None
                },
            };

            match header {
                Some(header) => {
                    *item.write() = Typed(box header as Box<Header + Send + Sync>);
                    Some(item)
                },
                None => {
                    Some(item)
                }
            }
        }).and_then(|item| {
            let read = item.read();
            debug!("downcasting {}", *read);
            let ret = match *read {
                Typed(ref val) => {
                    unsafe { Some(val.downcast_ref_unchecked()) }
                },
                _ => unreachable!()
            };
            unsafe { transmute::<Option<&H>, Option<&H>>(ret) }
        })
    }

    /// Returns a boolean of whether a certain header is in the map.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let has_type = headers.has::<ContentType>();
    /// ```
    pub fn has<H: Header>(&self) -> bool {
        self.data.contains_key(&CaseInsensitive(Slice(header_name::<H>())))
    }

    /// Removes a header from the map, if one existed.
    /// Returns true if a header has been removed.
    pub fn remove<H: Header>(&mut self) -> bool {
        self.data.remove(&CaseInsensitive(Slice(Header::header_name(None::<H>))))
    }

    /// Returns an iterator over the header fields.
    pub fn iter<'a>(&'a self) -> HeadersItems<'a> {
        HeadersItems {
            inner: self.data.iter()
        }
    }
}

impl fmt::Show for Headers {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!("Headers {\n".fmt(fmt));
        for (k, v) in self.iter() {
            try!(write!(fmt, "\t{}: {}\n", k, v));
        }
        "}".fmt(fmt)
    }
}

/// An `Iterator` over the fields in a `Headers` map.
pub struct HeadersItems<'a> {
    inner: Entries<'a, CaseInsensitive, RWLock<Item>>
}

impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> {
    fn next(&mut self) -> Option<(&'a str, HeaderView<'a>)> {
        match self.inner.next() {
            Some((k, v)) => Some((k.as_slice(), HeaderView(v))),
            None => None
        }
    }
}

/// Returned with the `HeadersItems` iterator.
pub struct HeaderView<'a>(&'a RWLock<Item>);

impl<'a> fmt::Show for HeaderView<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let HeaderView(item) = *self;
        item.read().fmt(fmt)
    }
}

impl Collection for Headers {
    fn len(&self) -> uint {
        self.data.len()
    }
}

impl Mutable for Headers {
    fn clear(&mut self) {
        self.data.clear()
    }
}

enum Item {
    Raw(Vec<Vec<u8>>),
    Typed(Box<Header + Send + Sync>)
}

impl fmt::Show for Item {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Typed(ref h) => h.fmt_header(fmt),
            Raw(ref raw) => {
                for part in raw.iter() {
                    try!(fmt.write(part.as_slice()));
                }
                Ok(())
            },
        }
    }
}

struct CaseInsensitive(SendStr);

impl Str for CaseInsensitive {
    fn as_slice(&self) -> &str {
        let CaseInsensitive(ref s) = *self;
        s.as_slice()
    }

}

impl fmt::Show for CaseInsensitive {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(fmt)
    }
}

impl PartialEq for CaseInsensitive {
    fn eq(&self, other: &CaseInsensitive) -> bool {
        self.as_slice().eq_ignore_ascii_case(other.as_slice())
    }
}

impl Eq for CaseInsensitive {}

impl<H: hash::Writer> hash::Hash<H> for CaseInsensitive {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        for byte in self.as_slice().bytes() {
            hasher.write([ASCII_LOWER_MAP[byte as uint]].as_slice());
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::MemReader;
    use std::fmt;
    use std::str::Slice;
    use std::hash::sip::hash;
    use mime::{Mime, Text, Plain};
    use super::CaseInsensitive;
    use super::{Headers, Header};
    use super::common::{ContentLength, ContentType};

    fn mem(s: &str) -> MemReader {
        MemReader::new(s.as_bytes().to_vec())
    }

    #[test]
    fn test_case_insensitive() {
        let a = CaseInsensitive(Slice("foobar"));
        let b = CaseInsensitive(Slice("FOOBAR"));

        assert_eq!(a, b);
        assert_eq!(hash(&a), hash(&b));
    }

    #[test]
    fn test_from_raw() {
        let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        assert_eq!(headers.get_ref(), Some(&ContentLength(10)));
    }

    #[test]
    fn test_content_type() {
        let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice());
        assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![]))));
    }

    #[deriving(Clone)]
    struct CrazyLength(Option<bool>, uint);

    impl Header for CrazyLength {
        fn header_name(_: Option<CrazyLength>) -> &'static str {
            "content-length"
        }
        fn parse_header(raw: &[Vec<u8>]) -> Option<CrazyLength> {
            use std::str::from_utf8;
            use std::from_str::FromStr;

            if raw.len() != 1 {
                return None;
            }
            // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
            match from_utf8(unsafe { raw.as_slice().unsafe_get(0).as_slice() }) {
                Some(s) => FromStr::from_str(s),
                None => None
            }.map(|u| CrazyLength(Some(false), u))
        }
        fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use std::fmt::Show;
            let CrazyLength(_, ref value) = *self;
            value.fmt(fmt)
        }
    }

    #[test]
    fn test_different_structs_for_same_header() {
        let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        let ContentLength(_) = headers.get::<ContentLength>().unwrap();
        assert!(headers.get::<CrazyLength>().is_none());
    }
}

<commit_msg>Add tests for double-reads for Header to ensure safety.<commit_after>//! Headers container, and common header fields.
//!
//! hyper has the opinion that Headers should be strongly-typed, because that's
//! why we're using Rust in the first place. To set or get any header, an object
//! must implement the `Header` trait from this module. Several common headers
//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
use std::ascii::{AsciiExt, ASCII_LOWER_MAP};
use std::fmt::{mod, Show};
use std::hash;
use std::intrinsics::TypeId;
use std::mem::{transmute, transmute_copy};
use std::raw::TraitObject;
use std::str::{from_utf8, SendStr, Slice, Owned};
use std::string::raw;
use std::collections::hashmap::{HashMap, Entries, Occupied, Vacant};
use std::sync::RWLock;

use uany::UncheckedAnyDowncast;
use typeable::Typeable;

use http::read_header;
use {HttpResult};

/// Common Headers
pub mod common;

/// A trait for any object that will represent a header field and value.
pub trait Header: Typeable + Send + Sync {
    /// Returns the name of the header field this belongs to.
    ///
    /// The market `Option` is to hint to the type system which implementation
    /// to call. This can be done away with once UFCS arrives.
    fn header_name(marker: Option<Self>) -> &'static str;
    /// Parse a header from a raw stream of bytes.
    ///
    /// It's possible that a request can include a header field more than once,
    /// and in that case, the slice will have a length greater than 1. However,
    /// it's not necessarily the case that a Header is *allowed* to have more
    /// than one field value. If that's the case, you **should** return `None`
    /// if `raw.len() > 1`.
    fn parse_header(raw: &[Vec<u8>]) -> Option<Self>;
    /// Format a header to be output into a TcpStream.
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result;
}

#[doc(hidden)]
trait Is {
    fn is<T: 'static>(self) -> bool;
}

impl<'a> Is for &'a Header {
    fn is<T: 'static>(self) -> bool {
        self.get_type() == TypeId::of::<T>()
    }
}

impl<'a> UncheckedAnyDowncast<'a> for &'a Header {
    #[inline]
    unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T {
        let to: TraitObject = transmute_copy(&self);
        transmute(to.data)
    }
}

fn header_name<T: Header>() -> &'static str {
    let name = Header::header_name(None::<T>);
    name
}

/// A map of header fields on requests and responses.
pub struct Headers {
    data: HashMap<CaseInsensitive, RWLock<Item>>
}

impl Headers {

    /// Creates a new, empty headers map.
    pub fn new() -> Headers {
        Headers {
            data: HashMap::new()
        }
    }

    #[doc(hidden)]
    pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> {
        let mut headers = Headers::new();
        loop {
            match try!(read_header(rdr)) {
                Some((name, value)) => {
                    // read_header already checks that name is a token, which
                    // means its safe utf8
                    let name = unsafe {
                        raw::from_utf8(name)
                    };

                    let name = CaseInsensitive(Owned(name));
                    let item = match headers.data.entry(name) {
                        Vacant(entry) => entry.set(RWLock::new(Raw(vec![]))),
                        Occupied(entry) => entry.into_mut()
                    };

                    match &mut *item.write() {
                        &Raw(ref mut raw) => raw.push(value),
                        // Unreachable
                        _ => {}
                    };
                },
                None => break,
            }
        }
        Ok(headers)
    }

    /// Set a header field to the corresponding value.
    ///
    /// The field is determined by the type of the value being set.
    pub fn set<H: Header>(&mut self, value: H) {
        self.data.insert(CaseInsensitive(Slice(header_name::<H>())), RWLock::new(Typed(box value as Box<Header + Send + Sync>)));
    }

    /// Get a clone of the header field's value, if it exists.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let content_type = headers.get::<ContentType>();
    /// ```
    pub fn get<H: Header + Clone>(&self) -> Option<H> {
        self.get_ref().map(|v: &H| v.clone())
    }

    /// Access the raw value of a header, if it exists and has not
    /// been already parsed.
    ///
    /// If the header field has already been parsed into a typed header,
    /// then you *must* access it through that representation.
    ///
    /// This operation is unsafe because the raw representation can be
    /// invalidated by lasting too long or by the header being parsed
    /// while you still have a reference to the data.
    ///
    /// Example:
    /// ```
    /// # use hyper::header::Headers;
    /// # let mut headers = Headers::new();
    /// let raw_content_type = unsafe { headers.get_raw("content-type") };
    /// ```
    pub unsafe fn get_raw(&self, name: &'static str) -> Option<*const [Vec<u8>]> {
        self.data.find(&CaseInsensitive(Slice(name))).and_then(|item| {
            match *item.read() {
                Raw(ref raw) => Some(raw.as_slice() as *const [Vec<u8>]),
                _ => None
            }
        })
    }

    /// Get a reference to the header field's value, if it exists.
    pub fn get_ref<H: Header>(&self) -> Option<&H> {
        self.data.find(&CaseInsensitive(Slice(header_name::<H>()))).and_then(|item| {
            let header = match *item.read() {
                // Huge borrowck hack here, should be refactored to just return here.
                Typed(ref typed) if typed.is::<H>() => None,
                // Typed, wrong type
                Typed(_) => return None,
                Raw(ref raw) => match Header::parse_header(raw.as_slice()) {
                    Some::<H>(h) => {
                        Some(h)
                    },
                    None => return None
                },
            };

            match header {
                Some(header) => {
                    *item.write() = Typed(box header as Box<Header + Send + Sync>);
                    Some(item)
                },
                None => {
                    Some(item)
                }
            }
        }).and_then(|item| {
            let read = item.read();
            debug!("downcasting {}", *read);
            let ret = match *read {
                Typed(ref val) => {
                    unsafe { Some(val.downcast_ref_unchecked()) }
                },
                _ => unreachable!()
            };
            unsafe { transmute::<Option<&H>, Option<&H>>(ret) }
        })
    }

    /// Returns a boolean of whether a certain header is in the map.
    ///
    /// Example:
    ///
    /// ```
    /// # use hyper::header::Headers;
    /// # use hyper::header::common::ContentType;
    /// # let mut headers = Headers::new();
    /// let has_type = headers.has::<ContentType>();
    /// ```
    pub fn has<H: Header>(&self) -> bool {
        self.data.contains_key(&CaseInsensitive(Slice(header_name::<H>())))
    }

    /// Removes a header from the map, if one existed.
    /// Returns true if a header has been removed.
    pub fn remove<H: Header>(&mut self) -> bool {
        self.data.remove(&CaseInsensitive(Slice(Header::header_name(None::<H>))))
    }

    /// Returns an iterator over the header fields.
    pub fn iter<'a>(&'a self) -> HeadersItems<'a> {
        HeadersItems {
            inner: self.data.iter()
        }
    }
}

impl fmt::Show for Headers {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!("Headers {\n".fmt(fmt));
        for (k, v) in self.iter() {
            try!(write!(fmt, "\t{}: {}\n", k, v));
        }
        "}".fmt(fmt)
    }
}

/// An `Iterator` over the fields in a `Headers` map.
pub struct HeadersItems<'a> {
    inner: Entries<'a, CaseInsensitive, RWLock<Item>>
}

impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> {
    fn next(&mut self) -> Option<(&'a str, HeaderView<'a>)> {
        match self.inner.next() {
            Some((k, v)) => Some((k.as_slice(), HeaderView(v))),
            None => None
        }
    }
}

/// Returned with the `HeadersItems` iterator.
pub struct HeaderView<'a>(&'a RWLock<Item>);

impl<'a> fmt::Show for HeaderView<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let HeaderView(item) = *self;
        item.read().fmt(fmt)
    }
}

impl Collection for Headers {
    fn len(&self) -> uint {
        self.data.len()
    }
}

impl Mutable for Headers {
    fn clear(&mut self) {
        self.data.clear()
    }
}

enum Item {
    Raw(Vec<Vec<u8>>),
    Typed(Box<Header + Send + Sync>)
}

impl fmt::Show for Item {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Typed(ref h) => h.fmt_header(fmt),
            Raw(ref raw) => {
                for part in raw.iter() {
                    try!(fmt.write(part.as_slice()));
                }
                Ok(())
            },
        }
    }
}

struct CaseInsensitive(SendStr);

impl Str for CaseInsensitive {
    fn as_slice(&self) -> &str {
        let CaseInsensitive(ref s) = *self;
        s.as_slice()
    }

}

impl fmt::Show for CaseInsensitive {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(fmt)
    }
}

impl PartialEq for CaseInsensitive {
    fn eq(&self, other: &CaseInsensitive) -> bool {
        self.as_slice().eq_ignore_ascii_case(other.as_slice())
    }
}

impl Eq for CaseInsensitive {}

impl<H: hash::Writer> hash::Hash<H> for CaseInsensitive {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        for byte in self.as_slice().bytes() {
            hasher.write([ASCII_LOWER_MAP[byte as uint]].as_slice());
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::MemReader;
    use std::fmt;
    use std::str::Slice;
    use std::hash::sip::hash;
    use mime::{Mime, Text, Plain};
    use super::CaseInsensitive;
    use super::{Headers, Header};
    use super::common::{ContentLength, ContentType};

    fn mem(s: &str) -> MemReader {
        MemReader::new(s.as_bytes().to_vec())
    }

    #[test]
    fn test_case_insensitive() {
        let a = CaseInsensitive(Slice("foobar"));
        let b = CaseInsensitive(Slice("FOOBAR"));

        assert_eq!(a, b);
        assert_eq!(hash(&a), hash(&b));
    }

    #[test]
    fn test_from_raw() {
        let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        assert_eq!(headers.get_ref(), Some(&ContentLength(10)));
    }

    #[test]
    fn test_content_type() {
        let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice());
        assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![]))));
    }

    #[deriving(Clone)]
    struct CrazyLength(Option<bool>, uint);

    impl Header for CrazyLength {
        fn header_name(_: Option<CrazyLength>) -> &'static str {
            "content-length"
        }
        fn parse_header(raw: &[Vec<u8>]) -> Option<CrazyLength> {
            use std::str::from_utf8;
            use std::from_str::FromStr;

            if raw.len() != 1 {
                return None;
            }
            // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
            match from_utf8(unsafe { raw.as_slice().unsafe_get(0).as_slice() }) {
                Some(s) => FromStr::from_str(s),
                None => None
            }.map(|u| CrazyLength(Some(false), u))
        }
        fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use std::fmt::Show;
            let CrazyLength(_, ref value) = *self;
            value.fmt(fmt)
        }
    }

    #[test]
    fn test_different_structs_for_same_header() {
        let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        let ContentLength(_) = headers.get::<ContentLength>().unwrap();
        assert!(headers.get::<CrazyLength>().is_none());
    }

    #[test]
    fn test_multiple_reads() {
        let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
        let ContentLength(one) = headers.get::<ContentLength>().unwrap();
        let ContentLength(two) = headers.get::<ContentLength>().unwrap();
        assert_eq!(one, two);
    }

    #[test]
    fn test_different_reads() {
        let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\nContent-Type: text/plain\r\n\r\n")).unwrap();
        let ContentLength(_) = headers.get::<ContentLength>().unwrap();
        let ContentType(_) = headers.get::<ContentType>().unwrap();
    }
}

<|endoftext|>


<commit_before>use std::{
    error::Error as StdError,
    fmt::{Display, Formatter, Result as FmtResult},
};

use reqwest::{header::InvalidHeaderValue, Error as ReqwestError, Response, StatusCode, Url};
use serde::de::{Deserialize, Deserializer, Error as DeError};
use url::ParseError as UrlError;

use crate::http::utils::deserialize_errors;
use crate::internal::prelude::{JsonMap, StdResult};

#[derive(Clone, Serialize, PartialEq, Debug)]
#[non_exhaustive]
pub struct DiscordJsonError {
    /// The error code.
    pub code: isize,
    /// The error message.
    pub message: String,
    /// The full explained errors with their path in the request
    /// body.
    pub errors: Vec<DiscordJsonSingleError>,
}

impl<'de> Deserialize<'de> for DiscordJsonError {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        let mut map = JsonMap::deserialize(deserializer)?;

        let code = map
            .remove("code")
            .ok_or_else(|| DeError::custom("expected code"))
            .and_then(isize::deserialize)
            .map_err(DeError::custom)?;

        let message = map
            .remove("message")
            .ok_or_else(|| DeError::custom("expected message"))
            .and_then(String::deserialize)
            .map_err(DeError::custom)?;

        let errors = match map.contains_key("errors") {
            true => map
                .remove("errors")
                .ok_or_else(|| DeError::custom("expected errors"))
                .and_then(deserialize_errors)
                .map_err(DeError::custom)?,
            false => vec![],
        };

        Ok(Self {
            code,
            message,
            errors,
        })
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct DiscordJsonSingleError {
    /// The error code.
    pub code: String,
    /// The error message.
    pub message: String,
    /// The path to the error in the request body itself, dot separated.
    pub path: String,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ErrorResponse {
    pub status_code: StatusCode,
    pub url: Url,
    pub error: DiscordJsonError,
}

impl ErrorResponse {
    // We need a freestanding from-function since we cannot implement an async
    // From-trait.
    pub async fn from_response(r: Response) -> Self {
        ErrorResponse {
            status_code: r.status(),
            url: r.url().clone(),
            error: r.json().await.unwrap_or_else(|_| DiscordJsonError {
                code: -1,
                message:
                    "[Serenity] Could not decode json when receiving error response from discord!"
                        .to_string(),
                errors: vec![],
            }),
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
    /// When a non-successful status code was received for a request.
    UnsuccessfulRequest(ErrorResponse),
    /// When the decoding of a ratelimit header could not be properly decoded
    /// into an `i64` or `f64`.
    RateLimitI64F64,
    /// When the decoding of a ratelimit header could not be properly decoded
    /// from UTF-8.
    RateLimitUtf8,
    /// When parsing an URL failed due to invalid input.
    Url(UrlError),
    /// Header value contains invalid input.
    InvalidHeader(InvalidHeaderValue),
    /// Reqwest's Error contain information on why sending a request failed.
    Request(ReqwestError),
    /// When using a proxy with an invalid scheme.
    InvalidScheme,
    /// When using a proxy with an invalid port.
    InvalidPort,
}

impl Error {
    // We need a freestanding from-function since we cannot implement an async
    // From-trait.
    pub async fn from_response(r: Response) -> Self {
        ErrorResponse::from_response(r).await.into()
    }

    /// Returns true when the error is caused by an unsuccessful request
    pub fn is_unsuccessful_request(&self) -> bool {
        matches!(self, Self::UnsuccessfulRequest(_))
    }

    /// Returns true when the error is caused by the url containing invalid input
    pub fn is_url_error(&self) -> bool {
        matches!(self, Self::Url(_))
    }

    /// Returns true when the error is caused by an invalid header
    pub fn is_invalid_header(&self) -> bool {
        matches!(self, Self::InvalidHeader(_))
    }

    /// Returns the status code if the error is an unsuccessful request
    pub fn status_code(&self) -> Option<StatusCode> {
        match self {
            Self::UnsuccessfulRequest(res) => Some(res.status_code),
            _ => None,
        }
    }
}

impl From<ErrorResponse> for Error {
    fn from(error: ErrorResponse) -> Error {
        Error::UnsuccessfulRequest(error)
    }
}

impl From<ReqwestError> for Error {
    fn from(error: ReqwestError) -> Error {
        Error::Request(error)
    }
}

impl From<UrlError> for Error {
    fn from(error: UrlError) -> Error {
        Error::Url(error)
    }
}

impl From<InvalidHeaderValue> for Error {
    fn from(error: InvalidHeaderValue) -> Error {
        Error::InvalidHeader(error)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        match self {
            Error::UnsuccessfulRequest(e) => {
                f.write_str(&e.error.message)?;

                // Put Discord's human readable error explanations in parantheses
                let mut errors_iter = e.error.errors.iter();
                if let Some(error) = errors_iter.next() {
                    f.write_str(" (")?;
                    f.write_str(&error.message)?;
                    for error in errors_iter {
                        f.write_str(", ")?;
                        f.write_str(&error.message)?;
                    }
                    f.write_str(")")?;
                }

                Ok(())
            },
            Error::RateLimitI64F64 => f.write_str("Error decoding a header into an i64 or f64"),
            Error::RateLimitUtf8 => f.write_str("Error decoding a header from UTF-8"),
            Error::Url(_) => f.write_str("Provided URL is incorrect."),
            Error::InvalidHeader(_) => f.write_str("Provided value is an invalid header value."),
            Error::Request(_) => f.write_str("Error while sending HTTP request."),
            Error::InvalidScheme => f.write_str("Invalid Url scheme."),
            Error::InvalidPort => f.write_str("Invalid port."),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::Url(inner) => Some(inner),
            Error::Request(inner) => Some(inner),
            _ => None,
        }
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
    use http_crate::response::Builder;
    use reqwest::ResponseBuilderExt;

    use super::*;

    #[tokio::test]
    async fn test_error_response_into() {
        let error = DiscordJsonError {
            code: 43121215,
            message: String::from("This is a Ferris error"),
            errors: vec![],
        };

        let mut builder = Builder::new();
        builder = builder.status(403);
        builder = builder.url(String::from("https://ferris.crab").parse().unwrap());
        let body_string = serde_json::to_string(&error).unwrap();
        let response = builder.body(body_string.into_bytes()).unwrap();

        let reqwest_response: reqwest::Response = response.into();
        let error_response = ErrorResponse::from_response(reqwest_response).await;

        let known = ErrorResponse {
            status_code: reqwest::StatusCode::from_u16(403).unwrap(),
            url: String::from("https://ferris.crab").parse().unwrap(),
            error,
        };

        assert_eq!(error_response, known);
    }
}
<commit_msg>Add paths to HTTP errors (#1481)<commit_after>use std::{
    error::Error as StdError,
    fmt::{Display, Formatter, Result as FmtResult},
};

use reqwest::{header::InvalidHeaderValue, Error as ReqwestError, Response, StatusCode, Url};
use serde::de::{Deserialize, Deserializer, Error as DeError};
use url::ParseError as UrlError;

use crate::http::utils::deserialize_errors;
use crate::internal::prelude::{JsonMap, StdResult};

#[derive(Clone, Serialize, PartialEq, Debug)]
#[non_exhaustive]
pub struct DiscordJsonError {
    /// The error code.
    pub code: isize,
    /// The error message.
    pub message: String,
    /// The full explained errors with their path in the request
    /// body.
    pub errors: Vec<DiscordJsonSingleError>,
}

impl<'de> Deserialize<'de> for DiscordJsonError {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        let mut map = JsonMap::deserialize(deserializer)?;

        let code = map
            .remove("code")
            .ok_or_else(|| DeError::custom("expected code"))
            .and_then(isize::deserialize)
            .map_err(DeError::custom)?;

        let message = map
            .remove("message")
            .ok_or_else(|| DeError::custom("expected message"))
            .and_then(String::deserialize)
            .map_err(DeError::custom)?;

        let errors = match map.contains_key("errors") {
            true => map
                .remove("errors")
                .ok_or_else(|| DeError::custom("expected errors"))
                .and_then(deserialize_errors)
                .map_err(DeError::custom)?,
            false => vec![],
        };

        Ok(Self {
            code,
            message,
            errors,
        })
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct DiscordJsonSingleError {
    /// The error code.
    pub code: String,
    /// The error message.
    pub message: String,
    /// The path to the error in the request body itself, dot separated.
    pub path: String,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ErrorResponse {
    pub status_code: StatusCode,
    pub url: Url,
    pub error: DiscordJsonError,
}

impl ErrorResponse {
    // We need a freestanding from-function since we cannot implement an async
    // From-trait.
    pub async fn from_response(r: Response) -> Self {
        ErrorResponse {
            status_code: r.status(),
            url: r.url().clone(),
            error: r.json().await.unwrap_or_else(|_| DiscordJsonError {
                code: -1,
                message:
                    "[Serenity] Could not decode json when receiving error response from discord!"
                        .to_string(),
                errors: vec![],
            }),
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
    /// When a non-successful status code was received for a request.
    UnsuccessfulRequest(ErrorResponse),
    /// When the decoding of a ratelimit header could not be properly decoded
    /// into an `i64` or `f64`.
    RateLimitI64F64,
    /// When the decoding of a ratelimit header could not be properly decoded
    /// from UTF-8.
    RateLimitUtf8,
    /// When parsing an URL failed due to invalid input.
    Url(UrlError),
    /// Header value contains invalid input.
    InvalidHeader(InvalidHeaderValue),
    /// Reqwest's Error contain information on why sending a request failed.
    Request(ReqwestError),
    /// When using a proxy with an invalid scheme.
    InvalidScheme,
    /// When using a proxy with an invalid port.
    InvalidPort,
}

impl Error {
    // We need a freestanding from-function since we cannot implement an async
    // From-trait.
    pub async fn from_response(r: Response) -> Self {
        ErrorResponse::from_response(r).await.into()
    }

    /// Returns true when the error is caused by an unsuccessful request
    pub fn is_unsuccessful_request(&self) -> bool {
        matches!(self, Self::UnsuccessfulRequest(_))
    }

    /// Returns true when the error is caused by the url containing invalid input
    pub fn is_url_error(&self) -> bool {
        matches!(self, Self::Url(_))
    }

    /// Returns true when the error is caused by an invalid header
    pub fn is_invalid_header(&self) -> bool {
        matches!(self, Self::InvalidHeader(_))
    }

    /// Returns the status code if the error is an unsuccessful request
    pub fn status_code(&self) -> Option<StatusCode> {
        match self {
            Self::UnsuccessfulRequest(res) => Some(res.status_code),
            _ => None,
        }
    }
}

impl From<ErrorResponse> for Error {
    fn from(error: ErrorResponse) -> Error {
        Error::UnsuccessfulRequest(error)
    }
}

impl From<ReqwestError> for Error {
    fn from(error: ReqwestError) -> Error {
        Error::Request(error)
    }
}

impl From<UrlError> for Error {
    fn from(error: UrlError) -> Error {
        Error::Url(error)
    }
}

impl From<InvalidHeaderValue> for Error {
    fn from(error: InvalidHeaderValue) -> Error {
        Error::InvalidHeader(error)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        match self {
            Error::UnsuccessfulRequest(e) => {
                f.write_str(&e.error.message)?;

                // Put Discord's human readable error explanations in parentheses
                let mut errors_iter = e.error.errors.iter();
                if let Some(error) = errors_iter.next() {
                    f.write_str(" (")?;
                    f.write_str(&error.path)?;
                    f.write_str(": ")?;
                    f.write_str(&error.message)?;
                    for error in errors_iter {
                        f.write_str(", ")?;
                        f.write_str(&error.path)?;
                        f.write_str(": ")?;
                        f.write_str(&error.message)?;
                    }
                    f.write_str(")")?;
                }

                Ok(())
            },
            Error::RateLimitI64F64 => f.write_str("Error decoding a header into an i64 or f64"),
            Error::RateLimitUtf8 => f.write_str("Error decoding a header from UTF-8"),
            Error::Url(_) => f.write_str("Provided URL is incorrect."),
            Error::InvalidHeader(_) => f.write_str("Provided value is an invalid header value."),
            Error::Request(_) => f.write_str("Error while sending HTTP request."),
            Error::InvalidScheme => f.write_str("Invalid Url scheme."),
            Error::InvalidPort => f.write_str("Invalid port."),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::Url(inner) => Some(inner),
            Error::Request(inner) => Some(inner),
            _ => None,
        }
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
    use http_crate::response::Builder;
    use reqwest::ResponseBuilderExt;

    use super::*;

    #[tokio::test]
    async fn test_error_response_into() {
        let error = DiscordJsonError {
            code: 43121215,
            message: String::from("This is a Ferris error"),
            errors: vec![],
        };

        let mut builder = Builder::new();
        builder = builder.status(403);
        builder = builder.url(String::from("https://ferris.crab").parse().unwrap());
        let body_string = serde_json::to_string(&error).unwrap();
        let response = builder.body(body_string.into_bytes()).unwrap();

        let reqwest_response: reqwest::Response = response.into();
        let error_response = ErrorResponse::from_response(reqwest_response).await;

        let known = ErrorResponse {
            status_code: reqwest::StatusCode::from_u16(403).unwrap(),
            url: String::from("https://ferris.crab").parse().unwrap(),
            error,
        };

        assert_eq!(error_response, known);
    }
}
<|endoftext|>


<commit_before>use parser::Identifier;
use memory::{MemoryBlock};

use operations::{Operation, expression, Target};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, TypeId};

pub fn define_stdin(scope: &mut ScopeStack, u8_type: TypeId) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdin");
    let stdin_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdin"), stdin_type);

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("read_exact")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdin_type),
                // Need an arg here for the thing being read into
                FuncArgType::Array {item: u8_type, size: None},
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            unimplemented!();
        }
    );

    stdin_type
}

pub fn define_stdout(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdout");
    let stdout_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdout"), stdout_type);

    let unit_type = scope.primitives().unit();

    let print_method_name = type_name.clone().concat(Identifier::from("print"));
    scope.declare_builtin_function(
        print_method_name.clone(),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            let unit_type = scope.primitives().unit();
            args.into_iter().skip(1).map(|arg| expression::call(
                scope,
                Identifier::from("std::fmt::Display::print"),
                vec![arg],
                Target::TypedBlock {
                    type_id: unit_type,
                    memory: MemoryBlock::default(),
                }
            )).collect::<Result<Vec<_>, _>>().map(|op_vecs| {
                op_vecs.into_iter().flat_map(|ops| ops).collect()
            })
        }
    );

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("println")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        move |scope, args, result| {
            let mut ops = expression::call(
                scope,
                print_method_name.clone(),
                args,
                Target::TypedBlock {
                    type_id: unit_type,
                    memory: result,
                }
            )?;

            // Write a newline using a temporary cell
            let u8_type = scope.primitives().u8();
            let mem = scope.allocate(u8_type);
            ops.push(Operation::TempAllocate {
                temp: mem,
                body: vec![
                    Operation::Increment {
                        target: mem.position(),
                        amount: b'\n',
                    },
                    Operation::Write {
                        target: mem,
                    },
                ],
                should_zero: true,
            });

            Ok(ops)
        }
    );

    stdout_type
}
<commit_msg>Renamed result -> target to follow the convention used elsewhere in the code<commit_after>use parser::Identifier;
use memory::{MemoryBlock};

use operations::{Operation, expression, Target};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, TypeId};

pub fn define_stdin(scope: &mut ScopeStack, u8_type: TypeId) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdin");
    let stdin_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdin"), stdin_type);

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("read_exact")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdin_type),
                // Need an arg here for the thing being read into
                FuncArgType::Array {item: u8_type, size: None},
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            unimplemented!();
        }
    );

    stdin_type
}

pub fn define_stdout(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdout");
    let stdout_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdout"), stdout_type);

    let unit_type = scope.primitives().unit();

    let print_method_name = type_name.clone().concat(Identifier::from("print"));
    scope.declare_builtin_function(
        print_method_name.clone(),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            let unit_type = scope.primitives().unit();
            args.into_iter().skip(1).map(|arg| expression::call(
                scope,
                Identifier::from("std::fmt::Display::print"),
                vec![arg],
                Target::TypedBlock {
                    type_id: unit_type,
                    memory: MemoryBlock::default(),
                }
            )).collect::<Result<Vec<_>, _>>().map(|op_vecs| {
                op_vecs.into_iter().flat_map(|ops| ops).collect()
            })
        }
    );

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("println")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        move |scope, args, target| {
            let mut ops = expression::call(
                scope,
                print_method_name.clone(),
                args,
                Target::TypedBlock {
                    type_id: unit_type,
                    memory: target,
                }
            )?;

            // Write a newline using a temporary cell
            let u8_type = scope.primitives().u8();
            let mem = scope.allocate(u8_type);
            ops.push(Operation::TempAllocate {
                temp: mem,
                body: vec![
                    Operation::Increment {
                        target: mem.position(),
                        amount: b'\n',
                    },
                    Operation::Write {
                        target: mem,
                    },
                ],
                should_zero: true,
            });

            Ok(ops)
        }
    );

    stdout_type
}
<|endoftext|>


<commit_before>// Single-character XOR cipher guesser library
//
// Dmitry Vasiliev <dima@hlabs.org>
//

// TODO:
//  - Tests
//  - Can we use letters frequency in is_english() function? Or just
//    implement trigram algorithm?

#[crate_id="single_xor_lib#0.1"];
#[crate_type="lib"];

use std::vec;

static ENGLISH_CHARS_BY_FREQ: &'static[u8] = bytes!(
    " eEtTaAiInNoOsSrRlLdDhHcCuUmMfFpPyYgGwWvVbBkKxXjJqQzZ");

pub enum DecryptionResult {
    Found(u8, ~[u8]),
    NotFound
}

struct ByteStat {
    byte: u8,
    num: uint
}

// XOR buffer with the key and return the result
fn xor_by_key(buffer: &[u8], key: u8) -> ~[u8] {
    buffer.iter().map(|c| c ^ key).collect()
}

// Return most frequent character from the buffer
fn get_most_freq_char(buffer: &[u8]) -> u8 {
    if buffer.is_empty() {
        fail!("Buffer is empty");
    }
    let mut chars = vec::from_fn(256, |i| ByteStat{byte: i as u8, num: 0});
    for &c in buffer.iter() {
        chars[c].num += 1;
    }
    // Reverse sorting
    chars.sort_by(|first, second| second.num.cmp(&first.num));
    // Most frequent character is the first one now
    chars[0].byte
}

// Is text in the buffer looks like an English text?
fn is_english(buffer: &[u8]) -> bool {
    // Here we just check that number of non letters in the text is lower than
    // 30%. More robust implementation can use most common English language
    // trigrams.
    let mut allowed = (buffer.len() * 30u) / 100u;
    for &c in buffer.iter() {
        match c as char {
            'a'..'z' | 'A'..'Z' => (),
            _ => {
                allowed -= 1u;
                if allowed <= 0 {
                    return false;
                }
            }
        }
    }
    true
}

// Try to decrypt encrypted text in the buffer
pub fn decrypt(buffer: &[u8]) -> DecryptionResult {
    if buffer.is_empty() {
        fail!("Buffer is empty");
    }
    let first = get_most_freq_char(buffer);
    for &c in ENGLISH_CHARS_BY_FREQ.iter() {
        // Most frequent letter in the encrypted text probably should
        // correspond to the most frequent letter in English
        let key = first ^ c;
        let decrypted = xor_by_key(buffer, key);
        if is_english(decrypted) {
            return Found(key, decrypted);
        }
    }
    NotFound
}
<commit_msg>Example implementation of trigrams matcher<commit_after>// Single-character XOR cipher guesser library
//
// Dmitry Vasiliev <dima@hlabs.org>
//

// TODO:
//  - Tests

#[crate_id="single_xor_lib#0.1"];
#[crate_type="lib"];

use std::vec;
use std::str;

static ENGLISH_CHARS_BY_FREQ: &'static[u8] = bytes!(
    " eEtTaAiInNoOsSrRlLdDhHcCuUmMfFpPyYgGwWvVbBkKxXjJqQzZ");

pub enum DecryptionResult {
    Found(u8, ~[u8]),
    NotFound
}

struct ByteStat {
    byte: u8,
    num: uint
}

// XOR buffer with the key and return the result
fn xor_by_key(buffer: &[u8], key: u8) -> ~[u8] {
    buffer.iter().map(|c| c ^ key).collect()
}

// Return most frequent character from the buffer
fn get_most_freq_char(buffer: &[u8]) -> u8 {
    if buffer.is_empty() {
        fail!("Buffer is empty");
    }
    let mut chars = vec::from_fn(256, |i| ByteStat{byte: i as u8, num: 0});
    for &c in buffer.iter() {
        chars[c].num += 1;
    }
    // Reverse sorting
    chars.sort_by(|first, second| second.num.cmp(&first.num));
    // Most frequent character is the first one now
    chars[0].byte
}

// Is text in the buffer looks like an English text?
fn is_english(buffer: &[u8]) -> bool {
    // FIXME: Example implementation with trigrams. Should be tuned because it
    // can also catch a gibberish with a correct trigram inside.
    // Also strings with mixed case should be considered.
    // Can we also use letters frequency?
    let string = match str::from_utf8_opt(buffer) {
        Some(string) => string,
        None => return false
    };
    let len = string.char_len() - 3;
    if len >= 0 {
        for i in range(0, len) {
            match string.slice(i, i + 3) {
                &"the" | &"and" | &"tha" | &"ent" | &"ing" | &"ion"
                | &"tio" | &"for" | &"nde" | &"has" | &"nce" | &"edt"
                | &"tis" | &"oft" | &"sth" | &"men" => return true,
                _ => ()
            }
        }
    }
    false
}

// Try to decrypt encrypted text in the buffer
pub fn decrypt(buffer: &[u8]) -> DecryptionResult {
    if buffer.is_empty() {
        fail!("Buffer is empty");
    }
    let first = get_most_freq_char(buffer);
    for &c in ENGLISH_CHARS_BY_FREQ.iter() {
        // Most frequent letter in the encrypted text probably should
        // correspond to the most frequent letter in English
        let key = first ^ c;
        let decrypted = xor_by_key(buffer, key);
        if is_english(decrypted) {
            return Found(key, decrypted);
        }
    }
    NotFound
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::io::stdin;
use std::fs::OpenOptions;
use std::result::Result as RResult;
use std::io::Read;
use std::ops::DerefMut;
use std::io::Write;
use std::io::stderr;
use std::process::exit;

use clap::ArgMatches;

use libimagrt::runtime::Runtime;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::storeid::build_entry_path;
use libimagutil::trace::trace_error;

use error::StoreError;
use error::StoreErrorKind;
use util::build_toml_header;

type Result<T> = RResult<T, StoreError>;

pub fn create(rt: &Runtime) {
    rt.cli()
        .subcommand_matches("create")
        .map(|scmd| {
            debug!("Found 'create' subcommand...");

            // unwrap is safe as value is required
            let path = scmd.value_of("path").or_else(|| scmd.value_of("id"));
            if path.is_none() {
                warn!("No ID / Path provided. Exiting now");
                write!(stderr(), "No ID / Path provided. Exiting now");
                exit(1);
            }

            let path = build_entry_path(rt.store(), path.unwrap());
            if path.is_err() {
                trace_error(&path.err().unwrap());
                exit(1);
            }
            let path = path.unwrap();
            debug!("path = {:?}", path);

            if scmd.subcommand_matches("entry").is_some() {
                create_from_cli_spec(rt, scmd, &path)
                    .or_else(|_| create_from_source(rt, scmd, &path))
                    .or_else(|_| create_with_content_and_header(rt,
                                                                &path,
                                                                String::new(),
                                                                EntryHeader::new()))
            } else {
                create_with_content_and_header(rt, &path, String::new(), EntryHeader::new())
            }
            .unwrap_or_else(|e| debug!("Error building Entry: {:?}", e))
        });
}

fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Result<()> {
    let content = matches.subcommand_matches("entry")
        .map(|entry_subcommand| {
            debug!("Found entry subcommand, parsing content");
            entry_subcommand
                .value_of("content")
                .map(String::from)
                .unwrap_or_else(|| {
                    entry_subcommand
                        .value_of("content-from")
                        .map(|src| string_from_raw_src(src))
                        .unwrap_or(String::new())
                })
        })
        .unwrap_or_else(|| {
            debug!("Didn't find entry subcommand, getting raw content");
            matches.value_of("from-raw")
                .map(|raw_src| string_from_raw_src(raw_src))
                .unwrap_or(String::new())
        });

    debug!("Got content with len = {}", content.len());

    let header = matches.subcommand_matches("entry")
        .map(|entry_matches| build_toml_header(entry_matches, EntryHeader::new()))
        .unwrap_or(EntryHeader::new());

    create_with_content_and_header(rt, path, content, header)
}

fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Result<()> {
    let content = matches
        .value_of("from-raw")
        .ok_or(StoreError::new(StoreErrorKind::NoCommandlineCall, None))
        .map(|raw_src| string_from_raw_src(raw_src));

    if content.is_err() {
        return content.map(|_| ());
    }
    let content = content.unwrap();
    debug!("Content with len = {}", content.len());

    Entry::from_str(path.clone(), &content[..])
        .map(|mut new_e| {
            rt.store()
                .create(path.clone())
                .map(|mut old_e| {
                    *old_e.deref_mut() = new_e;
                });

            debug!("Entry build");
        })
        .map_err(|serr| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(serr))))
}

fn create_with_content_and_header(rt: &Runtime,
                                  path: &PathBuf,
                                  content: String,
                                  header: EntryHeader) -> Result<()>
{
    debug!("Creating entry with content");
    rt.store()
        .create(PathBuf::from(path))
        .map(|mut element| {
            {
                let mut e_content = element.get_content_mut();
                *e_content = content;
                debug!("New content set");
            }
            {
                let mut e_header  = element.get_header_mut();
                *e_header = header;
                debug!("New header set");
            }
        })
        .map_err(|e| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(e))))
}

fn string_from_raw_src(raw_src: &str) -> String {
    let mut content = String::new();
    if raw_src == "-" {
        debug!("Reading entry from stdin");
        let res = stdin().read_to_string(&mut content);
        debug!("Read {:?} bytes", res);
    } else {
        debug!("Reading entry from file at {:?}", raw_src);
        OpenOptions::new()
            .read(true)
            .write(false)
            .create(false)
            .open(raw_src)
            .and_then(|mut f| f.read_to_string(&mut content));
    }
    content
}
<commit_msg>Use unused results<commit_after>use std::path::PathBuf;
use std::io::stdin;
use std::fs::OpenOptions;
use std::result::Result as RResult;
use std::io::Read;
use std::ops::DerefMut;
use std::io::Write;
use std::io::stderr;
use std::process::exit;

use clap::ArgMatches;

use libimagrt::runtime::Runtime;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::storeid::build_entry_path;
use libimagutil::trace::trace_error;

use error::StoreError;
use error::StoreErrorKind;
use util::build_toml_header;

type Result<T> = RResult<T, StoreError>;

pub fn create(rt: &Runtime) {
    rt.cli()
        .subcommand_matches("create")
        .map(|scmd| {
            debug!("Found 'create' subcommand...");

            // unwrap is safe as value is required
            let path = scmd.value_of("path").or_else(|| scmd.value_of("id"));
            if path.is_none() {
                warn!("No ID / Path provided. Exiting now");
                write!(stderr(), "No ID / Path provided. Exiting now").ok();
                exit(1);
            }

            let path = build_entry_path(rt.store(), path.unwrap());
            if path.is_err() {
                trace_error(&path.err().unwrap());
                exit(1);
            }
            let path = path.unwrap();
            debug!("path = {:?}", path);

            if scmd.subcommand_matches("entry").is_some() {
                create_from_cli_spec(rt, scmd, &path)
                    .or_else(|_| create_from_source(rt, scmd, &path))
                    .or_else(|_| create_with_content_and_header(rt,
                                                                &path,
                                                                String::new(),
                                                                EntryHeader::new()))
            } else {
                create_with_content_and_header(rt, &path, String::new(), EntryHeader::new())
            }
            .unwrap_or_else(|e| debug!("Error building Entry: {:?}", e))
        });
}

fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Result<()> {
    let content = matches.subcommand_matches("entry")
        .map(|entry_subcommand| {
            debug!("Found entry subcommand, parsing content");
            entry_subcommand
                .value_of("content")
                .map(String::from)
                .unwrap_or_else(|| {
                    entry_subcommand
                        .value_of("content-from")
                        .map(|src| string_from_raw_src(src))
                        .unwrap_or(String::new())
                })
        })
        .unwrap_or_else(|| {
            debug!("Didn't find entry subcommand, getting raw content");
            matches.value_of("from-raw")
                .map(|raw_src| string_from_raw_src(raw_src))
                .unwrap_or(String::new())
        });

    debug!("Got content with len = {}", content.len());

    let header = matches.subcommand_matches("entry")
        .map(|entry_matches| build_toml_header(entry_matches, EntryHeader::new()))
        .unwrap_or(EntryHeader::new());

    create_with_content_and_header(rt, path, content, header)
}

fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &PathBuf) -> Result<()> {
    let content = matches
        .value_of("from-raw")
        .ok_or(StoreError::new(StoreErrorKind::NoCommandlineCall, None))
        .map(|raw_src| string_from_raw_src(raw_src));

    if content.is_err() {
        return content.map(|_| ());
    }
    let content = content.unwrap();
    debug!("Content with len = {}", content.len());

    Entry::from_str(path.clone(), &content[..])
        .and_then(|new_e| {
            let r = rt.store()
                .create(path.clone())
                .map(|mut old_e| {
                    *old_e.deref_mut() = new_e;
                });

            debug!("Entry build");
            r
        })
        .map_err(|serr| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(serr))))
}

fn create_with_content_and_header(rt: &Runtime,
                                  path: &PathBuf,
                                  content: String,
                                  header: EntryHeader) -> Result<()>
{
    debug!("Creating entry with content");
    rt.store()
        .create(PathBuf::from(path))
        .map(|mut element| {
            {
                let mut e_content = element.get_content_mut();
                *e_content = content;
                debug!("New content set");
            }
            {
                let mut e_header  = element.get_header_mut();
                *e_header = header;
                debug!("New header set");
            }
        })
        .map_err(|e| StoreError::new(StoreErrorKind::BackendError, Some(Box::new(e))))
}

fn string_from_raw_src(raw_src: &str) -> String {
    let mut content = String::new();
    if raw_src == "-" {
        debug!("Reading entry from stdin");
        let res = stdin().read_to_string(&mut content);
        debug!("Read {:?} bytes", res);
    } else {
        debug!("Reading entry from file at {:?}", raw_src);
        let _ = OpenOptions::new()
            .read(true)
            .write(false)
            .create(false)
            .open(raw_src)
            .and_then(|mut f| f.read_to_string(&mut content));
    }
    content
}
<|endoftext|>