/**
 * Add required SimpleDB parameters to the array
 * 
 * @param sdb the SimpleDB handle
 * @param params the parameter array
 */
int sdb_params_add_required(struct SDB* sdb, struct sdb_params* params)
{
	SDB_SAFE(sdb_params_add(params, "SignatureVersion", sdb->sdb_signature_ver_str));
	SDB_SAFE(sdb_params_add(params, "Version", "2007-11-07"));
	SDB_SAFE(sdb_params_add(params, "AWSAccessKeyId", sdb->sdb_key));
	
	return SDB_OK;
}
/**
 * Create the URL-encoded parameters string
 * 
 * @param sdb the SimpleDB handle
 * @param params the parameter array
 * @param pbuffer the variable for the output buffer (will be allocated by the routine, but has to be freed by caller)
 * @return SDB_OK if no errors occurred
 */
int sdb_params_export(struct SDB* sdb, struct sdb_params* params, char** pbuffer)
{
	// Sign the parameters
	
	char signature[EVP_MAX_MD_SIZE * 2];
	SDB_SAFE(sdb_params_sign(sdb, params, signature, NULL));
	SDB_SAFE(sdb_params_add(params, "Signature", signature));
	
	
	// Determine the appropriate size
	
	size_t i, l = 0;
	for (i = 0; i < params->size; i++) {
		l += strlen(params->params[i].key) + 1;
		l += strlen(params->params[i].value) * 3 + 1;
	}
	
	
	// Allocate buffer
	
	*pbuffer = (char*) malloc(l + 4);
	char* b = *pbuffer;
	*b = '\0';
	
	
	// Build the string
	
	for (i = 0; i < params->size; i++) {
	
		if (i > 0) strcat(b, "&");
		
		strcat(b, params->params[i].key);
		strcat(b, "=");
		
		char* e = curl_easy_escape(sdb->curl_handle, params->params[i].value, strlen(params->params[i].value));
		if (e == NULL) {
			free(b);
			*pbuffer = NULL;
			return SDB_E_URL_ENCODE_FAILED;
		} 
		
		strcat(b, e);
		
		curl_free(e);
	}
	
	
	return SDB_OK;
}
Example #3
0
/**
 * Add required SimpleDB parameters to the array
 * 
 * @param sdb the SimpleDB handle
 * @param params the parameter array
 */
int sdb_params_add_required(struct SDB* sdb, struct sdb_params* params)
{
	SDB_SAFE(sdb_params_add(params, "SignatureVersion", sdb->sdb_signature_ver_str));
	SDB_SAFE(sdb_params_add(params, "SignatureMethod", "HmacSHA256"));
	SDB_SAFE(sdb_params_add(params, "AWSAccessKeyId", sdb->sdb_key));
	
	// Version 2007-11-07 deprecated Aug 24, 2010 
	size_t i = 0;
	for (i = 0; i < params->size; i++) {
		if (strcmp(params->params[i].key, "Action") == 0) {
			if (strcmp(params->params[i].value, "Query") == 0 ||
			strcmp(params->params[i].value, "QueryWithAttributes") == 0) {
				SDB_SAFE(sdb_params_add(params, "Version", "2007-11-07"));
			} else {
				SDB_SAFE(sdb_params_add(params, "Version", "2009-04-15"));
			}
			break;
		}
	}
	
	return SDB_OK;
}
/**
 * Sign the parameters
 * 
 * @param sdb the SimpleDB handle
 * @param params the parameter array
 * @param buffer the buffer to write the signature to (must be at least EVP_MAX_MD_SIZE * 2 bytes)
 * @param plen the pointer to the place to store the length of the signature (can be NULL)
 * @return SDB_OK if no errors occurred
 */
