Add the ability to return a super basic HTML page
This commit is contained in:
parent
ef3a57328e
commit
f7d8e46752
|
@ -5,6 +5,7 @@ dependencies = [
|
||||||
"clap 2.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clippy 0.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"horrorshow 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"iron 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"iron 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -142,6 +143,11 @@ dependencies = [
|
||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "horrorshow"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hpack"
|
name = "hpack"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -742,6 +748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb"
|
"checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb"
|
||||||
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
|
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
|
||||||
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
|
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
|
||||||
|
"checksum horrorshow 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "234628f89d562b0ad97069e3f808cf109d0ed51b71a7825bfa6d32f317569543"
|
||||||
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
|
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
|
||||||
"checksum httparse 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8abece705b1d32c478f49447b3a575cd07f6e362ff12518f2ee2c9b9ced64e"
|
"checksum httparse 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8abece705b1d32c478f49447b3a575cd07f6e362ff12518f2ee2c9b9ced64e"
|
||||||
"checksum hyper 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "d7da01615e9402761faab442396821b57ecb5adb12ac51958561411a82cfdf66"
|
"checksum hyper 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "d7da01615e9402761faab442396821b57ecb5adb12ac51958561411a82cfdf66"
|
||||||
|
|
|
@ -6,6 +6,7 @@ authors = ["Frank Denis <github@pureftpd.org>"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "*"
|
clap = "*"
|
||||||
flate2 = "*"
|
flate2 = "*"
|
||||||
|
horrorshow = "*"
|
||||||
hyper = "*"
|
hyper = "*"
|
||||||
iron = "*"
|
iron = "*"
|
||||||
log = "*"
|
log = "*"
|
||||||
|
|
|
@ -7,6 +7,8 @@ extern crate flate2;
|
||||||
extern crate iron;
|
extern crate iron;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate router;
|
extern crate router;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate horrorshow;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use asns::*;
|
use asns::*;
|
||||||
|
use horrorshow::prelude::*;
|
||||||
use iron::{BeforeMiddleware, typemap};
|
use iron::{BeforeMiddleware, typemap};
|
||||||
use iron::headers::{CacheControl, CacheDirective};
|
use iron::headers::{CacheControl, CacheDirective, Accept};
|
||||||
use iron::mime::*;
|
use iron::mime::*;
|
||||||
use iron::modifiers::Header;
|
use iron::modifiers::Header;
|
||||||
use iron::prelude::*;
|
use iron::prelude::*;
|
||||||
|
@ -34,6 +35,11 @@ impl BeforeMiddleware for ASNsMiddleware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum OutputType {
|
||||||
|
Json,
|
||||||
|
Html,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WebService;
|
pub struct WebService;
|
||||||
|
|
||||||
impl WebService {
|
impl WebService {
|
||||||
|
@ -47,13 +53,116 @@ impl WebService {
|
||||||
"See https://iptoasn.com")))
|
"See https://iptoasn.com")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn accept_type(req: &Request) -> OutputType {
|
||||||
|
let mut output_type = OutputType::Json;
|
||||||
|
if let Some(header_accept) = req.headers.get::<Accept>() {
|
||||||
|
for header in header_accept.iter() {
|
||||||
|
match header.item {
|
||||||
|
Mime(TopLevel::Text, SubLevel::Html, _) => {
|
||||||
|
output_type = OutputType::Html;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Mime(_, SubLevel::Json, _) => {
|
||||||
|
output_type = OutputType::Json;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output_type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_json(_ip_str: &str,
|
||||||
|
map: serde_json::Map<&'static str, serde_json::value::Value>,
|
||||||
|
cache_header: Header<CacheControl>)
|
||||||
|
-> IronResult<Response> {
|
||||||
|
let json = serde_json::to_string(&map).unwrap();
|
||||||
|
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(ip_str: &str,
|
||||||
|
map: serde_json::Map<&'static str, serde_json::value::Value>,
|
||||||
|
cache_header: Header<CacheControl>)
|
||||||
|
-> IronResult<Response> {
|
||||||
|
let mime_html = Mime(TopLevel::Text,
|
||||||
|
SubLevel::Html,
|
||||||
|
vec![(Attr::Charset, Value::Utf8)]);
|
||||||
|
let html = html!{
|
||||||
|
head {
|
||||||
|
title { : "iptoasn lookup" }
|
||||||
|
meta(name="viewport", content="width=device-widthinitial-scale=1") { }
|
||||||
|
link(rel="stylesheet", href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css", integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi", crossorigin="anonymous") { }
|
||||||
|
style {
|
||||||
|
: "body { margin: 1em 4em }"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body(class="container-fluid") {
|
||||||
|
header {
|
||||||
|
h1 {
|
||||||
|
: format_args!("Information for IP address: {}", ip_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
tr {
|
||||||
|
th { : "Announced" }
|
||||||
|
td { : format_args!("{}", map.get("announced")
|
||||||
|
.unwrap().as_bool().unwrap() ) }
|
||||||
|
}
|
||||||
|
@ if map.get("announced").unwrap().as_bool().unwrap() == true {
|
||||||
|
tr {
|
||||||
|
th { : "First IP" }
|
||||||
|
td { : format_args!("{}", map.get("first_ip")
|
||||||
|
.unwrap().as_str().unwrap() )}
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { : "Last IP" }
|
||||||
|
td { : format_args!("{}", map.get("last_ip")
|
||||||
|
.unwrap().as_str().unwrap() )}
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { : "AS Number" }
|
||||||
|
td { : format_args!("{}", map.get("as_number")
|
||||||
|
.unwrap().as_u64().unwrap() )}
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { : "AS Country code" }
|
||||||
|
td { : format_args!("{}", map.get("as_country_code")
|
||||||
|
.unwrap().as_str().unwrap() )}
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
th { : "AS Description" }
|
||||||
|
td { : format_args!("{}", map.get("as_description")
|
||||||
|
.unwrap().as_str().unwrap() )}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into_string()
|
||||||
|
.unwrap();
|
||||||
|
let html = format!("<!doctype html>\n<html>\n{}</html>", html);
|
||||||
|
Ok(Response::with((status::Ok, mime_html, cache_header, html)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(output_type: OutputType,
|
||||||
|
ip_str: &str,
|
||||||
|
map: serde_json::Map<&'static str, serde_json::value::Value>,
|
||||||
|
cache_header: Header<CacheControl>)
|
||||||
|
-> IronResult<Response> {
|
||||||
|
match output_type {
|
||||||
|
OutputType::Json => Self::output_json(ip_str, map, cache_header),
|
||||||
|
_ => Self::output_html(ip_str, map, cache_header),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ip_lookup(req: &mut Request) -> IronResult<Response> {
|
fn ip_lookup(req: &mut Request) -> IronResult<Response> {
|
||||||
let mime_text = Mime(TopLevel::Text,
|
let mime_text = Mime(TopLevel::Text,
|
||||||
SubLevel::Plain,
|
SubLevel::Plain,
|
||||||
vec![(Attr::Charset, Value::Utf8)]);
|
vec![(Attr::Charset, Value::Utf8)]);
|
||||||
let mime_json = Mime(TopLevel::Application,
|
|
||||||
SubLevel::Json,
|
|
||||||
vec![(Attr::Charset, Value::Utf8)]);
|
|
||||||
let cache_header = Header(CacheControl(vec![CacheDirective::Public,
|
let cache_header = Header(CacheControl(vec![CacheDirective::Public,
|
||||||
CacheDirective::MaxAge(TTL)]));
|
CacheDirective::MaxAge(TTL)]));
|
||||||
let ip_str = match req.extensions.get::<Router>().unwrap().find("ip") {
|
let ip_str = match req.extensions.get::<Router>().unwrap().find("ip") {
|
||||||
|
@ -80,8 +189,7 @@ impl WebService {
|
||||||
None => {
|
None => {
|
||||||
let mut map = serde_json::Map::new();
|
let mut map = serde_json::Map::new();
|
||||||
map.insert("announced", serde_json::value::Value::Bool(false));
|
map.insert("announced", serde_json::value::Value::Bool(false));
|
||||||
let json = serde_json::to_string(&map).unwrap();
|
return Self::output(Self::accept_type(&req), ip_str, map, cache_header);
|
||||||
return Ok(Response::with((status::Ok, mime_json, cache_header, json)));
|
|
||||||
}
|
}
|
||||||
Some(found) => found,
|
Some(found) => found,
|
||||||
};
|
};
|
||||||
|
@ -97,8 +205,7 @@ impl WebService {
|
||||||
serde_json::value::Value::String(found.country.clone()));
|
serde_json::value::Value::String(found.country.clone()));
|
||||||
map.insert("as_description",
|
map.insert("as_description",
|
||||||
serde_json::value::Value::String(found.description.clone()));
|
serde_json::value::Value::String(found.description.clone()));
|
||||||
let json = serde_json::to_string(&map).unwrap();
|
Self::output(Self::accept_type(&req), ip_str, map, cache_header)
|
||||||
Ok(Response::with((status::Ok, mime_json, cache_header, json)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(asns_arc: Arc<RwLock<Arc<ASNs>>>, listen_addr: &str) {
|
pub fn start(asns_arc: Arc<RwLock<Arc<ASNs>>>, listen_addr: &str) {
|
||||||
|
|
Loading…
Reference in New Issue