From 26b58324c468b9f3208a14548b173e1514cd9574 Mon Sep 17 00:00:00 2001 From: xkeyC <3334969096@qq.com> Date: Tue, 12 Mar 2024 20:07:06 +0800 Subject: [PATCH] feat: [RustHTTP] DNS Host Map --- lib/common/io/rs_http.dart | 20 ++++-- lib/common/rust/api/http_api.dart | 5 ++ lib/common/rust/frb_generated.dart | 63 ++++++++++++++++++- lib/common/rust/frb_generated.io.dart | 9 +++ lib/common/rust/frb_generated.web.dart | 9 +++ lib/common/rust/http_package.dart | 1 + rust/Cargo.toml | 2 + rust/src/api/http_api.rs | 8 ++- rust/src/frb_generated.rs | 62 ++++++++++++++++++- rust/src/http_package/dns.rs | 39 +++++++++--- rust/src/http_package/mod.rs | 84 +++++++++++++++++++------- 11 files changed, 262 insertions(+), 40 deletions(-) diff --git a/lib/common/io/rs_http.dart b/lib/common/io/rs_http.dart index 08a9b64..271946b 100644 --- a/lib/common/io/rs_http.dart +++ b/lib/common/io/rs_http.dart @@ -15,15 +15,18 @@ class RSHttp { } static Future get(String url, - {Map? headers}) async { + {Map? headers, String? withIpAddress}) async { final r = await rust_http.fetch( - method: MyMethod.gets, url: url, headers: headers); + method: MyMethod.gets, + url: url, + headers: headers, + withIpAddress: withIpAddress); return r; } static Future getText(String url, - {Map? headers}) async { - final r = await get(url, headers: headers); + {Map? headers, String? withIpAddress}) async { + final r = await get(url, headers: headers, withIpAddress: withIpAddress); if (r.data == null) return ""; final str = utf8.decode(r.data!); return str; @@ -32,13 +35,18 @@ class RSHttp { static Future postData(String url, {Map? headers, String? contentType, - Uint8List? data}) async { + Uint8List? data, + String? withIpAddress}) async { if (contentType != null) { headers ??= {}; headers["Content-Type"] = contentType; } final r = await rust_http.fetch( - method: MyMethod.post, url: url, headers: headers, inputData: data); + method: MyMethod.post, + url: url, + headers: headers, + inputData: data, + withIpAddress: withIpAddress); return r; } diff --git a/lib/common/rust/api/http_api.dart b/lib/common/rust/api/http_api.dart index 63a41cb..93422ba 100644 --- a/lib/common/rust/api/http_api.dart +++ b/lib/common/rust/api/http_api.dart @@ -16,17 +16,22 @@ Future fetch( required String url, Map? headers, Uint8List? inputData, + String? withIpAddress, dynamic hint}) => RustLib.instance.api.fetch( method: method, url: url, headers: headers, inputData: inputData, + withIpAddress: withIpAddress, hint: hint); Future> dnsLookupTxt({required String host, dynamic hint}) => RustLib.instance.api.dnsLookupTxt(host: host, hint: hint); +Future> dnsLookupIps({required String host, dynamic hint}) => + RustLib.instance.api.dnsLookupIps(host: host, hint: hint); + enum MyMethod { options, gets, diff --git a/lib/common/rust/frb_generated.dart b/lib/common/rust/frb_generated.dart index 671f883..ea4a97f 100644 --- a/lib/common/rust/frb_generated.dart +++ b/lib/common/rust/frb_generated.dart @@ -64,6 +64,8 @@ class RustLib extends BaseEntrypoint { } abstract class RustLibApi extends BaseApi { + Future> dnsLookupIps({required String host, dynamic hint}); + Future> dnsLookupTxt({required String host, dynamic hint}); Future fetch( @@ -71,6 +73,7 @@ abstract class RustLibApi extends BaseApi { required String url, Map? headers, Uint8List? inputData, + String? withIpAddress, dynamic hint}); Future setDefaultHeader( @@ -91,6 +94,31 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { required super.portManager, }); + @override + Future> dnsLookupIps({required String host, dynamic hint}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(host, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 4, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_String, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: kDnsLookupIpsConstMeta, + argValues: [host], + apiImpl: this, + hint: hint, + )); + } + + TaskConstMeta get kDnsLookupIpsConstMeta => const TaskConstMeta( + debugName: "dns_lookup_ips", + argNames: ["host"], + ); + @override Future> dnsLookupTxt({required String host, dynamic hint}) { return handler.executeNormal(NormalTask( @@ -122,6 +150,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { required String url, Map? headers, Uint8List? inputData, + String? withIpAddress, dynamic hint}) { return handler.executeNormal(NormalTask( callFfi: (port_) { @@ -130,6 +159,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_String(url, serializer); sse_encode_opt_Map_String_String(headers, serializer); sse_encode_opt_list_prim_u_8_strict(inputData, serializer); + sse_encode_opt_String(withIpAddress, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 2, port: port_); }, @@ -138,7 +168,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { decodeErrorData: sse_decode_AnyhowException, ), constMeta: kFetchConstMeta, - argValues: [method, url, headers, inputData], + argValues: [method, url, headers, inputData, withIpAddress], apiImpl: this, hint: hint, )); @@ -146,7 +176,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { TaskConstMeta get kFetchConstMeta => const TaskConstMeta( debugName: "fetch", - argNames: ["method", "url", "headers", "inputData"], + argNames: ["method", "url", "headers", "inputData", "withIpAddress"], ); @override @@ -188,7 +218,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_list_String(arguments, serializer); sse_encode_String(workingDirectory, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, - funcId: 4, port: port_); + funcId: 5, port: port_); }, codec: SseCodec( decodeSuccessData: sse_decode_String, @@ -273,6 +303,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw == null ? null : dco_decode_Map_String_String(raw); } + @protected + String? dco_decode_opt_String(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_String(raw); + } + @protected int? dco_decode_opt_box_autoadd_u_64(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -431,6 +467,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + String? sse_decode_opt_String(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return (sse_decode_String(deserializer)); + } else { + return null; + } + } + @protected int? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -595,6 +642,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + void sse_encode_opt_String(String? self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_String(self, serializer); + } + } + @protected void sse_encode_opt_box_autoadd_u_64(int? self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs diff --git a/lib/common/rust/frb_generated.io.dart b/lib/common/rust/frb_generated.io.dart index 6ddac61..2770ab1 100644 --- a/lib/common/rust/frb_generated.io.dart +++ b/lib/common/rust/frb_generated.io.dart @@ -53,6 +53,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Map? dco_decode_opt_Map_String_String(dynamic raw); + @protected + String? dco_decode_opt_String(dynamic raw); + @protected int? dco_decode_opt_box_autoadd_u_64(dynamic raw); @@ -113,6 +116,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { Map? sse_decode_opt_Map_String_String( SseDeserializer deserializer); + @protected + String? sse_decode_opt_String(SseDeserializer deserializer); + @protected int? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer); @@ -179,6 +185,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_opt_Map_String_String( Map? self, SseSerializer serializer); + @protected + void sse_encode_opt_String(String? self, SseSerializer serializer); + @protected void sse_encode_opt_box_autoadd_u_64(int? self, SseSerializer serializer); diff --git a/lib/common/rust/frb_generated.web.dart b/lib/common/rust/frb_generated.web.dart index 01c3e3e..037444b 100644 --- a/lib/common/rust/frb_generated.web.dart +++ b/lib/common/rust/frb_generated.web.dart @@ -52,6 +52,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Map? dco_decode_opt_Map_String_String(dynamic raw); + @protected + String? dco_decode_opt_String(dynamic raw); + @protected int? dco_decode_opt_box_autoadd_u_64(dynamic raw); @@ -112,6 +115,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { Map? sse_decode_opt_Map_String_String( SseDeserializer deserializer); + @protected + String? sse_decode_opt_String(SseDeserializer deserializer); + @protected int? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer); @@ -178,6 +184,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_opt_Map_String_String( Map? self, SseSerializer serializer); + @protected + void sse_encode_opt_String(String? self, SseSerializer serializer); + @protected void sse_encode_opt_box_autoadd_u_64(int? self, SseSerializer serializer); diff --git a/lib/common/rust/http_package.dart b/lib/common/rust/http_package.dart index e9cc363..5235fb4 100644 --- a/lib/common/rust/http_package.dart +++ b/lib/common/rust/http_package.dart @@ -12,6 +12,7 @@ enum MyHttpVersion { http11, http2, http3, + httpUnknown, } class RustHttpResponse { diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 4676e12..8b8a032 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -22,3 +22,5 @@ reqwest = { version = "0.11", features = ["rustls-tls-native-roots", "cookies", hickory-resolver = {version = "0.24.0"} anyhow = "1.0" win32job = "2" +lazy_static = "1.4.0" +scopeguard = "1.2.0" diff --git a/rust/src/api/http_api.rs b/rust/src/api/http_api.rs index 18e4ba1..b13a5ad 100644 --- a/rust/src/api/http_api.rs +++ b/rust/src/api/http_api.rs @@ -36,10 +36,14 @@ pub fn set_default_header(headers: HashMap) { pub async fn fetch(method: MyMethod, url: String, headers: Option>, - input_data: Option>) -> anyhow::Result { - http_package::fetch(_my_method_to_hyper_method(method), url, headers, input_data).await + input_data: Option>, with_ip_address: Option) -> anyhow::Result { + http_package::fetch(_my_method_to_hyper_method(method), url, headers, input_data, with_ip_address).await } pub async fn dns_lookup_txt(host: String) -> anyhow::Result> { http_package::dns_lookup_txt(host).await +} + +pub async fn dns_lookup_ips(host: String) -> anyhow::Result> { + http_package::dns_lookup_ips(host).await } \ No newline at end of file diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 36d4a2c..d2944a0 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -38,6 +38,39 @@ flutter_rust_bridge::frb_generated_default_handler!(); // Section: wire_funcs +fn wire_dns_lookup_ips_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "dns_lookup_ips", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_host = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| async move { + transform_result_sse( + (move || async move { crate::api::http_api::dns_lookup_ips(api_host).await })() + .await, + ) + } + }, + ) +} fn wire_dns_lookup_txt_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, @@ -98,6 +131,7 @@ fn wire_fetch_impl( let api_headers = >>::sse_decode(&mut deserializer); let api_input_data = >>::sse_decode(&mut deserializer); + let api_with_ip_address = >::sse_decode(&mut deserializer); deserializer.end(); move |context| async move { transform_result_sse( @@ -107,6 +141,7 @@ fn wire_fetch_impl( api_url, api_headers, api_input_data, + api_with_ip_address, ) .await })() @@ -275,6 +310,7 @@ impl SseDecode for crate::http_package::MyHttpVersion { 2 => crate::http_package::MyHttpVersion::HTTP_11, 3 => crate::http_package::MyHttpVersion::HTTP_2, 4 => crate::http_package::MyHttpVersion::HTTP_3, + 5 => crate::http_package::MyHttpVersion::HTTP_UNKNOWN, _ => unreachable!("Invalid variant for MyHttpVersion: {}", inner), }; } @@ -312,6 +348,17 @@ impl SseDecode for Option> { } } +impl SseDecode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(::sse_decode(deserializer)); + } else { + return None; + } + } +} + impl SseDecode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -407,10 +454,11 @@ fn pde_ffi_dispatcher_primary_impl( ) { // Codec=Pde (Serialization + dispatch), see doc to use other codecs match func_id { + 4 => wire_dns_lookup_ips_impl(port, ptr, rust_vec_len, data_len), 3 => wire_dns_lookup_txt_impl(port, ptr, rust_vec_len, data_len), 2 => wire_fetch_impl(port, ptr, rust_vec_len, data_len), 1 => wire_set_default_header_impl(port, ptr, rust_vec_len, data_len), - 4 => wire_start_process_impl(port, ptr, rust_vec_len, data_len), + 5 => wire_start_process_impl(port, ptr, rust_vec_len, data_len), _ => unreachable!(), } } @@ -438,6 +486,7 @@ impl flutter_rust_bridge::IntoDart for crate::http_package::MyHttpVersion { Self::HTTP_11 => 2.into_dart(), Self::HTTP_2 => 3.into_dart(), Self::HTTP_3 => 4.into_dart(), + Self::HTTP_UNKNOWN => 5.into_dart(), } } } @@ -574,6 +623,7 @@ impl SseEncode for crate::http_package::MyHttpVersion { crate::http_package::MyHttpVersion::HTTP_11 => 2, crate::http_package::MyHttpVersion::HTTP_2 => 3, crate::http_package::MyHttpVersion::HTTP_3 => 4, + crate::http_package::MyHttpVersion::HTTP_UNKNOWN => 5, _ => { unimplemented!(""); } @@ -616,6 +666,16 @@ impl SseEncode for Option> { } } +impl SseEncode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + ::sse_encode(value, serializer); + } + } +} + impl SseEncode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { diff --git a/rust/src/http_package/dns.rs b/rust/src/http_package/dns.rs index 16732b3..6e85766 100644 --- a/rust/src/http_package/dns.rs +++ b/rust/src/http_package/dns.rs @@ -1,11 +1,17 @@ -use std::io; +use hickory_resolver::config::{NameServerConfigGroup, ResolverConfig, ResolverOpts}; use hickory_resolver::{lookup_ip::LookupIpIntoIter, TokioAsyncResolver}; use hyper::client::connect::dns::Name; use once_cell::sync::OnceCell; use reqwest::dns::{Addrs, Resolve, Resolving}; +use std::collections::HashMap; +use std::io; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use std::sync::Arc; -use hickory_resolver::config::{NameServerConfigGroup, ResolverConfig, ResolverOpts}; +use std::sync::{Arc, RwLock}; +use lazy_static::lazy_static; + +lazy_static! { + pub static ref MY_HOSTS_MAP: RwLock> = RwLock::from(HashMap::new()); +} /// Wrapper around an `AsyncResolver`, which implements the `Resolve` trait. #[derive(Debug, Default, Clone)] @@ -22,6 +28,14 @@ struct SocketAddrs { impl Resolve for MyHickoryDnsResolver { fn resolve(&self, name: Name) -> Resolving { + let my_hosts = MY_HOSTS_MAP.read().unwrap(); + let name_str = name.to_string(); + if let Some(ip) = my_hosts.get(name_str.as_str()) { + let addrs: Addrs = Box::new(std::iter::once(SocketAddr::new(*ip, 0))); + println!("using host map === {:?}", name_str); + return Box::pin(async move { Ok(addrs) }); + } + let resolver = self.clone(); Box::pin(async move { let resolver = resolver.state.get_or_try_init(new_resolver)?; @@ -38,11 +52,21 @@ impl MyHickoryDnsResolver { pub(crate) async fn lookup_txt(&self, name: String) -> anyhow::Result> { let resolver = self.state.get_or_try_init(new_resolver)?; let txt = resolver.txt_lookup(name).await?; - let t = txt.iter() + let t = txt + .iter() .map(|rdata| rdata.to_string()) .collect::>(); Ok(t) } + pub(crate) async fn lookup_ips(&self, name: String) -> anyhow::Result> { + let resolver = self.state.get_or_try_init(new_resolver)?; + let ips = resolver.ipv4_lookup(name).await?; + let t = ips + .iter() + .map(|ip| ip.to_string()) + .collect::>(); + Ok(t) + } } impl Iterator for SocketAddrs { @@ -58,14 +82,15 @@ fn new_resolver() -> io::Result { &[ IpAddr::V4(Ipv4Addr::new(119, 29, 29, 29)), IpAddr::V4(Ipv4Addr::new(223, 6, 6, 6)), + IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), + IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)), IpAddr::V4(Ipv4Addr::new(180, 76, 76, 76)), IpAddr::V4(Ipv4Addr::new(1, 2, 4, 8)), IpAddr::V4(Ipv4Addr::new(166, 111, 8, 28)), IpAddr::V4(Ipv4Addr::new(101, 226, 4, 6)), IpAddr::V4(Ipv4Addr::new(114, 114, 114, 114)), - IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)), - IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), - ], 53, true); + ], 53, true, + ); let cfg = ResolverConfig::from_parts(None, vec![], group); let mut opts = ResolverOpts::default(); opts.edns0 = true; diff --git a/rust/src/http_package/mod.rs b/rust/src/http_package/mod.rs index 0c1a748..b55551e 100644 --- a/rust/src/http_package/mod.rs +++ b/rust/src/http_package/mod.rs @@ -1,16 +1,27 @@ pub mod dns; +use scopeguard::defer; +use lazy_static::lazy_static; +use hyper::Uri; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use reqwest::{Method, RequestBuilder}; use std::collections::HashMap; use std::str::FromStr; use std::sync::{Arc, RwLock}; use std::time::Duration; -use flutter_rust_bridge::for_generated::lazy_static; +#[derive(Debug)] #[allow(non_camel_case_types)] -pub enum MyHttpVersion { HTTP_09, HTTP_10, HTTP_11, HTTP_2, HTTP_3 } +pub enum MyHttpVersion { + HTTP_09, + HTTP_10, + HTTP_11, + HTTP_2, + HTTP_3, + HTTP_UNKNOWN, +} +#[derive(Debug)] pub struct RustHttpResponse { pub status_code: u16, pub headers: HashMap, @@ -23,28 +34,34 @@ pub struct RustHttpResponse { fn _hyper_version_to_my_version(v: reqwest::Version) -> MyHttpVersion { match v { - reqwest::Version::HTTP_09 => { MyHttpVersion::HTTP_09 } - reqwest::Version::HTTP_10 => { MyHttpVersion::HTTP_10 } - reqwest::Version::HTTP_11 => { MyHttpVersion::HTTP_11 } - reqwest::Version::HTTP_2 => { MyHttpVersion::HTTP_2 } - reqwest::Version::HTTP_3 => { MyHttpVersion::HTTP_3 } - _ => { panic!("Unsupported HTTP version") } + reqwest::Version::HTTP_09 => MyHttpVersion::HTTP_09, + reqwest::Version::HTTP_10 => MyHttpVersion::HTTP_10, + reqwest::Version::HTTP_11 => MyHttpVersion::HTTP_11, + reqwest::Version::HTTP_2 => MyHttpVersion::HTTP_2, + reqwest::Version::HTTP_3 => MyHttpVersion::HTTP_3, + _ => MyHttpVersion::HTTP_UNKNOWN, } } lazy_static! { static ref DEFAULT_HEADER: RwLock = RwLock::from(HeaderMap::new()); - static ref DNS_CLIENT : Arc = Arc::from(dns::MyHickoryDnsResolver::default()); - static ref HTTP_CLIENT: reqwest::Client = { - reqwest::Client::builder() - .dns_resolver(DNS_CLIENT.clone()) - .use_rustls_tls() - .connect_timeout(Duration::from_secs(10)) - .gzip(true) - .no_proxy() - .build() - .unwrap() - }; + static ref DNS_CLIENT: Arc = Arc::from(dns::MyHickoryDnsResolver::default()); + static ref HTTP_CLIENT: reqwest::Client = new_http_client(true); +} + +fn new_http_client(keep_alive: bool) -> reqwest::Client { + let mut c = reqwest::Client::builder() + .dns_resolver(DNS_CLIENT.clone()) + .use_rustls_tls() + .connect_timeout(Duration::from_secs(10)) + .gzip(true) + .no_proxy(); + if !keep_alive { + c = c.tcp_keepalive(None); + } else { + c = c.tcp_keepalive(Duration::from_secs(120)); + } + c.build().unwrap() } pub fn set_default_header(headers: HashMap) { @@ -63,13 +80,34 @@ pub async fn fetch( url: String, headers: Option>, input_data: Option>, + with_ip_address: Option, ) -> anyhow::Result { - let mut req = _mix_header(HTTP_CLIENT.request(method, url), headers); + let address_clone = with_ip_address.clone(); + let url_clone = url.clone(); + + if address_clone.is_some() { + let addr = std::net::IpAddr::from_str(with_ip_address.unwrap().as_str()).unwrap(); + let mut hosts = dns::MY_HOSTS_MAP.write().unwrap(); + let url_host = Uri::from_str(url.as_str()).unwrap().host().unwrap().to_string(); + hosts.insert(url_host, addr); + } + + defer! { + if address_clone.is_some() { + let mut hosts = dns::MY_HOSTS_MAP.write().unwrap(); + hosts.remove(url.clone().as_str()); + } + } + + let mut req = if address_clone.is_some() { + _mix_header(new_http_client(false).request(method, url_clone), headers) + } else { + _mix_header(HTTP_CLIENT.request(method, url_clone), headers) + }; if input_data.is_some() { req = req.body(input_data.unwrap()); } let resp = req.send().await?; - let url = resp.url().to_string(); let status_code = resp.status().as_u16(); let resp_headers = _reade_resp_header(resp.headers()); @@ -104,6 +142,10 @@ pub async fn dns_lookup_txt(name: String) -> anyhow::Result> { DNS_CLIENT.lookup_txt(name).await } +pub async fn dns_lookup_ips(name: String) -> anyhow::Result> { + DNS_CLIENT.lookup_ips(name).await +} + fn _reade_resp_header(r_header: &HeaderMap) -> HashMap { let mut resp_headers = HashMap::new(); for ele in r_header {