int sdb_params_sign(struct SDB* sdb, struct sdb_params* params, char* buffer, size_t* plen)
{
	assert(params->size >= 2);
	
	
	// Signature version 0
	
	if (sdb->sdb_signature_ver == 0) {
	
		assert(strcmp(params->params[0].key, "Action") == 0);
		assert(strcmp(params->params[1].key, "Timestamp") == 0);
		
		size_t l = strlen(params->params[0].value) + strlen(params->params[1].value) + 4;
		char* b = (char*) alloca(l);
		
		strcpy(b, params->params[0].value);
		strcat(b, params->params[1].value);
		
		return sdb_sign(sdb, b, buffer, plen); 
	}
	
	
	// Signature version 1
	
	if (sdb->sdb_signature_ver == 1) {
		
		SDB_SAFE(sdb_params_sort(params));
		
		size_t i, l = 0;
		for (i = 0; i < params->size; i++) {
			l += strlen(params->params[i].key);
			l += strlen(params->params[i].value);
		}
		
		char* b = (char*) alloca(l);
		*b = '\0';
		
		for (i = 0; i < params->size; i++) {
			strcat(b, params->params[i].key);
			strcat(b, params->params[i].value);
		}
		
		return sdb_sign(sdb, b, buffer, plen); 
	}
	
	
	return SDB_E_INVALID_SIGNATURE_VER;
}
Example #5
0
/**
 * Execute a command
 * 
 * @param sdb the SimpleDB handle
 * @param cmd the command name
 * @param params the parameters
 * @param response the pointer to the result-set
 * @return the result
 */
int sdb_execute_rs(struct SDB* sdb, const char* cmd, struct sdb_params* _params, struct sdb_response** response)
{
	// Prepare the command execution
	
	struct sdb_params* params = sdb_params_alloc(_params->size + 8);
	SDB_SAFE(sdb_params_add(params, "Action", cmd));
	char timestamp[32]; sdb_timestamp(timestamp);
	SDB_SAFE(sdb_params_add(params, "Timestamp", timestamp));
	
	
	// Add the command parameters
	
	SDB_SAFE(sdb_params_add_all(params, _params));
	
	
	// Add the next token
	
	if (*response != NULL) {
		if ((*response)->has_more) {
			assert((*response)->internal->next_token);
			SDB_SAFE(sdb_params_add(params, "NextToken", (const char*) (*response)->internal->next_token));
		}
	}
	
	
	// Add the required parameters
	
	SDB_SAFE(sdb_params_add_required(sdb, params));
	char* post = sdb_post(sdb, params);
	long postsize = strlen(post);
	sdb_params_free(params);
	
	
	// Configure Curl and execute the command
	
	CURL* curl = sdb->curl_handle;
	
	sdb->rec.size = 0;
	curl_easy_setopt(curl, CURLOPT_URL, AWS_URL);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sdb->rec);
	curl_easy_setopt(curl, CURLOPT_POST, 1L);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post);
#ifdef _DEBUG_PRINT_RESPONSE
	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
#endif
	CURLcode cr = curl_easy_perform(curl);
	free(post);
	
	
	// Statistics
	
	if (cr == CURLE_OK) {
		sdb->stat.num_commands++;
		if (strncmp(cmd, "Put", 3) == 0) sdb->stat.num_puts++;
		sdb_update_size_stats(sdb, curl, postsize, sdb->rec.size);
	}
	
	
	// Handle Curl errors and internal AWS errors
	
	if (cr != CURLE_OK) return SDB_CURL_ERROR(cr);
	if (strncmp(sdb->rec.buffer, "<html", 5) == 0) return SDB_E_AWS_INTERNAL_ERROR_2;
	
#ifdef _DEBUG_PRINT_RESPONSE
	sdb->rec.buffer[sdb->rec.size] = '\0';
	printf("\n%s\n\n", sdb->rec.buffer);
