1- //! A [`HrnResolver`] which uses `reqwest ` and `dns.google` (8.8.8.8) to resolve Human Readable
1+ //! A [`HrnResolver`] which uses `bitreq ` and `dns.google` (8.8.8.8) to resolve Human Readable
22//! Names into bitcoin payment instructions.
33
44use std:: boxed:: Box ;
@@ -23,31 +23,36 @@ use crate::hrn_resolution::{
2323
2424const DOH_ENDPOINT : & ' static str = "https://dns.google/dns-query?dns=" ;
2525
26- /// An [`HrnResolver`] which uses `reqwest ` and `dns.google` (8.8.8.8) to resolve Human Readable
26+ /// An [`HrnResolver`] which uses `bitreq ` and `dns.google` (8.8.8.8) to resolve Human Readable
2727/// Names into bitcoin payment instructions.
2828///
2929/// Note that using this may reveal our IP address to the recipient and information about who we're
3030/// paying to Google (via `dns.google`).
3131#[ derive( Debug , Clone ) ]
3232pub struct HTTPHrnResolver {
33- client : reqwest:: Client ,
33+ #[ cfg( feature = "http_proxied" ) ]
34+ proxy : Option < bitreq:: Proxy > ,
3435}
3536
3637impl HTTPHrnResolver {
37- /// Create a new `HTTPHrnResolver` with a default `reqwest::Client`.
38+ /// Create a new `HTTPHrnResolver`
3839 pub fn new ( ) -> Self {
39- HTTPHrnResolver :: default ( )
40+ HTTPHrnResolver {
41+ #[ cfg( feature = "http_proxied" ) ]
42+ proxy : None ,
43+ }
4044 }
4145
42- /// Create a new `HTTPHrnResolver` with a custom `reqwest::Client`.
43- pub fn with_client ( client : reqwest:: Client ) -> Self {
44- HTTPHrnResolver { client }
46+ /// Create a new `HTTPHrnResolver` which makes all requests via the given proxy.
47+ #[ cfg( feature = "http_proxied" ) ]
48+ pub fn new_proxied ( proxy : bitreq:: Proxy ) -> Self {
49+ HTTPHrnResolver { proxy : Some ( proxy) }
4550 }
4651}
4752
4853impl Default for HTTPHrnResolver {
4954 fn default ( ) -> Self {
50- HTTPHrnResolver { client : reqwest :: Client :: new ( ) }
55+ HTTPHrnResolver :: new ( )
5156 }
5257}
5358
@@ -120,6 +125,19 @@ struct LNURLCallbackResponse {
120125const DNS_ERR : & ' static str = "DNS Request to dns.google failed" ;
121126
122127impl HTTPHrnResolver {
128+ async fn http_get ( & self , url : & str , accept_dns_message : bool ) -> Result < Vec < u8 > , ( ) > {
129+ let mut req = bitreq:: get ( url) ;
130+ if accept_dns_message {
131+ req = req. with_header ( "accept" , "application/dns-message" ) ;
132+ }
133+ #[ cfg( feature = "http_proxied" ) ]
134+ if let Some ( proxy) = & self . proxy {
135+ req = req. with_proxy ( proxy. clone ( ) )
136+ }
137+ let resp = req. send_async ( ) . await . map_err ( |_| ( ) ) ?;
138+ Ok ( resp. into_bytes ( ) )
139+ }
140+
123141 async fn resolve_dns ( & self , hrn : & HumanReadableName ) -> Result < HrnResolution , & ' static str > {
124142 let dns_name =
125143 Name :: try_from ( format ! ( "{}.user._bitcoin-payment.{}." , hrn. user( ) , hrn. domain( ) ) )
@@ -129,10 +147,7 @@ impl HTTPHrnResolver {
129147
130148 while let Some ( query) = pending_queries. pop ( ) {
131149 let request_url = query_to_url ( query) ;
132- let req =
133- self . client . get ( request_url) . header ( "accept" , "application/dns-message" ) . build ( ) ;
134- let resp = self . client . execute ( req. map_err ( |_| DNS_ERR ) ?) . await . map_err ( |_| DNS_ERR ) ?;
135- let body = resp. bytes ( ) . await . map_err ( |_| DNS_ERR ) ?;
150+ let body = self . http_get ( & request_url, true ) . await . map_err ( |_| DNS_ERR ) ?;
136151
137152 let mut answer = QueryBuf :: new_zeroed ( 0 ) ;
138153 answer. extend_from_slice ( & body[ ..] ) ;
@@ -156,8 +171,9 @@ impl HTTPHrnResolver {
156171
157172 async fn resolve_lnurl_impl ( & self , lnurl_url : & str ) -> Result < HrnResolution , & ' static str > {
158173 let err = "Failed to fetch LN-Address initial well-known endpoint" ;
159- let init_result = self . client . get ( lnurl_url) . send ( ) . await . map_err ( |_| err) ?;
160- let init: LNURLInitResponse = init_result. json ( ) . await . map_err ( |_| err) ?;
174+ let resp = self . http_get ( lnurl_url, false ) . await . map_err ( |_| err) ?;
175+ let resp_json = String :: from_utf8 ( resp) . map_err ( |_| err) ?;
176+ let init: LNURLInitResponse = serde_json:: from_str ( & resp_json) . map_err ( |_| err) ?;
161177
162178 if init. tag != "payRequest" {
163179 return Err ( "LNURL initial init_response had an incorrect tag value" ) ;
@@ -218,8 +234,10 @@ impl HrnResolver for HTTPHrnResolver {
218234 } else {
219235 write ! ( & mut callback, "?amount={}" , amt. milli_sats( ) ) . expect ( "Write to String" ) ;
220236 }
221- let http_response = self . client . get ( callback) . send ( ) . await . map_err ( |_| err) ?;
222- let response: LNURLCallbackResponse = http_response. json ( ) . await . map_err ( |_| err) ?;
237+ let resp = self . http_get ( & callback, false ) . await . map_err ( |_| err) ?;
238+ let resp_json = String :: from_utf8 ( resp) . map_err ( |_| err) ?;
239+ let response: LNURLCallbackResponse =
240+ serde_json:: from_str ( & resp_json) . map_err ( |_| err) ?;
223241
224242 if !response. routes . is_empty ( ) {
225243 return Err ( "LNURL callback response contained a non-empty routes array" ) ;
0 commit comments