<commit_before>use crate::matching::{MatchResult, match_request};

use pact_matching::models::{RequestResponsePact, Request, OptionalBody, HttpPart};
use pact_matching::models::parse_query_string;

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use log::{error, warn, info, debug};
use hyper::{Body, Response, Server, Error};
use hyper::http::response::{Builder as ResponseBuilder};
use hyper::http::header::{HeaderName, HeaderValue};
use hyper::service::service_fn;
use hyper::service::make_service_fn;
use serde_json::json;
use maplit::*;
use hyper::server::conn::AddrIncoming;
use rustls::ServerConfig;
use crate::mock_server::{MockServer, MockServerConfig};

#[derive(Debug, Clone)]
enum InteractionError {
    RequestHeaderEncodingError,
    RequestBodyError,
    ResponseHeaderEncodingError,
    ResponseBodyError
}

fn extract_path(uri: &hyper::Uri) -> String {
    uri.path_and_query()
        .map(|path_and_query| path_and_query.path())
        .unwrap_or("/")
        .into()
}

fn extract_query_string(uri: &hyper::Uri) -> Option<HashMap<String, Vec<String>>> {
    uri.path_and_query()
        .and_then(|path_and_query| path_and_query.query())
        .and_then(|query| parse_query_string(&query.into()))
}

fn extract_headers(headers: &hyper::HeaderMap) -> Result<Option<HashMap<String, Vec<String>>>, InteractionError> {
  if !headers.is_empty() {
    let result: Result<HashMap<String, Vec<String>>, InteractionError> = headers.keys()
      .map(|name| -> Result<(String, Vec<String>), InteractionError> {
        let values = headers.get_all(name);
        let parsed_vals: Vec<Result<String, InteractionError>> = values.iter()
          .map(|val| val.to_str()
            .map(|v| v.to_string())
            .map_err(|err| {
              warn!("Failed to parse HTTP header value: {}", err);
              InteractionError::RequestHeaderEncodingError
            })
          ).collect();
        if parsed_vals.iter().find(|val| val.is_err()).is_some() {
          Err(InteractionError::RequestHeaderEncodingError)
        } else {
          Ok((name.as_str().into(), parsed_vals.iter().cloned()
            .map(|val| val.unwrap_or_default())
            .flat_map(|val| val.split(",").map(|v| v.to_string()).collect::<Vec<String>>())
            .map(|val| val.trim().to_string())
            .collect()))
        }
      })
      .collect();

    result.map(|map| Some(map))
  } else {
    Ok(None)
  }
}

fn extract_body(bytes: bytes::Bytes, request: &Request) -> OptionalBody {
    if bytes.len() > 0 {
      OptionalBody::Present(bytes.to_vec(), request.content_type().map(|c| c.to_string()))
    } else {
      OptionalBody::Empty
    }
}

async fn hyper_request_to_pact_request(req: hyper::Request<Body>) -> Result<Request, InteractionError> {
    let method = req.method().to_string();
    let path = extract_path(req.uri());
    let query = extract_query_string(req.uri());
    let headers = extract_headers(req.headers())?;

    let body_bytes = hyper::body::to_bytes(req.into_body())
        .await
        .map_err(|_| InteractionError::RequestBodyError)?;

    let request = Request {
      method,
      path,
      query,
      headers,
      .. Request::default()
    };

    Ok(Request {
      body: extract_body(body_bytes, &request),
      .. request.clone()
    })
}

fn set_hyper_headers(builder: &mut ResponseBuilder, headers: &Option<HashMap<String, Vec<String>>>) -> Result<(), InteractionError> {
    let hyper_headers = builder.headers_mut().unwrap();
    match headers {
        Some(header_map) => {
            for (k, v) in header_map {
                for val in v {
                    // FIXME?: Headers are not sent in "raw" mode.
                    // Names are converted to lower case and values are parsed.
                    hyper_headers.append(
                        HeaderName::from_bytes(k.as_bytes())
                            .map_err(|err| {
                                error!("Invalid header name '{}' ({})", k, err);
                                InteractionError::ResponseHeaderEncodingError
                            })?,
                        val.parse::<HeaderValue>()
                            .map_err(|err| {
                                error!("Invalid header value '{}': '{}' ({})", k, val, err);
                                InteractionError::ResponseHeaderEncodingError
                            })?
                    );
                }
            }
        },
        _ => {}
    }
    Ok(())
}

fn error_body(request: &Request, error: &String) -> String {
    let body = json!({ "error" : format!("{} : {:?}", error, request) });
    body.to_string()
}

fn match_result_to_hyper_response(
  request: &Request,
  match_result: MatchResult,
  config: &MockServerConfig
) -> Result<Response<Body>, InteractionError> {
  let cors_preflight = config.cors_preflight;

  match match_result {
    MatchResult::RequestMatch(ref interaction) => {
      let response = pact_matching::generate_response(&interaction.response, &hashmap!{});
      info!("Request matched, sending response {}", response);
      if interaction.response.has_text_body() {
        debug!("     body: '{}'", interaction.response.body.str_value());
      }

      let mut builder = Response::builder()
        .status(response.status)
        .header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")
        .header(hyper::header::ACCESS_CONTROL_ALLOW_HEADERS, "*")
        .header(hyper::header::ACCESS_CONTROL_ALLOW_METHODS, "GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH")
        .header(hyper::header::ACCESS_CONTROL_EXPOSE_HEADERS, "Location, Link");

      set_hyper_headers(&mut builder, &response.headers)?;

      builder.body(match response.body {
        OptionalBody::Present(ref s, _) => Body::from(s.clone()),
        _ => Body::empty()
      })
        .map_err(|_| InteractionError::ResponseBodyError)
    },
    _ => {
      debug!("Request did not match: {}", match_result);
      if cors_preflight && request.method.to_uppercase() == "OPTIONS" {
        info!("Responding to CORS pre-flight request");
        let origin = if cors_preflight {
          match request.headers {
            Some(ref h) => h.iter()
              .find(|kv| kv.0.to_lowercase() == "referer")
              .map(|kv| kv.1.clone().join(", ")).unwrap_or("*".to_string()),
            None => "*".to_string()
          }
        } else { "*".to_string() };
        Response::builder()
          .status(204)
          .header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, origin)
          .header(hyper::header::ACCESS_CONTROL_ALLOW_METHODS, "GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH")
          .header(hyper::header::ACCESS_CONTROL_ALLOW_HEADERS, "*")
          .header(hyper::header::ACCESS_CONTROL_ALLOW_METHODS, "DELETE, GET, PATCH, POST, PUT")
          .header(hyper::header::ACCESS_CONTROL_EXPOSE_HEADERS, "Location, Link")
          .body(Body::empty())
          .map_err(|_| InteractionError::ResponseBodyError)
      } else {
        Response::builder()
          .status(500)
          .header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")
          .header(hyper::header::CONTENT_TYPE, "application/json; charset=utf-8")
          .header("X-Pact", match_result.match_key())
          .body(Body::from(error_body(&request, &match_result.match_key())))
          .map_err(|_| InteractionError::ResponseBodyError)
      }
    }
  }
}

async fn handle_request(
  req: hyper::Request<Body>,
  pact: Arc<RequestResponsePact>,
  matches: Arc<Mutex<Vec<MatchResult>>>,
  config: Arc<MockServerConfig>
) -> Result<Response<Body>, InteractionError> {
    debug!("Creating pact request from hyper request");

    let pact_request = hyper_request_to_pact_request(req).await?;
    info!("Received request {}", pact_request);
    if pact_request.has_text_body() {
      debug!("     body: '{}'", pact_request.body.str_value());
    }

    let match_result = match_request(&pact_request, &pact.interactions);

    matches.lock().unwrap().push(match_result.clone());

    match_result_to_hyper_response(&pact_request, match_result, &config)
}

// TODO: Should instead use some form of X-Pact headers
fn handle_mock_request_error(result: Result<Response<Body>, InteractionError>) -> Result<Response<Body>, Error> {
    match result {
        Ok(response) => Ok(response),
        Err(error) => {
            let response = match error {
                InteractionError::RequestHeaderEncodingError => Response::builder()
                    .status(400)
                    .body(Body::from("Found an invalid header encoding")),
                InteractionError::RequestBodyError => Response::builder()
                    .status(500)
                    .body(Body::from("Could not process request body")),
                InteractionError::ResponseBodyError => Response::builder()
                    .status(500)
                    .body(Body::from("Could not process response body")),
                InteractionError::ResponseHeaderEncodingError => Response::builder()
                    .status(500)
                    .body(Body::from("Could not set response header"))
            };
            Ok(response.unwrap())
        }
    }
}

// Create and bind the server, but do not start it.
// Returns a future that drives the server.
// The reason that the function itself is still async (even if it performs
// no async operations) is that it needs a tokio context to be able to call try_bind.
pub(crate) async fn create_and_bind(
  pact: RequestResponsePact,
  addr: std::net::SocketAddr,
  shutdown: impl std::future::Future<Output = ()>,
  matches: Arc<Mutex<Vec<MatchResult>>>,
  mock_server: &MockServer
) -> Result<(impl std::future::Future<Output = ()>, std::net::SocketAddr), hyper::Error> {
  let pact = Arc::new(pact);
  let config = Arc::new(mock_server.config.clone());

  let server = Server::try_bind(&addr)?
    .serve(make_service_fn(move |_| {
      let pact = pact.clone();
      let matches = matches.clone();
      let config = config.clone();

      async {
        Ok::<_, hyper::Error>(
          service_fn(move |req| {
            let pact = pact.clone();
            let matches = matches.clone();
            let config = config.clone();

            async {
              handle_mock_request_error(
                handle_request(req, pact, matches, config).await
              )
            }
          })
        )
      }
    }));

  let socket_addr = server.local_addr();

  Ok((
      // This is the future that drives the server:
      async {
          let _ = server
              .with_graceful_shutdown(shutdown)
              .await;
      },
      socket_addr
  ))
}

