diff --git a/src/asns.rs b/src/asns.rs index 5196b79..6a63d48 100644 --- a/src/asns.rs +++ b/src/asns.rs @@ -2,7 +2,7 @@ use flate2::read::GzDecoder; use hyper::net::HttpsConnector; use hyper::{self, Client}; use hyper_native_tls::NativeTlsClient; -use std::cmp::{Eq, PartialOrd, PartialEq, Ord, Ordering}; +use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use std::collections::Bound::{Included, Unbounded}; use std::collections::BTreeSet; use std::io::prelude::*; diff --git a/src/main.rs b/src/main.rs index 00c65f6..27f93ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,25 +1,25 @@ -#![cfg_attr(feature="clippy", feature(plugin))] -#![cfg_attr(feature="clippy", plugin(clippy))] +#![cfg_attr(feature = "clippy", feature(plugin))] +#![cfg_attr(feature = "clippy", plugin(clippy))] extern crate clap; extern crate flate2; -extern crate iron; -#[macro_use] -extern crate router; #[macro_use] extern crate horrorshow; extern crate hyper; extern crate hyper_native_tls; -extern crate serde; -extern crate serde_json; +extern crate iron; #[macro_use] extern crate log; +#[macro_use] +extern crate router; +extern crate serde; +extern crate serde_json; mod asns; mod webservice; use asns::*; -use clap::{Arg, App}; +use clap::{App, Arg}; use std::sync::{Arc, RwLock}; use std::thread; use std::time::Duration; @@ -48,20 +48,24 @@ fn main() { .version("0.2.0") .author("Frank Denis") .about("Webservice for https://iptoasn.com") - .arg(Arg::with_name("listen_addr") - .short("l") - .long("listen") - .value_name("ip:port") - .help("Webservice IP and port") - .takes_value(true) - .default_value("0.0.0.0:53661")) - .arg(Arg::with_name("db_url") - .short("u") - .long("dburl") - .value_name("url") - .help("URL of the gzipped database") - .takes_value(true) - .default_value("https://iptoasn.com/data/ip2asn-combined.tsv.gz")) + .arg( + Arg::with_name("listen_addr") + .short("l") + .long("listen") + .value_name("ip:port") + .help("Webservice IP and port") + .takes_value(true) + .default_value("0.0.0.0:53661"), + ) + .arg( + Arg::with_name("db_url") + .short("u") + .long("dburl") + .value_name("url") + .help("URL of the gzipped database") + .takes_value(true) + .default_value("https://iptoasn.com/data/ip2asn-combined.tsv.gz"), + ) .get_matches(); let db_url = matches.value_of("db_url").unwrap().to_owned(); let listen_addr = matches.value_of("listen_addr").unwrap(); @@ -69,9 +73,9 @@ fn main() { let asns_arc = Arc::new(RwLock::new(Arc::new(asns))); let asns_arc_copy = asns_arc.clone(); thread::spawn(move || loop { - thread::sleep(Duration::from_secs(3600)); - update_asns(&asns_arc_copy, &db_url); - }); + thread::sleep(Duration::from_secs(3600)); + update_asns(&asns_arc_copy, &db_url); + }); info!("Starting the webservice"); WebService::start(asns_arc, listen_addr); } diff --git a/src/webservice.rs b/src/webservice.rs index 535a025..e9e839f 100644 --- a/src/webservice.rs +++ b/src/webservice.rs @@ -1,7 +1,7 @@ use asns::*; use horrorshow::prelude::*; -use iron::{BeforeMiddleware, typemap}; -use iron::headers::{CacheControl, CacheDirective, Accept}; +use iron::{typemap, BeforeMiddleware}; +use iron::headers::{Accept, CacheControl, CacheDirective}; use iron::mime::*; use iron::modifiers::Header; use iron::prelude::*; @@ -45,13 +45,18 @@ pub struct WebService; impl WebService { fn index(_: &mut Request) -> IronResult { - Ok(Response::with((status::Ok, - Mime(TopLevel::Text, - SubLevel::Plain, - vec![(Attr::Charset, Value::Utf8)]), - Header(CacheControl(vec![CacheDirective::Public, - CacheDirective::MaxAge(TTL)])), - "See https://iptoasn.com"))) + Ok(Response::with(( + status::Ok, + Mime( + TopLevel::Text, + SubLevel::Plain, + vec![(Attr::Charset, Value::Utf8)], + ), + Header(CacheControl( + vec![CacheDirective::Public, CacheDirective::MaxAge(TTL)], + )), + "See https://iptoasn.com", + ))) } fn accept_type(req: &Request) -> OutputType { @@ -74,22 +79,28 @@ impl WebService { output_type } - fn output_json(map: serde_json::Map, - cache_header: Header) - -> IronResult { + fn output_json( + map: serde_json::Map, + cache_header: Header, + ) -> IronResult { let json = serde_json::to_string(&map).unwrap(); - let mime_json = Mime(TopLevel::Application, - SubLevel::Json, - vec![(Attr::Charset, Value::Utf8)]); + let mime_json = Mime( + TopLevel::Application, + SubLevel::Json, + vec![(Attr::Charset, Value::Utf8)], + ); Ok(Response::with((status::Ok, mime_json, cache_header, json))) } - fn output_html(map: serde_json::Map, - cache_header: Header) - -> IronResult { - let mime_html = Mime(TopLevel::Text, - SubLevel::Html, - vec![(Attr::Charset, Value::Utf8)]); + fn output_html( + map: serde_json::Map, + cache_header: Header, + ) -> IronResult { + let mime_html = Mime( + TopLevel::Text, + SubLevel::Html, + vec![(Attr::Charset, Value::Utf8)], + ); let html = html!{ head { title { : "iptoasn lookup" } @@ -145,10 +156,11 @@ impl WebService { Ok(Response::with((status::Ok, mime_html, cache_header, html))) } - fn output(output_type: OutputType, - map: serde_json::Map, - cache_header: Header) - -> IronResult { + fn output( + output_type: OutputType, + map: serde_json::Map, + cache_header: Header, + ) -> IronResult { match output_type { OutputType::Json => Self::output_json(map, cache_header), _ => Self::output_html(map, cache_header), @@ -156,54 +168,77 @@ impl WebService { } fn ip_lookup(req: &mut Request) -> IronResult { - let mime_text = Mime(TopLevel::Text, - SubLevel::Plain, - vec![(Attr::Charset, Value::Utf8)]); - let cache_header = Header(CacheControl(vec![CacheDirective::Public, - CacheDirective::MaxAge(TTL)])); + let mime_text = Mime( + TopLevel::Text, + SubLevel::Plain, + vec![(Attr::Charset, Value::Utf8)], + ); + let cache_header = Header(CacheControl( + vec![CacheDirective::Public, CacheDirective::MaxAge(TTL)], + )); let ip_str = match req.extensions.get::().unwrap().find("ip") { None => { - let response = Response::with((status::BadRequest, - mime_text, - cache_header, - "Missing IP address")); + let response = Response::with(( + status::BadRequest, + mime_text, + cache_header, + "Missing IP address", + )); return Ok(response); } Some(ip_str) => ip_str, }; let ip = match IpAddr::from_str(ip_str) { Err(_) => { - return Ok(Response::with((status::BadRequest, - mime_text, - cache_header, - "Invalid IP address"))); + return Ok(Response::with(( + status::BadRequest, + mime_text, + cache_header, + "Invalid IP address", + ))); } Ok(ip) => ip, }; let asns = req.extensions.get::().unwrap(); let mut map = serde_json::Map::new(); - map.insert("ip".to_string(), - serde_json::value::Value::String(ip_str.to_string())); + map.insert( + "ip".to_string(), + serde_json::value::Value::String(ip_str.to_string()), + ); let found = match asns.lookup_by_ip(ip) { None => { - map.insert("announced".to_string(), - serde_json::value::Value::Bool(false)); + map.insert( + "announced".to_string(), + serde_json::value::Value::Bool(false), + ); return Self::output(Self::accept_type(&req), map, cache_header); } Some(found) => found, }; - map.insert("announced".to_string(), - serde_json::value::Value::Bool(true)); - map.insert("first_ip".to_string(), - serde_json::value::Value::String(found.first_ip.to_string())); - map.insert("last_ip".to_string(), - serde_json::value::Value::String(found.last_ip.to_string())); - map.insert("as_number".to_string(), - serde_json::value::Value::Number(serde_json::Number::from(found.number))); - map.insert("as_country_code".to_string(), - serde_json::value::Value::String(found.country.clone())); - map.insert("as_description".to_string(), - serde_json::value::Value::String(found.description.clone())); + map.insert( + "announced".to_string(), + serde_json::value::Value::Bool(true), + ); + map.insert( + "first_ip".to_string(), + serde_json::value::Value::String(found.first_ip.to_string()), + ); + map.insert( + "last_ip".to_string(), + serde_json::value::Value::String(found.last_ip.to_string()), + ); + map.insert( + "as_number".to_string(), + serde_json::value::Value::Number(serde_json::Number::from(found.number)), + ); + map.insert( + "as_country_code".to_string(), + serde_json::value::Value::String(found.country.clone()), + ); + map.insert( + "as_description".to_string(), + serde_json::value::Value::String(found.description.clone()), + ); Self::output(Self::accept_type(&req), map, cache_header) }