#endif
	
	
	// Parse the response and check for errors
	
	if (*response == NULL) {
		*response = sdb_response_allocate();
	}
	else {
		sdb_response_prepare_append(*response);
	}
	(*response)->internal->errout = sdb->errout;
	int __ret = sdb_response_parse(*response, sdb->rec.buffer, sdb->rec.size);
	
	if (SDB_FAILED(__ret)) {
		sdb_free(response);
		return __ret;
	}
	
	sdb->stat.box_usage += (*response)->box_usage;
	
	if ((*response)->error != 0) {
		__ret = (*response)->error;
		if (SDB_AWS_ERROR(__ret) != SDB_E_AWS_SERVICE_UNAVAILABLE) sdb_free(response);
		return SDB_AWS_ERROR(__ret);
	}
	
	
	// Save the parameters in the case manual NEXT handling is allowed
	
	if (!sdb->auto_next && (*response)->has_more) {
		if ((*response)->internal->next == NULL) {
			(*response)->internal->params = sdb_params_deep_copy(_params);
			(*response)->internal->command = (char*) malloc(strlen(cmd) + 4);
			strcpy((*response)->internal->command, cmd);
		}
		else if ((*response)->internal->params == NULL) {
			(*response)->internal->params = (*response)->internal->next->params;
			(*response)->internal->command = (*response)->internal->next->command;
			(*response)->internal->next->params = NULL;
			(*response)->internal->next->command = NULL;
			assert((*response)->internal->params);
			assert((*response)->internal->command);
		}
	}
	
	
	return SDB_OK;
}
Example #6
0
/**
 * Execute a command and ignore the result-set
 * 
 * @param sdb the SimpleDB handle
 * @param cmd the command name
 * @param _params the parameters
 * @return the result
 */
int sdb_execute(struct SDB* sdb, const char* cmd, struct sdb_params* _params)
{
	// Prepare the command execution
	
	struct sdb_params* params = sdb_params_alloc(_params->size + 8);
	SDB_SAFE(sdb_params_add(params, "Action", cmd));
	char timestamp[32]; sdb_timestamp(timestamp);
	SDB_SAFE(sdb_params_add(params, "Timestamp", timestamp));
	
	
	// Add the command parameters
	
	SDB_SAFE(sdb_params_add_all(params, _params));
	
	
	// Add the required parameters
	
	SDB_SAFE(sdb_params_add_required(sdb, params));
	char* post = sdb_post(sdb, params);
	long postsize = strlen(post);
	sdb_params_free(params);
	
	
	// Configure Curl and execute the command
	
	CURL* curl = sdb->curl_handle;
	
	sdb->rec.size = 0;
	curl_easy_setopt(curl, CURLOPT_URL, AWS_URL);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sdb->rec);
	curl_easy_setopt(curl, CURLOPT_POST, 1L);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post);
#ifdef _DEBUG_PRINT_RESPONSE
	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
#endif
	CURLcode cr = curl_easy_perform(curl);
	free(post);
	
	
	// Statistics
	
	if (cr == CURLE_OK) {
		sdb->stat.num_commands++;
		if (strncmp(cmd, "Put", 3) == 0) sdb->stat.num_puts++;
		sdb_update_size_stats(sdb, curl, postsize, sdb->rec.size);
	}
	
	
	// Handle Curl errors and internal AWS errors
	
	if (cr != CURLE_OK) return SDB_CURL_ERROR(cr);
	if (strncmp(sdb->rec.buffer, "<html", 5) == 0) return SDB_E_AWS_INTERNAL_ERROR_2;
	
#ifdef _DEBUG_PRINT_RESPONSE
	sdb->rec.buffer[sdb->rec.size] = '\0';
	printf("\n%s\n\n", sdb->rec.buffer);
#endif
	
	
	// Parse the response and check for errors
	
	struct sdb_response response; sdb_response_init(&response);
	response.internal->errout = sdb->errout;
	int __ret = sdb_response_parse(&response, sdb->rec.buffer, sdb->rec.size);
	
	if (SDB_FAILED(__ret)) {
		sdb_response_cleanup(&response);
		return __ret;
	}
	
	sdb->stat.box_usage += response.box_usage;
	
	if (response.error != 0) {
		__ret = response.error;
		sdb_response_cleanup(&response);
		return SDB_AWS_ERROR(__ret);
	}
	
	
	// Cleanup
	
	sdb_response_cleanup(&response);
	return SDB_OK;
}
Example #7
0
/**
 * Create the URL-encoded parameters string with SignatureVersion 2 sig.
 * 
 * @param sdb the SimpleDB handle
 * @param params the parameter array
 * @param pbuffer the variable for the output buffer (will be allocated by the routine, but has to be freed by caller)
 * @return SDB_OK if no errors occurred
 */