pub(crate) async fn create_and_bind_tls(
  pact: RequestResponsePact,
  addr: std::net::SocketAddr,
  shutdown: impl std::future::Future<Output = ()>,
  matches: Arc<Mutex<Vec<MatchResult>>>,
  tls: &ServerConfig,
  mock_server: &MockServer
) -> Result<(impl std::future::Future<Output = ()>, std::net::SocketAddr), hyper::Error> {
  let pact = Arc::new(pact);
  let config = Arc::new(mock_server.config.clone());

  let incoming = AddrIncoming::bind(&addr)?;
  let socket_addr = incoming.local_addr();
  let server = Server::builder(crate::tls::TlsAcceptor::new(tls.clone(), incoming))
    .serve(make_service_fn(move |_| {
      let pact = pact.clone();
      let matches = matches.clone();
      let config = config.clone();

      async {
        Ok::<_, hyper::Error>(
          service_fn(move |req| {
            let pact = pact.clone();
            let matches = matches.clone();
            let config = config.clone();

            async {
              handle_mock_request_error(
                handle_request(req, pact, matches, config).await
              )
            }
          })
        )
      }
    }));

  Ok((
    // This is the future that drives the server:
    async {
      let _ = server
        .with_graceful_shutdown(shutdown)
        .await;
    },
    socket_addr
  ))
}

#[cfg(test)]
mod tests {
  use super::*;
  use hyper::HeaderMap;
  use hyper::header::{ACCEPT, USER_AGENT, CONTENT_TYPE};
  use expectest::prelude::*;
  use expectest::expect;

  #[tokio::test]
  async fn can_fetch_results_on_current_thread() {
    let (shutdown_tx, shutdown_rx) = futures::channel::oneshot::channel();
    let matches = Arc::new(Mutex::new(vec![]));

    let (future, _) = create_and_bind(
      RequestResponsePact::default(),
      ([0, 0, 0, 0], 0 as u16).into(),
      async {
          shutdown_rx.await.ok();
      },
      matches.clone(),
      &MockServer::default()
    ).await.unwrap();

    let join_handle = tokio::task::spawn(future);

    shutdown_tx.send(()).unwrap();

    // Server has shut down, now flush the server future from runtime
    join_handle.await.unwrap();

    // 0 matches have been produced
    let all_matches = matches.lock().unwrap().clone();
    assert_eq!(all_matches, vec![]);
  }

  #[test]
  fn handle_hyper_headers_with_multiple_values() {
    let mut headers = HeaderMap::new();
    headers.append(ACCEPT, "application/xml, application/json".parse().unwrap());
    headers.append(USER_AGENT, "test".parse().unwrap());
    headers.append(USER_AGENT, "test2".parse().unwrap());
    headers.append(CONTENT_TYPE, "text/plain".parse().unwrap());
    let result = extract_headers(&headers);
    expect!(result).to(be_ok().value(Some(hashmap! {
      "accept".to_string() => vec!["application/xml".to_string(), "application/json".to_string()],
      "user-agent".to_string() => vec!["test".to_string(), "test2".to_string()],
      "content-type".to_string() => vec!["text/plain".to_string()]
    })));
  }
}
<commit_msg>fix: access-control-allow-methods header was duplicated<commit_after>use crate::matching::{MatchResult, match_request};

use pact_matching::models::{RequestResponsePact, Request, OptionalBody, HttpPart};
use pact_matching::models::parse_query_string;

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use log::{error, warn, info, debug};
use hyper::{Body, Response, Server, Error};
use hyper::http::response::{Builder as ResponseBuilder};
use hyper::http::header::{HeaderName, HeaderValue};
use hyper::service::service_fn;
use hyper::service::make_service_fn;
use serde_json::json;
use maplit::*;
use hyper::server::conn::AddrIncoming;
use rustls::ServerConfig;
use crate::mock_server::{MockServer, MockServerConfig};

#[derive(Debug, Clone)]
enum InteractionError {
    RequestHeaderEncodingError,
    RequestBodyError,
    ResponseHeaderEncodingError,
    ResponseBodyError
}

fn extract_path(uri: &hyper::Uri) -> String {
    uri.path_and_query()
        .map(|path_and_query| path_and_query.path())
        .unwrap_or("/")
        .into()
}

fn extract_query_string(uri: &hyper::Uri) -> Option<HashMap<String, Vec<String>>> {
    uri.path_and_query()
        .and_then(|path_and_query| path_and_query.query())
        .and_then(|query| parse_query_string(&query.into()))
}

fn extract_headers(headers: &hyper::HeaderMap) -> Result<Option<HashMap<String, Vec<String>>>, InteractionError> {
  if !headers.is_empty() {
    let result: Result<HashMap<String, Vec<String>>, InteractionError> = headers.keys()
      .map(|name| -> Result<(String, Vec<String>), InteractionError> {
        let values = headers.get_all(name);
        let parsed_vals: Vec<Result<String, InteractionError>> = values.iter()
          .map(|val| val.to_str()
            .map(|v| v.to_string())
            .map_err(|err| {
              warn!("Failed to parse HTTP header value: {}", err);
              InteractionError::RequestHeaderEncodingError
            })
          ).collect();
        if parsed_vals.iter().find(|val| val.is_err()).is_some() {
          Err(InteractionError::RequestHeaderEncodingError)
        } else {
          Ok((name.as_str().into(), parsed_vals.iter().cloned()
            .map(|val| val.unwrap_or_default())
            .flat_map(|val| val.split(",").map(|v| v.to_string()).collect::<Vec<String>>())
            .map(|val| val.trim().to_string())
            .collect()))
        }
      })
      .collect();

    result.map(|map| Some(map))
  } else {
    Ok(None)
  }
}

fn extract_body(bytes: bytes::Bytes, request: &Request) -> OptionalBody {
    if bytes.len() > 0 {
      OptionalBody::Present(bytes.to_vec(), request.content_type().map(|c| c.to_string()))
    } else {
      OptionalBody::Empty
    }
}

async fn hyper_request_to_pact_request(req: hyper::Request<Body>) -> Result<Request, InteractionError> {
    let method = req.method().to_string();
    let path = extract_path(req.uri());
    let query = extract_query_string(req.uri());
    let headers = extract_headers(req.headers())?;

    let body_bytes = hyper::body::to_bytes(req.into_body())
        .await
        .map_err(|_| InteractionError::RequestBodyError)?;

    let request = Request {
      method,
      path,
      query,
      headers,
      .. Request::default()
    };

    Ok(Request {
      body: extract_body(body_bytes, &request),
      .. request.clone()
    })
}

fn set_hyper_headers(builder: &mut ResponseBuilder, headers: &Option<HashMap<String, Vec<String>>>) -> Result<(), InteractionError> {
    let hyper_headers = builder.headers_mut().unwrap();
    match headers {
        Some(header_map) => {
            for (k, v) in header_map {
                for val in v {
                    // FIXME?: Headers are not sent in "raw" mode.
                    // Names are converted to lower case and values are parsed.
                    hyper_headers.append(
                        HeaderName::from_bytes(k.as_bytes())
                            .map_err(|err| {
                                error!("Invalid header name '{}' ({})", k, err);
                                InteractionError::ResponseHeaderEncodingError
                            })?,
                        val.parse::<HeaderValue>()
                            .map_err(|err| {
                                error!("Invalid header value '{}': '{}' ({})", k, val, err);
                                InteractionError::ResponseHeaderEncodingError
                            })?
                    );
                }
            }
        },
        _ => {}
    }
    Ok(())
}

fn error_body(request: &Request, error: &String) -> String {
    let body = json!({ "error" : format!("{} : {:?}", error, request) });
    body.to_string()
}

fn match_result_to_hyper_response(
  request: &Request,
  match_result: MatchResult,
  config: &MockServerConfig
) -> Result<Response<Body>, InteractionError> {
  let cors_preflight = config.cors_preflight;

  match match_result {
    MatchResult::RequestMatch(ref interaction) => {
      let response = pact_matching::generate_response(&interaction.response, &hashmap!{});
      info!("Request matched, sending response {}", response);
      if interaction.response.has_text_body() {
        debug!("     body: '{}'", interaction.response.body.str_value());
      }

      let mut builder = Response::builder()
        .status(response.status)
        .header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")
        .header(hyper::header::ACCESS_CONTROL_ALLOW_HEADERS, "*")
        .header(hyper::header::ACCESS_CONTROL_ALLOW_METHODS, "GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH")
        .header(hyper::header::ACCESS_CONTROL_EXPOSE_HEADERS, "Location, Link");

      set_hyper_headers(&mut builder, &response.headers)?;

      builder.body(match response.body {
        OptionalBody::Present(ref s, _) => Body::from(s.clone()),
        _ => Body::empty()
      })
        .map_err(|_| InteractionError::ResponseBodyError)
    },
    _ => {
      debug!("Request did not match: {}", match_result);
      if cors_preflight && request.method.to_uppercase() == "OPTIONS" {
        info!("Responding to CORS pre-flight request");
        let origin = if cors_preflight {
          match request.headers {
            Some(ref h) => h.iter()
              .find(|kv| kv.0.to_lowercase() == "referer")
              .map(|kv| kv.1.clone().join(", ")).unwrap_or("*".to_string()),
            None => "*".to_string()
          }
        } else { "*".to_string() };
        Response::builder()
          .status(204)
          .header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, origin)
          .header(hyper::header::ACCESS_CONTROL_ALLOW_METHODS, "GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH")
          .header(hyper::header::ACCESS_CONTROL_ALLOW_HEADERS, "*")
          .header(hyper::header::ACCESS_CONTROL_EXPOSE_HEADERS, "Location, Link")
          .body(Body::empty())
          .map_err(|_| InteractionError::ResponseBodyError)
      } else {
        Response::builder()
          .status(500)
          .header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")
          .header(hyper::header::CONTENT_TYPE, "application/json; charset=utf-8")
          .header("X-Pact", match_result.match_key())
          .body(Body::from(error_body(&request, &match_result.match_key())))
          .map_err(|_| InteractionError::ResponseBodyError)
      }
    }
  }
}

