Skip to content

Commit 0cd2018

Browse files
committed
Adding in basic logging support. The logging framework does not yet have very many messages, but if TRACE is passed in then all the libcrul messages will be logged. The libcurl logging will log the contents of the payloads, but we will not log that information in the event that there is some sensitive information.
1 parent 8e12a46 commit 0cd2018

File tree

3 files changed

+123
-25
lines changed

3 files changed

+123
-25
lines changed

src/ds3.c

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
82122
ds3_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+
399469
static 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 ----------//
562643
static 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) {
676757
static 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

20612142
void 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

src/ds3.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ LIBRARY_API size_t ds3_str_size(const ds3_str* string);
8585
LIBRARY_API ds3_str* ds3_str_dup(const ds3_str* string);
8686
LIBRARY_API void ds3_str_free(ds3_str* string);
8787

88+
typedef enum {
89+
ERROR, WARN, INFO, DEBUG, TRACE
90+
}ds3_log_lvl;
91+
92+
typedef struct {
93+
void (* log_callback)(const char* log_message, void* user_data);
94+
void* user_data;
95+
ds3_log_lvl log_lvl;
96+
}ds3_log;
97+
8898
typedef struct {
8999
ds3_str* access_id;
90100
ds3_str* secret_key;
@@ -95,6 +105,7 @@ typedef struct {
95105
ds3_str* proxy;
96106
uint64_t num_redirects;
97107
ds3_creds* creds;
108+
ds3_log* log;
98109
}ds3_client;
99110

100111
typedef struct _ds3_request ds3_request;
@@ -211,6 +222,7 @@ typedef struct {
211222
LIBRARY_API ds3_creds* ds3_create_creds(const char* access_id, const char* secret_key);
212223
LIBRARY_API ds3_client* ds3_create_client(const char* endpoint, ds3_creds* creds);
213224
LIBRARY_API ds3_error* ds3_create_client_from_env(ds3_client** client);
225+
LIBRARY_API 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);
214226

215227
LIBRARY_API ds3_request* ds3_init_get_service(void);
216228
LIBRARY_API ds3_request* ds3_init_get_bucket(const char* bucket_name);

test/test.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,25 @@
88
#include <boost/test/unit_test.hpp>
99

1010
struct TestCleanup {
11-
TestCleanup() {
12-
printf("global setup\n");
13-
}
11+
TestCleanup() {}
1412
~TestCleanup() {
15-
printf("global teardown\n");
1613
ds3_cleanup();
1714
}
1815
};
1916

2017
BOOST_GLOBAL_FIXTURE( TestCleanup );
2118

22-
ds3_client* get_client() {
19+
void test_log(const char* message, void* user_data) {
20+
fprintf(stderr, "Log Message: %s\n", message);
21+
}
2322

23+
ds3_client* get_client() {
2424
ds3_client* client;
2525

2626
ds3_error* error = ds3_create_client_from_env(&client);
2727

28+
ds3_client_register_logging(client, INFO, test_log, NULL);
29+
2830
if (error != NULL) {
2931
fprintf(stderr, "Failed to construct ds3_client from enviornment variables: %s\n", error->message->value);
3032
exit(1);

0 commit comments

Comments
 (0)