From 2f2cb8935b6059e9f14c69dc32963e6428cbaa38 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 12 Jun 2009 14:28:59 -0700 Subject: [PATCH] s3: handle 'get bucket' opereation --- src/Makefile.am | 2 +- src/s3/s3access.h | 8 ++ src/s3/s3gw.c | 142 ---------------------- src/s3/s3gw.cc | 292 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 301 insertions(+), 143 deletions(-) delete mode 100644 src/s3/s3gw.c create mode 100644 src/s3/s3gw.cc diff --git a/src/Makefile.am b/src/Makefile.am index f0dec0793a31f..e7517932ee74c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -123,7 +123,7 @@ testradospp_LDADD = librados.la libcrush.la radosacl_SOURCES = radosacl.cc radosacl_LDADD = librados.la libcrush.la -s3gw_SOURCES = s3/s3gw.c s3/s3fs.c +s3gw_SOURCES = s3/s3gw.cc s3/s3fs.c s3gw_LDADD = librados.la libcrush.la -lfcgi ## object classes diff --git a/src/s3/s3access.h b/src/s3/s3access.h index e16f4f72d58f0..db2f801cbbc89 100644 --- a/src/s3/s3access.h +++ b/src/s3/s3access.h @@ -1,9 +1,17 @@ #ifndef __S3ACCESS_H #define __S3ACCESS_H +#ifdef __cplusplus +extern "C" { +#endif + typedef void *S3AccessHandle; int list_buckets_init(const char *id, S3AccessHandle *handle); int list_buckets_next(const char *id, char *buf, int size, S3AccessHandle *handle); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/s3/s3gw.c b/src/s3/s3gw.c deleted file mode 100644 index 0789b59e5011a..0000000000000 --- a/src/s3/s3gw.c +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include - -#include "fcgiapp.h" - -#include "s3access.h" - - -struct req_state { - FCGX_Stream *in; - FCGX_Stream *out; - int indent; -}; - -static void init_state(struct req_state *s, FCGX_Stream *in, FCGX_Stream *out) -{ - s->in = in; - s->out = out; - s->indent = 0; -} - -static void buf_to_hex(const unsigned char *buf, int len, char *str) -{ - int i; - str[0] = '\0'; - for (i = 0; i < len; i++) { - sprintf(&str[i*2], "%02x", (int)buf[i]); - } -} - -static void open_section(struct req_state *s, const char *name) -{ - FCGX_FPrintF(s->out, "%*s<%s>\n", s->indent, "", name); - ++s->indent; -} - -static void close_section(struct req_state *s, const char *name) -{ - --s->indent; - FCGX_FPrintF(s->out, "%*s\n", s->indent, "", name); -} - -static void dump_value(struct req_state *s, const char *name, const char *val) -{ - FCGX_FPrintF(s->out, "%*s<%s>%s\n", s->indent, "", name, val, name); -} - -static void dump_entry(struct req_state *s, const char *val) -{ - FCGX_FPrintF(s->out, "%*s\n", s->indent, "", val); -} - - - -static void dump_owner(struct req_state *s, const char *id, int id_size, const char *name) -{ - char id_str[id_size*2 + 1]; - - buf_to_hex((const unsigned char *)id, id_size, id_str); - - open_section(s, "Owner"); - dump_value(s, "ID", id_str); - dump_value(s, "DisplayName", name); - close_section(s, "Owner"); -} - -static void dump_start(struct req_state *s) -{ - dump_entry(s, "xml version=\"1.0\" encoding=\"UTF-8\""); -} - -static void list_all_buckets_start(struct req_state *s) -{ - open_section(s, "ListAllMyBucketsResult"); -} - -static void list_all_buckets_end(struct req_state *s) -{ - close_section(s, "ListAllMyBucketsResult"); -} - - -static void dump_bucket(struct req_state *s, const char *name, const char *date) -{ - open_section(s, "Bucket"); - dump_value(s, "Name", name); - dump_value(s, "CreationDate", date); - close_section(s, "Bucket"); -} - -void do_retrieve(struct req_state *s, const char *path_name) -{ - unsigned long long id = 0x0123456789ABCDEF; - S3AccessHandle handle; - int r; -#define BUF_SIZE 256 - char buf[BUF_SIZE]; - dump_start(s); - list_all_buckets_start(s); - dump_owner(s, (const char *)&id, sizeof(id), "foobi"); - r = list_buckets_init((const char *)&id, &handle); - open_section(s, "Buckets"); - while (r >= 0) { - r = list_buckets_next((const char *)&id, buf, BUF_SIZE, &handle); - if (r < 0) - continue; - dump_bucket(s, buf, "123123"); - } - close_section(s, "Buckets"); - list_all_buckets_end(s); -} - -int main(void) -{ - int i, scale; - FCGX_Stream *in, *out, *err; - FCGX_ParamArray envp; - struct req_state s; - - while (FCGX_Accept(&in, &out, &err, &envp) >= 0) - { - char *method; - char* path_name; - - FCGX_FPrintF(out,"Content-type: text/plain\r\n\r\n"); - - method = FCGX_GetParam("REQUEST_METHOD",envp); - if (!method) - continue; - - path_name = FCGX_GetParam("SCRIPT_NAME",envp); - if (!path_name) /* really shouldn't happen.. */ - continue; - - init_state(&s, in, out); - - if (strcmp(method, "GET") == 0) - do_retrieve(&s, path_name); - } - return 0; -} diff --git a/src/s3/s3gw.cc b/src/s3/s3gw.cc new file mode 100644 index 0000000000000..cde1a9e9c9977 --- /dev/null +++ b/src/s3/s3gw.cc @@ -0,0 +1,292 @@ +#include +#include +#include + +#include "fcgiapp.h" + +#include "s3access.h" + +#include +#include +#include + +using namespace std; + + +struct req_state { + FCGX_Stream *in; + FCGX_Stream *out; + int indent; + const char *path_name; + const char *host; + const char *method; + const char *query; +}; + + +class NameVal +{ + string str; + string name; + string val; + public: + NameVal(string nv) : str(nv) {} + + int parse(); + + string& get_name() { return name; } + string& get_val() { return val; } +}; + +int NameVal::parse() +{ + int delim_pos = str.find('='); + + if (delim_pos < 0) + return -1; + + name = str.substr(0, delim_pos); + val = str.substr(delim_pos + 1); + + cout << "parsed: name=" << name << " val=" << val << std::endl; + return 0; +} + +class XMLArgs +{ + string str, empty_str; + map val_map; + public: + XMLArgs(string s) : str(s) {} + int parse(); + string& get(string& name); + string& get(const char *name); +}; + +int XMLArgs::parse() +{ + int pos, fpos; + bool end = false; + if (str[pos] == '?') pos++; + + while (!end) { + fpos = str.find('&', pos); + if (fpos < pos) { + end = true; + fpos = str.size(); + } + NameVal nv(str.substr(pos, fpos - pos)); + if (nv.parse() >= 0) { + val_map[nv.get_name()] = nv.get_val(); + } + + pos = fpos + 1; + } + + return 0; +} + +string& XMLArgs::get(string& name) +{ + map::iterator iter; + iter = val_map.find(name); + if (iter == val_map.end()) + return empty_str; + return iter->second; +} + +string& XMLArgs::get(const char *name) +{ + string s(name); + return get(s); +} + +static void init_state(struct req_state *s, FCGX_ParamArray envp, FCGX_Stream *in, FCGX_Stream *out) +{ + s->in = in; + s->out = out; + s->indent = 0; + s->path_name = FCGX_GetParam("SCRIPT_NAME", envp); + s->method = FCGX_GetParam("REQUEST_METHOD", envp); + s->host = FCGX_GetParam("HTTP_HOST", envp); + s->query = FCGX_GetParam("QUERY_STRING", envp); + +} + +static void buf_to_hex(const unsigned char *buf, int len, char *str) +{ + int i; + str[0] = '\0'; + for (i = 0; i < len; i++) { + sprintf(&str[i*2], "%02x", (int)buf[i]); + } +} + +static void open_section(struct req_state *s, const char *name) +{ + FCGX_FPrintF(s->out, "%*s<%s>\n", s->indent, "", name); + ++s->indent; +} + +static void close_section(struct req_state *s, const char *name) +{ + --s->indent; + FCGX_FPrintF(s->out, "%*s\n", s->indent, "", name); +} + +static void dump_value(struct req_state *s, const char *name, const char *val) +{ + FCGX_FPrintF(s->out, "%*s<%s>%s\n", s->indent, "", name, val, name); +} + +static void dump_entry(struct req_state *s, const char *val) +{ + FCGX_FPrintF(s->out, "%*s\n", s->indent, "", val); +} + + + +static void dump_owner(struct req_state *s, const char *id, int id_size, const char *name) +{ + char id_str[id_size*2 + 1]; + + buf_to_hex((const unsigned char *)id, id_size, id_str); + + open_section(s, "Owner"); + dump_value(s, "ID", id_str); + dump_value(s, "DisplayName", name); + close_section(s, "Owner"); +} + +static void dump_start(struct req_state *s) +{ + dump_entry(s, "xml version=\"1.0\" encoding=\"UTF-8\""); +} + +static void list_all_buckets_start(struct req_state *s) +{ + open_section(s, "ListAllMyBucketsResult"); +} + +static void list_all_buckets_end(struct req_state *s) +{ + close_section(s, "ListAllMyBucketsResult"); +} + + +static void dump_bucket(struct req_state *s, const char *name, const char *date) +{ + open_section(s, "Bucket"); + dump_value(s, "Name", name); + dump_value(s, "CreationDate", date); + close_section(s, "Bucket"); +} + +void do_list_buckets(struct req_state *s) +{ + unsigned long long id = 0x0123456789ABCDEF; + S3AccessHandle handle; + int r; +#define BUF_SIZE 256 + char buf[BUF_SIZE]; + list_all_buckets_start(s); + dump_owner(s, (const char *)&id, sizeof(id), "foobi"); + r = list_buckets_init((const char *)&id, &handle); + open_section(s, "Buckets"); + while (r >= 0) { + r = list_buckets_next((const char *)&id, buf, BUF_SIZE, &handle); + if (r < 0) + continue; + dump_bucket(s, buf, "123123"); + } + close_section(s, "Buckets"); + list_all_buckets_end(s); +} + +void do_list_objects(struct req_state *s) +{ + int pos; + string bucket, host_str; + string prefix, marker, max_keys, delimiter; + const char *p; + unsigned long long id = 0x0123456789ABCDEF; + + if (s->path_name[0] == '/') { + string tmp = s->path_name; + bucket = tmp.substr(1); + p = s->query; + } else if (s->path_name [0] == '?') { + if (!s->host) + return; + host_str = s->host; + pos = host_str.find('.'); + if (pos >= 0) { + bucket = host_str.substr(pos); + } else { + bucket = host_str; + } + p = s->path_name; + } else { + return; + } + + XMLArgs args(p); + args.parse(); + + prefix = args.get("prefix"); + marker = args.get("marker"); + max_keys = args.get("max-keys"); + delimiter = args.get("delimiter"); + + open_section(s, "ListBucketResult"); + dump_value(s, "Name", bucket.c_str()); + if (!prefix.empty()) + dump_value(s, "Prefix", prefix.c_str()); + if (!marker.empty()) + dump_value(s, "Marker", marker.c_str()); + if (!max_keys.empty()) + dump_value(s, "MaxKeys", max_keys.c_str()); + if (!delimiter.empty()) + dump_value(s, "Delimiter", delimiter.c_str()); + open_section(s, "Contents"); + dump_value(s, "Key", "Nelson"); + dump_value(s, "LastModified", "2006-01-01T12:00:00.000Z"); + dump_value(s, "ETag", ""828ef3fdfa96f00ad9f27c383fc9ac7f""); + dump_value(s, "Size", "5"); + dump_value(s, "StorageClass", "STANDARD"); + dump_owner(s, (const char *)&id, sizeof(id), "foobi"); + close_section(s, "Contents"); + close_section(s, "ListBucketResult"); + //if (args.get("name")) +} + +void do_retrieve(struct req_state *s) +{ + dump_start(s); + if (strcmp(s->path_name, "/") == 0) + do_list_buckets(s); + else + do_list_objects(s); +} + +int main(void) +{ + FCGX_Stream *in, *out, *err; + FCGX_ParamArray envp; + struct req_state s; + + while (FCGX_Accept(&in, &out, &err, &envp) >= 0) + { + FCGX_FPrintF(out,"Content-type: text/plain\r\n\r\n"); + + init_state(&s, envp, in, out); + + if (!s.method) + continue; + + if (strcmp(s.method, "GET") == 0) + do_retrieve(&s); + } + return 0; +} + -- 2.39.5