20 #include <curl/curl.h> 32 if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
33 fprintf(stderr,
"Encountered an error initializing libcurl\n");
68 char* curl_escaped_url = curl_easy_escape(NULL, url, 0);
69 char* escaped_url = g_strdup(curl_escaped_url);
70 curl_free(curl_escaped_url);
76 gchar** split = g_strsplit(url, delimiters[num_delimiters-1], 0);
79 for (ptr = split; *ptr; ptr++) {
80 if( num_delimiters > 1){
88 escaped_ptr = g_strjoinv(delimiters[num_delimiters-1], split);
95 const char *delimiters[1]={
"/"};
101 const char *delimiters[2]={
"=",
","};
106 char* content_type,
char* checksum_value,
char* amz_headers) {
108 if (resource_name == NULL) {
109 fprintf(stderr,
"resource_name is required\n");
113 fprintf(stderr,
"date is required");
118 return (
unsigned char*) g_strconcat(verb_str,
"\n", checksum_value,
"\n", content_type,
"\n", date,
"\n", amz_headers, resource_name, NULL);
122 GDateTime* time = g_date_time_new_now_local();
123 char* date_string = g_date_time_format(time,
"%a, %d %b %Y %H:%M:%S %z");
125 g_date_time_unref(time);
131 char* date,
char* content_type,
char* checksum_value,
char* amz_headers) {
137 unsigned char* signature_str =
_generate_signature_str(verb, resource_name, date, content_type, checksum_value, amz_headers);
138 char* escaped_str = g_strescape((
char*) signature_str, NULL);
144 g_hmac_update(hmac, signature_str, strlen((
const char*)signature_str));
145 g_hmac_get_digest(hmac, buffer, &bufSize);
147 signature = g_base64_encode(buffer, bufSize);
149 g_free(signature_str);
160 static void _hash_for_each(gpointer _key, gpointer _value, gpointer _user_data) {
161 char* key = (
char*) _key;
162 char* value = (
char*) _value;
163 query_entries* entries = (query_entries*) _user_data;
165 entries->entries[entries->size] = g_strconcat(key, NULL);
167 entries->entries[entries->size] = g_strconcat(key,
"=", value, NULL);
173 if (g_hash_table_size(query_params) > 0) {
174 query_entries q_entries;
179 memset(&q_entries, 0,
sizeof(query_entries));
182 entries = g_new0(
char*, g_hash_table_size(query_params) + 1);
183 q_entries.entries = entries;
186 return_string = g_strjoinv(
"&", entries);
189 char* current_string = entries[i];
190 if (current_string == NULL) {
193 g_free(current_string);
198 return return_string;
204 static struct curl_slist*
_append_headers(
struct curl_slist* header_list, GHashTable* headers_map) {
207 struct curl_slist* updated_list = header_list;
208 g_hash_table_iter_init(&iter, headers_map);
210 while (g_hash_table_iter_next(&iter, &key, &value)) {
211 char* header_value = g_strconcat((
char*)key,
": ", (
char*)value, NULL);
212 updated_list = curl_slist_append(updated_list, header_value);
213 g_free(header_value);
218 static int ds3_curl_logger(CURL *handle, curl_infotype type,
char* data,
size_t size,
void* userp) {
219 char* text =
"curl_log";
223 case CURLINFO_HEADER_OUT:
224 text =
"HEADER_SENT";
226 case CURLINFO_HEADER_IN:
227 text =
"HEADER_RECV";
230 case CURLINFO_DATA_IN:
231 case CURLINFO_DATA_OUT:
232 case CURLINFO_SSL_DATA_IN:
233 case CURLINFO_SSL_DATA_OUT:
240 message = g_strndup(data, size);
249 char** val1 = (
char**)a;
250 char** val2 = (
char**)b;
252 return g_strcmp0(*val1, *val2);
256 GList* keys = g_hash_table_get_keys(headers);
258 GString* canonicalized_headers = g_string_new(
"");
259 GPtrArray *signing_strings = g_ptr_array_new_with_free_func(g_free);
260 GString* header_signing_value;
265 if(g_str_has_prefix((
char*)key->data,
"x-amz")){
266 header_signing_value = g_string_new((gchar*)key->data);
267 header_signing_value = g_string_append(g_string_ascii_down(header_signing_value),
":");
268 header_signing_value = g_string_append(header_signing_value, (gchar*)g_hash_table_lookup(headers, key->data));
270 signing_value = g_string_free(header_signing_value, FALSE);
271 g_ptr_array_add(signing_strings, signing_value);
278 for (i = 0; i < signing_strings->len; i++) {
279 g_string_append(canonicalized_headers, (gchar*)g_ptr_array_index(signing_strings, i));
280 g_string_append(canonicalized_headers,
"\n");
284 g_ptr_array_free(signing_strings, TRUE);
286 return g_string_free(canonicalized_headers, FALSE);
290 gchar* versioning_query = NULL;
292 gchar* path_copy = g_strdup(path->
value);
293 gchar* canonicalized_query;
294 gchar** query_strings;
295 GPtrArray* array = g_ptr_array_new();
298 if (g_hash_table_contains(query_params,
"delete")) {
299 g_ptr_array_add(array,
"delete");
302 if (g_hash_table_contains(query_params,
"versioning")) {
303 gchar* version_level = g_hash_table_lookup(query_params,
"versioning");
304 versioning_query = g_strdup_printf(
"versioning=%s", version_level);
305 g_ptr_array_add(array, versioning_query);
308 if (g_hash_table_contains(query_params,
"versions")) {
309 g_ptr_array_add(array,
"versions");
313 g_ptr_array_add(array, NULL);
314 query_strings = (gchar**)g_ptr_array_free(array, FALSE);
316 canonicalized_query = g_strjoinv(
"&", query_strings);
319 if (versioning_query != NULL) {
320 g_free(versioning_query);
322 g_free(query_strings);
324 if (strlen(canonicalized_query) > 0) {
325 gchar* canonicalized_path = g_strjoin(
"?", path_copy, canonicalized_query, NULL);
326 g_free(canonicalized_query);
328 return canonicalized_path;
330 g_free(canonicalized_query);
342 to_read = size * nmemb;
347 header_buff = g_new0(
char, to_read+1);
348 strncpy(header_buff, (
char*)buffer, to_read);
349 header_buff = g_strchomp(header_buff);
352 if (strlen(header_buff) == 0) {
358 if (g_str_has_prefix(header_buff,
"HTTP/1.1") == TRUE) {
361 uint64_t status_code;
362 split_result = g_strsplit(header_buff,
" ", 1000);
363 status_code = g_ascii_strtoll(split_result[1], &endpointer, 10);
364 if (status_code == 0 && endpointer != NULL) {
365 fprintf(stderr,
"Encountered a problem parsing the status code\n");
366 g_strfreev(split_result);
370 if (status_code == 100) {
372 g_strfreev(split_result);
375 char* status_message = g_strjoinv(
" ", split_result + 2);
378 g_free(status_message);
379 g_strfreev(split_result);
382 fprintf(stderr,
"Unsupported Protocol\n");
387 split_result = g_strsplit(header_buff,
": ", 2);
394 g_strfreev(split_result);
414 void* read_user_struct,
415 size_t (*read_handler_func)(
void*,
size_t,
size_t,
void*),
416 void* write_user_struct,
417 size_t (*write_handler_func)(
void*,
size_t,
size_t,
void*),
438 while (retry_count < client->num_redirects) {
445 char* canonicalized_resource;
449 struct curl_slist* headers;
451 char* checksum_value;
458 response_data.
headers = response_headers;
459 response_data.
body = g_byte_array_new();
461 if (client->
log != NULL) {
463 curl_easy_setopt(handle, CURLOPT_DEBUGDATA, client->
log);
464 curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
467 curl_easy_setopt(handle, CURLOPT_URL, url);
469 curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 0);
473 curl_easy_setopt(handle, CURLOPT_HEADERDATA, &response_data);
475 if (client->
proxy != NULL) {
476 curl_easy_setopt(handle, CURLOPT_PROXY, client->
proxy->
value);
480 if (read_user_struct != NULL && read_handler_func != NULL) {
481 response_data.
user_data = read_user_struct;
482 response_data.
user_func = read_handler_func;
487 curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response_data);
489 if (write_user_struct != NULL && write_handler_func != NULL) {
490 curl_easy_setopt(handle, CURLOPT_READFUNCTION, write_handler_func);
491 curl_easy_setopt(handle, CURLOPT_READDATA, write_user_struct);
494 switch(request->
verb) {
496 curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST,
"POST");
497 curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
498 curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, request->
length);
502 curl_easy_setopt(handle, CURLOPT_PUT, 1L);
503 curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
504 curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, request->
length);
508 curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST,
"DELETE");
512 curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST,
"HEAD");
513 curl_easy_setopt(handle, CURLOPT_NOBODY, 1L);
523 date_header = g_strconcat(
"Date: ", date, NULL);
529 char* checksum_header;
532 headers = curl_slist_append(headers, checksum_header);
533 g_free(checksum_header);
540 g_free(canonicalized_resource);
542 auth_header = g_strconcat(
"Authorization: AWS ", client->
creds->
access_id->
value,
":", signature, NULL);
544 headers = curl_slist_append(headers, auth_header);
545 headers = curl_slist_append(headers, date_header);
548 curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
551 res = curl_easy_perform(handle);
558 curl_slist_free_all(headers);
564 if (res != CURLE_OK) {
565 char * message = g_strconcat(
"Request failed: ", curl_easy_strerror(res), NULL);
568 g_byte_array_free(response_data.
body, TRUE);
582 if (response_data.
body != NULL) {
584 g_byte_array_free(response_data.
body, TRUE);
601 error->
message =
ds3_str_init(
"Encountered too many redirects while attempting to fulfill the request");
609 g_byte_array_free(response_data.
body, TRUE);
612 if (return_headers != NULL) {
613 *return_headers = response_headers;
629 curl_global_cleanup();
ds3_checksum_type checksum_type
static size_t _process_header_line(void *buffer, size_t size, size_t nmemb, void *user_data)
char * escape_url(const char *url)
static size_t _process_response_body(void *buffer, size_t size, size_t nmemb, void *user_data)
static void _hash_for_each(gpointer _key, gpointer _value, gpointer _user_data)
static char * _get_checksum_type_header(const ds3_checksum_type type)
char * escape_url_object_name(const char *url)
static char * _canonicalize_amz_headers(GHashTable *headers)
void ds3_log_message(const ds3_log *log, ds3_log_lvl lvl, const char *message,...)
char * escape_url_extended(const char *url, const char **delimiters, uint32_t num_delimiters)
char * escape_url_range_header(const char *url)
static char * _net_gen_query_params(GHashTable *query_params)
ds3_error * ds3_create_error(ds3_error_code code, const char *message)
static int ds3_curl_logger(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
ds3_string_multimap * headers
GHashTable * query_params
size_t ds3_load_buffer(void *buffer, size_t size, size_t nmemb, void *user_data)
void ds3_str_free(ds3_str *string)
static char * _net_get_verb(http_verb verb)
static char * _net_compute_signature(const ds3_log *log, const ds3_creds *creds, http_verb verb, char *resource_name, char *date, char *content_type, char *checksum_value, char *amz_headers)
ds3_string_multimap * ds3_string_multimap_init(void)
static struct curl_slist * _append_headers(struct curl_slist *header_list, GHashTable *headers_map)
void ds3_connection_release(ds3_connection_pool *pool, ds3_connection *connection)
static unsigned char * _generate_signature_str(http_verb verb, char *resource_name, char *date, char *content_type, char *checksum_value, char *amz_headers)
ds3_error_response * error
void ds3_string_multimap_free(ds3_string_multimap *map)
ds3_str * ds3_str_init_with_size(const char *string, size_t size)
static char * _generate_date_string(void)
void ds3_string_multimap_insert(ds3_string_multimap *map, const ds3_str *key, const ds3_str *value)
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 *), ds3_string_multimap **return_headers)
size_t(* user_func)(void *, size_t, size_t, void *)
ds3_connection_pool * connection_pool
ds3_connection * ds3_connection_acquire(ds3_connection_pool *pool)
static char * _canonicalized_resource(ds3_str *path, GHashTable *query_params)
ds3_str * ds3_str_init(const char *string)
static void _init_curl(void)
static gint _gstring_sort(gconstpointer a, gconstpointer b)