@@ -79,6 +79,46 @@ typedef struct {
7979 ds3_str * value ;
8080}ds3_response_header ;
8181
82+ static void LOG (const ds3_log * log , ds3_log_lvl lvl , const char * message , ...) {
83+ if (log == NULL ) {
84+ return ;
85+ }
86+
87+ if (log -> log_callback == NULL ) {
88+ fprintf (stderr , "ERROR: ds3_c_sdk - User supplied log_callback is null, failed to log message.\n" );
89+ return ;
90+ }
91+
92+ if (lvl <= log -> log_lvl ) {
93+ va_list args ;
94+ char * log_message ;
95+
96+ va_start (args , message );
97+ log_message = g_strdup_vprintf (message , args );
98+ va_end (args );
99+
100+ log -> log_callback (log_message , log -> user_data );
101+
102+ g_free (log_message );
103+ }
104+ }
105+
106+ void ds3_client_register_logging (ds3_client * client , ds3_log_lvl log_lvl , void (* log_callback )(const char * log_message , void * user_data ), void * user_data ) {
107+ if (client == NULL ) {
108+ fprintf (stderr , "Cannot configure a null ds3_client for logging.\n" );
109+ return ;
110+ }
111+ if (client -> log != NULL ) {
112+ g_free (client -> log );
113+ }
114+ ds3_log * log = g_new0 (ds3_log , 1 );
115+ log -> log_callback = log_callback ;
116+ log -> user_data = user_data ;
117+ log -> log_lvl = log_lvl ;
118+
119+ client -> log = log ;
120+ }
121+
82122ds3_str * ds3_str_init (const char * string ) {
83123 size_t size = strlen (string );
84124 return ds3_str_init_with_size (string , size );
@@ -396,14 +436,44 @@ static struct curl_slist* _append_headers(struct curl_slist* header_list, GHashT
396436 return header_list ;
397437}
398438
439+ static int ds3_curl_logger (CURL * handle , curl_infotype type , char * data , size_t size , void * userp ) {
440+ char * text = "curl_log" ;
441+ ds3_log * log = (ds3_log * ) userp ;
442+ char * message ;
443+ switch (type ) {
444+ case CURLINFO_HEADER_OUT :
445+ text = "HEADER_SENT" ;
446+ break ;
447+ case CURLINFO_HEADER_IN :
448+ text = "HEADER_RECV" ;
449+ break ;
450+
451+ case CURLINFO_DATA_IN :
452+ case CURLINFO_DATA_OUT :
453+ case CURLINFO_SSL_DATA_IN :
454+ case CURLINFO_SSL_DATA_OUT :
455+ // do not log any payload data
456+ return 0 ;
457+ default :
458+ break ;
459+ }
460+
461+ message = strndup (data , size );
462+
463+ LOG (log , TRACE , "%s: %s" , text , g_strchomp (message ));
464+
465+ g_free (message );
466+ return 0 ;
467+ }
468+
399469static ds3_error * _net_process_request (const ds3_client * client , const ds3_request * _request , void * read_user_struct , size_t (* read_handler_func )(void * , size_t , size_t , void * ), void * write_user_struct , size_t (* write_handler_func )(void * , size_t , size_t , void * ), GHashTable * * return_headers ) {
400470 _init_curl ();
401471
402472 struct _ds3_request * request = (struct _ds3_request * ) _request ;
403473 CURL * handle = curl_easy_init ();
404474 CURLcode res ;
405475
406- if (handle ) {
476+ if (handle ) {
407477 char * url ;
408478
409479 char * date ;
@@ -415,6 +485,8 @@ static ds3_error* _net_process_request(const ds3_client* client, const ds3_reque
415485 ds3_response_data response_data ;
416486 GHashTable * response_headers = g_hash_table_new_full (g_str_hash , g_str_equal , NULL , _ds3_free_response_header );
417487
488+ LOG (client -> log , DEBUG , "Preparing to send request" );
489+
418490 memset (& response_data , 0 , sizeof (ds3_response_data ));
419491 response_data .headers = response_headers ;
420492 response_data .body = g_byte_array_new ();
@@ -426,6 +498,13 @@ static ds3_error* _net_process_request(const ds3_client* client, const ds3_reque
426498 url = g_strconcat (client -> endpoint -> value , request -> path -> value ,"?" ,query_params , NULL );
427499 g_free (query_params );
428500 }
501+
502+ if (client -> log != NULL ) {
503+ curl_easy_setopt (handle , CURLOPT_DEBUGFUNCTION , ds3_curl_logger );
504+ curl_easy_setopt (handle , CURLOPT_DEBUGDATA , client -> log );
505+ curl_easy_setopt (handle , CURLOPT_VERBOSE , 1L ); // turn on verbose logging
506+ }
507+
429508 curl_easy_setopt (handle , CURLOPT_URL , url );
430509 curl_easy_setopt (handle , CURLOPT_FOLLOWLOCATION , 1L ); //tell curl to follow redirects
431510 curl_easy_setopt (handle , CURLOPT_MAXREDIRS , client -> num_redirects );
@@ -524,6 +603,8 @@ static ds3_error* _net_process_request(const ds3_client* client, const ds3_reque
524603 return error ;
525604 }
526605
606+ LOG (client -> log , DEBUG , "Request completed with status code of: %d" , response_data .status_code );
607+
527608 if (response_data .status_code < 200 || response_data .status_code >= 300 ) {
528609 ds3_error * error = _ds3_create_error (DS3_ERROR_BAD_STATUS_CODE , "Got an unexpected status code." );
529610 error -> error = g_new0 (ds3_error_response , 1 );
@@ -560,7 +641,7 @@ static void _cleanup_hash_value(gpointer value) {
560641
561642//---------- Ds3 code ----------//
562643static GHashTable * _create_hash_table (void ) {
563- GHashTable * hash = g_hash_table_new_full (g_str_hash , g_str_equal , NULL , _cleanup_hash_value );
644+ GHashTable * hash = g_hash_table_new_full (g_str_hash , g_str_equal , _cleanup_hash_value , _cleanup_hash_value );
564645 return hash ;
565646}
566647
@@ -676,7 +757,7 @@ void ds3_request_set_max_keys(ds3_request* _request, uint32_t max_keys) {
676757static struct _ds3_request * _common_request_init (http_verb verb , ds3_str * path ) {
677758 struct _ds3_request * request = g_new0 (struct _ds3_request , 1 );
678759 request -> headers = _create_hash_table ();
679- request -> query_params = g_hash_table_new_full ( g_str_hash , g_str_equal , _cleanup_hash_value , _cleanup_hash_value );
760+ request -> query_params = _create_hash_table ( );
680761 request -> verb = verb ;
681762 request -> path = path ;
682763 return request ;
@@ -868,7 +949,7 @@ static uint64_t xml_get_uint64_from_attribute(xmlDocPtr doc, struct _xmlAttr* at
868949 return xml_get_uint64 (doc , (xmlNodePtr ) attribute );
869950}
870951
871- static ds3_bool xml_get_bool_from_attribute (xmlDocPtr doc , struct _xmlAttr * attribute ) {
952+ static ds3_bool xml_get_bool_from_attribute (const ds3_log * log , xmlDocPtr doc , struct _xmlAttr * attribute ) {
872953 xmlChar * text ;
873954 ds3_bool result ;
874955 text = xmlNodeListGetString (doc , attribute -> xmlChildrenNode , 1 );
@@ -879,7 +960,7 @@ static ds3_bool xml_get_bool_from_attribute(xmlDocPtr doc, struct _xmlAttr* attr
879960 result = False ;
880961 }
881962 else {
882- fprintf ( stderr , "Unknown boolean value\n " );
963+ LOG ( log , ERROR , "Unknown boolean value" );
883964 result = False ;
884965 }
885966 xmlFree (text );
@@ -1219,7 +1300,7 @@ ds3_error* ds3_delete_bucket(const ds3_client* client, const ds3_request* reques
12191300 return _internal_request_dispatcher (client , request , NULL , NULL , NULL , NULL );
12201301}
12211302
1222- static ds3_bulk_object _parse_bulk_object (xmlDocPtr doc , xmlNodePtr object_node ) {
1303+ static ds3_bulk_object _parse_bulk_object (const ds3_log * log , xmlDocPtr doc , xmlNodePtr object_node ) {
12231304 xmlNodePtr child_node ;
12241305 xmlChar * text ;
12251306 struct _xmlAttr * attribute ;
@@ -1237,7 +1318,7 @@ static ds3_bulk_object _parse_bulk_object(xmlDocPtr doc, xmlNodePtr object_node)
12371318 xmlFree (text );
12381319 }
12391320 else if (attribute_equal (attribute , "InCache" ) == true) {
1240- response .in_cache = xml_get_bool_from_attribute (doc , attribute );
1321+ response .in_cache = xml_get_bool_from_attribute (log , doc , attribute );
12411322 }
12421323 else if (attribute_equal (attribute , "Length" ) == true) {
12431324 response .length = xml_get_uint64_from_attribute (doc , attribute );
@@ -1257,7 +1338,7 @@ static ds3_bulk_object _parse_bulk_object(xmlDocPtr doc, xmlNodePtr object_node)
12571338 return response ;
12581339}
12591340
1260- static ds3_bulk_object_list * _parse_bulk_objects (xmlDocPtr doc , xmlNodePtr objects_node ) {
1341+ static ds3_bulk_object_list * _parse_bulk_objects (const ds3_log * log , xmlDocPtr doc , xmlNodePtr objects_node ) {
12611342 xmlNodePtr child_node ;
12621343 xmlChar * text ;
12631344 struct _xmlAttr * attribute ;
@@ -1293,7 +1374,7 @@ static ds3_bulk_object_list* _parse_bulk_objects(xmlDocPtr doc, xmlNodePtr objec
12931374
12941375 for (child_node = objects_node -> xmlChildrenNode ; child_node != NULL ; child_node = child_node -> next ) {
12951376 if (element_equal (child_node , "Object" ) == true) {
1296- ds3_bulk_object object = _parse_bulk_object (doc , child_node );
1377+ ds3_bulk_object object = _parse_bulk_object (log , doc , child_node );
12971378 g_array_append_val (object_array , object );
12981379 }
12991380 else {
@@ -1390,7 +1471,7 @@ static ds3_job_status _match_job_status(const xmlChar* text) {
13901471 }
13911472}
13921473
1393- static ds3_error * _parse_master_object_list (xmlDocPtr doc , ds3_bulk_response * * _response ){
1474+ static ds3_error * _parse_master_object_list (const ds3_log * log , xmlDocPtr doc , ds3_bulk_response * * _response ){
13941475 struct _xmlAttr * attribute ;
13951476 GArray * objects_array ;
13961477 xmlChar * text ;
@@ -1502,18 +1583,18 @@ static ds3_error* _parse_master_object_list(xmlDocPtr doc, ds3_bulk_response** _
15021583 xmlFree (text );
15031584 }
15041585 else {
1505- fprintf ( stderr , "Unknown attribute: (%s)\n " , attribute -> name );
1586+ LOG ( log , ERROR , "Unknown attribute: (%s)" , attribute -> name );
15061587 }
15071588 }
15081589
15091590 for (child_node = root -> xmlChildrenNode ; child_node != NULL ; child_node = child_node -> next ) {
15101591 if (element_equal (child_node , "Objects" ) == true) {
1511- ds3_bulk_object_list * obj_list = _parse_bulk_objects (doc , child_node );
1592+ ds3_bulk_object_list * obj_list = _parse_bulk_objects (log , doc , child_node );
15121593 g_array_append_val (objects_array , obj_list );
15131594 }
15141595 else {
15151596 //TODO add Node xml handling
1516- fprintf ( stderr , "Unknown element: (%s)\n " , child_node -> name );
1597+ LOG ( log , ERROR , "Unknown element: (%s)" , child_node -> name );
15171598 }
15181599 }
15191600
@@ -1754,7 +1835,7 @@ ds3_error* ds3_bulk(const ds3_client* client, const ds3_request* _request, ds3_b
17541835 return NULL ;
17551836 }
17561837
1757- error_response = _parse_master_object_list (doc , response );
1838+ error_response = _parse_master_object_list (client -> log , doc , response );
17581839
17591840 xmlFreeDoc (doc );
17601841 g_byte_array_free (xml_blob , TRUE);
@@ -1805,7 +1886,7 @@ ds3_error* ds3_allocate_chunk(const ds3_client* client, const ds3_request* reque
18051886
18061887 root = xmlDocGetRootElement (doc );
18071888 if (element_equal (root , "Objects" ) == true) {
1808- object_list = _parse_bulk_objects (doc , root );
1889+ object_list = _parse_bulk_objects (client -> log , doc , root );
18091890 ds3_response -> objects = object_list ;
18101891 }
18111892 else {
@@ -1857,7 +1938,7 @@ ds3_error* ds3_get_available_chunks(const ds3_client* client, const ds3_request*
18571938 }
18581939 }
18591940
1860- _parse_master_object_list (doc , & bulk_response );
1941+ _parse_master_object_list (client -> log , doc , & bulk_response );
18611942 ds3_response -> object_list = bulk_response ;
18621943
18631944 xmlFreeDoc (doc );
@@ -1894,7 +1975,7 @@ static ds3_error* _common_job(const ds3_client* client, const ds3_request* reque
18941975 return _ds3_create_error (DS3_ERROR_REQUEST_FAILED , "Unexpected empty response body." );
18951976 }
18961977
1897- _parse_master_object_list (doc , & bulk_response );
1978+ _parse_master_object_list (client -> log , doc , & bulk_response );
18981979
18991980 xmlFreeDoc (doc );
19001981 g_byte_array_free (xml_blob , TRUE);
@@ -2059,15 +2140,18 @@ void ds3_free_creds(ds3_creds* creds) {
20592140}
20602141
20612142void ds3_free_client (ds3_client * client ) {
2062- if (client == NULL ) {
2143+ if (client == NULL ) {
20632144 return ;
20642145 }
2065- if (client -> endpoint != NULL ) {
2146+ if (client -> endpoint != NULL ) {
20662147 ds3_str_free (client -> endpoint );
20672148 }
2068- if (client -> proxy != NULL ) {
2149+ if (client -> proxy != NULL ) {
20692150 ds3_str_free (client -> proxy );
20702151 }
2152+ if (client -> log != NULL ) {
2153+ g_free (client -> log );
2154+ }
20712155 g_free (client );
20722156}
20732157
0 commit comments