-
-
Save iandelahorne/6206839 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _S3_H | |
#define _S3_H | |
struct s3_string { | |
char *ptr; | |
size_t len; | |
}; | |
struct s3_string * s3_string_init(); | |
size_t s3_string_curl_writefunc(void *ptr, size_t len, size_t nmemb, struct s3_string *s); | |
void s3_string_free(struct s3_string *str); | |
#endif /* _S3_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include "s3.h" | |
size_t | |
s3_string_curl_writefunc(void *ptr, size_t len, size_t nmemb, struct s3_string *s) { | |
size_t new_len = s->len + len *nmemb; | |
s->ptr = realloc(s->ptr, new_len + 1); | |
if (s->ptr == NULL) { | |
fprintf(stderr, "realloc() failed\n"); | |
exit(EXIT_FAILURE); | |
} | |
memcpy(s->ptr+s->len, ptr, len*nmemb); | |
s->ptr[new_len] = '\0'; | |
s->len = new_len; | |
return len*nmemb; | |
} | |
struct s3_string * | |
s3_string_init() { | |
struct s3_string *s; | |
s = malloc(sizeof (struct s3_string)); | |
s->len = 0; | |
s->ptr = malloc(s->len+1); | |
if (s->ptr == NULL) { | |
fprintf(stderr, "malloc() failed\n"); | |
exit(EXIT_FAILURE); | |
} | |
s->ptr[0] = '\0'; | |
return s; | |
} | |
void | |
s3_string_free(struct s3_string *str) { | |
free(str->ptr); | |
free(str); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <openssl/engine.h> | |
#include <openssl/hmac.h> | |
#include <openssl/evp.h> | |
#include <openssl/bio.h> | |
#include <curl/curl.h> | |
#include <libxml/parser.h> | |
#include <libxml/tree.h> | |
#include <libxml/xpath.h> | |
#include <libxml/xpathInternals.h> | |
#define NS_DELIM '.' | |
#include "s3.h" | |
/* | |
* Example code that signs a request for listing the bucket's contents | |
*/ | |
struct s3_content { | |
char *key; | |
char *lastmod; /* time_t */ | |
size_t size; | |
char *etag; | |
}; | |
struct s3_xml_data { | |
int level; | |
}; | |
#define S3_SECRET_LENGTH 128 | |
#define S3_ID_LENGTH 128 | |
struct S3 { | |
char *secret; | |
char *id; | |
char *base_url; | |
}; | |
char * | |
hmac_sign(const char *key, const char *str, size_t len) { | |
unsigned char *digest; | |
char *buf; | |
unsigned int digest_len = EVP_MAX_MD_SIZE; /* HMAC_Final needs at most EVP_MAX_MD_SIZE bytes */ | |
HMAC_CTX ctx; | |
BIO *bmem, *b64; | |
BUF_MEM *bufptr; | |
ENGINE_load_builtin_engines(); | |
ENGINE_register_all_complete(); | |
/* Setup HMAC context, init with sha1 and our key*/ | |
HMAC_CTX_init(&ctx); | |
HMAC_Init_ex(&ctx, key, strlen((char *)key), EVP_sha1(), NULL); | |
/* Create Base64 BIO filter that outputs to memory */ | |
b64 = BIO_new(BIO_f_base64()); | |
bmem = BIO_new(BIO_s_mem()); | |
b64 = BIO_push(b64, bmem); | |
/* Give us a buffer to write result into */ | |
digest = malloc(digest_len); | |
/* Push data into HMAC */ | |
HMAC_Update(&ctx, (unsigned char *)str, (unsigned int)len); | |
/* Flush HMAC data into buffer */ | |
HMAC_Final(&ctx, digest, &digest_len); | |
/* Write data into BIO, flush and fetch the data */ | |
BIO_write(b64, digest, digest_len); | |
(void) BIO_flush(b64); | |
BIO_get_mem_ptr(b64, &bufptr); | |
buf = malloc(bufptr->length); | |
memcpy(buf, bufptr->data, bufptr->length - 1); | |
buf[bufptr->length - 1] = '\0'; | |
BIO_free_all(b64); | |
HMAC_CTX_cleanup(&ctx); | |
free(digest); | |
return buf; | |
} | |
static struct S3 * | |
s3_init(const char *id, const char *secret, const char *base_url) { | |
struct S3 *s3 = malloc(sizeof (struct S3)); | |
s3->id = malloc(S3_ID_LENGTH); | |
s3->secret = malloc(S3_SECRET_LENGTH); | |
/* XXX better length */ | |
s3->base_url = malloc(256); | |
strlcpy(s3->id, id, S3_ID_LENGTH); | |
strlcpy(s3->secret, secret, S3_SECRET_LENGTH); | |
strlcpy(s3->base_url, base_url, 255); | |
return s3; | |
} | |
static void | |
s3_free(struct S3 *s3) { | |
free(s3->id); | |
free(s3->secret); | |
free(s3->base_url); | |
free(s3); | |
} | |
void | |
register_namespaces(xmlXPathContextPtr ctx, const xmlChar *nsList) { | |
xmlChar* nsListDup; | |
xmlChar* prefix; | |
xmlChar* href; | |
xmlChar* next; | |
nsListDup = xmlStrdup(nsList); | |
if(nsListDup == NULL) { | |
fprintf(stderr, "Error: unable to strdup namespaces list\n"); | |
return; | |
} | |
next = nsListDup; | |
while(next != NULL) { | |
/* skip spaces */ | |
while((*next) == ' ') next++; | |
if((*next) == '\0') break; | |
/* find prefix */ | |
prefix = next; | |
next = (xmlChar*)xmlStrchr(next, '='); | |
if(next == NULL) { | |
fprintf(stderr,"Error: invalid namespaces list format\n"); | |
xmlFree(nsListDup); | |
return; | |
} | |
*(next++) = '\0'; | |
/* find href */ | |
href = next; | |
next = (xmlChar*)xmlStrchr(next, ' '); | |
if(next != NULL) { | |
*(next++) = '\0'; | |
} | |
/* do register namespace */ | |
if(xmlXPathRegisterNs(ctx, prefix, href) != 0) { | |
fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href); | |
xmlFree(nsListDup); | |
return; | |
} | |
} | |
xmlFree(nsListDup); | |
} | |
struct s3_content * | |
parse_content(xmlNode *root) { | |
struct s3_content *content = malloc(sizeof(struct s3_content)); | |
xmlNode *node = NULL; | |
for (node = root; node; node = node->next) { | |
if (node->type == XML_ELEMENT_NODE) { | |
xmlChar *value = xmlNodeGetContent(node->children); | |
size_t len = strlen((const char *) value); | |
if (strcasecmp("key", (const char *)node->name) == 0) { | |
content->key = malloc(len + 2); | |
strlcpy(content->key, (const char *)value, len + 1); | |
} else if (strcasecmp("lastmodified", (const char *)node->name) == 0) { | |
content->lastmod = malloc(len + 2); | |
strlcpy(content->lastmod, (const char *)value, len + 1); | |
} else if (strcasecmp("etag", (const char *)node->name) == 0) { | |
content->etag = malloc(len + 2); | |
strlcpy(content->etag, (const char *)value, len + 1); | |
} else { | |
printf("node type: Element, name: %s\n", node->name); | |
printf("node xmlsNodeGetContent: %s\n",value); | |
} | |
xmlFree(value); | |
} | |
} | |
return content; | |
} | |
void | |
libxml_walk_nodes(xmlNode *root) { | |
xmlNode *node = NULL; | |
for (node = root; node; node = node->next) { | |
if (node->type == XML_ELEMENT_NODE) { | |
printf("node type: Element, name: %s\n", node->name); | |
} | |
libxml_walk_nodes(node->children); | |
} | |
} | |
void walk_xpath_nodes(xmlNodeSetPtr nodes) { | |
xmlNodePtr cur; | |
int size; | |
int i; | |
size = (nodes) ? nodes->nodeNr : 0; | |
printf("size is %d nodes\n", size); | |
for (i = 0; i < size ; i++) { | |
if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { | |
cur = nodes->nodeTab[i]; | |
/*printf("name: %s\n", cur->name); */ | |
struct s3_content *content = parse_content(cur->children); | |
printf("Got %s\n", content->key); | |
} | |
} | |
} | |
void | |
execute_xpath_expr(const xmlDocPtr doc, const xmlChar *xpath_expr, const xmlChar *ns_list) { | |
xmlXPathContextPtr xpath_ctx; | |
xmlXPathObjectPtr xpath_obj; | |
xpath_ctx = xmlXPathNewContext(doc); | |
if (xpath_ctx == NULL) { | |
fprintf(stderr,"Error: unable to create new XPath context\n"); | |
} | |
register_namespaces(xpath_ctx, ns_list); | |
xpath_obj = xmlXPathEvalExpression(xpath_expr, xpath_ctx); | |
if(xpath_obj == NULL) { | |
fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpath_expr); | |
} | |
walk_xpath_nodes(xpath_obj->nodesetval); | |
xmlXPathFreeObject(xpath_obj); | |
xmlXPathFreeContext(xpath_ctx); | |
} | |
void | |
libxml_do_stuff(char *str) { | |
xmlDocPtr doc; | |
doc = xmlReadMemory(str, strlen(str), "noname.xml", NULL, 0); | |
/* xmlNode *root_element = xmlDocGetRootElement(doc); */ | |
/* Since Amazon uses an XML Namespace, we need to declare it and use it as a prefix in Xpath queries, even though it's */ | |
execute_xpath_expr(doc, (const xmlChar *)"//amzn:Contents", (const xmlChar *)"amzn=http://s3.amazonaws.com/doc/2006-03-01/"); | |
xmlFreeDoc(doc); | |
} | |
static void | |
s3_list_bucket(struct S3 *s3, const char *bucket) { | |
char *date; | |
char *data, *digest; | |
char *hdr; | |
time_t now; | |
struct tm tm; | |
char *url; | |
CURL *curl; | |
struct curl_slist *headers = NULL; | |
struct s3_string *str; | |
const char *method = "GET"; | |
str = s3_string_init(); | |
date = malloc(128); | |
now = time(0); | |
tm = *gmtime(&now); | |
strftime(date, 128, "%a, %d %b %Y %H:%M:%S %Z", &tm); | |
data = malloc(1024); | |
snprintf(data, 1023, "%s\n\n\n%s\n/%s/", method, date, bucket); | |
fprintf(stderr, "data is %s\n", data); | |
digest = hmac_sign(s3->secret, data, strlen(data)); | |
fprintf(stderr, "Authentication: AWS %s:%s\n", s3->id, digest); | |
asprintf(&url, "http://%s.%s/?delimiter=/", bucket, s3->base_url); | |
fprintf(stderr, "url is %s\n", url); | |
curl = curl_easy_init(); | |
hdr = malloc(1024); | |
snprintf(hdr, 1023, "Date: %s", date); | |
headers = curl_slist_append(headers, hdr); | |
snprintf(hdr, 1023, "Authorization: AWS %s:%s", s3->id, digest); | |
headers = curl_slist_append(headers, hdr); | |
free(hdr); | |
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); | |
/* curl_easy_setopt(curl, CURLOPT_HEADER, 1); */ | |
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); | |
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); | |
/* http://stackoverflow.com/questions/2329571/c-libcurl-get-output-into-a-string */ | |
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, s3_string_curl_writefunc); | |
curl_easy_setopt(curl, CURLOPT_WRITEDATA, str); | |
curl_easy_setopt(curl, CURLOPT_URL, url); | |
#if 0 | |
curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080"); | |
#endif | |
curl_easy_perform(curl); | |
curl_easy_cleanup(curl); | |
curl_slist_free_all(headers); | |
libxml_do_stuff(str->ptr); | |
printf("%s\n", str->ptr); | |
s3_string_free(str); | |
free(data); | |
free(date); | |
free(digest); | |
} | |
int main (int argc, char **argv) { | |
struct S3 *s3; | |
const char *s3_id = "TRATT"; | |
const char *s3_key = "HEMLIGT"; | |
s3 = s3_init(s3_id, s3_key "s3.amazonaws.com"); | |
const char *bucket = "drutmule"; | |
s3_list_bucket(s3, bucket); | |
return 0; | |
s3_free(s3); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment