2121#include <curl/curl.h>
2222#include <stdio.h>
2323#include <string.h>
24+ #include <unistd.h>
2425
2526#include "oauth2/http.h"
2627#include "oauth2/mem.h"
@@ -604,6 +605,8 @@ typedef struct oauth2_http_call_ctx_t {
604605 char * basic_auth_password ;
605606 char * bearer_token ;
606607 int timeout ;
608+ int retries ;
609+ int retry_interval ;
607610 bool ssl_verify ;
608611 char * outgoing_proxy ;
609612 oauth2_nv_list_t * cookie ;
@@ -615,6 +618,8 @@ typedef struct oauth2_http_call_ctx_t {
615618} oauth2_http_call_ctx_t ;
616619
617620#define OAUTH2_HTTP_CALL_TIMEOUT_DEFAULT 15
621+ #define OAUTH2_HTTP_CALL_RETRIES_DEFAULT 1
622+ #define OAUTH2_HTTP_CALL_RETRY_INTERVAL_DEFAULT 300
618623#define OAUTH2_HTTP_CALL_SSL_VERIFY_DEFAULT true
619624
620625oauth2_http_call_ctx_t * oauth2_http_call_ctx_init (oauth2_log_t * log )
@@ -628,6 +633,10 @@ oauth2_http_call_ctx_t *oauth2_http_call_ctx_init(oauth2_log_t *log)
628633
629634 oauth2_http_call_ctx_timeout_set (log , ctx ,
630635 OAUTH2_HTTP_CALL_TIMEOUT_DEFAULT );
636+ oauth2_http_call_ctx_retries_set (log , ctx ,
637+ OAUTH2_HTTP_CALL_RETRIES_DEFAULT );
638+ oauth2_http_call_ctx_retry_interval_set (
639+ log , ctx , OAUTH2_HTTP_CALL_RETRY_INTERVAL_DEFAULT );
631640 oauth2_http_call_ctx_ssl_verify_set (
632641 log , ctx , OAUTH2_HTTP_CALL_SSL_VERIFY_DEFAULT );
633642 oauth2_http_call_ctx_outgoing_proxy_set (log , ctx , NULL );
@@ -680,6 +689,8 @@ void oauth2_http_call_ctx_free(oauth2_log_t *log, oauth2_http_call_ctx_t *ctx)
680689}
681690
682691_OAUTH2_TYPE_IMPLEMENT_MEMBER_SET (http , call_ctx , timeout , int , integer )
692+ _OAUTH2_TYPE_IMPLEMENT_MEMBER_SET (http , call_ctx , retries , int , integer )
693+ _OAUTH2_TYPE_IMPLEMENT_MEMBER_SET (http , call_ctx , retry_interval , int , integer )
683694_OAUTH2_TYPE_IMPLEMENT_MEMBER_SET (http , call_ctx , ssl_verify , bool , bln )
684695_OAUTH2_TYPE_IMPLEMENT_MEMBER_SET (http , call_ctx , outgoing_proxy , char * , str )
685696_OAUTH2_TYPE_IMPLEMENT_MEMBER_SET (http , call_ctx , ca_info , char * , str )
@@ -770,6 +781,13 @@ static char *_oauth2_http_call_ctx2s(oauth2_log_t *log,
770781 ctx -> to_str = oauth2_stradd (ctx -> to_str , " ssl_key" ,
771782 _OAUTH2_STR_EQUAL , ctx -> ssl_key );
772783
784+ ctx -> to_str = oauth2_intadd (ctx -> to_str , " timeout" , _OAUTH2_STR_EQUAL ,
785+ ctx -> timeout );
786+ ctx -> to_str = oauth2_intadd (ctx -> to_str , " retries" , _OAUTH2_STR_EQUAL ,
787+ ctx -> retries );
788+ ctx -> to_str = oauth2_intadd (ctx -> to_str , " retry_interval" ,
789+ _OAUTH2_STR_EQUAL , ctx -> retry_interval );
790+
773791 ptr = oauth2_nv_list2s (log , ctx -> hdr );
774792 if (ptr ) {
775793 ctx -> to_str =
@@ -970,6 +988,8 @@ bool oauth2_http_call(oauth2_log_t *log, const char *url, const char *data,
970988 bool rc = false;
971989 char * str = NULL ;
972990 long response_code = 0 ;
991+ int i = 0 ;
992+ int retries = 1 ;
973993
974994 char err [CURL_ERROR_SIZE ];
975995 CURL * curl = NULL ;
@@ -1095,29 +1115,54 @@ bool oauth2_http_call(oauth2_log_t *log, const char *url, const char *data,
10951115
10961116 curl_easy_setopt (curl , CURLOPT_URL , url );
10971117
1098- errornum = curl_easy_perform (curl );
1099- if (errornum != CURLE_OK ) {
1100- oauth2_error (log , "curl_easy_perform() failed on: %s (%s: %s)" ,
1101- url , curl_easy_strerror (errornum ),
1102- err [0 ] ? err : "" );
1103- if (errornum == CURLE_OPERATION_TIMEDOUT )
1118+ if (ctx )
1119+ retries = ctx -> retries ;
1120+
1121+ oauth2_debug (log , "looping: i=%d, retries=%d" , i , retries );
1122+
1123+ for (i = 0 ; i <= retries ; i ++ ) {
1124+ oauth2_debug (log , "looping: i=%d, retries=%d" , i , retries );
1125+ errornum = curl_easy_perform (curl );
1126+ if (errornum == CURLE_OK ) {
1127+ rc = true;
1128+ break ;
1129+ }
1130+ if (errornum == CURLE_OPERATION_TIMEDOUT ) {
1131+ /* in case of a request/transfer timeout (which includes
1132+ * the connect timeout) we'll not retry */
1133+ oauth2_error (log ,
1134+ "curl_easy_perform failed with a timeout "
1135+ "for %s: [%s; %s]; won't retry" ,
1136+ url , curl_easy_strerror (errornum ),
1137+ err [0 ] ? err : "" );
11041138 // 408 Request Timeout
11051139 // 504 Gateway Timeout
11061140 * status_code = 504 ;
1107- goto end ;
1141+ break ;
1142+ }
1143+ oauth2_error (
1144+ log ,
1145+ "curl_easy_perform(%d/%d) failed for: %s with [%s: %s]" ,
1146+ i + 1 , retries + 1 , url , curl_easy_strerror (errornum ),
1147+ err [0 ] ? err : "" );
1148+ /* in case of a connectivity/network glitch we'll back off
1149+ * before retrying */
1150+ if (i < retries )
1151+ usleep ((ctx ? ctx -> retry_interval : 300 ) * 1000 );
11081152 }
11091153
11101154 curl_easy_getinfo (curl , CURLINFO_RESPONSE_CODE , & response_code );
11111155 oauth2_debug (log , "HTTP response code=%ld" , response_code );
11121156 if (status_code )
11131157 * status_code = (oauth2_uint_t )response_code ;
11141158
1159+ if (rc == false)
1160+ goto end ;
1161+
11151162 * response = oauth2_mem_alloc (buf .size + 1 );
11161163 strncpy (* response , buf .memory , buf .size );
11171164 (* response )[buf .size ] = '\0' ;
11181165
1119- rc = true;
1120-
11211166end :
11221167
11231168 if (buf .memory )
@@ -1126,8 +1171,9 @@ bool oauth2_http_call(oauth2_log_t *log, const char *url, const char *data,
11261171 curl_slist_free_all (h_list );
11271172 curl_easy_cleanup (curl );
11281173
1129- oauth2_debug (log , "leave [%d]: %s" , rc ,
1130- (response && * response ) ? * response : "(null)" );
1174+ oauth2_debug (log , "leave [%d]: %s (status=%d)" , rc ,
1175+ (response && * response ) ? * response : "(null)" ,
1176+ status_code ? * status_code : -1 );
11311177
11321178 return rc ;
11331179}
0 commit comments