DS3 C SDK  3.0.0
Provides access to the Spectra S3 API with C
ds3_net.c
Go to the documentation of this file.
1 /*
2  * ******************************************************************************
3  * Copyright 2014-2016 Spectra Logic Corporation. All Rights Reserved.
4  * Licensed under the Apache License, Version 2.0 (the "License"). You may not use
5  * this file except in compliance with the License. A copy of the License is located at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * or in the "license" file accompanying this file.
10  * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11  * CONDITIONS OF ANY KIND, either express or implied. See the License for the
12  * specific language governing permissions and limitations under the License.
13  * ****************************************************************************
14  */
15 
16 /* This Code is Auto-Generated; DO NOT MODIFY! */
17 
18 
19 #include <curl/curl.h>
20 
21 #include "ds3_request.h"
22 #include "ds3.h"
23 #include "ds3_net.h"
24 #include "ds3_utils.h"
25 #include "ds3_string_multimap.h"
27 
28 static void _init_curl(void) {
29  static ds3_bool initialized = False;
30 
31  if (!initialized) {
32  if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
33  fprintf(stderr, "Encountered an error initializing libcurl\n");
34  }
35  initialized = True;
36  }
37 }
38 
39 static char* _net_get_verb(http_verb verb) {
40  switch(verb) {
41  case HTTP_GET: return "GET";
42  case HTTP_PUT: return "PUT";
43  case HTTP_POST: return "POST";
44  case HTTP_DELETE : return "DELETE";
45  case HTTP_HEAD : return "HEAD";
46  }
47 
48  return NULL;
49 }
50 
51 static char* _get_checksum_type_header(const ds3_checksum_type type) {
52  switch(type) {
53  case DS3_CHECKSUM_TYPE_MD5: return "Content-MD5:";
54  case DS3_CHECKSUM_TYPE_SHA_256: return "Content-SHA256:";
55  case DS3_CHECKSUM_TYPE_SHA_512: return "Content-SHA512:";
56  case DS3_CHECKSUM_TYPE_CRC_32: return "Content-CRC32:";
57  case DS3_CHECKSUM_TYPE_CRC_32C: return "Content-CRC32C:";
58  }
59 
60  return NULL;
61 }
62 
63 
64 // curl_easy_escape'd strings must be freed using curl_free. Copy
65 // the escaped string, using glib, since users of this function will
66 // eventually wind up freeing it with g_free.
67 char* escape_url(const char* url) {
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);
71  return escaped_url;
72 }
73 
74 // Like escape_url but don't encode "/".
75 char* escape_url_extended(const char* url, const char** delimiters, uint32_t num_delimiters) {
76  gchar** split = g_strsplit(url, delimiters[num_delimiters-1], 0);
77  gchar** ptr;
78  gchar* escaped_ptr;
79  for (ptr = split; *ptr; ptr++) {
80  if( num_delimiters > 1){
81  escaped_ptr = escape_url_extended(*ptr, delimiters, num_delimiters-1);
82  }else{
83  escaped_ptr = escape_url(*ptr);
84  }
85  g_free(*ptr);
86  *ptr = escaped_ptr;
87  }
88  escaped_ptr = g_strjoinv(delimiters[num_delimiters-1], split);
89  g_strfreev(split);
90  return escaped_ptr;
91 }
92 
93 // Like escape_url but don't encode "/".
94 char* escape_url_object_name(const char* url) {
95  const char *delimiters[1]={"/"};
96  return escape_url_extended(url, delimiters, 1);
97 }
98 
99 // Like escape_url but don't encode "=".
100 char* escape_url_range_header(const char* url) {
101  const char *delimiters[2]={"=", ","};
102  return escape_url_extended(url, delimiters, 2);
103 }
104 
105 static unsigned char* _generate_signature_str(http_verb verb, char* resource_name, char* date,
106  char* content_type, char* checksum_value, char* amz_headers) {
107  char* verb_str;
108  if (resource_name == NULL) {
109  fprintf(stderr, "resource_name is required\n");
110  return NULL;
111  }
112  if (date == NULL) {
113  fprintf(stderr, "date is required");
114  return NULL;
115  }
116  verb_str = _net_get_verb(verb);
117 
118  return (unsigned char*) g_strconcat(verb_str, "\n", checksum_value, "\n", content_type, "\n", date, "\n", amz_headers, resource_name, NULL);
119 }
120 
121 static char* _generate_date_string(void) {
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");
124 
125  g_date_time_unref(time);
126 
127  return date_string;
128 }
129 
130 static char* _net_compute_signature(const ds3_log* log, const ds3_creds* creds, http_verb verb, char* resource_name,
131  char* date, char* content_type, char* checksum_value, char* amz_headers) {
132  GHmac* hmac;
133  gchar* signature;
134  gsize bufSize = 256;
135  guint8 buffer[256];
136 
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);
139 
140  ds3_log_message(log, DS3_DEBUG, "signature string: %s", escaped_str);
141  g_free(escaped_str);
142 
143  hmac = g_hmac_new(G_CHECKSUM_SHA1, (unsigned char*) creds->secret_key->value, creds->secret_key->size);
144  g_hmac_update(hmac, signature_str, strlen((const char*)signature_str));
145  g_hmac_get_digest(hmac, buffer, &bufSize);
146 
147  signature = g_base64_encode(buffer, bufSize);
148 
149  g_free(signature_str);
150  g_hmac_unref(hmac);
151 
152  return signature;
153 }
154 
155 typedef struct {
156  char** entries;
157  size_t size;
158 }query_entries;
159 
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;
164  if (value == NULL) {
165  entries->entries[entries->size] = g_strconcat(key, NULL);
166  } else {
167  entries->entries[entries->size] = g_strconcat(key, "=", value, NULL);
168  }
169  entries->size++;
170 }
171 
172 static char* _net_gen_query_params(GHashTable* query_params) {
173  if (g_hash_table_size(query_params) > 0) {
174  query_entries q_entries;
175  char** entries;
176  char* return_string;
177  int i;
178  //build the query string
179  memset(&q_entries, 0, sizeof(query_entries));
180 
181  //We need the +1 so that it is NULL terminating for g_strjoinv
182  entries = g_new0(char*, g_hash_table_size(query_params) + 1);
183  q_entries.entries = entries;
184  g_hash_table_foreach(query_params, _hash_for_each, &q_entries);
185 
186  return_string = g_strjoinv("&", entries);
187 
188  for (i = 0; ; i++) {
189  char* current_string = entries[i];
190  if (current_string == NULL) {
191  break;
192  }
193  g_free(current_string);
194  }
195 
196  g_free(entries);
197  return return_string;
198  } else {
199  return NULL;
200  }
201 }
202 
203 static struct curl_slist* _append_headers(struct curl_slist* header_list, GHashTable* headers_map) {
204  GHashTableIter iter;
205  gpointer key, value;
206  struct curl_slist* updated_list = header_list;
207  g_hash_table_iter_init(&iter, headers_map);
208 
209  while (g_hash_table_iter_next(&iter, &key, &value)) {
210  char* header_value = g_strconcat((char*)key, ": ", (char*)value, NULL);
211  updated_list = curl_slist_append(updated_list, header_value);
212  g_free(header_value);
213  }
214  return updated_list;
215 }
216 
217 static int ds3_curl_logger(CURL *handle, curl_infotype type, char* data, size_t size, void* userp) {
218  char* text = "curl_log";
219  ds3_log* log = (ds3_log*) userp;
220  char* message;
221  switch(type) {
222  case CURLINFO_HEADER_OUT:
223  text = "HEADER_SENT";
224  break;
225  case CURLINFO_HEADER_IN:
226  text = "HEADER_RECV";
227  break;
228 
229  case CURLINFO_DATA_IN:
230  case CURLINFO_DATA_OUT:
231  case CURLINFO_SSL_DATA_IN:
232  case CURLINFO_SSL_DATA_OUT:
233  // do not log any payload data
234  return 0;
235  default:
236  break;
237  }
238 
239  message = g_strndup(data, size);
240 
241  ds3_log_message(log, DS3_TRACE, "%s: %s", text, g_strchomp(message));
242 
243  g_free(message);
244  return 0;
245 }
246 
247 static gint _gstring_sort(gconstpointer a, gconstpointer b) {
248  char** val1 = (char**)a;
249  char** val2 = (char**)b;
250 
251  return g_strcmp0(*val1, *val2);
252 }
253 
254 static char* _canonicalize_amz_headers(GHashTable* headers) {
255  GList* keys = g_hash_table_get_keys(headers);
256  GList* key = keys;
257  GString* canonicalized_headers = g_string_new("");
258  GPtrArray *signing_strings = g_ptr_array_new_with_free_func(g_free); // stores char*
259  GString* header_signing_value;
260  char* signing_value;
261  int i;
262 
263  while(key != NULL) {
264  if(g_str_has_prefix((char*)key->data, "x-amz")){
265  header_signing_value = g_string_new((gchar*)key->data);
266  header_signing_value = g_string_append(g_string_ascii_down(header_signing_value), ":");
267  header_signing_value = g_string_append(header_signing_value, (gchar*)g_hash_table_lookup(headers, key->data));
268 
269  signing_value = g_string_free(header_signing_value, FALSE);
270  g_ptr_array_add(signing_strings, signing_value);
271  }
272  key = key->next;
273  }
274 
275  g_ptr_array_sort(signing_strings, _gstring_sort);
276 
277  for (i = 0; i < signing_strings->len; i++) {
278  g_string_append(canonicalized_headers, (gchar*)g_ptr_array_index(signing_strings, i));
279  g_string_append(canonicalized_headers, "\n");
280  }
281 
282  g_list_free(keys);
283  g_ptr_array_free(signing_strings, TRUE);
284 
285  return g_string_free(canonicalized_headers, FALSE);
286 }
287 
288 static char* _canonicalized_resource(ds3_str* path, GHashTable* query_params) {
289  if (g_hash_table_contains(query_params, "delete")) {
290  return g_strconcat(path->value, "?delete", NULL);
291  } else {
292  return g_strdup(path->value);
293  }
294 }
295 
296 static size_t _process_header_line(void* buffer, size_t size, size_t nmemb, void* user_data) {
297  size_t to_read;
298  char* header_buff;
299  char** split_result;
300  ds3_str* header_key;
301  ds3_str* header_value;
302  ds3_response_data* response_data = (ds3_response_data*) user_data;
303 
304  to_read = size * nmemb;
305  if (to_read < 2) {
306  return 0;
307  }
308 
309  header_buff = g_new0(char, to_read+1); //+1 for the null byte
310  strncpy(header_buff, (char*)buffer, to_read);
311  header_buff = g_strchomp(header_buff);
312 
313  // If we have read all the headers, then the last line will only be \n\r
314  if (strlen(header_buff) == 0) {
315  g_free(header_buff);
316  return to_read;
317  }
318 
319  if (response_data->header_count < 1) {
320  if (g_str_has_prefix(header_buff, "HTTP/1.1") == TRUE) {
321  // parse out status code and the status string
322  char* endpointer;
323  uint64_t status_code;
324  split_result = g_strsplit(header_buff, " ", 1000);
325  status_code = g_ascii_strtoll(split_result[1], &endpointer, 10);
326  if (status_code == 0 && endpointer != NULL) {
327  fprintf(stderr, "Encountered a problem parsing the status code\n");
328  g_strfreev(split_result);
329  g_free(header_buff);
330  return 0;
331  }
332  if (status_code == 100) {
333  g_free(header_buff);
334  g_strfreev(split_result);
335  return to_read;
336  } else {
337  char* status_message = g_strjoinv(" ", split_result + 2);
338  response_data->status_code = status_code;
339  response_data->status_message = ds3_str_init(status_message);
340  g_free(status_message);
341  g_strfreev(split_result);
342  }
343  } else {
344  fprintf(stderr, "Unsupported Protocol\n");
345  g_free(header_buff);
346  return 0;
347  }
348  } else {
349  split_result = g_strsplit(header_buff, ": ", 2);
350  header_key = ds3_str_init(split_result[0]);
351  header_value = ds3_str_init(split_result[1]);
352 
353  ds3_string_multimap_insert(response_data->headers, header_key, header_value);
354  ds3_str_free(header_key);
355  ds3_str_free(header_value);
356  g_strfreev(split_result);
357  }
358  response_data->header_count++;
359  g_free(header_buff);
360  return to_read;
361 }
362 
363 static size_t _process_response_body(void* buffer, size_t size, size_t nmemb, void* user_data) {
364  ds3_response_data* response_data = (ds3_response_data*) user_data;
365 
366  // If we got an error, collect the error body
367  if (response_data->status_code >= 300) {
368  return ds3_load_buffer(buffer, size, nmemb, response_data->body);
369  } else { // If we did not get an error, call the user's defined callbacks.
370  return response_data->user_func(buffer, size, nmemb, response_data->user_data);
371  }
372 }
373 
375  const ds3_request* _request,
376  void* read_user_struct,
377  size_t (*read_handler_func)(void*, size_t, size_t, void*),
378  void* write_user_struct,
379  size_t (*write_handler_func)(void*, size_t, size_t, void*),
380  ds3_string_multimap** return_headers) {
381  struct _ds3_request* request = (struct _ds3_request*) _request;
382  CURL* handle;
383  CURLcode res;
384  char* url;
385  int retry_count = 0;
386  char* query_params;
387 
388  _init_curl();
389 
390  query_params = _net_gen_query_params(request->query_params);
391 
392  if (query_params == NULL) {
393  url = g_strconcat(client->endpoint->value, request->path->value, NULL);
394  } else {
395  url = g_strconcat(client->endpoint->value, request->path->value,"?",query_params, NULL);
396  g_free(query_params);
397  }
398 
399  while (retry_count < client->num_redirects) {
400  handle = curl_easy_init();
401 
402  if (handle) {
403  char* amz_headers;
404  char* canonicalized_resource;
405  char* date;
406  char* date_header;
407  char* signature;
408  struct curl_slist* headers;
409  char* auth_header;
410  char* checksum_value;
411  ds3_response_data response_data;
412  ds3_string_multimap* response_headers = ds3_string_multimap_init();
413 
414  ds3_log_message(client->log, DS3_DEBUG, "Preparing to send request");
415 
416  memset(&response_data, 0, sizeof(ds3_response_data));
417  response_data.headers = response_headers;
418  response_data.body = g_byte_array_new();
419 
420  if (client->log != NULL) {
421  curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, ds3_curl_logger);
422  curl_easy_setopt(handle, CURLOPT_DEBUGDATA, client->log);
423  curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); // turn on verbose logging
424  }
425 
426  curl_easy_setopt(handle, CURLOPT_URL, url);
427 
428  curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 0); // explicitly disable
429 
430  // Setup header collection
431  curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, _process_header_line);
432  curl_easy_setopt(handle, CURLOPT_HEADERDATA, &response_data);
433 
434  if (client->proxy != NULL) {
435  curl_easy_setopt(handle, CURLOPT_PROXY, client->proxy->value);
436  }
437 
438  // Register the read and write handlers if they are set
439  if (read_user_struct != NULL && read_handler_func != NULL) {
440  response_data.user_data = read_user_struct;
441  response_data.user_func = read_handler_func;
442  }
443 
444  // We must always set this so we can collect the error message body
445  curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, _process_response_body);
446  curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response_data);
447 
448  if (write_user_struct != NULL && write_handler_func != NULL) {
449  curl_easy_setopt(handle, CURLOPT_READFUNCTION, write_handler_func);
450  curl_easy_setopt(handle, CURLOPT_READDATA, write_user_struct);
451  }
452 
453  switch(request->verb) {
454  case HTTP_POST: {
455  curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "POST");
456  curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
457  curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, request->length);
458  break;
459  }
460  case HTTP_PUT: {
461  curl_easy_setopt(handle, CURLOPT_PUT, 1L);
462  curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
463  curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, request->length);
464  break;
465  }
466  case HTTP_DELETE: {
467  curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "DELETE");
468  break;
469  }
470  case HTTP_HEAD: {
471  curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "HEAD");
472  curl_easy_setopt(handle, CURLOPT_NOBODY, 1L);
473  break;
474  }
475  case HTTP_GET: {
476  //Placeholder if we need to put anything here.
477  break;
478  }
479  }
480 
481  date = _generate_date_string();
482  date_header = g_strconcat("Date: ", date, NULL);
483  headers = NULL;
484 
485  if (request->checksum == NULL) {
486  checksum_value = "";
487  } else {
488  char* checksum_header;
489  checksum_value = request->checksum->value;
490  checksum_header = g_strconcat(_get_checksum_type_header(request->checksum_type), checksum_value, NULL);
491  headers = curl_slist_append(headers, checksum_header);
492  g_free(checksum_header);
493  }
494  amz_headers = _canonicalize_amz_headers(request->headers);
495  canonicalized_resource = _canonicalized_resource(request->path, request->query_params);
496  signature = _net_compute_signature(client->log, client->creds, request->verb, canonicalized_resource, date, "", checksum_value, amz_headers);
497 
498  g_free(amz_headers);
499  g_free(canonicalized_resource);
500 
501  auth_header = g_strconcat("Authorization: AWS ", client->creds->access_id->value, ":", signature, NULL);
502 
503  headers = curl_slist_append(headers, auth_header);
504  headers = curl_slist_append(headers, date_header);
505  headers = _append_headers(headers, request->headers);
506 
507  curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
508 
509  res = curl_easy_perform(handle);
510 
511  g_free(date);
512  g_free(date_header);
513  g_free(signature);
514  g_free(auth_header);
515  curl_slist_free_all(headers);
516  curl_easy_cleanup(handle);
517 
518  //process the response
519  if (res != CURLE_OK) {
520  char * message = g_strconcat("Request failed: ", curl_easy_strerror(res), NULL);
522  g_free(url);
523  g_byte_array_free(response_data.body, TRUE);
524  ds3_str_free(response_data.status_message);
525  ds3_string_multimap_free(response_headers);
526  g_free(message);
527  return error;
528  }
529 
530  ds3_log_message(client->log, DS3_DEBUG, "Request completed with status code of: %d", response_data.status_code);
531 
532  if (response_data.status_code == 307) {
533  ds3_log_message(client->log, DS3_INFO, "Request encountered a 307 redirect");
534  ds3_str_free(response_data.status_message);
535 
536  if (response_data.body != NULL) {
537  g_byte_array_free(response_data.body, TRUE);
538  }
539  ds3_string_multimap_free(response_headers);
540  retry_count++;
541  ds3_log_message(client->log, DS3_DEBUG, "Retry Attempt: %d | Max Retries: %d", retry_count, client->num_redirects);
542  continue;
543  }
544 
545  if (response_data.status_code < 200 || response_data.status_code >= 300) {
546  ds3_error* error = ds3_create_error(DS3_ERROR_BAD_STATUS_CODE, "Got an unexpected status code.");
547  error->error = g_new0(ds3_error_response, 1);
548  error->error->http_error_code = response_data.status_code;
549  error->error->code = ds3_str_init(response_data.status_message->value);
550  if (response_data.body != NULL) {
551  error->error->message = ds3_str_init_with_size((char*)response_data.body->data, response_data.body->len);
552  g_byte_array_free(response_data.body, TRUE);
553  } else {
554  ds3_log_message(client->log, DS3_ERROR, "The response body for the error is empty");
555  error->error->message = NULL;
556  }
557  ds3_string_multimap_free(response_headers);
558  ds3_str_free(response_data.status_message);
559  g_free(url);
560  return error;
561  }
562  g_byte_array_free(response_data.body, TRUE);
563  ds3_str_free(response_data.status_message);
564 
565  if (return_headers != NULL) {
566  *return_headers = response_headers;
567  } else {
568  ds3_string_multimap_free(response_headers);
569  }
570 
571  break;
572  } else {
573  return ds3_create_error(DS3_ERROR_CURL_HANDLE, "Failed to create curl handle");
574  }
575  }
576  g_free(url);
577 
578  if (retry_count == client->num_redirects) {
579  return ds3_create_error(DS3_ERROR_TOO_MANY_REDIRECTS, "Encountered too many redirects while attempting to fulfil the request");
580  }
581  return NULL;
582 }
583 
584 void net_cleanup(void) {
585  curl_global_cleanup();
586 }
Definition: ds3.h:76
ds3_checksum_type checksum_type
Definition: ds3_request.h:35
int http_error_code
Definition: ds3.h:1113
static size_t _process_header_line(void *buffer, size_t size, size_t nmemb, void *user_data)
Definition: ds3_net.c:296
char * escape_url(const char *url)
Definition: ds3_net.c:67
ds3_str * message
Definition: ds3.h:1114
size_t size
Definition: ds3_string.h:38
static size_t _process_response_body(void *buffer, size_t size, size_t nmemb, void *user_data)
Definition: ds3_net.c:363
uint64_t length
Definition: ds3_request.h:33
static void _hash_for_each(gpointer _key, gpointer _value, gpointer _user_data)
Definition: ds3_net.c:160
Definition: ds3.h:83
static char * _get_checksum_type_header(const ds3_checksum_type type)
Definition: ds3_net.c:51
ds3_checksum_type
Definition: ds3.h:497
ds3_creds * creds
Definition: ds3.h:1579
char * escape_url_object_name(const char *url)
Definition: ds3_net.c:94
ds3_bool
Definition: ds3.h:63
static char * _canonicalize_amz_headers(GHashTable *headers)
Definition: ds3_net.c:254
void ds3_log_message(const ds3_log *log, ds3_log_lvl lvl, const char *message,...)
Definition: ds3_utils.c:38
ds3_log * log
Definition: ds3.h:1580
ds3_str * path
Definition: ds3_request.h:32
Definition: ds3.h:72
char * escape_url_extended(const char *url, const char **delimiters, uint32_t num_delimiters)
Definition: ds3_net.c:75
Definition: ds3.h:64
Definition: ds3.h:89
char * escape_url_range_header(const char *url)
Definition: ds3_net.c:100
ds3_str * status_message
Definition: ds3_request.h:51
ds3_str * code
Definition: ds3.h:1112
static char * _net_gen_query_params(GHashTable *query_params)
Definition: ds3_net.c:172
ds3_error * ds3_create_error(ds3_error_code code, const char *message)
Definition: ds3_utils.c:22
ds3_str * checksum
Definition: ds3_request.h:34
http_verb verb
Definition: ds3_request.h:31
http_verb
Definition: ds3.h:67
static int ds3_curl_logger(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
Definition: ds3_net.c:217
ds3_string_multimap * headers
Definition: ds3_request.h:53
ds3_str * access_id
Definition: ds3.h:90
GHashTable * query_params
Definition: ds3_request.h:37
size_t ds3_load_buffer(void *buffer, size_t size, size_t nmemb, void *user_data)
Definition: ds3_utils.c:30
Definition: ds3.h:70
void ds3_str_free(ds3_str *string)
Definition: ds3_string.c:48
The public definitions for the Spectra S3 C SDK.
static char * _net_get_verb(http_verb verb)
Definition: ds3_net.c:39
uint64_t num_redirects
Definition: ds3.h:1578
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)
Definition: ds3_net.c:130
ds3_string_multimap * ds3_string_multimap_init(void)
void net_cleanup(void)
Definition: ds3_net.c:584
static struct curl_slist * _append_headers(struct curl_slist *header_list, GHashTable *headers_map)
Definition: ds3_net.c:203
Definition: ds3.h:78
static unsigned char * _generate_signature_str(http_verb verb, char *resource_name, char *date, char *content_type, char *checksum_value, char *amz_headers)
Definition: ds3_net.c:105
ds3_error_response * error
Definition: ds3.h:1572
void ds3_string_multimap_free(ds3_string_multimap *map)
ds3_str * ds3_str_init_with_size(const char *string, size_t size)
Definition: ds3_string.c:26
static char * _generate_date_string(void)
Definition: ds3_net.c:121
GHashTable * headers
Definition: ds3_request.h:36
ds3_str * proxy
Definition: ds3.h:1577
void ds3_string_multimap_insert(ds3_string_multimap *map, const ds3_str *key, const ds3_str *value)
Definition: ds3.h:68
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)
Definition: ds3_net.c:374
size_t(* user_func)(void *, size_t, size_t, void *)
Definition: ds3_request.h:58
GByteArray * body
Definition: ds3_request.h:56
Definition: ds3.h:80
uint64_t status_code
Definition: ds3_request.h:50
static char * _canonicalized_resource(ds3_str *path, GHashTable *query_params)
Definition: ds3_net.c:288
ds3_str * ds3_str_init(const char *string)
Definition: ds3_string.c:21
static void _init_curl(void)
Definition: ds3_net.c:28
ds3_str * secret_key
Definition: ds3.h:91
Definition: ds3.h:69
static gint _gstring_sort(gconstpointer a, gconstpointer b)
Definition: ds3_net.c:247
Definition: ds3.h:64
ds3_str * endpoint
Definition: ds3.h:1576
char * value
Definition: ds3_string.h:37
Definition: ds3.h:79