async fn handle_request(
  req: hyper::Request<Body>,
  pact: Arc<RequestResponsePact>,
  matches: Arc<Mutex<Vec<MatchResult>>>,
  config: Arc<MockServerConfig>
) -> Result<Response<Body>, InteractionError> {
    debug!("Creating pact request from hyper request");

    let pact_request = hyper_request_to_pact_request(req).await?;
    info!("Received request {}", pact_request);
    if pact_request.has_text_body() {
      debug!("     body: '{}'", pact_request.body.str_value());
    }

    let match_result = match_request(&pact_request, &pact.interactions);

    matches.lock().unwrap().push(match_result.clone());

    match_result_to_hyper_response(&pact_request, match_result, &config)
}

// TODO: Should instead use some form of X-Pact headers
fn handle_mock_request_error(result: Result<Response<Body>, InteractionError>) -> Result<Response<Body>, Error> {
    match result {
        Ok(response) => Ok(response),
        Err(error) => {
            let response = match error {
                InteractionError::RequestHeaderEncodingError => Response::builder()
                    .status(400)
                    .body(Body::from("Found an invalid header encoding")),
                InteractionError::RequestBodyError => Response::builder()
                    .status(500)
                    .body(Body::from("Could not process request body")),
                InteractionError::ResponseBodyError => Response::builder()
                    .status(500)
                    .body(Body::from("Could not process response body")),
                InteractionError::ResponseHeaderEncodingError => Response::builder()
                    .status(500)
                    .body(Body::from("Could not set response header"))
            };
            Ok(response.unwrap())
        }
    }
}

// Create and bind the server, but do not start it.
// Returns a future that drives the server.
// The reason that the function itself is still async (even if it performs
// no async operations) is that it needs a tokio context to be able to call try_bind.
pub(crate) async fn create_and_bind(
  pact: RequestResponsePact,
  addr: std::net::SocketAddr,
  shutdown: impl std::future::Future<Output = ()>,
  matches: Arc<Mutex<Vec<MatchResult>>>,
  mock_server: &MockServer
) -> Result<(impl std::future::Future<Output = ()>, std::net::SocketAddr), hyper::Error> {
  let pact = Arc::new(pact);
  let config = Arc::new(mock_server.config.clone());

  let server = Server::try_bind(&addr)?
    .serve(make_service_fn(move |_| {
      let pact = pact.clone();
      let matches = matches.clone();
      let config = config.clone();

      async {
        Ok::<_, hyper::Error>(
          service_fn(move |req| {
            let pact = pact.clone();
            let matches = matches.clone();
            let config = config.clone();

            async {
              handle_mock_request_error(
                handle_request(req, pact, matches, config).await
              )
            }
          })
        )
      }
    }));

  let socket_addr = server.local_addr();

  Ok((
      // This is the future that drives the server:
      async {
          let _ = server
              .with_graceful_shutdown(shutdown)
              .await;
      },
      socket_addr
  ))
}

pub(crate) async fn create_and_bind_tls(
  pact: RequestResponsePact,
  addr: std::net::SocketAddr,
  shutdown: impl std::future::Future<Output = ()>,
  matches: Arc<Mutex<Vec<MatchResult>>>,
  tls: &ServerConfig,
  mock_server: &MockServer
) -> Result<(impl std::future::Future<Output = ()>, std::net::SocketAddr), hyper::Error> {
  let pact = Arc::new(pact);
  let config = Arc::new(mock_server.config.clone());

  let incoming = AddrIncoming::bind(&addr)?;
  let socket_addr = incoming.local_addr();
  let server = Server::builder(crate::tls::TlsAcceptor::new(tls.clone(), incoming))
    .serve(make_service_fn(move |_| {
      let pact = pact.clone();
      let matches = matches.clone();
      let config = config.clone();

      async {
        Ok::<_, hyper::Error>(
          service_fn(move |req| {
            let pact = pact.clone();
            let matches = matches.clone();
            let config = config.clone();

            async {
              handle_mock_request_error(
                handle_request(req, pact, matches, config).await
              )
            }
          })
        )
      }
    }));

  Ok((
    // This is the future that drives the server:
    async {
      let _ = server
        .with_graceful_shutdown(shutdown)
        .await;
    },
    socket_addr
  ))
}

#[cfg(test)]
mod tests {
  use super::*;
  use hyper::HeaderMap;
  use hyper::header::{ACCEPT, USER_AGENT, CONTENT_TYPE};
  use expectest::prelude::*;
  use expectest::expect;

  #[tokio::test]
  async fn can_fetch_results_on_current_thread() {
    let (shutdown_tx, shutdown_rx) = futures::channel::oneshot::channel();
    let matches = Arc::new(Mutex::new(vec![]));

    let (future, _) = create_and_bind(
      RequestResponsePact::default(),
      ([0, 0, 0, 0], 0 as u16).into(),
      async {
          shutdown_rx.await.ok();
      },
      matches.clone(),
      &MockServer::default()
    ).await.unwrap();

    let join_handle = tokio::task::spawn(future);

    shutdown_tx.send(()).unwrap();

    // Server has shut down, now flush the server future from runtime
    join_handle.await.unwrap();

    // 0 matches have been produced
    let all_matches = matches.lock().unwrap().clone();
    assert_eq!(all_matches, vec![]);
  }

  #[test]
  fn handle_hyper_headers_with_multiple_values() {
    let mut headers = HeaderMap::new();
    headers.append(ACCEPT, "application/xml, application/json".parse().unwrap());
    headers.append(USER_AGENT, "test".parse().unwrap());
    headers.append(USER_AGENT, "test2".parse().unwrap());
    headers.append(CONTENT_TYPE, "text/plain".parse().unwrap());
    let result = extract_headers(&headers);
    expect!(result).to(be_ok().value(Some(hashmap! {
      "accept".to_string() => vec!["application/xml".to_string(), "application/json".to_string()],
      "user-agent".to_string() => vec!["test".to_string(), "test2".to_string()],
      "content-type".to_string() => vec!["text/plain".to_string()]
    })));
  }
}
<|endoftext|>


<commit_before><commit_msg>Fix Invalid import<commit_after><|endoftext|>


<commit_before>//! Records a WAV file (roughly 3 seconds long) using the default input device and config.
//!
//! The input data is recorded to "$CARGO_MANIFEST_DIR/recorded.wav".
use nannou::prelude::*;
use nannou_audio as audio;
use nannou_audio::Buffer;
use std::fs::File;
use std::io::BufWriter;
extern crate hound;

type WavWriter = hound::WavWriter<BufWriter<File>>;

fn main() {
    nannou::app(model).run();
}

struct Model {
    stream: audio::Stream<CaptureModel>,
}

struct CaptureModel {
    writer: WavWriter,
}

fn model(app: &App) -> Model {
    // Create a window to receive key pressed events.
    app.new_window()
        .key_pressed(key_pressed)
        .view(view)
        .build()
        .unwrap();

    // Initialise the audio host so we can spawn an audio stream.
    let audio_host = audio::Host::new();

    // Get specs from device config.
    let spec = hound::WavSpec {
        channels: 1,
        sample_rate: 44100,
        bits_per_sample: 32,
        sample_format: hound::SampleFormat::Float,
    };
    let writer = hound::WavWriter::create("recorded.wav", spec).unwrap();
    let capture_model = CaptureModel { writer };

    let stream = audio_host
        .new_input_stream(capture_model)
        .capture(capture_fn)
        .build()
        .unwrap();

    Model { stream }
}

// A function that captures the audio from the buffer and
// writes it into the the WavWriter.
fn capture_fn(audio: &mut CaptureModel, buffer: &Buffer) {
    // when the program ends, writer is dropped and
    // when writer is dropped, it writes data to disk.
    for frame in buffer.frames() {
        audio
            .writer
            .write_sample(frame[0] as f32)
            .expect("error while writing");
    }
}

fn key_pressed(_app: &App, model: &mut Model, key: Key) {
    match key {
        Key::R => {}
        Key::P => {}
        _ => {}
    }
}

fn view(_app: &App, _model: &Model, frame: Frame) {
    frame.clear(DIMGRAY);
}
<commit_msg>Add record indicator and clean-up<commit_after>//! Records a WAV file using the default input device and default input format.
//!
//! The input data is recorded to "$CARGO_MANIFEST_DIR/recorded.wav".
use nannou::prelude::*;
use nannou_audio as audio;
use nannou_audio::Buffer;
use std::fs::File;
use std::io::BufWriter;
extern crate hound;