int sdb_params_export(struct SDB* sdb, struct sdb_params* params, char** pbuffer)
{
	assert(params->size >= 2);
	
	// Sign the parameters
	
	char signature[EVP_MAX_MD_SIZE * 2];
	
	// Determine the appropriate size
	
	size_t i, l = 0;
	for (i = 0; i < params->size; i++) {
		l += strlen(params->params[i].key) + 1;
		l += strlen(params->params[i].value) * 3 + 1;
	}
	
	// Allocate buffer
	
	*pbuffer = (char*) malloc(l + 4);
	char* b = *pbuffer;
	*b = '\0';
	
	// Build the string
	
	SDB_SAFE(sdb_params_sort(params));
	for (i = 0; i < params->size; i++) {
	
		if (i > 0) strcat(b, "&");
		
		strcat(b, params->params[i].key);
		strcat(b, "=");
		
		char* e = sdb_escape(sdb, params->params[i].value, strlen(params->params[i].value));
		if (e == NULL) {
			free(b);
			*pbuffer = NULL;
			return SDB_E_URL_ENCODE_FAILED;
		} 
		
		strcat(b, e);
		curl_free(e);
	}
	
	// string is built, now build complete string to sign
	
	l = strlen(b) + 25;
	char* s = (char*) alloca(l);
	*s = '\0';
	
	strcat(s, "POST\n");
	strcat(s, "sdb.amazonaws.com\n");
	strcat(s, "/\n");
	strcat(s, b);
	
	// Create the signature and add it to the URL-encoded param string
	
	SDB_SAFE(sdb_sign(sdb, s, signature, NULL));
	
	strcat(b, "&Signature=");
	char* e = sdb_escape(sdb->curl_handle, signature, strlen(signature));
	if (e == NULL) {
		free(b);
		*pbuffer = NULL;
		return SDB_E_URL_ENCODE_FAILED;
	}
	strcat(b, e);
	free(e);
	
	return SDB_OK;
}
Example #8
0
/**
 * Parse the list of items
 * 
 * @param response the response data structure (must be initalized)
 * @param items the list of items
 * @return SDB_OK if no errors occurred
 */
int sdb_response_parse_items(struct sdb_response* response, xmlNodePtr items)
{
	xmlNodePtr cur, content;
	int size = 0;
	
	
	// Count the attributes and determine whether we have more incoming data
	 
	response->has_more = FALSE;
	
	for (cur = items->children; cur != NULL; cur = cur->next) {
		
		
		// The item
		
		if (strcmp((char*) cur->name, "Item") == 0 || strcmp((char*) cur->name, "ItemName") == 0) {
			size++;
			continue;
		}
		
		
		// The next token
		
		if (strcmp((char*) cur->name, "NextToken") == 0) {
			assert(cur->children != NULL);
			content = cur->children;
			response->internal->next_token = XML_GET_CONTENT(content); 
			assert(response->internal->next_token != NULL);
			response->has_more = TRUE;
			continue;
		}
		
		
		// The list of nodes to ignore
		
		if (strcmp((char*) cur->name, "RequestID") == 0) continue;
		if (strcmp((char*) cur->name, "RequestId") == 0) continue;
		
		
		// Handle errors
		
		if (response->internal->errout != NULL) {
			fprintf(response->internal->errout, "SimpleDB ERROR: Invalid node \"%s\" in the AWS list of items\n", cur->name);
		}
		return SDB_E_INVALID_META_RESPONSE;
	}
	
	
	// Allocate the memory if this is a new result set, otherwise prepare to append
	
	int start = 0;
	
	if (response->type == SDB_R_NONE) {
		
		response->size = size;
		response->type = SDB_R_ITEM_LIST;
		response->items = (struct sdb_item*) malloc(size * sizeof(struct sdb_item));  
	}
	else if (response->type == SDB_R_ITEM_LIST) {
		
		struct sdb_item* old = response->items;
		int newsize = response->size + size;
		start = response->size;
		
		response->items = (struct sdb_item*) malloc(newsize * sizeof(struct sdb_item));
		memcpy(response->items, old, response->size * sizeof(struct sdb_item));
		free(old);
		
		response->size = newsize;
	}
	else assert(0);
	
	
	
	// Pull out the items 
	
	int index = start;
	for (cur = items->children; cur != NULL; cur = cur->next) {
		
		
		// Item name
		
		if (strcmp((char*) cur->name, "ItemName") == 0) {
			assert(cur->children != NULL);
			content = cur->children;
			response->items[index].name = (char*) XML_GET_CONTENT(content);
			response->items[index].size = 0; 
			response->items[index].attributes = NULL; 
			assert(response->items[index].name != NULL);
			index++;
			continue;
		}
		
		
		// Item with attributes
		
		if (strcmp((char*) cur->name, "Item") == 0) {
			SDB_SAFE(sdb_response_parse_item(response, &response->items[index++], cur));
		}
	}
	
	assert(index - start == size);
	
	return SDB_OK;
}
Example #9
0
/**
 * Parse the response
 * 
 * @param response the response data structure
 * @param buffer the buffer to parse
 * @param length the length of the data in the buffer
 * @return SDB_OK if no errors occurred
 */
