in S3_HLS_S3_Put_Client.c [624:861]
int32_t S3_HLS_Client_Upload_Buffer(S3_HLS_CLIENT_CTX* ctx, char* object_key, uint8_t* first_data, uint32_t first_length, uint8_t* second_data, uint32_t second_length) {
uint8_t retry_flag = 0;
PUT_DEBUG("Upload start!\n");
PUT_DEBUG("Validate parameters\n");
if(NULL == ctx || NULL == object_key || NULL == first_data)
return S3_HLS_INVALID_PARAMETER;
if(0 == strlen(object_key))
return S3_HLS_INVALID_PARAMETER;
if('/' != object_key[0])
return S3_HLS_INVALID_PARAMETER;
if(NULL == second_data && 0 != second_length)
return S3_HLS_INVALID_PARAMETER;
PUT_DEBUG("Format date and timestamp!\n");
time_t current_time;
time(¤t_time);
struct tm* time_tm = gmtime(¤t_time);
int32_t length = sprintf(ctx->date_buffer, S3_HLS_DATE_FORMAT, time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday);
if(0 >= length)
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
length = sprintf(ctx->timestamp_buffer, S3_HLS_TIMESTAMP_HEADER_FORMAT, time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec);
if(0 >= length)
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
PUT_DEBUG("Get Content Hash\n");
S3_SHA256_CTX sha256_ctx;
S3_SHA256_Init(&sha256_ctx);
S3_SHA256_Update(&sha256_ctx, first_data, first_length);
if(NULL != second_data)
S3_SHA256_Update(&sha256_ctx, second_data, second_length);
S3_SHA256_HASH payload_hash;
S3_SHA256_Final(&sha256_ctx, payload_hash);
char payload_hash_string[S3_HLS_HEX_HASH_STIRNG_LENGTH + 1];
for(uint8_t i = 0; i < sizeof(payload_hash); i++) {
if(0 >= sprintf(payload_hash_string + (i * 2), "%02x", payload_hash[i]))
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
}
payload_hash_string[S3_HLS_HEX_HASH_STIRNG_LENGTH] = '\0';
PUT_DEBUG("Generate content_hash header!\n");
if(0 >= sprintf(ctx->content_hash, S3_HLS_CONTENT_SHA256_HEADER_FORMAT, payload_hash_string))
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
S3_SHA256_HASH canonical_hash;
S3_HLS_Hash_Put_Canonical_Request(ctx, object_key, canonical_hash);
char canonical_hash_string[S3_HLS_HEX_HASH_STIRNG_LENGTH + 1];
for(uint8_t i = 0; i < S3_SHA256_DIGEST_LENGTH; i++) {
if(0 >= sprintf(canonical_hash_string + (i * 2), "%02x", canonical_hash[i])) {
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
}
}
canonical_hash_string[S3_HLS_HEX_HASH_STIRNG_LENGTH] = '\0'; // add null terminator
if(0 >= sprintf( ctx->string_to_sign,
S3_HLS_STRING_TO_SIGN_FORMAT,
ctx->timestamp_buffer + S3_HLS_TIMESTAMP_VALUE_OFFSET,
ctx->date_buffer,
ctx->region,
canonical_hash_string
)) {
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
}
if(0 != pthread_mutex_lock(&ctx->credential_lock))
return S3_HLS_LOCK_FAILED;
S3_SHA256_HASH date_key;
S3_HMAC_SHA256(
ctx->secret_access_key,
strlen(ctx->secret_access_key),
ctx->date_buffer,
strlen(ctx->date_buffer),
date_key
);
S3_SHA256_HASH region_key;
S3_HMAC_SHA256(date_key, SHA256_DIGEST_LENGTH, ctx->region, strlen(ctx->region), region_key);
S3_SHA256_HASH service_key;
S3_HMAC_SHA256(region_key, SHA256_DIGEST_LENGTH, S3_SERVICE_KEY, strlen(S3_SERVICE_KEY), service_key);
S3_SHA256_HASH signing_key;
S3_HMAC_SHA256(service_key, SHA256_DIGEST_LENGTH, AWS_SIGV4_REQUEST, strlen(AWS_SIGV4_REQUEST), signing_key);
PUT_DEBUG("String To Sign: \n%s\n", ctx->string_to_sign);
S3_SHA256_HASH signature;
S3_HMAC_SHA256(signing_key, SHA256_DIGEST_LENGTH, ctx->string_to_sign, strlen(ctx->string_to_sign), signature);
char signature_hash_string[S3_HLS_HEX_HASH_STIRNG_LENGTH + 1];
for(uint8_t i = 0; i < S3_SHA256_DIGEST_LENGTH; i++) {
if(0 >= sprintf(signature_hash_string + (i * 2), "%02x", signature[i])) {
pthread_mutex_unlock(&ctx->credential_lock);
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
}
}
signature_hash_string[S3_HLS_HEX_HASH_STIRNG_LENGTH] = '\0';
PUT_DEBUG("String signed!\n");
PUT_DEBUG("Auth header address: %ld!\n", ctx->auth_header);
length = sprintf(
ctx->auth_header,
S3_HLS_AUTHENTICATION_HEADER_FORMAT,
ctx->access_key,
ctx->date_buffer,
ctx->region,
NULL != ctx->token_header ? S3_HLS_TOKEN_HEADER_IN_CANONICAL_REQUEST : S3_HLS_EMPTY_STRING,
NULL == ctx->tag_header ? S3_HLS_EMPTY_STRING : S3_HLS_TAG_HEADER_IN_CANONICAL_REQUEST,
signature_hash_string
);
pthread_mutex_unlock(&ctx->credential_lock);
if(0 >= length)
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
PUT_DEBUG("Auth header: \n%s\n", ctx->auth_header);
length = sprintf(ctx->uri, S3_HLS_HTTPS_URI_FORMAT, ctx->endpoint, object_key);
if(0 >= length)
return S3_HLS_UNKNOWN_INTERNAL_ERROR;
/* get a curl handle */
printf("Start Upload!\n");
if(NULL == ctx->curl) {
l_retry_entry:
ctx->curl = curl_easy_init();
if(NULL == ctx->curl) {
fprintf(stderr, "curl_easy_init() failed!\n");
return S3_HLS_HTTP_CLIENT_INIT_ERROR;
}
curl_easy_setopt(ctx->curl, CURLOPT_READFUNCTION, S3_HLS_Upload_Data);
}
S3_HLS_UPLOAD_CTX upload_ctx;
upload_ctx.first_part_start = first_data;
upload_ctx.first_part_length = first_length;
upload_ctx.second_part_start = second_data;
upload_ctx.second_part_length = second_length;
upload_ctx.pos = 0;
// adding headers
struct curl_slist *headers = NULL;
// set upload methods
curl_easy_setopt(ctx->curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(ctx->curl, CURLOPT_PUT, 1L);
/* First set the URL that is about to receive our POST. */
curl_easy_setopt(ctx->curl, CURLOPT_URL, ctx->uri);
PUT_DEBUG("Upload CTX: %ld\n", &upload_ctx);
curl_easy_setopt(ctx->curl, CURLOPT_READDATA, &upload_ctx);
uint32_t payload_length = first_length + second_length;
curl_easy_setopt(ctx->curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)payload_length);
/* enable TCP keep-alive for this transfer */
curl_easy_setopt(ctx->curl, CURLOPT_TCP_KEEPALIVE, 1L);
/* keep-alive idle time to 120 seconds */
curl_easy_setopt(ctx->curl, CURLOPT_TCP_KEEPIDLE, 180L);
/* interval time between keep-alive probes: 60 seconds */
curl_easy_setopt(ctx->curl, CURLOPT_TCP_KEEPINTVL, 60L);
curl_easy_setopt(ctx->curl, CURLOPT_TIMEOUT, S3_HLS_CURL_TRANSFER_TIMEOUT);
curl_easy_setopt(ctx->curl, CURLOPT_CONNECTTIMEOUT, S3_HLS_CURL_CONNECTION_TIMEOUT);
curl_easy_setopt(ctx->curl, CURLOPT_SSL_VERIFYSTATUS, 0);
curl_easy_setopt(ctx->curl, CURLOPT_SSL_VERIFYPEER, 0);
headers = curl_slist_append(headers, ctx->content_hash);
headers = curl_slist_append(headers, ctx->timestamp_buffer);
headers = curl_slist_append(headers, "Expect:");
headers = curl_slist_append(headers, "Accept:");
if(NULL != ctx->token_header) {
headers = curl_slist_append(headers, ctx->token_header);
}
if(NULL != ctx->tag_header) {
headers = curl_slist_append(headers, ctx->tag_header);
}
PUT_DEBUG("Auth Header: %s\n", ctx->auth_header);
headers = curl_slist_append(headers, ctx->auth_header);
/* Now specify we want to POST data */
curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, headers);
/* get verbose debug output please */
curl_easy_setopt(ctx->curl, CURLOPT_VERBOSE, 1L);
PUT_DEBUG("Start Put!\n");
/* Perform the request, res will get the return code */
CURLcode res = curl_easy_perform(ctx->curl);
PUT_DEBUG("Put Done!\n");
curl_slist_free_all(headers);
/* Check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
printf("Error, clean up curl!\n");
curl_easy_cleanup(ctx->curl);
ctx->curl = NULL;
printf("Curl cleaned!\n");
if(!retry_flag) {
retry_flag = 1;
goto l_retry_entry;
}
return S3_HLS_UPLOAD_FAILED;
}
return S3_HLS_OK;
}