type WavWriter = hound::WavWriter<BufWriter<File>>;

fn main() {
    nannou::app(model).run();
}

struct Model {
    stream: audio::Stream<CaptureModel>,
}

struct CaptureModel {
    writer: WavWriter,
}

fn model(app: &App) -> Model {
    // Create a window to receive key pressed events.
    app.new_window()
        .key_pressed(key_pressed)
        .view(view)
        .build()
        .unwrap();

    // Initialise the audio host so we can spawn an audio stream.
    let audio_host = audio::Host::new();

    // Create a writer
    let spec = get_spec(&audio_host);
    let writer = hound::WavWriter::create("recorded.wav", spec).unwrap();
    let capture_model = CaptureModel { writer };

    let stream = audio_host
        .new_input_stream(capture_model)
        .capture(capture_fn)
        .build()
        .unwrap();

    Model { stream }
}

// A function that captures the audio from the buffer and
// writes it into the the WavWriter.
fn capture_fn(audio: &mut CaptureModel, buffer: &Buffer) {
    // When the program ends, writer is dropped and data gets written to the disk.
    for frame in buffer.frames() {
        for sample in frame {
            audio
                .writer
                .write_sample(*sample)
                .expect("error while writing the sample");
        }
    }
}

fn key_pressed(_app: &App, model: &mut Model, key: Key) {
    match key {
        Key::Space => {
            if model.stream.is_paused() {
                model.stream.play().unwrap();
            } else if model.stream.is_playing() {
                model.stream.pause().unwrap();
            }
        }
        _ => {}
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    frame.clear(DIMGRAY);

    if model.stream.is_playing() && app.elapsed_frames() % 30 < 20 {
        let draw = app.draw();
        draw.ellipse().w_h(100.0, 100.0).color(RED);

        draw.to_frame(app, &frame).unwrap();
    }
}

// Get specification from default device format.
fn get_spec(audio_host: &nannou_audio::Host) -> hound::WavSpec {
    let default_input_format = audio_host
        .default_input_device()
        .unwrap()
        .default_input_format()
        .unwrap();

    let (bits_per_sample, sample_format) = match default_input_format.data_type {
        audio::cpal::SampleFormat::I16 => (16, hound::SampleFormat::Int),
        audio::cpal::SampleFormat::U16 => (16, hound::SampleFormat::Int),
        audio::cpal::SampleFormat::F32 => (32, hound::SampleFormat::Float),
    };

    hound::WavSpec {
        channels: default_input_format.channels,
        sample_rate: default_input_format.sample_rate.0,
        bits_per_sample,
        sample_format,
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use fnv::FnvHashMap;
use std::cmp;
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;
use std::thread;

use command_buffer::pool::CommandPool;
use command_buffer::pool::CommandPoolAlloc;
use command_buffer::pool::CommandPoolBuilderAlloc;
use command_buffer::pool::UnsafeCommandPool;
use command_buffer::pool::UnsafeCommandPoolAlloc;
use instance::QueueFamily;

use OomError;
use VulkanObject;
use device::Device;
use device::DeviceOwned;

/// Standard implementation of a command pool.
///
/// Will use one Vulkan pool per thread in order to avoid locking. Will try to reuse command
/// buffers. Command buffers can't be moved between threads during the building process, but
/// finished command buffers can.
pub struct StandardCommandPool {
    // The device.
    device: Arc<Device>,

    // Identifier of the queue family.
    queue_family: u32,

    // For each thread, we store thread-specific info.
    per_thread: Mutex<FnvHashMap<thread::ThreadId, Weak<Mutex<StandardCommandPoolPerThread>>>>,
}

unsafe impl Send for StandardCommandPool {
}
unsafe impl Sync for StandardCommandPool {
}

struct StandardCommandPoolPerThread {
    // The Vulkan pool of this thread.
    pool: UnsafeCommandPool,
    // List of existing primary command buffers that are available for reuse.
    available_primary_command_buffers: Vec<UnsafeCommandPoolAlloc>,
    // List of existing secondary command buffers that are available for reuse.
    available_secondary_command_buffers: Vec<UnsafeCommandPoolAlloc>,
}

impl StandardCommandPool {
    /// Builds a new pool.
    ///
    /// # Panic
    ///
    /// - Panics if the device and the queue family don't belong to the same physical device.
    ///
    pub fn new(device: Arc<Device>, queue_family: QueueFamily) -> StandardCommandPool {
        assert_eq!(device.physical_device().internal_object(),
                   queue_family.physical_device().internal_object());

        StandardCommandPool {
            device: device,
            queue_family: queue_family.id(),
            per_thread: Mutex::new(Default::default()),
        }
    }
}

unsafe impl CommandPool for Arc<StandardCommandPool> {
    type Iter = Box<Iterator<Item = StandardCommandPoolBuilder>>; // TODO: meh for Box
    type Builder = StandardCommandPoolBuilder;
    type Alloc = StandardCommandPoolAlloc;

    fn alloc(&self, secondary: bool, count: u32) -> Result<Self::Iter, OomError> {
        // Find the correct `StandardCommandPoolPerThread` structure.
        let mut hashmap = self.per_thread.lock().unwrap();
        //hashmap.retain(|_, w| w.upgrade().is_some());     // TODO: unstable     // TODO: meh for iterating everything every time

        // TODO: this hashmap lookup can probably be optimized
        let curr_thread_id = thread::current().id();
        let per_thread = hashmap.get(&curr_thread_id).and_then(|p| p.upgrade());
        let per_thread = match per_thread {
            Some(pt) => pt,
            None => {
                let new_pool =
                    UnsafeCommandPool::new(self.device.clone(), self.queue_family(), false, true)?;
                let pt = Arc::new(Mutex::new(StandardCommandPoolPerThread {
                                                 pool: new_pool,
                                                 available_primary_command_buffers: Vec::new(),
                                                 available_secondary_command_buffers: Vec::new(),
                                             }));

                hashmap.insert(curr_thread_id, Arc::downgrade(&pt));
                pt
            },
        };

        let mut pt_lock = per_thread.lock().unwrap();

        // Build an iterator to pick from already-existing command buffers.
        let (num_from_existing, from_existing) = {
            // Which list of already-existing command buffers we are going to pick CBs from.
            let mut existing = if secondary {
                &mut pt_lock.available_secondary_command_buffers
            } else {
                &mut pt_lock.available_primary_command_buffers
            };
            let num_from_existing = cmp::min(count as usize, existing.len());
            let from_existing = existing
                .drain(0 .. num_from_existing)
                .collect::<Vec<_>>()
                .into_iter();
            (num_from_existing, from_existing)
        };

        // Build an iterator to construct the missing command buffers from the Vulkan pool.
        let num_new = count as usize - num_from_existing;
        debug_assert!(num_new <= count as usize); // Check overflows.
        let newly_allocated = pt_lock.pool.alloc_command_buffers(secondary, num_new)?;

        // Returning them as a chain.
        let device = self.device.clone();
        let per_thread = per_thread.clone();
        let final_iter = from_existing
            .chain(newly_allocated)
            .map(move |cmd| {
                StandardCommandPoolBuilder {
                    inner: StandardCommandPoolAlloc {
                        cmd: Some(cmd),
                        pool: per_thread.clone(),
                        secondary: secondary,
                        device: device.clone(),
                    },
                    dummy_avoid_send_sync: PhantomData,
                }
            })
            .collect::<Vec<_>>();

        Ok(Box::new(final_iter.into_iter()))
    }

    #[inline]
    fn queue_family(&self) -> QueueFamily {
        self.device
            .physical_device()
            .queue_family_by_id(self.queue_family)
            .unwrap()
    }
}

unsafe impl DeviceOwned for StandardCommandPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

/// Command buffer allocated from a `StandardCommandPool` and that is currently being built.
pub struct StandardCommandPoolBuilder {
    // The only difference between a `StandardCommandPoolBuilder` and a `StandardCommandPoolAlloc`
    // is that the former must not implement `Send` and `Sync`. Therefore we just share the structs.
    inner: StandardCommandPoolAlloc,
    // Unimplemented `Send` and `Sync` from the builder.
    dummy_avoid_send_sync: PhantomData<*const u8>,
}

unsafe impl CommandPoolBuilderAlloc for StandardCommandPoolBuilder {
    type Alloc = StandardCommandPoolAlloc;

    #[inline]
    fn inner(&self) -> &UnsafeCommandPoolAlloc {
        self.inner.inner()
    }

    #[inline]
    fn into_alloc(self) -> Self::Alloc {
        self.inner
    }

    #[inline]
    fn queue_family(&self) -> QueueFamily {
        self.inner.queue_family()
    }
}

unsafe impl DeviceOwned for StandardCommandPoolBuilder {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }
}

/// Command buffer allocated from a `StandardCommandPool`.
pub struct StandardCommandPoolAlloc {
    // The actual command buffer. Must always be `Some`. Value extracted in the destructor.
    cmd: Option<UnsafeCommandPoolAlloc>,
    // We hold a reference to the command pool for our destructor.
    pool: Arc<Mutex<StandardCommandPoolPerThread>>,
    // True if secondary command buffer.
    secondary: bool,
    // The device we belong to. Necessary because of the `DeviceOwned` trait implementation.
    device: Arc<Device>,
}

unsafe impl Send for StandardCommandPoolAlloc {
}
unsafe impl Sync for StandardCommandPoolAlloc {
}

unsafe impl CommandPoolAlloc for StandardCommandPoolAlloc {
    #[inline]
    fn inner(&self) -> &UnsafeCommandPoolAlloc {
        self.cmd.as_ref().unwrap()
    }

    #[inline]
    fn queue_family(&self) -> QueueFamily {
        let queue_family_id = self.pool.lock().unwrap().pool.queue_family().id();

        self.device
            .physical_device()
            .queue_family_by_id(queue_family_id)
            .unwrap()
    }
}

unsafe impl DeviceOwned for StandardCommandPoolAlloc {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        // Note that we could grab the device from `self.pool`. Unfortunately this requires a mutex
        // lock, so it isn't compatible with the API of `DeviceOwned`.
        &self.device
    }
}

impl Drop for StandardCommandPoolAlloc {
    fn drop(&mut self) {
        let mut pool = self.pool.lock().unwrap();

        if self.secondary {
            pool.available_secondary_command_buffers
                .push(self.cmd.take().unwrap());
        } else {
            pool.available_primary_command_buffers
                .push(self.cmd.take().unwrap());
        }
    }
}
<commit_msg>Improve std cmd pool hashmap lookup<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use fnv::FnvHashMap;
use std::collections::hash_map::Entry;
use std::cmp;
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;
use std::thread;

use command_buffer::pool::CommandPool;
use command_buffer::pool::CommandPoolAlloc;
use command_buffer::pool::CommandPoolBuilderAlloc;
use command_buffer::pool::UnsafeCommandPool;
use command_buffer::pool::UnsafeCommandPoolAlloc;
use instance::QueueFamily;

use OomError;
use VulkanObject;
use device::Device;
use device::DeviceOwned;

/// Standard implementation of a command pool.
///
/// Will use one Vulkan pool per thread in order to avoid locking. Will try to reuse command
/// buffers. Command buffers can't be moved between threads during the building process, but
/// finished command buffers can.
pub struct StandardCommandPool {
    // The device.
    device: Arc<Device>,

    // Identifier of the queue family.
    queue_family: u32,

    // For each thread, we store thread-specific info.
    per_thread: Mutex<FnvHashMap<thread::ThreadId, Weak<Mutex<StandardCommandPoolPerThread>>>>,
}

unsafe impl Send for StandardCommandPool {
}
unsafe impl Sync for StandardCommandPool {
}

struct StandardCommandPoolPerThread {
    // The Vulkan pool of this thread.
    pool: UnsafeCommandPool,
    // List of existing primary command buffers that are available for reuse.
    available_primary_command_buffers: Vec<UnsafeCommandPoolAlloc>,
    // List of existing secondary command buffers that are available for reuse.
    available_secondary_command_buffers: Vec<UnsafeCommandPoolAlloc>,
}

impl StandardCommandPool {
    /// Builds a new pool.
    ///
    /// # Panic
    ///
    /// - Panics if the device and the queue family don't belong to the same physical device.
    ///
    pub fn new(device: Arc<Device>, queue_family: QueueFamily) -> StandardCommandPool {
        assert_eq!(device.physical_device().internal_object(),
                   queue_family.physical_device().internal_object());

        StandardCommandPool {
            device: device,
            queue_family: queue_family.id(),
            per_thread: Mutex::new(Default::default()),
        }
    }
}

unsafe impl CommandPool for Arc<StandardCommandPool> {
    type Iter = Box<Iterator<Item = StandardCommandPoolBuilder>>; // TODO: meh for Box
    type Builder = StandardCommandPoolBuilder;
    type Alloc = StandardCommandPoolAlloc;

    fn alloc(&self, secondary: bool, count: u32) -> Result<Self::Iter, OomError> {
        // Find the correct `StandardCommandPoolPerThread` structure.
        let mut hashmap = self.per_thread.lock().unwrap();
        // TODO: meh for iterating everything every time
        hashmap.retain(|_, w| w.upgrade().is_some());

        // Get an appropriate `Arc<Mutex<StandardCommandPoolPerThread>>`.
        let per_thread = match hashmap.entry(thread::current().id()) {
            Entry::Occupied(mut entry) => {
                if let Some(entry) = entry.get().upgrade() {
                    entry
                } else {
                    let new_pool =
                        UnsafeCommandPool::new(self.device.clone(), self.queue_family(), false, true)?;
                    let pt = Arc::new(Mutex::new(StandardCommandPoolPerThread {
                                                    pool: new_pool,
                                                    available_primary_command_buffers: Vec::new(),
                                                    available_secondary_command_buffers: Vec::new(),
                                                }));

                    entry.insert(Arc::downgrade(&pt));
                    pt
                }
            },
            Entry::Vacant(entry) => {
                let new_pool =
                    UnsafeCommandPool::new(self.device.clone(), self.queue_family(), false, true)?;
                let pt = Arc::new(Mutex::new(StandardCommandPoolPerThread {
                                                 pool: new_pool,
                                                 available_primary_command_buffers: Vec::new(),
                                                 available_secondary_command_buffers: Vec::new(),
                                             }));

                entry.insert(Arc::downgrade(&pt));
                pt
            },
        };

        let mut pt_lock = per_thread.lock().unwrap();

        // Build an iterator to pick from already-existing command buffers.
        let (num_from_existing, from_existing) = {
            // Which list of already-existing command buffers we are going to pick CBs from.
            let mut existing = if secondary {
                &mut pt_lock.available_secondary_command_buffers
            } else {
                &mut pt_lock.available_primary_command_buffers
            };
            let num_from_existing = cmp::min(count as usize, existing.len());
            let from_existing = existing
                .drain(0 .. num_from_existing)
                .collect::<Vec<_>>()
                .into_iter();
            (num_from_existing, from_existing)
        };

        // Build an iterator to construct the missing command buffers from the Vulkan pool.
        let num_new = count as usize - num_from_existing;
        debug_assert!(num_new <= count as usize); // Check overflows.
        let newly_allocated = pt_lock.pool.alloc_command_buffers(secondary, num_new)?;

        // Returning them as a chain.
        let device = self.device.clone();
        let per_thread = per_thread.clone();
        let final_iter = from_existing
            .chain(newly_allocated)
            .map(move |cmd| {
                StandardCommandPoolBuilder {
                    inner: StandardCommandPoolAlloc {
                        cmd: Some(cmd),
                        pool: per_thread.clone(),
                        secondary: secondary,
                        device: device.clone(),
                    },
                    dummy_avoid_send_sync: PhantomData,
                }
            })
            .collect::<Vec<_>>();

        Ok(Box::new(final_iter.into_iter()))
    }

    #[inline]
    fn queue_family(&self) -> QueueFamily {
        self.device
            .physical_device()
            .queue_family_by_id(self.queue_family)
            .unwrap()
    }
}

unsafe impl DeviceOwned for StandardCommandPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

/// Command buffer allocated from a `StandardCommandPool` and that is currently being built.
pub struct StandardCommandPoolBuilder {
    // The only difference between a `StandardCommandPoolBuilder` and a `StandardCommandPoolAlloc`
    // is that the former must not implement `Send` and `Sync`. Therefore we just share the structs.
    inner: StandardCommandPoolAlloc,
    // Unimplemented `Send` and `Sync` from the builder.
    dummy_avoid_send_sync: PhantomData<*const u8>,
}

unsafe impl CommandPoolBuilderAlloc for StandardCommandPoolBuilder {
    type Alloc = StandardCommandPoolAlloc;

    #[inline]
    fn inner(&self) -> &UnsafeCommandPoolAlloc {
        self.inner.inner()
    }

    #[inline]
    fn into_alloc(self) -> Self::Alloc {
        self.inner
    }

    #[inline]
    fn queue_family(&self) -> QueueFamily {
        self.inner.queue_family()
    }
}

unsafe impl DeviceOwned for StandardCommandPoolBuilder {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }
}

