@@ -14,12 +14,18 @@ use crate::dns01_client::Record;
1414
1515use super :: Dns01Api ;
1616
17- const CLOUDFLARE_API_URL : & str = "https://api.cloudflare.com/client/v4" ;
17+ const DEFAULT_CLOUDFLARE_API_URL : & str = "https://api.cloudflare.com/client/v4" ;
1818
1919#[ derive( Debug , Serialize , Deserialize ) ]
2020pub struct CloudflareClient {
2121 zone_id : String ,
2222 api_token : String ,
23+ #[ serde( default = "default_api_url" ) ]
24+ api_url : String ,
25+ }
26+
27+ fn default_api_url ( ) -> String {
28+ DEFAULT_CLOUDFLARE_API_URL . to_string ( )
2329}
2430
2531#[ derive( Deserialize ) ]
@@ -59,20 +65,29 @@ struct ZonesResultInfo {
5965}
6066
6167impl CloudflareClient {
62- pub async fn new ( api_token : String , base_domain : String ) -> Result < Self > {
63- let zone_id = Self :: resolve_zone_id ( & api_token, & base_domain) . await ?;
64- Ok ( Self { api_token, zone_id } )
68+ pub async fn new (
69+ base_domain : String ,
70+ api_token : String ,
71+ api_url : Option < String > ,
72+ ) -> Result < Self > {
73+ let api_url = api_url. unwrap_or_else ( || DEFAULT_CLOUDFLARE_API_URL . to_string ( ) ) ;
74+ let zone_id = Self :: resolve_zone_id ( & api_token, & base_domain, & api_url) . await ?;
75+ Ok ( Self {
76+ zone_id,
77+ api_token,
78+ api_url,
79+ } )
6580 }
6681
67- async fn resolve_zone_id ( api_token : & str , base_domain : & str ) -> Result < String > {
82+ async fn resolve_zone_id ( api_token : & str , base_domain : & str , api_url : & str ) -> Result < String > {
6883 let base = base_domain
6984 . trim ( )
7085 . trim_start_matches ( "*." )
7186 . trim_end_matches ( '.' )
7287 . to_lowercase ( ) ;
7388
7489 let client = Client :: new ( ) ;
75- let url = format ! ( "{CLOUDFLARE_API_URL }/zones" ) ;
90+ let url = format ! ( "{api_url }/zones" ) ;
7691
7792 let per_page = 50u32 ;
7893 let mut page = 1u32 ;
@@ -150,8 +165,7 @@ impl CloudflareClient {
150165
151166 async fn add_record ( & self , record : & impl Serialize ) -> Result < Response > {
152167 let client = Client :: new ( ) ;
153- let url = format ! ( "{CLOUDFLARE_API_URL}/zones/{}/dns_records" , self . zone_id) ;
154-
168+ let url = format ! ( "{}/zones/{}/dns_records" , self . api_url, self . zone_id) ;
155169 let response = client
156170 . post ( & url)
157171 . header ( "Authorization" , format ! ( "Bearer {}" , self . api_token) )
@@ -176,8 +190,8 @@ impl CloudflareClient {
176190 async fn remove_record_inner ( & self , record_id : & str ) -> Result < ( ) > {
177191 let client = Client :: new ( ) ;
178192 let url = format ! (
179- "{CLOUDFLARE_API_URL }/zones/{zone_id }/dns_records/{record_id }" ,
180- zone_id = self . zone_id
193+ "{}/zones/{}/dns_records/{}" ,
194+ self . api_url , self . zone_id, record_id
181195 ) ;
182196
183197 debug ! ( url = %url, "cloudflare remove_record request" ) ;
@@ -201,7 +215,7 @@ impl CloudflareClient {
201215
202216 async fn get_records_inner ( & self , domain : & str ) -> Result < Vec < Record > > {
203217 let client = Client :: new ( ) ;
204- let url = format ! ( "{CLOUDFLARE_API_URL }/zones/{}/dns_records" , self . zone_id) ;
218+ let url = format ! ( "{}/zones/{}/dns_records" , self . api_url , self . zone_id) ;
205219
206220 let per_page = 100u32 ;
207221 let mut records = Vec :: new ( ) ;
@@ -338,8 +352,9 @@ mod tests {
338352
339353 async fn create_client ( ) -> CloudflareClient {
340354 CloudflareClient :: new (
341- std:: env:: var ( "CLOUDFLARE_API_TOKEN" ) . expect ( "CLOUDFLARE_API_TOKEN not set" ) ,
342355 std:: env:: var ( "TEST_DOMAIN" ) . expect ( "TEST_DOMAIN not set" ) ,
356+ std:: env:: var ( "CLOUDFLARE_API_TOKEN" ) . expect ( "CLOUDFLARE_API_TOKEN not set" ) ,
357+ std:: env:: var ( "CLOUDFLARE_API_URL" ) . ok ( ) ,
343358 )
344359 . await
345360 . unwrap ( )
0 commit comments