int sdb_response_parse(struct sdb_response* response, const char* buffer, size_t length)
{
	// Parse the XML
	
	response->internal->doc = xmlReadMemory(buffer, length, "response.xml", NULL, 0);
	if (response->internal->doc == NULL) return SDB_E_INVALID_XML_RESPONSE;
	
	
	// Get the root node
	
	xmlNodePtr root = xmlDocGetRootElement(response->internal->doc);
	
	
	// Iterate over the root node
	
	xmlNodePtr cur;
	for (cur = root->children; cur != NULL; cur = cur->next) {
		
		
		// Error node
		
		if (strcmp((char*) cur->name, "Errors") == 0) {
			SDB_SAFE(sdb_response_parse_errors(response, cur));
			continue;
		}
		
		
		// Response metadata
		
		if (strcmp((char*) cur->name, "ResponseMetadata") == 0) {
			SDB_SAFE(sdb_response_parse_metadata(response, cur));
			continue;
		}
		
		
		// List domains result
		
		if (strcmp((char*) cur->name, "ListDomainsResult") == 0) {
			SDB_SAFE(sdb_response_parse_domains(response, cur));
			continue;
		}
		
		
		// Domain metadata result
		
		if (strcmp((char*) cur->name, "DomainMetadataResult") == 0) {
			SDB_SAFE(sdb_response_parse_domain_metadata(response, cur));
			continue;
		}
		
		
		// Get attributes result
		
		if (strcmp((char*) cur->name, "GetAttributesResult") == 0) {
			SDB_SAFE(sdb_response_parse_attributes(response, cur));
			continue;
		}
		
		
		// Get the items with attributes result
		
		if (strcmp((char*) cur->name, "QueryResult") == 0 || strcmp((char*) cur->name, "QueryWithAttributesResult") == 0 || strcmp((char*) cur->name, "SelectResult") == 0) {
			SDB_SAFE(sdb_response_parse_items(response, cur));
			continue;
		}
		
		
		// The list of response nodes to ignore
		
		if (strcmp((char*) cur->name, "RequestID") == 0) continue;
		if (strcmp((char*) cur->name, "RequestId") == 0) continue;
		
		
		// Deal with errors here
		
		if (response->internal->errout != NULL) {
			fprintf(response->internal->errout, "SimpleDB ERROR: Invalid node \"%s\" in the AWS response\n", cur->name);
		}
		return SDB_E_INVALID_ERR_RESPONSE;
	}
	
	
	return SDB_OK;
}