/// Command buffer allocated from a `StandardCommandPool`.
pub struct StandardCommandPoolAlloc {
    // The actual command buffer. Must always be `Some`. Value extracted in the destructor.
    cmd: Option<UnsafeCommandPoolAlloc>,
    // We hold a reference to the command pool for our destructor.
    pool: Arc<Mutex<StandardCommandPoolPerThread>>,
    // True if secondary command buffer.
    secondary: bool,
    // The device we belong to. Necessary because of the `DeviceOwned` trait implementation.
    device: Arc<Device>,
}

unsafe impl Send for StandardCommandPoolAlloc {
}
unsafe impl Sync for StandardCommandPoolAlloc {
}

unsafe impl CommandPoolAlloc for StandardCommandPoolAlloc {
    #[inline]
    fn inner(&self) -> &UnsafeCommandPoolAlloc {
        self.cmd.as_ref().unwrap()
    }

    #[inline]
    fn queue_family(&self) -> QueueFamily {
        let queue_family_id = self.pool.lock().unwrap().pool.queue_family().id();

        self.device
            .physical_device()
            .queue_family_by_id(queue_family_id)
            .unwrap()
    }
}

unsafe impl DeviceOwned for StandardCommandPoolAlloc {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        // Note that we could grab the device from `self.pool`. Unfortunately this requires a mutex
        // lock, so it isn't compatible with the API of `DeviceOwned`.
        &self.device
    }
}

