Skip to content

Commit

Permalink
Always close connections
Browse files Browse the repository at this point in the history
This is a workaround for a hyper bug:
hyperium/hyper#658
  • Loading branch information
brianloveswords committed Sep 29, 2015
1 parent ee837d7 commit f5b8e6b
Showing 1 changed file with 68 additions and 76 deletions.
144 changes: 68 additions & 76 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use deployer::repo_config::RepoConfig;
use deployer::signature::Signature;
use deployer::task_manager::{TaskManager, Runnable};
use iron::status;
use iron::{Iron, Request, Response, IronResult};
use iron::{Iron, Request, Response};
use iron::headers::Connection;
use iron::modifiers::Header;
use router::{Router};
use std::io::Read;
use std::path::Path;
Expand Down Expand Up @@ -68,22 +70,13 @@ header! { (XSignature, "X-Signature") => [String] }

fn main() {
let mut router = Router::new();
// let global_manager = Arc::new(Mutex::new(TaskManager::new()));
let global_manager = Arc::new(Mutex::new(TaskManager::new()));

router.post("/ping", move |req: &mut Request| {
let task_id = Uuid::new_v4();
println!("[{}]: request received, processing", task_id);
println!("[{}]: loading body into string", task_id);
let mut payload = String::new();
if req.body.read_to_string(&mut payload).is_err() {
println!("[{}]: could not read body into string", task_id);
return Ok(Response::with((status::InternalServerError)))
}
println!("[{}]: done, responding", task_id);
Ok(Response::with((status::Ok, "pong")))
router.get("/health", move |_: &mut Request| {
Ok(Response::with((Header(Connection::close()), status::Ok, "okay")))
});

// let shared_manager = global_manager.clone();
let shared_manager = global_manager.clone();
router.post("/hookshot", move |req: &mut Request| {
let task_id = Uuid::new_v4();
println!("[{}]: request received, processing", task_id);
Expand All @@ -92,84 +85,83 @@ fn main() {
let mut payload = String::new();
if req.body.read_to_string(&mut payload).is_err() {
println!("[{}]: could not read body into string", task_id);
return Ok(Response::with((status::InternalServerError)))
return Ok(Response::with((Header(Connection::close()), status::InternalServerError)))
}

// Get the signature from the header. We support both `X-Hub-Signature` and
// `X-Signature` but they both represent the same type underneath, a
// string. It might eventually be better to put this functionality on the
// Signature type itself.
// println!("[{}]: looking up signature", task_id);
// let signature = {
// let possible_headers = (req.headers.get::<XSignature>(), req.headers.get::<XHubSignature>());

// let signature_string = match possible_headers {
// (Some(h), None) => h.to_string(),
// (None, Some(h)) => h.to_string(),
// (None, None) => {
// println!("[{}]: missing signature", task_id);
// return Ok(Response::with((status::Unauthorized, "missing signature")))
// },
// (Some(_), Some(_)) =>{
// println!("[{}]: too many signatures", task_id);
// return Ok(Response::with((status::Unauthorized, "too many signatures")))
// },
// };

// match Signature::from(signature_string) {
// Some(signature) => signature,
// None => {
// println!("[{}]: could not parse signature", task_id);
// return Ok(Response::with((status::Unauthorized, "could not parse signature")))
// },
// }
// };
println!("[{}]: looking up signature", task_id);
let signature = {
let possible_headers = (req.headers.get::<XSignature>(), req.headers.get::<XHubSignature>());

let signature_string = match possible_headers {
(Some(h), None) => h.to_string(),
(None, Some(h)) => h.to_string(),
(None, None) => {
println!("[{}]: missing signature", task_id);
return Ok(Response::with((Header(Connection::close()), status::Unauthorized, "missing signature")))
},
(Some(_), Some(_)) =>{
println!("[{}]: too many signatures", task_id);
return Ok(Response::with((Header(Connection::close()), status::Unauthorized, "too many signatures")))
},
};

match Signature::from(signature_string) {
Some(signature) => signature,
None => {
println!("[{}]: could not parse signature", task_id);
return Ok(Response::with((Header(Connection::close()), status::Unauthorized, "could not parse signature")))
},
}
};

// Bail out if the signature doesn't match what we're expecting.
// TODO: don't hardcode this secret, pull from `deployer` configuration
// println!("[{}]: signature found, verifying", task_id);
// if signature.verify(&payload, HMAC_KEY) == false {
// println!("[{}]: signature mismatch", task_id);
// return Ok(Response::with((status::Unauthorized, "signature doesn't match")))
// }
println!("[{}]: signature found, verifying", task_id);
if signature.verify(&payload, HMAC_KEY) == false {
println!("[{}]: signature mismatch", task_id);
return Ok(Response::with((Header(Connection::close()), status::Unauthorized, "signature doesn't match")))
}

// Try to parse the message.
// TODO: we can be smarter about this. If we see the XHubSignature above, we
// should try to parse as a github message, otherwise go simple message.
// println!("[{}]: attempting to parse message from payload", task_id);
// let repo = match SimpleMessage::from(&payload) {
// Ok(message) => GitRepo::from(message, CHECKOUT_ROOT),
// Err(_) => match GitHubMessage::from(&payload) {
// Ok(message) => GitRepo::from(message, CHECKOUT_ROOT),
// Err(_) => {
// println!("[{}]: could not parse message", task_id);
// return Ok(Response::with((status::BadRequest, "could not parse message")))
// },
// },
// };

// let task = DeployTask { repo: repo, id: task_id };
// println!("[{}]: acquiring task manager lock", task_id);
// {
// let mut task_manager = shared_manager.lock().unwrap();
// let key = task_manager.ensure_queue(task.repo.branch.clone());

// println!("[{}]: attempting to schedule", task_id);
// match task_manager.add_task(&key, task) {
// Ok(_) => println!("[{}]: scheduled", task_id),
// Err(_) => {
// println!("[{}]: could not add task to queue", task_id);
// return Ok(Response::with((status::ServiceUnavailable)))
// },
// };
// }
// println!("[{}]: releasing task manager lock", task_id);
println!("[{}]: attempting to parse message from payload", task_id);
let repo = match SimpleMessage::from(&payload) {
Ok(message) => GitRepo::from(message, CHECKOUT_ROOT),
Err(_) => match GitHubMessage::from(&payload) {
Ok(message) => GitRepo::from(message, CHECKOUT_ROOT),
Err(_) => {
println!("[{}]: could not parse message", task_id);
return Ok(Response::with((Header(Connection::close()), status::BadRequest, "could not parse message")))
},
},
};

let task = DeployTask { repo: repo, id: task_id };
println!("[{}]: acquiring task manager lock", task_id);
{
let mut task_manager = shared_manager.lock().unwrap();
let key = task_manager.ensure_queue(task.repo.branch.clone());

println!("[{}]: attempting to schedule", task_id);
match task_manager.add_task(&key, task) {
Ok(_) => println!("[{}]: scheduled", task_id),
Err(_) => {
println!("[{}]: could not add task to queue", task_id);
return Ok(Response::with((Header(Connection::close()), status::ServiceUnavailable)))
},
};
}
println!("[{}]: releasing task manager lock", task_id);
println!("[{}]: request complete", task_id);
Ok(Response::with((status::Ok, task_id.to_string())))
Ok(Response::with((Header(Connection::close()), status::Ok, task_id.to_string())))
});

println!("listening on port 4200");

// This will block until the server is shut down.
Iron::new(router).http("0.0.0.0:4200").unwrap();
global_manager.lock().unwrap().shutdown();
}

0 comments on commit f5b8e6b

Please sign in to comment.