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) {
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 if (g_hash_table_contains(query_params,
"delete")) {
291 return g_strconcat(path->
value,
"?delete", NULL);
293 return g_strdup(path->
value);
305 to_read = size * nmemb;
310 header_buff = g_new0(
char, to_read+1);
311 strncpy(header_buff, (
char*)buffer, to_read);
312 header_buff = g_strchomp(header_buff);
315 if (strlen(header_buff) == 0) {
321 if (g_str_has_prefix(header_buff,
"HTTP/1.1") == TRUE) {
324 uint64_t status_code;
325 split_result = g_strsplit(header_buff,
" ", 1000);
326 status_code = g_ascii_strtoll(split_result[1], &endpointer, 10);
327 if (status_code == 0 && endpointer != NULL) {
328 fprintf(stderr,
"Encountered a problem parsing the status code\n");
329 g_strfreev(split_result);
333 if (status_code == 100) {
335 g_strfreev(split_result);
338 char* status_message = g_strjoinv(
" ", split_result + 2);
341 g_free(status_message);
342 g_strfreev(split_result);
345 fprintf(stderr,
"Unsupported Protocol\n");
350 split_result = g_strsplit(header_buff,
": ", 2);
357 g_strfreev(split_result);
377 void* read_user_struct,
378 size_t (*read_handler_func)(
void*,
size_t,
size_t,
void*),
379 void* write_user_struct,
380 size_t (*write_handler_func)(
void*,
size_t,
size_t,
void*),
401 while (retry_count < client->num_redirects) {
408 char* canonicalized_resource;
412 struct curl_slist* headers;
414 char* checksum_value;
421 response_data.
headers = response_headers;
422 response_data.
body = g_byte_array_new();
424 if (client->
log != NULL) {
426 curl_easy_setopt(handle, CURLOPT_DEBUGDATA, client->
log);
427 curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
430 curl_easy_setopt(handle, CURLOPT_URL, url);
432 curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 0);
436 curl_easy_setopt(handle, CURLOPT_HEADERDATA, &response_data);
438 if (client->
proxy != NULL) {
439 curl_easy_setopt(handle, CURLOPT_PROXY, client->
proxy->
value);
443 if (read_user_struct != NULL && read_handler_func != NULL) {
444 response_data.
user_data = read_user_struct;
445 response_data.
user_func = read_handler_func;
450 curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response_data);
452 if (write_user_struct != NULL && write_handler_func != NULL) {
453 curl_easy_setopt(handle, CURLOPT_READFUNCTION, write_handler_func);
454 curl_easy_setopt(handle, CURLOPT_READDATA, write_user_struct);
457 switch(request->
verb) {
459 curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST,
"POST");
460 curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
461 curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, request->
length);
465 curl_easy_setopt(handle, CURLOPT_PUT, 1L);
466 curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
467 curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, request->
length);
471 curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST,
"DELETE");
475 curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST,
"HEAD");
476 curl_easy_setopt(handle, CURLOPT_NOBODY, 1L);
486 date_header = g_strconcat(
"Date: ", date, NULL);
492 char* checksum_header;
495 headers = curl_slist_append(headers, checksum_header);
496 g_free(checksum_header);
503 g_free(canonicalized_resource);
505 auth_header = g_strconcat(
"Authorization: AWS ", client->
creds->
access_id->
value,
":", signature, NULL);
507 headers = curl_slist_append(headers, auth_header);
508 headers = curl_slist_append(headers, date_header);
511 curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
514 res = curl_easy_perform(handle);
521 curl_slist_free_all(headers);
527 if (res != CURLE_OK) {
528 char * message = g_strconcat(
"Request failed: ", curl_easy_strerror(res), NULL);
531 g_byte_array_free(response_data.
body, TRUE);
545 if (response_data.
body != NULL) {
547 g_byte_array_free(response_data.
body, TRUE);
564 error->
message =
ds3_str_init(
"Encountered too many redirects while attempting to fulfill the request");
572 g_byte_array_free(response_data.
body, TRUE);
575 if (return_headers != NULL) {
576 *return_headers = response_headers;
592 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)