impl Drop for StandardCommandPoolAlloc {
    fn drop(&mut self) {
        let mut pool = self.pool.lock().unwrap();

        if self.secondary {
            pool.available_secondary_command_buffers
                .push(self.cmd.take().unwrap());
        } else {
            pool.available_primary_command_buffers
                .push(self.cmd.take().unwrap());
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(interpolate_idents)]

#[macro_use]
extern crate apache2;

use apache2::{Request, Status, Pool, CmdParms, BoolType, StringType, RSRC_CONF, ACCESS_CONF};

new_module!(
   conf, b"mod_conf\0",
   config {
      directory {
         DirectoryConfig {
            dir_var: StringType
         },
         create_directory_config
      },
      server {
         ServerConfig {
            enabled: BoolType,
            string_var: StringType
         },
         create_server_config
      }, [
         (FLAG, b"EnabledVar\0", enabled_var, RSRC_CONF, b"Example flag\0"),
         (TAKE1, b"StringVar\0", string_var, RSRC_CONF, b"Example string directive\0"),
         (TAKE1, b"DirVar\0", dir_var, ACCESS_CONF, b"Directory string directive\0")
      ]
   }
);

fn create_server_config<'a>(pool: &mut Pool) -> ServerConfig<'a> {
   let mut config = ServerConfig::new(pool).unwrap();

   config.set_enabled(false);

   config
}

fn create_directory_config<'a>(pool: &mut Pool, _: Option<&'a str>) -> DirectoryConfig<'a> {
   DirectoryConfig::new(pool).unwrap()
}

fn enabled_var(parms: &mut CmdParms, _: Option<DirectoryConfig>, on: bool) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_enabled(on);

   Ok(())
}

fn string_var<'a>(parms: &mut CmdParms, _: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_string_var(w);

   Ok(())
}

fn dir_var<'a>(_: &mut CmdParms, mconfig: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = mconfig.unwrap();

   config.set_dir_var(w);

   Ok(())
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "conf" {
      return Ok(Status::DECLINED)
   }

   let server_config = get_server_config(
      &mut try!(r.pool()),
      &try!(try!(r.server()).module_config())
   );

   r.set_content_type("text/plain; charset=utf-8");

   let enabled = try!(server_config.enabled());
   try!(r.write(format!("EnabledVar: {:?}\n", enabled)));

   let string_var = try!(server_config.string_var());
   try!(r.write(format!("StringVar: {:?}\n", string_var)));

   let dir_config = get_dir_config(
      &mut try!(r.pool()),
      &try!(r.per_dir_config())
   );

   let dir_var = try!(dir_config.dir_var());
   try!(r.write(format!("DirVar: {:?}\n", dir_var)));

   Ok(Status::OK)
}
<commit_msg>Transferring the unwrap_str function from the mod_info_rs example to mod_conf.<commit_after>#![feature(plugin)]
#![plugin(interpolate_idents)]

#[macro_use]
extern crate apache2;

use apache2::{Request, Status, Pool, CmdParms, BoolType, StringType, RSRC_CONF, ACCESS_CONF};

new_module!(
   conf, b"mod_conf\0",
   config {
      directory {
         DirectoryConfig {
            dir_var: StringType
         },
         create_directory_config
      },
      server {
         ServerConfig {
            enabled: BoolType,
            string_var: StringType
         },
         create_server_config
      }, [
         (FLAG, b"EnabledVar\0", enabled_var, RSRC_CONF, b"Example flag\0"),
         (TAKE1, b"StringVar\0", string_var, RSRC_CONF, b"Example string directive\0"),
         (TAKE1, b"DirVar\0", dir_var, ACCESS_CONF, b"Directory string directive\0")
      ]
   }
);

fn create_server_config<'a>(pool: &mut Pool) -> ServerConfig<'a> {
   let mut config = ServerConfig::new(pool).unwrap();

   config.set_enabled(false);

   config
}

fn create_directory_config<'a>(pool: &mut Pool, _: Option<&'a str>) -> DirectoryConfig<'a> {
   DirectoryConfig::new(pool).unwrap()
}

fn enabled_var(parms: &mut CmdParms, _: Option<DirectoryConfig>, on: bool) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_enabled(on);

   Ok(())
}

fn string_var<'a>(parms: &mut CmdParms, _: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_string_var(w);

   Ok(())
}

fn dir_var<'a>(_: &mut CmdParms, mconfig: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = mconfig.unwrap();

   config.set_dir_var(w);

   Ok(())
}

fn unwrap_str<'a>(wrapped: Result<&'a str, ()>) -> &'a str {
   wrapped.unwrap_or("--")
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "conf" {
      return Ok(Status::DECLINED)
   }

   let server_config = get_server_config(
      &mut try!(r.pool()),
      &try!(try!(r.server()).module_config())
   );

   r.set_content_type("text/plain; charset=utf-8");

   let enabled = try!(server_config.enabled());
   try!(r.write(format!("EnabledVar: {}\n", enabled)));

   let string_var = unwrap_str(server_config.string_var());
   try!(r.write(format!("StringVar: {}\n", string_var)));

   let dir_config = get_dir_config(
      &mut try!(r.pool()),
      &try!(r.per_dir_config())
   );

   let dir_var = unwrap_str(dir_config.dir_var());
   try!(r.write(format!("DirVar: {}\n", dir_var)));

   Ok(Status::OK)
}
<|endoftext|>


<commit_before>fn sort(word: &String) -> String {
    let mut sorted: Vec<char> = word.chars().collect();
    sorted.sort();
    let mut output = String::with_capacity(sorted.len());
    for c in sorted.iter() {
        output.push(*c);
    }
    output
}

pub fn anagrams_for<'a>(word: &str, inputs: &[&'a str]) -> Vec<&'a str> {
    let lower = word.to_lowercase();
    let sorted = sort(&lower);
    let mut anagrams = Vec::new();
    for input in inputs.iter() {
        let input_lower = input.to_lowercase();
        if lower != input_lower {
            if sorted == sort(&input_lower) {
                anagrams.push(*input);
            }
        }
    }
    anagrams
}
<commit_msg>anagram: use filter<commit_after>fn sort(word: &String) -> String {
    let mut sorted: Vec<char> = word.chars().collect();
    sorted.sort();
    let mut output = String::with_capacity(sorted.len());
    for c in sorted.iter() {
        output.push(*c);
    }
    output
}

pub fn anagrams_for<'a>(word: &str, inputs: &[&'a str]) -> Vec<&'a str> {
    let lower = word.to_lowercase();
    let sorted = sort(&lower);
    inputs.iter().filter(|input| {
        let input_lower = input.to_lowercase();
        lower != input_lower && sorted == sort(&input_lower)
    }).cloned().collect()
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Loading and saving TOML-encoded configurations.

use std::path::Path;
use std::io::{Read, Write};
use std::fs::{self, File};
use std::error::Error;

use serde::{Serialize, Deserialize};
use toml;

/// Implements loading and saving TOML-encoded configurations.
#[derive(Debug)]
pub struct ConfigFile {}

impl ConfigFile {
    /// Loads TOML-encoded file.
    pub fn load<P, T>(path: P) -> Result<T, Box<Error>>
    where
        T: for<'r> Deserialize<'r>,
        P: AsRef<Path>,
    {
        let mut file = File::open(path.as_ref())?;
        let mut toml = String::new();
        file.read_to_string(&mut toml)?;
        toml::de::from_str(&toml).map_err(|e| Box::new(e) as Box<Error>)
    }

    /// Saves TOML-encoded file.
    pub fn save<P, T>(value: &T, path: P) -> Result<(), Box<Error>>
    where
        T: Serialize,
        P: AsRef<Path>,
    {
        if let Some(dir) = path.as_ref().parent() {
            fs::create_dir_all(dir)?;
        }

        let mut file = File::create(path.as_ref())?;
        let value_toml = toml::Value::try_from(value)?;
        file.write_all(&format!("{}", value_toml).into_bytes())?;

        Ok(())
    }
}
<commit_msg>Properly handle toml deserialization errors<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Loading and saving TOML-encoded configurations.

use std::path::{Path, PathBuf};
use std::io::{Read, Write};
use std::fs::{self, File};
use std::error::Error;
use std::fmt;

use serde::{Serialize, Deserialize};
use toml;

#[derive(Debug)]
struct DeserializeError {
    path: PathBuf,
    inner: toml::de::Error,
}

impl DeserializeError {
    pub fn new(path: PathBuf, inner: toml::de::Error) -> Self {
        Self { path, inner }
    }
}

impl fmt::Display for DeserializeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Could not read {}: {}", self.path.display(), self.inner)
    }
}

impl Error for DeserializeError {
    fn description(&self) -> &str {
        "Could not read toml config."
    }

    fn cause(&self) -> Option<&Error> {
        Some(&self.inner)
    }
}

/// Implements loading and saving TOML-encoded configurations.
#[derive(Debug)]
pub struct ConfigFile {}

impl ConfigFile {
    /// Loads TOML-encoded file.
    pub fn load<P, T>(path: P) -> Result<T, Box<Error>>
    where
        T: for<'r> Deserialize<'r>,
        P: AsRef<Path>,
    {
        let mut file = File::open(path.as_ref())?;
        let mut toml = String::new();
        file.read_to_string(&mut toml)?;
        toml::de::from_str(&toml).map_err(|e| {
            Box::new(DeserializeError::new(path.as_ref().to_owned(), e)) as Box<Error>
        })
    }

