diff options
Diffstat (limited to 'storage/maria/libmarias3/src/request.c')
-rw-r--r-- | storage/maria/libmarias3/src/request.c | 967 |
1 files changed, 967 insertions, 0 deletions
diff --git a/storage/maria/libmarias3/src/request.c b/storage/maria/libmarias3/src/request.c new file mode 100644 index 00000000..26165474 --- /dev/null +++ b/storage/maria/libmarias3/src/request.c @@ -0,0 +1,967 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * Copyright 2019 MariaDB Corporation Ab. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" +#include "common.h" +#include "sha256.h" + +#include <math.h> + +const char *default_domain = "s3.amazonaws.com"; + +static void set_error(ms3_st *ms3, const char *error) +{ + ms3_cfree(ms3->last_error); + + if (!error) + { + ms3->last_error = NULL; + return; + } + + ms3->last_error = ms3_cstrdup(error); +} + +static void set_error_nocopy(ms3_st *ms3, char *error) +{ + ms3_cfree(ms3->last_error); + + if (!error) + { + ms3->last_error = NULL; + return; + } + + ms3->last_error = error; +} + +static uint8_t build_request_uri(CURL *curl, const char *base_domain, + const char *bucket, const char *object, const char *query, bool use_http, + uint8_t protocol_version) +{ + char uri_buffer[MAX_URI_LENGTH]; + const char *domain; + const uint8_t path_parts = 10; // "https://" + "." + "/" + const char *http_protocol = "http"; + const char *https_protocol = "https"; + const char *protocol; + + if (base_domain) + { + domain = base_domain; + } + else + { + domain = default_domain; + } + + if (use_http) + { + protocol = http_protocol; + } + else + { + protocol = https_protocol; + } + + if (query) + { + if (path_parts + strlen(domain) + strlen(bucket) + strlen(object) + strlen( + query) >= MAX_URI_LENGTH - 1) + { + return MS3_ERR_URI_TOO_LONG; + } + + if (protocol_version == 1) + { + snprintf(uri_buffer, MAX_URI_LENGTH - 1, "%s://%s/%s%s?%s", protocol, + domain, bucket, + object, query); + } + else + { + snprintf(uri_buffer, MAX_URI_LENGTH - 1, "%s://%s.%s%s?%s", protocol, + bucket, domain, + object, query); + } + } + else + { + if (path_parts + strlen(domain) + strlen(bucket) + strlen( + object) >= MAX_URI_LENGTH - 1) + { + return MS3_ERR_URI_TOO_LONG; + } + + if (protocol_version == 1) + { + snprintf(uri_buffer, MAX_URI_LENGTH - 1, "%s://%s/%s%s", protocol, + domain, + bucket, + object); + } + else + { + snprintf(uri_buffer, MAX_URI_LENGTH - 1, "%s://%s.%s%s", protocol, + bucket, domain, + object); + } + } + + ms3debug("URI: %s", uri_buffer); + curl_easy_setopt(curl, CURLOPT_URL, uri_buffer); + return 0; +} + +/* Handles object name to path conversion. + * Must always start with a '/' even if object is empty. + * Object should be urlencoded. Unfortunately curl also urlencodes slashes. + * So this breaks up on slashes and reassembles the encoded parts. + * Not very efficient but works until we write a custom encoder. + */ + +static char *generate_path(CURL *curl, const char *object, char *path_buffer) +{ + char *tok_ptr = NULL; + char *save_ptr = NULL; + char *out_ptr = path_buffer; + char *path; + + // Keep scanbuild happy + path_buffer[0] = '\0'; + + if (!object) + { + sprintf(path_buffer, "/"); + return path_buffer; + } + + path = ms3_cstrdup(object); // Because strtok_r is destructive + + tok_ptr = strtok_r((char *)path, "/", &save_ptr); + + while (tok_ptr != NULL) + { + char *encoded = curl_easy_escape(curl, tok_ptr, (int)strlen(tok_ptr)); + snprintf(out_ptr, 1024 - (out_ptr - path_buffer), "/%s", encoded); + out_ptr += strlen(encoded) + 1; + curl_free(encoded); + tok_ptr = strtok_r(NULL, "/", &save_ptr); + } + + if (path_buffer[0] != '/') + { + sprintf(path_buffer, "/"); + } + + ms3_cfree(path); + return path_buffer; +} + + +/* At a later date we need to make this accept multi-param/values to support + * pagination + */ + +static char *generate_query(CURL *curl, const char *value, + const char *continuation, uint8_t list_version, bool use_delimiter, + char *query_buffer) +{ + char *encoded; + query_buffer[0] = '\0'; + + if (use_delimiter) + { + snprintf(query_buffer, 3072, "delimiter=%%2F"); + } + + if (list_version == 2) + { + if (continuation) + { + encoded = curl_easy_escape(curl, continuation, (int)strlen(continuation)); + + if (strlen(query_buffer)) + { + snprintf(query_buffer + strlen(query_buffer), 3072 - strlen(query_buffer), + "&continuation-token=%s&list-type=2", encoded); + } + else + { + snprintf(query_buffer, 3072, "continuation-token=%s&list-type=2", encoded); + } + + curl_free(encoded); + } + else + { + if (strlen(query_buffer)) + { + snprintf(query_buffer + strlen(query_buffer), 3072 - strlen(query_buffer), + "&list-type=2"); + } + else + { + sprintf(query_buffer, "list-type=2"); + } + } + } + else if (continuation) + { + // Continuation is really marker here + encoded = curl_easy_escape(curl, continuation, (int)strlen(continuation)); + + if (strlen(query_buffer)) + { + snprintf(query_buffer + strlen(query_buffer), 3072 - strlen(query_buffer), + "&marker=%s", + encoded); + } + else + { + snprintf(query_buffer, 3072, "marker=%s", encoded); + } + + curl_free(encoded); + } + + if (value) + { + encoded = curl_easy_escape(curl, value, (int)strlen(value)); + + if (strlen(query_buffer)) + { + snprintf(query_buffer + strlen(query_buffer), 3072 - strlen(query_buffer), + "&prefix=%s", + encoded); + } + else + { + snprintf(query_buffer, 3072, "prefix=%s", + encoded); + } + + curl_free(encoded); + } + + return query_buffer; +} + + +/* +<HTTPMethod>\n +<CanonicalURI>\n +<CanonicalQueryString>\n +<CanonicalHeaders>\n +<SignedHeaders>\n - host;x-amz-content-sha256;x-amz-date +<HashedPayload> - empty if no POST data +*/ +static uint8_t generate_request_hash(uri_method_t method, const char *path, + const char *bucket, + const char *query, char *post_hash, struct curl_slist *headers, bool has_source, bool has_token, + char *return_hash) +{ + char signing_data[3072]; + size_t pos = 0; + uint8_t sha256hash[32]; // SHA_256 binary length + uint8_t hash_pos = 0; + uint8_t i; + struct curl_slist *current_header = headers; + + // Method first + switch (method) + { + case MS3_GET: + { + sprintf(signing_data, "GET\n"); + pos += 4; + break; + } + + case MS3_HEAD: + { + sprintf(signing_data, "HEAD\n"); + pos += 5; + break; + } + + case MS3_PUT: + { + sprintf(signing_data, "PUT\n"); + pos += 4; + break; + } + + case MS3_DELETE: + { + sprintf(signing_data, "DELETE\n"); + pos += 7; + break; + } + + default: + { + ms3debug("Bad method detected"); + return MS3_ERR_IMPOSSIBLE; + } + } + + // URL path + if (bucket) + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, "/%s%s\n", bucket, + path); + pos += strlen(path) + strlen(bucket) + 2; + } + else + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, "%s\n", path); + pos += strlen(path) + 1; + } + + // URL query (if exists) + if (query) + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, "%s\n", query); + pos += strlen(query) + 1; + } + else + { + sprintf(signing_data + pos, "\n"); + pos++; + } + + do + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, "%s\n", + current_header->data); + pos += strlen(current_header->data) + 1; + } + while ((current_header = current_header->next)); + + // List if header names + // The newline between headers and this is important + if (has_source && has_token) + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, + "\nhost;x-amz-content-sha256;x-amz-copy-source;x-amz-date;x-amz-security-token\n"); + pos += 77; + } + else if (has_source) + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, + "\nhost;x-amz-content-sha256;x-amz-copy-source;x-amz-date\n"); + pos += 56; + } + else if (has_token) + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, + "\nhost;x-amz-content-sha256;x-amz-date;x-amz-security-token\n"); + pos += 59; + } + else + { + snprintf(signing_data + pos, sizeof(signing_data) - pos, + "\nhost;x-amz-content-sha256;x-amz-date\n"); + pos += 38; + } + + // Hash of post data (can be hash of empty) + snprintf(signing_data + pos, sizeof(signing_data) - pos, "%.*s", 64, post_hash); + //pos+= 64; + ms3debug("Signature data1: %s", signing_data); + + // Hash all of the above + sha256((uint8_t *)signing_data, strlen(signing_data), (uint8_t *)sha256hash); + + for (i = 0; i < 32; i++) + { + sprintf(return_hash + hash_pos, "%.2x", sha256hash[i]); + hash_pos += 2; + } + + ms3debug("Signature data: %s", signing_data); + ms3debug("Signature: %.*s", 64, return_hash); + + return 0; +} + +static uint8_t build_request_headers(CURL *curl, struct curl_slist **head, + const char *base_domain, const char *region, const char *key, + const char *secret, const char *object, const char *query, + uri_method_t method, const char *bucket, const char *source_bucket, + const char *source_key, struct put_buffer_st *post_data, + uint8_t protocol_version, const char *session_token) +{ + uint8_t ret = 0; + time_t now; + struct tm tmp_tm; + char headerbuf[3072]; + char secrethead[45]; + char date[9]; + char sha256hash[65]; + char post_hash[65]; + uint8_t tmp_hash[32]; + // Alternate between these two so hmac doesn't overwrite itself + uint8_t hmac_hash[32]; + uint8_t hmac_hash2[32]; + uint8_t hash_pos = 0; + const char *domain; + struct curl_slist *headers = NULL; + uint8_t offset; + uint8_t i; + bool has_source = false; + bool has_token = false; + struct curl_slist *current_header; + + // Host header + if (base_domain) + { + domain = base_domain; + } + else + { + domain = default_domain; + } + + if (protocol_version == 2) + { + snprintf(headerbuf, sizeof(headerbuf), "host:%s.%s", bucket, domain); + } + else + { + snprintf(headerbuf, sizeof(headerbuf), "host:%s", domain); + } + headers = curl_slist_append(headers, headerbuf); + *head = headers; + + // Hash post data + sha256(post_data->data, post_data->length, tmp_hash); + + for (i = 0; i < 32; i++) + { + sprintf(post_hash + hash_pos, "%.2x", tmp_hash[i]); + hash_pos += 2; + } + + snprintf(headerbuf, sizeof(headerbuf), "x-amz-content-sha256:%.*s", 64, + post_hash); + headers = curl_slist_append(headers, headerbuf); + + if (source_bucket) + { + char *bucket_escape; + char *key_escape; + bucket_escape = curl_easy_escape(curl, source_bucket, (int)strlen(source_bucket)); + key_escape = curl_easy_escape(curl, source_key, (int)strlen(source_key)); + snprintf(headerbuf, sizeof(headerbuf), "x-amz-copy-source:/%s/%s", + bucket_escape, key_escape); + headers = curl_slist_append(headers, headerbuf); + ms3_cfree(bucket_escape); + ms3_cfree(key_escape); + } + + // Date/time header + time(&now); + snprintf(headerbuf, sizeof(headerbuf), "x-amz-date:"); + offset = strlen(headerbuf); + gmtime_r(&now, &tmp_tm); + strftime(headerbuf + offset, sizeof(headerbuf) - offset, "%Y%m%dT%H%M%SZ", + &tmp_tm); + headers = curl_slist_append(headers, headerbuf); + + // Temp Credentials Security Token + if (session_token) + { + snprintf(headerbuf, sizeof(headerbuf), "x-amz-security-token:%s",session_token); + headers = curl_slist_append(headers, headerbuf); + has_token = true; + } + + if (source_bucket) + { + has_source = true; + } + + // Builds the request hash + if (protocol_version == 1) + { + ret = generate_request_hash(method, object, bucket, query, post_hash, headers, + has_source, has_token, + sha256hash); + } + else + { + ret = generate_request_hash(method, object, NULL, query, post_hash, headers, + has_source, has_token, + sha256hash); + } + + if (ret) + { + return ret; + } + + // User signing key hash + // Date hashed using AWS4:secret_key + snprintf(secrethead, sizeof(secrethead), "AWS4%.*s", 40, secret); + strftime(headerbuf, sizeof(headerbuf), "%Y%m%d", &tmp_tm); + hmac_sha256((uint8_t *)secrethead, strlen(secrethead), (uint8_t *)headerbuf, + strlen(headerbuf), hmac_hash); + + // Region signed by above key + hmac_sha256(hmac_hash, 32, (uint8_t *)region, strlen(region), + hmac_hash2); + + // Service signed by above key (s3 always) + sprintf(headerbuf, "s3"); + hmac_sha256(hmac_hash2, 32, (uint8_t *)headerbuf, strlen(headerbuf), + hmac_hash); + + // Request version signed by above key (always "aws4_request") + sprintf(headerbuf, "aws4_request"); + hmac_sha256(hmac_hash, 32, (uint8_t *)headerbuf, strlen(headerbuf), + hmac_hash2); + + // Sign everything with the key + snprintf(headerbuf, sizeof(headerbuf), "AWS4-HMAC-SHA256\n"); + offset = strlen(headerbuf); + strftime(headerbuf + offset, sizeof(headerbuf) - offset, "%Y%m%dT%H%M%SZ\n", + &tmp_tm); + offset = strlen(headerbuf); + strftime(date, 9, "%Y%m%d", &tmp_tm); + snprintf(headerbuf + offset, sizeof(headerbuf) - offset, + "%.*s/%s/s3/aws4_request\n%.*s", 8, date, region, 64, sha256hash); + ms3debug("Data to sign: %s", headerbuf); + hmac_sha256(hmac_hash2, 32, (uint8_t *)headerbuf, strlen(headerbuf), + hmac_hash); + + hash_pos = 0; + + for (i = 0; i < 32; i++) + { + sprintf(sha256hash + hash_pos, "%.2x", hmac_hash[i]); + hash_pos += 2; + } + + // Make auth header + if (source_bucket && session_token) + { + snprintf(headerbuf, sizeof(headerbuf), + "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-copy-source;x-amz-date;x-amz-security-token;x-amz-copy-source, Signature=%s", + key, date, region, sha256hash); + } + else if (source_bucket) + { + snprintf(headerbuf, sizeof(headerbuf), + "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-copy-source;x-amz-date, Signature=%s", + key, date, region, sha256hash); + } + else if (session_token) + { + snprintf(headerbuf, sizeof(headerbuf), + "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=%s", + key, date, region, sha256hash); + } + else + { + snprintf(headerbuf, sizeof(headerbuf), + "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=%s", + key, date, region, sha256hash); + } + + headers = curl_slist_append(headers, headerbuf); + + // Disable this header or PUT will barf with a 501 + sprintf(headerbuf, "Transfer-Encoding:"); + headers = curl_slist_append(headers, headerbuf); + + if ((method == MS3_PUT) && !source_bucket) + { + snprintf(headerbuf, sizeof(headerbuf), "Content-Length:%zu", post_data->length); + headers = curl_slist_append(headers, headerbuf); + } + + current_header = headers; + + do + { + ms3debug("Header: %s", current_header->data); + } + while ((current_header = current_header->next)); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + switch (method) + { + case MS3_GET: + { + // Nothing extra to do here + break; + } + + case MS3_HEAD: + { + curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + break; + } + + case MS3_PUT: + { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); + break; + } + + case MS3_DELETE: + { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + break; + } + + default: + ms3debug("Bad method detected"); + return MS3_ERR_IMPOSSIBLE; + } + + return 0; +} +static size_t header_callback(char *buffer, size_t size, + size_t nitems, void *userdata) +{ + ms3debug("%.*s\n", (int)(nitems * size), buffer); + + if (userdata) + { + // HEAD request + if (!strncasecmp(buffer, "Last-Modified", 13)) + { + ms3_status_st *status = (ms3_status_st *) userdata; + // Date/time, format: Fri, 15 Mar 2019 16:58:54 GMT + struct tm ttmp = {0}; + strptime(buffer + 15, "%a, %d %b %Y %H:%M:%S %Z", &ttmp); + status->created = mktime(&ttmp); + } + else if (!strncasecmp(buffer, "Content-Length", 14)) + { + ms3_status_st *status = (ms3_status_st *) userdata; + // Length + status->length = strtoull(buffer + 16, NULL, 10); + } + } + + return nitems * size; +} + +static size_t body_callback(void *buffer, size_t size, + size_t nitems, void *userdata) +{ + uint8_t *ptr; + size_t realsize = nitems * size; + + struct memory_buffer_st *mem = (struct memory_buffer_st *)userdata; + + if (realsize + mem->length >= mem->alloced) + { + size_t additional_size = mem->buffer_chunk_size; + + if (realsize >= mem->buffer_chunk_size) + { + additional_size = (ceil((double)realsize / (double)mem->buffer_chunk_size) + 1) + * mem->buffer_chunk_size; + } + + ptr = (uint8_t *)ms3_crealloc(mem->data, mem->alloced + additional_size); + + if (!ptr) + { + ms3debug("Curl response OOM"); + return 0; + } + + mem->alloced += additional_size; + mem->data = ptr; + } + + memcpy(&(mem->data[mem->length]), buffer, realsize); + mem->length += realsize; + mem->data[mem->length] = '\0'; + + ms3debug("Read %zu bytes, buffer %zu bytes", realsize, mem->length); +// ms3debug("Data: %s", (char*)buffer); + return nitems * size; +} + +uint8_t execute_request(ms3_st *ms3, command_t cmd, const char *bucket, + const char *object, const char *source_bucket, const char *source_object, + const char *filter, const uint8_t *data, size_t data_size, + char *continuation, + void *ret_ptr) +{ + CURL *curl = NULL; + struct curl_slist *headers = NULL; + uint8_t res = 0; + struct memory_buffer_st mem; + uri_method_t method; + char *path = NULL; + char *query = NULL; + struct put_buffer_st post_data; + CURLcode curl_res; + long response_code = 0; + + mem.data = NULL; + mem.length = 0; + mem.alloced = 1; + mem.buffer_chunk_size = ms3->buffer_chunk_size; + + post_data.data = (uint8_t *) data; + post_data.length = data_size; + post_data.offset = 0; + + curl = ms3->curl; + + if (!ms3->first_run) + { + curl_easy_reset(curl); + } + else + { + ms3->first_run = false; + } + + path = generate_path(curl, object, ms3->path_buffer); + + if (cmd == MS3_CMD_LIST_RECURSIVE) + { + query = generate_query(curl, filter, continuation, ms3->list_version, false, + ms3->query_buffer); + } + else if (cmd == MS3_CMD_LIST) + { + query = generate_query(curl, filter, continuation, ms3->list_version, true, + ms3->query_buffer); + } + + res = build_request_uri(curl, ms3->base_domain, bucket, path, query, + ms3->use_http, ms3->protocol_version); + + if (res) + { + return res; + } + + switch (cmd) + { + case MS3_CMD_COPY: + case MS3_CMD_PUT: + method = MS3_PUT; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (char *)data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data_size); + break; + + case MS3_CMD_DELETE: + method = MS3_DELETE; + break; + + case MS3_CMD_HEAD: + method = MS3_HEAD; + curl_easy_setopt(curl, CURLOPT_HEADERDATA, ret_ptr); + break; + + case MS3_CMD_LIST: + case MS3_CMD_LIST_RECURSIVE: + case MS3_CMD_GET: + case MS3_CMD_LIST_ROLE: + method = MS3_GET; + break; + + case MS3_CMD_ASSUME_ROLE: + default: + ms3debug("Bad cmd detected"); + ms3_cfree(mem.data); + + return MS3_ERR_IMPOSSIBLE; + } + + if (ms3->iam_role) + { + ms3debug("Using assumed role: %s",ms3->iam_role); + res = build_request_headers(curl, &headers, ms3->base_domain, ms3->region, + ms3->role_key, ms3->role_secret, path, query, method, bucket, source_bucket, + source_object, &post_data, ms3->protocol_version, ms3->role_session_token); + } + else + { + res = build_request_headers(curl, &headers, ms3->base_domain, ms3->region, + ms3->s3key, ms3->s3secret, path, query, method, bucket, source_bucket, + source_object, &post_data, ms3->protocol_version, NULL); + } + if (res) + { + ms3_cfree(mem.data); + curl_slist_free_all(headers); + + return res; + } + + if (ms3->disable_verification) + { + ms3debug("Disabling SSL verification"); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + } + + if (ms3->port) + curl_easy_setopt(curl, CURLOPT_PORT, (long)ms3->port); + + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, body_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&mem); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + curl_res = curl_easy_perform(curl); + + if (curl_res != CURLE_OK) + { + ms3debug("Curl error: %s", curl_easy_strerror(curl_res)); + set_error(ms3, curl_easy_strerror(curl_res)); + ms3_cfree(mem.data); + curl_slist_free_all(headers); + + return MS3_ERR_REQUEST_ERROR; + } + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + ms3debug("Response code: %ld", response_code); + + if (response_code == 404) + { + char *message = parse_error_message((char *)mem.data, mem.length); + + if (message) + { + ms3debug("Response message: %s", message); + } + + set_error_nocopy(ms3, message); + res = MS3_ERR_NOT_FOUND; + } + else if (response_code == 403) + { + char *message = parse_error_message((char *)mem.data, mem.length); + + if (message) + { + ms3debug("Response message: %s", message); + } + + set_error_nocopy(ms3, message); + res = MS3_ERR_AUTH; + } + else if (response_code >= 400) + { + char *message = parse_error_message((char *)mem.data, mem.length); + + if (message) + { + ms3debug("Response message: %s", message); + } + + set_error_nocopy(ms3, message); + res = MS3_ERR_SERVER; + if (ms3->iam_role) + { + res = MS3_ERR_AUTH_ROLE; + } + } + + switch (cmd) + { + case MS3_CMD_LIST_RECURSIVE: + case MS3_CMD_LIST: + { + char *cont = NULL; + parse_list_response((const char *)mem.data, mem.length, &ms3->list_container, ms3->list_version, + &cont); + + if (cont) + { + res = execute_request(ms3, cmd, bucket, object, source_bucket, source_object, + filter, data, data_size, cont, + NULL); + if (res) + { + return res; + } + + ms3_cfree(cont); + } + + ms3_cfree(mem.data); + break; + } + + case MS3_CMD_COPY: + case MS3_CMD_PUT: + { + ms3_cfree(mem.data); + break; + } + + case MS3_CMD_GET: + { + struct memory_buffer_st *buf = (struct memory_buffer_st *) ret_ptr; + + if (res) + { + ms3_cfree(mem.data); + } + else + { + buf->data = mem.data; + buf->length = mem.length; + } + + break; + } + + case MS3_CMD_DELETE: + { + ms3_cfree(mem.data); + break; + } + + case MS3_CMD_HEAD: + { + ms3_cfree(mem.data); + break; + } + + case MS3_CMD_LIST_ROLE: + case MS3_CMD_ASSUME_ROLE: + default: + { + ms3_cfree(mem.data); + ms3debug("Bad cmd detected"); + res = MS3_ERR_IMPOSSIBLE; + } + } + + curl_slist_free_all(headers); + + return res; +} |