@ -1,8 +1,8 @@
use crate ::acme_proto ::structs ::HttpApiError ;
use crate ::endpoint ::Endpoint ;
use acme_common ::crypto ::X509Certificate ;
use acme_common ::error ::Error ;
use reqwest ::blocking ::{ Client , Response } ;
use reqwest ::header ::{ self , HeaderMap , HeaderValue } ;
use attohttpc ::{ charsets , header , Response , Session } ;
use std ::fs ::File ;
use std ::io ::prelude ::* ;
use std ::{ thread , time } ;
@ -40,12 +40,9 @@ fn update_nonce(endpoint: &mut Endpoint, response: &Response) -> Result<(), Erro
}
fn check_status ( response : & Response ) -> Result < ( ) , Error > {
if ! response . is_success ( ) {
let status = response . status ( ) ;
if ! status . is_success ( ) {
let msg = status
. canonical_reason ( )
. unwrap_or ( "<no description provided>" ) ;
let msg = format ! ( "HTTP error: {}: {}" , status . as_u16 ( ) , msg ) ;
let msg = format ! ( "HTTP error: {}: {}" , status . as_u16 ( ) , status . as_str ( ) ) ;
return Err ( msg . into ( ) ) ;
}
Ok ( ( ) )
@ -55,14 +52,14 @@ fn rate_limit(endpoint: &mut Endpoint) {
endpoint . rl . block_until_allowed ( ) ;
}
pub fn header_to_string ( header_value : & HeaderValue ) -> Result < String , Error > {
pub fn header_to_string ( header_value : & header ::HeaderValue ) -> Result < String , Error > {
let s = header_value
. to_str ( )
. map_err ( | _ | Error ::from ( "Invalid nonce format." ) ) ? ;
Ok ( s . to_string ( ) )
}
fn get_client ( root_certs : & [ String ] ) -> Result < Client , Error > {
fn get_session ( root_certs : & [ String ] ) -> Result < Session , Error > {
let useragent = format ! (
"{}/{} ({}) {}" ,
crate ::APP_NAME ,
@ -70,31 +67,25 @@ fn get_client(root_certs: &[String]) -> Result<Client, Error> {
env ! ( "ACMED_TARGET" ) ,
env ! ( "ACMED_HTTP_LIB_AGENT" )
) ;
let mut headers = HeaderMap ::with_capacity ( 2 ) ;
// TODO: allow to change the language
headers . insert (
header ::ACCEPT_LANGUAGE ,
HeaderValue ::from_static ( "en-US,en;q=0.5" ) ,
) ;
headers . insert ( header ::USER_AGENT , HeaderValue ::from_str ( & useragent ) ? ) ;
let mut client_builder = Client ::builder ( ) . default_headers ( headers ) . referer ( false ) ;
let mut session = Session ::new ( ) ;
session . default_charset ( Some ( charsets ::UTF_8 ) ) ;
session . try_header ( header ::ACCEPT_LANGUAGE , "en-US,en;q=0.5" ) ? ;
session . try_header ( header ::USER_AGENT , & useragent ) ? ;
for crt_file in root_certs . iter ( ) {
let mut buff = Vec ::new ( ) ;
File ::open ( crt_file ) ? . read_to_end ( & mut buff ) ? ;
let crt = reqwest ::Certificate ::from_pem ( & buff ) ? ;
client_builder = client_builder . add_root_certificate ( crt ) ;
let crt = X509Certificate ::from_pem_native ( & buff ) ? ;
session . add_root_certificate ( crt ) ;
}
let client = client_builder . build ( ) ? ;
Ok ( client )
Ok ( session )
}
pub fn get ( endpoint : & mut Endpoint , root_certs : & [ String ] , url : & str ) -> Result < Response , Error > {
let client = get_client ( root_certs ) ? ;
let mut session = get_session ( root_certs ) ? ;
session . try_header ( header ::ACCEPT , CONTENT_TYPE_JSON ) ? ;
rate_limit ( endpoint ) ;
let response = client
. get ( url )
. header ( header ::ACCEPT , HeaderValue ::from_static ( CONTENT_TYPE_JSON ) )
. send ( ) ? ;
let response = session . get ( url ) . send ( ) ? ;
update_nonce ( endpoint , & response ) ? ;
check_status ( & response ) ? ;
Ok ( response )
@ -111,20 +102,17 @@ pub fn post<F>(
where
F : Fn ( & str , & str ) -> Result < String , Error > ,
{
let client = get_client ( root_certs ) ? ;
let mut session = get_session ( root_certs ) ? ;
session . try_header ( header ::ACCEPT , accept ) ? ;
session . try_header ( header ::CONTENT_TYPE , content_type ) ? ;
if endpoint . nonce . is_none ( ) {
let _ = new_nonce ( endpoint , root_certs ) ;
}
for _ in 0 . . crate ::DEFAULT_HTTP_FAIL_NB_RETRY {
let nonce = & endpoint . nonce . clone ( ) . unwrap ( ) ;
let body = data_builder ( & nonce , url ) ? . into_bytes ( ) ;
let body = data_builder ( & nonce , url ) ? ;
rate_limit ( endpoint ) ;
let response = client
. post ( url )
. body ( body )
. header ( header ::ACCEPT , HeaderValue ::from_str ( accept ) ? )
. header ( header ::CONTENT_TYPE , HeaderValue ::from_str ( content_type ) ? )
. send ( ) ? ;
let response = session . post ( url ) . text ( & body ) . send ( ) ? ;
update_nonce ( endpoint , & response ) ? ;
match check_status ( & response ) {
Ok ( _ ) = > {