    /// Saves TOML-encoded file.
    pub fn save<P, T>(value: &T, path: P) -> Result<(), Box<Error>>
    where
        T: Serialize,
        P: AsRef<Path>,
    {
        if let Some(dir) = path.as_ref().parent() {
            fs::create_dir_all(dir)?;
        }

        let mut file = File::create(path.as_ref())?;
        let value_toml = toml::Value::try_from(value)?;
        file.write_all(&format!("{}", value_toml).into_bytes())?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Extracts a subsequence of a text document, remembering the mapping of ranges
//! between original and extracted texts.
use std::ops::{self, Sub};

use stdx::equal_range_by;
use syntax::{TextRange, TextSize};

use super::highlights::ordering;

#[derive(Default)]
pub(super) struct Injector {
    buf: String,
    ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
}

impl Injector {
    pub(super) fn add(&mut self, text: &str, source_range: TextRange) {
        let len = TextSize::of(text);
        assert_eq!(len, source_range.len());

        let target_range = TextRange::at(TextSize::of(&self.buf), len);
        self.ranges
            .push((target_range, Some(Delta::new(target_range.start(), source_range.start()))));
        self.buf.push_str(text);
    }
    pub(super) fn add_unmapped(&mut self, text: &str) {
        let len = TextSize::of(text);

        let target_range = TextRange::at(TextSize::of(&self.buf), len);
        self.ranges.push((target_range, None));
        self.buf.push_str(text);
    }

    pub(super) fn text(&self) -> &str {
        &self.buf
    }
    pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
        let (start, len) = equal_range_by(&self.ranges, |&(r, _)| ordering(r, range));
        (start..start + len).filter_map(move |i| {
            let (target_range, delta) = self.ranges[i];
            let intersection = target_range.intersect(range).unwrap();
            Some(intersection + delta?)
        })
    }
}

#[derive(Clone, Copy)]
enum Delta<T> {
    Add(T),
    Sub(T),
}

impl<T> Delta<T> {
    fn new(from: T, to: T) -> Delta<T>
    where
        T: Ord + Sub<Output = T>,
    {
        if to >= from {
            Delta::Add(to - from)
        } else {
            Delta::Sub(from - to)
        }
    }
}

impl ops::Add<Delta<TextSize>> for TextSize {
    type Output = TextSize;

    fn add(self, rhs: Delta<TextSize>) -> TextSize {
        match rhs {
            Delta::Add(it) => self + it,
            Delta::Sub(it) => self - it,
        }
    }
}

impl ops::Add<Delta<TextSize>> for TextRange {
    type Output = TextRange;

    fn add(self, rhs: Delta<TextSize>) -> TextRange {
        TextRange::at(self.start() + rhs, self.len())
    }
}
<commit_msg>Reduce duplication<commit_after>//! Extracts a subsequence of a text document, remembering the mapping of ranges
//! between original and extracted texts.
use std::ops::{self, Sub};

use stdx::equal_range_by;
use syntax::{TextRange, TextSize};

use super::highlights::ordering;

#[derive(Default)]
pub(super) struct Injector {
    buf: String,
    ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
}

impl Injector {
    pub(super) fn add(&mut self, text: &str, source_range: TextRange) {
        let len = TextSize::of(text);
        assert_eq!(len, source_range.len());
        self.add_impl(text, Some(source_range.start()));
    }
    pub(super) fn add_unmapped(&mut self, text: &str) {
        self.add_impl(text, None);
    }
    fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
        let len = TextSize::of(text);
        let target_range = TextRange::at(TextSize::of(&self.buf), len);
        self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it))));
        self.buf.push_str(text);
    }

    pub(super) fn text(&self) -> &str {
        &self.buf
    }
    pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
        let (start, len) = equal_range_by(&self.ranges, |&(r, _)| ordering(r, range));
        (start..start + len).filter_map(move |i| {
            let (target_range, delta) = self.ranges[i];
            let intersection = target_range.intersect(range).unwrap();
            Some(intersection + delta?)
        })
    }
}

#[derive(Clone, Copy)]
enum Delta<T> {
    Add(T),
    Sub(T),
}

impl<T> Delta<T> {
    fn new(from: T, to: T) -> Delta<T>
    where
        T: Ord + Sub<Output = T>,
    {
        if to >= from {
            Delta::Add(to - from)
        } else {
            Delta::Sub(from - to)
        }
    }
}

impl ops::Add<Delta<TextSize>> for TextSize {
    type Output = TextSize;

    fn add(self, rhs: Delta<TextSize>) -> TextSize {
        match rhs {
            Delta::Add(it) => self + it,
            Delta::Sub(it) => self - it,
        }
    }
}

impl ops::Add<Delta<TextSize>> for TextRange {
    type Output = TextRange;

    fn add(self, rhs: Delta<TextSize>) -> TextRange {
        TextRange::at(self.start() + rhs, self.len())
    }
}
<|endoftext|>


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

//! Check license of third-party deps by inspecting src/vendor

use std::collections::{BTreeSet, HashSet};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::process::Command;

use serde_json;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0 rls
];

/// Which crates to check against the whitelist?
static WHITELIST_CRATES: &'static [CrateVersion] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_trans", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
static WHITELIST: &'static [Crate] = &[
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("byteorder"),
    Crate("cc"),
    Crate("cfg-if"),
    Crate("flate2"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("jobserver"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("log"),
    Crate("miniz-sys"),
    Crate("num_cpus"),
    Crate("rand"),
    Crate("rustc"),
    Crate("rustc-demangle"),
    Crate("rustc_trans"),
    Crate("tempdir"),
    Crate("winapi"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-x86_64-pc-windows-gnu"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to...

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name,)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl<'a> Crate<'a> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dep is in-tree
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(" ");
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        if EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception))
        }) {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check
/// failed.
///
/// Specifically, this checks that the dependencies are on the WHITELIST.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from cargo metadata
    let resolve = get_deps(path, cargo);

    // Get the whitelist into a convenient form
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate);
        unapproved.append(&mut bad);
    }

    if unapproved.len() > 0 {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Get the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a, 'b>(
    whitelist: &'a HashSet<Crate>,
    resolve: &'a Resolve,
    visited: &'b mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
) -> BTreeSet<Crate<'a>> {
    // Will contain bad deps
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this dependency is not on the WHITELIST, add to bad set
    if !whitelist.contains(&krate.into()) {
        unapproved.insert(krate.into());
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!)
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        // We don't check in-tree deps
        if !is_path_dep {
            let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate);
            unapproved.append(&mut bad);
        }
    }

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

//! Check license of third-party deps by inspecting src/vendor

use std::collections::{BTreeSet, HashSet};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::process::Command;

use serde_json;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0 rls
];

/// Which crates to check against the whitelist?
static WHITELIST_CRATES: &'static [CrateVersion] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_trans", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
static WHITELIST: &'static [Crate] = &[
//    Crate("ar"),
//    Crate("backtrace"),
//    Crate("backtrace-sys"),
//    Crate("bitflags"),
//    Crate("byteorder"),
//    Crate("cc"),
//    Crate("cfg-if"),
//    Crate("cmake"),
//    Crate("filetime"),
//    Crate("flate2"),
//    Crate("fuchsia-zircon"),
//    Crate("fuchsia-zircon-sys"),
//    Crate("jobserver"),
//    Crate("kernel32-sys"),
//    Crate("lazy_static"),
//    Crate("libc"),
//    Crate("log"),
//    Crate("log_settings"),
//    Crate("miniz-sys"),
//    Crate("num_cpus"),
//    Crate("owning_ref"),
//    Crate("parking_lot"),
//    Crate("parking_lot_core"),
//    Crate("rand"),
//    Crate("redox_syscall"),
//    Crate("rustc-demangle"),
//    Crate("smallvec"),
//    Crate("stable_deref_trait"),
//    Crate("tempdir"),
//    Crate("unicode-width"),
//    Crate("winapi"),
//    Crate("winapi-build"),
//    Crate("winapi-i686-pc-windows-gnu"),
//    Crate("winapi-x86_64-pc-windows-gnu"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to...

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name,)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl<'a> Crate<'a> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dep is in-tree
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(" ");
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        if EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception))
        }) {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check
/// failed.
///
/// Specifically, this checks that the dependencies are on the WHITELIST.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from cargo metadata
    let resolve = get_deps(path, cargo);

    // Get the whitelist into a convenient form
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if unapproved.len() > 0 {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Get the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a, 'b>(
    whitelist: &'a HashSet<Crate>,
    resolve: &'a Resolve,
    visited: &'b mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // Will contain bad deps
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist
    if must_be_on_whitelist {
        // If this dependency is not on the WHITELIST, add to bad set
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!)
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::result;
use std::fmt::{self, Display};
use std::error::{self, Error as CpuidError};

use kvm;
use sys_util;

// Query the CPU vendor.  ebx/ecx/edx pack an ASCII string into these 3 regs
// in little endian format.  We set to "CrOSVMBestVM".
// https://en.wikipedia.org/wiki/CPUID#EAX=0:_Get_vendor_ID_(including_EAX=1:_Get_CPUID)
const VENDOR_EBX_VAL: u32 = 0x4d567473;  // MVts
const VENDOR_ECX_VAL: u32 = 0x65424d56;  // eBMV
const VENDOR_EDX_VAL: u32 = 0x534f7243;  // SOrC

#[derive(Debug, PartialEq)]
pub enum Error {
    GetSupportedCpusFailed(sys_util::Error),
    SetSupportedCpusFailed(sys_util::Error),
}
pub type Result<T> = result::Result<T, Error>;

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::GetSupportedCpusFailed(_) =>
                "GetSupportedCpus ioctl failed",
            &Error::SetSupportedCpusFailed(_) =>
                "SetSupportedCpus ioctl failed",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CPUID Error: {}", Error::description(self))
    }
}

