1use crate::http::{HeaderName, HeaderValue, Response};
4use crate::layer::MapOutputLayer;
5use crate::net::address::ip::geo::GeoLocation;
6
7const GEO_ATTRIBUTION_HEADER: &str = "x-geo-attribution";
11
12pub fn geo_attribution_layer(
16 notices: Vec<&'static str>,
17) -> MapOutputLayer<impl Fn(Response) -> Response + Clone + Send + Sync + 'static> {
18 let name = HeaderName::from_static(GEO_ATTRIBUTION_HEADER);
19 MapOutputLayer::new(move |mut resp: Response| {
20 for notice in ¬ices {
21 resp.headers_mut()
22 .append(name.clone(), HeaderValue::from_static(notice));
23 }
24 resp
25 })
26}
27
28#[must_use]
32pub fn geo_attribution_html_comment(notices: &[&str]) -> Option<String> {
33 (!notices.is_empty()).then(|| {
34 let body = notices.join(" | ").replace("--", "- -");
35 format!("<!-- {body} -->")
36 })
37}
38
39#[must_use]
43pub fn geo_location_rows(loc: &GeoLocation) -> Vec<(&'static str, String)> {
44 let mut rows = Vec::new();
45 if let Some(c) = &loc.country {
46 let name = c
47 .name()
48 .map(str::to_owned)
49 .unwrap_or_else(|| c.code().to_owned());
50 rows.push(("Country", format!("{name} ({})", c.code())));
51 }
52 if let Some(c) = &loc.continent {
53 rows.push((
54 "Continent",
55 c.name()
56 .map(str::to_owned)
57 .unwrap_or_else(|| c.code().to_owned()),
58 ));
59 }
60 if let Some(region) = loc.subdivisions.first().and_then(|s| s.name.as_deref()) {
61 rows.push(("Region", region.to_owned()));
62 }
63 if let Some(city) = &loc.city {
64 rows.push(("City", city.to_string()));
65 }
66 if let Some(postal) = &loc.postal_code {
67 rows.push(("Postal", postal.to_string()));
68 }
69 if let Some(l) = &loc.location {
70 rows.push((
71 "Coordinates",
72 format!("{:.4}, {:.4}", l.latitude, l.longitude),
73 ));
74 if let Some(tz) = &l.time_zone {
75 rows.push(("Time Zone", tz.to_string()));
76 }
77 }
78 if let Some(asys) = &loc.autonomous_system {
79 if let Some(asn) = asys.asn {
80 rows.push(("ASN", format!("AS{}", asn.as_u32())));
81 }
82 if let Some(org) = &asys.organization {
83 rows.push(("Network", org.to_string()));
84 }
85 }
86 rows
87}