@@ -29,7 +29,28 @@ const DOH_ENDPOINT: &'static str = "https://dns.google/dns-query?dns=";
2929///
3030/// Note that using this may reveal our IP address to the recipient and information about who we're
3131/// paying to Google (via `dns.google`).
32- pub struct HTTPHrnResolver ;
32+ #[ derive( Debug , Clone ) ]
33+ pub struct HTTPHrnResolver {
34+ client : reqwest:: Client ,
35+ }
36+
37+ impl HTTPHrnResolver {
38+ /// Create a new `HTTPHrnResolver` with a default `reqwest::Client`.
39+ pub fn new ( ) -> Self {
40+ HTTPHrnResolver :: default ( )
41+ }
42+
43+ /// Create a new `HTTPHrnResolver` with a custom `reqwest::Client`.
44+ pub fn with_client ( client : reqwest:: Client ) -> Self {
45+ HTTPHrnResolver { client }
46+ }
47+ }
48+
49+ impl Default for HTTPHrnResolver {
50+ fn default ( ) -> Self {
51+ HTTPHrnResolver { client : reqwest:: Client :: new ( ) }
52+ }
53+ }
3354
3455const B64_CHAR : [ u8 ; 64 ] = [
3556 b'A' , b'B' , b'C' , b'D' , b'E' , b'F' , b'G' , b'H' , b'I' , b'J' , b'K' , b'L' , b'M' , b'N' , b'O' , b'P' ,
@@ -107,11 +128,10 @@ impl HTTPHrnResolver {
107128 let mut pending_queries = vec ! [ initial_query] ;
108129
109130 while let Some ( query) = pending_queries. pop ( ) {
110- let client = reqwest:: Client :: new ( ) ;
111-
112131 let request_url = query_to_url ( query) ;
113- let req = client. get ( request_url) . header ( "accept" , "application/dns-message" ) . build ( ) ;
114- let resp = client. execute ( req. map_err ( |_| DNS_ERR ) ?) . await . map_err ( |_| DNS_ERR ) ?;
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 ) ?;
115135 let body = resp. bytes ( ) . await . map_err ( |_| DNS_ERR ) ?;
116136
117137 let mut answer = QueryBuf :: new_zeroed ( 0 ) ;
@@ -136,8 +156,15 @@ impl HTTPHrnResolver {
136156
137157 async fn resolve_lnurl_impl ( & self , lnurl_url : & str ) -> Result < HrnResolution , & ' static str > {
138158 let err = "Failed to fetch LN-Address initial well-known endpoint" ;
139- let init: LNURLInitResponse =
140- reqwest:: get ( lnurl_url) . await . map_err ( |_| err) ?. json ( ) . await . map_err ( |_| err) ?;
159+ let init: LNURLInitResponse = self
160+ . client
161+ . get ( lnurl_url)
162+ . send ( )
163+ . await
164+ . map_err ( |_| err) ?
165+ . json ( )
166+ . await
167+ . map_err ( |_| err) ?;
141168
142169 if init. tag != "payRequest" {
143170 return Err ( "LNURL initial init_response had an incorrect tag value" ) ;
@@ -198,8 +225,15 @@ impl HrnResolver for HTTPHrnResolver {
198225 } else {
199226 write ! ( & mut callback, "?amount={}" , amt. milli_sats( ) ) . expect ( "Write to String" ) ;
200227 }
201- let callback_response: LNURLCallbackResponse =
202- reqwest:: get ( callback) . await . map_err ( |_| err) ?. json ( ) . await . map_err ( |_| err) ?;
228+ let callback_response: LNURLCallbackResponse = self
229+ . client
230+ . get ( callback)
231+ . send ( )
232+ . await
233+ . map_err ( |_| err) ?
234+ . json ( )
235+ . await
236+ . map_err ( |_| err) ?;
203237
204238 if !callback_response. routes . is_empty ( ) {
205239 return Err ( "LNURL callback response contained a non-empty routes array" ) ;
@@ -257,7 +291,7 @@ mod tests {
257291
258292 #[ tokio:: test]
259293 async fn test_dns_via_http_hrn_resolver ( ) {
260- let resolver = HTTPHrnResolver ;
294+ let resolver = HTTPHrnResolver :: default ( ) ;
261295 let instructions = PaymentInstructions :: parse (
262296263297 bitcoin:: Network :: Bitcoin ,
@@ -303,10 +337,11 @@ mod tests {
303337
304338 #[ tokio:: test]
305339 async fn test_http_hrn_resolver ( ) {
340+ let resolver = HTTPHrnResolver :: default ( ) ;
306341 let instructions = PaymentInstructions :: parse (
307342308343 bitcoin:: Network :: Bitcoin ,
309- & HTTPHrnResolver ,
344+ & resolver ,
310345 true ,
311346 )
312347 . await
@@ -323,7 +358,7 @@ mod tests {
323358 assert_eq ! ( hrn. user( ) , "lnurltest" ) ;
324359 assert_eq ! ( hrn. domain( ) , "bitcoin.ninja" ) ;
325360
326- instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) , & HTTPHrnResolver ) . await . unwrap ( )
361+ instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) , & resolver ) . await . unwrap ( )
327362 } else {
328363 panic ! ( ) ;
329364 } ;
@@ -348,11 +383,12 @@ mod tests {
348383
349384 #[ tokio:: test]
350385 async fn test_http_lnurl_resolver ( ) {
386+ let resolver = HTTPHrnResolver :: default ( ) ;
351387 let instructions = PaymentInstructions :: parse (
352388 // lnurl encoding for [email protected] 353389 "lnurl1dp68gurn8ghj7cnfw33k76tw9ehxjmn2vyhjuam9d3kz66mwdamkutmvde6hymrs9akxuatjd36x2um5ahcq39" ,
354390 Network :: Bitcoin ,
355- & HTTPHrnResolver ,
391+ & resolver ,
356392 true ,
357393 )
358394 . await
@@ -365,7 +401,7 @@ mod tests {
365401 assert_eq ! ( instr. pop_callback( ) , None ) ;
366402 assert ! ( instr. bip_353_dnssec_proof( ) . is_none( ) ) ;
367403
368- instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) , & HTTPHrnResolver ) . await . unwrap ( )
404+ instr. set_amount ( Amount :: from_sats ( 100_000 ) . unwrap ( ) , & resolver ) . await . unwrap ( )
369405 } else {
370406 panic ! ( ) ;
371407 } ;
0 commit comments