// CPUID bits in ebx, ecx, and edx.
const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.
const EBX_CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
const EBX_CPU_COUNT_SHIFT: u32 = 16; // Index of this CPU.
const EBX_CPUID_SHIFT: u32 = 24; // Index of this CPU.
const ECX_EPB_SHIFT: u32 = 3; // "Energy Performance Bias" bit.
const ECX_HYPERVISOR_SHIFT: u32 = 31; // Flag to be set when the cpu is running on a hypervisor.
const EDX_HTT_SHIFT: u32 = 28; // Hyper Threading Enabled.

fn filter_cpuid(cpu_id: u64, cpu_count: u64, kvm_cpuid: &mut kvm::CpuId) -> Result<()> {
    let entries = kvm_cpuid.mut_entries_slice();

    for entry in entries.iter_mut() {
        match entry.function {
            0 => {
                // Vendor name.
                entry.ebx = VENDOR_EBX_VAL;
                entry.ecx = VENDOR_ECX_VAL;
                entry.edx = VENDOR_EDX_VAL;
            }
            1 => {
                // X86 hypervisor feature
                if entry.index == 0 {
                    entry.ecx |= 1 << ECX_HYPERVISOR_SHIFT;
                }
                entry.ebx = (cpu_id << EBX_CPUID_SHIFT) as u32 |
                            (EBX_CLFLUSH_CACHELINE << EBX_CLFLUSH_SIZE_SHIFT);
                if cpu_count > 1 {
                    entry.ebx |= (cpu_count as u32) << EBX_CPU_COUNT_SHIFT;
                    entry.edx |= 1 << EDX_HTT_SHIFT;
                }
            }
            6 => {
                // Clear X86 EPB feature.  No frequency selection in the hypervisor.
                entry.ecx &= !(1 << ECX_EPB_SHIFT);
            }
            _ => (),
        }
    }

    Ok(())
}

/// Sets up the cpuid entries for the given vcpu.  Can fail if there are too many CPUs specified or
/// if an ioctl returns an error.
///
/// # Arguments
///
/// * `kvm` - `Kvm` structure created with KVM_CREATE_VM ioctl.
/// * `vcpu` - `Vcpu` for setting CPU ID.
/// * `cpu_id` - The index of the CPU `vcpu` is for.
/// * `nrcpus` - The number of vcpus being used by this VM.
pub fn setup_cpuid(kvm: &kvm::Kvm, vcpu: &kvm::Vcpu, cpu_id: u64, nrcpus: u64) -> Result<()> {
    let mut kvm_cpuid = kvm.get_supported_cpuid()
        .map_err(Error::GetSupportedCpusFailed)?;

    filter_cpuid(cpu_id, nrcpus, &mut kvm_cpuid)?;

    vcpu.set_cpuid2(&kvm_cpuid)
        .map_err(Error::SetSupportedCpusFailed)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn feature_and_vendor_name() {
        let mut cpuid = kvm::CpuId::new(2);

        {
            let entries = cpuid.mut_entries_slice();
            entries[0].function = 0;
            entries[1].function = 1;
            entries[1].ecx = 0x10;
            entries[1].edx = 0;
        }
        assert_eq!(Ok(()), filter_cpuid(1, 2, &mut cpuid));
        {
            let entries = cpuid.mut_entries_slice();
            assert_eq!(entries[0].function, 0);
            assert_eq!(entries[0].ebx, VENDOR_EBX_VAL);
            assert_eq!(entries[0].ecx, VENDOR_ECX_VAL);
            assert_eq!(entries[0].edx, VENDOR_EDX_VAL);
            assert_eq!(1, (entries[1].ebx >> EBX_CPUID_SHIFT) & 0x000000ff);
            assert_eq!(2, (entries[1].ebx >> EBX_CPU_COUNT_SHIFT) & 0x000000ff);
            assert_eq!(EBX_CLFLUSH_CACHELINE,
                       (entries[1].ebx >> EBX_CLFLUSH_SIZE_SHIFT) & 0x000000ff);
            assert_ne!(0, entries[1].ecx & (1 << ECX_HYPERVISOR_SHIFT));
            assert_ne!(0, entries[1].edx & (1 << EDX_HTT_SHIFT));
        }
    }
}
<commit_msg>x86_64: use project name in cpuid vendor<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::result;
use std::fmt::{self, Display};
use std::error::{self, Error as CpuidError};

use kvm;
use sys_util;

// Query the CPU vendor.  ebx/ecx/edx pack an ASCII string into these 3 regs
// in little endian format.  We set to "crosvmBestVM".
// https://en.wikipedia.org/wiki/CPUID#EAX=0:_Get_vendor_ID_(including_EAX=1:_Get_CPUID)
const VENDOR_EBX_VAL: u32 = 0x736f7263;  // sorc
const VENDOR_ECX_VAL: u32 = 0x4d567473;  // MVts
const VENDOR_EDX_VAL: u32 = 0x65426d76;  // eBmv

#[derive(Debug, PartialEq)]
pub enum Error {
    GetSupportedCpusFailed(sys_util::Error),
    SetSupportedCpusFailed(sys_util::Error),
}
pub type Result<T> = result::Result<T, Error>;

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::GetSupportedCpusFailed(_) =>
                "GetSupportedCpus ioctl failed",
            &Error::SetSupportedCpusFailed(_) =>
                "SetSupportedCpus ioctl failed",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CPUID Error: {}", Error::description(self))
    }
}

// CPUID bits in ebx, ecx, and edx.
const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.
const EBX_CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
const EBX_CPU_COUNT_SHIFT: u32 = 16; // Index of this CPU.
const EBX_CPUID_SHIFT: u32 = 24; // Index of this CPU.
const ECX_EPB_SHIFT: u32 = 3; // "Energy Performance Bias" bit.
const ECX_HYPERVISOR_SHIFT: u32 = 31; // Flag to be set when the cpu is running on a hypervisor.
const EDX_HTT_SHIFT: u32 = 28; // Hyper Threading Enabled.

fn filter_cpuid(cpu_id: u64, cpu_count: u64, kvm_cpuid: &mut kvm::CpuId) -> Result<()> {
    let entries = kvm_cpuid.mut_entries_slice();

    for entry in entries.iter_mut() {
        match entry.function {
            0 => {
                // Vendor name.
                entry.ebx = VENDOR_EBX_VAL;
                entry.ecx = VENDOR_ECX_VAL;
                entry.edx = VENDOR_EDX_VAL;
            }
            1 => {
                // X86 hypervisor feature
                if entry.index == 0 {
                    entry.ecx |= 1 << ECX_HYPERVISOR_SHIFT;
                }
                entry.ebx = (cpu_id << EBX_CPUID_SHIFT) as u32 |
                            (EBX_CLFLUSH_CACHELINE << EBX_CLFLUSH_SIZE_SHIFT);
                if cpu_count > 1 {
                    entry.ebx |= (cpu_count as u32) << EBX_CPU_COUNT_SHIFT;
                    entry.edx |= 1 << EDX_HTT_SHIFT;
                }
            }
            6 => {
                // Clear X86 EPB feature.  No frequency selection in the hypervisor.
                entry.ecx &= !(1 << ECX_EPB_SHIFT);
            }
            _ => (),
        }
    }

    Ok(())
}

/// Sets up the cpuid entries for the given vcpu.  Can fail if there are too many CPUs specified or
/// if an ioctl returns an error.
///
/// # Arguments
///
/// * `kvm` - `Kvm` structure created with KVM_CREATE_VM ioctl.
/// * `vcpu` - `Vcpu` for setting CPU ID.
/// * `cpu_id` - The index of the CPU `vcpu` is for.
/// * `nrcpus` - The number of vcpus being used by this VM.
pub fn setup_cpuid(kvm: &kvm::Kvm, vcpu: &kvm::Vcpu, cpu_id: u64, nrcpus: u64) -> Result<()> {
    let mut kvm_cpuid = kvm.get_supported_cpuid()
        .map_err(Error::GetSupportedCpusFailed)?;

    filter_cpuid(cpu_id, nrcpus, &mut kvm_cpuid)?;

    vcpu.set_cpuid2(&kvm_cpuid)
        .map_err(Error::SetSupportedCpusFailed)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn feature_and_vendor_name() {
        let mut cpuid = kvm::CpuId::new(2);

        {
            let entries = cpuid.mut_entries_slice();
            entries[0].function = 0;
            entries[1].function = 1;
            entries[1].ecx = 0x10;
            entries[1].edx = 0;
        }
        assert_eq!(Ok(()), filter_cpuid(1, 2, &mut cpuid));
        {
            let entries = cpuid.mut_entries_slice();
            assert_eq!(entries[0].function, 0);
            assert_eq!(entries[0].ebx, VENDOR_EBX_VAL);
            assert_eq!(entries[0].ecx, VENDOR_ECX_VAL);
            assert_eq!(entries[0].edx, VENDOR_EDX_VAL);
            assert_eq!(1, (entries[1].ebx >> EBX_CPUID_SHIFT) & 0x000000ff);
            assert_eq!(2, (entries[1].ebx >> EBX_CPU_COUNT_SHIFT) & 0x000000ff);
            assert_eq!(EBX_CLFLUSH_CACHELINE,
                       (entries[1].ebx >> EBX_CLFLUSH_SIZE_SHIFT) & 0x000000ff);
            assert_ne!(0, entries[1].ecx & (1 << ECX_HYPERVISOR_SHIFT));
            assert_ne!(0, entries[1].edx & (1 << EDX_HTT_SHIFT));
        }
    }
}
<|endoftext|>