From: MORITA Kazutaka <morita.kazut...@lab.ntt.co.jp>

Signed-off-by: MORITA Kazutaka <morita.kazut...@lab.ntt.co.jp>
---
 sheep/Makefile.am |   2 +-
 sheep/http/s3.c   | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 284 insertions(+), 1 deletion(-)
 create mode 100644 sheep/http/s3.c

diff --git a/sheep/Makefile.am b/sheep/Makefile.am
index a9497fc..aa1f079 100644
--- a/sheep/Makefile.am
+++ b/sheep/Makefile.am
@@ -30,7 +30,7 @@ sheep_SOURCES         = sheep.c group.c request.c gateway.c 
store.c vdi.c \
                          plain_store.c config.c migrate.c md.c
 
 if BUILD_HTTP
-sheep_SOURCES          += http.c kvs.c
+sheep_SOURCES          += http.c kvs.c http/s3.c
 endif
 if BUILD_COROSYNC
 sheep_SOURCES          += cluster/corosync.c
diff --git a/sheep/http/s3.c b/sheep/http/s3.c
new file mode 100644
index 0000000..b415145
--- /dev/null
+++ b/sheep/http/s3.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2013 MORITA Kazutaka <morita.kazut...@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "http.h"
+
+#include "kvs.h"
+
+#define MAX_BUCKET_LISTING 1000
+
+/* Escape 'str' for use in XML. */
+static const char *xml_escape(const char *str)
+{
+       /* FIXME: implement this function */
+       return str;
+}
+
+static void s3_write_err_response(struct http_request *req, const char *code,
+                                 const char *desc)
+{
+       http_request_writef(req,
+               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
+               "<Error>\r\n"
+               "<Code>%s</Code>\r\n<Message>%s</Message>\r\n"
+               "</Error>\r\n", code, desc);
+}
+
+/* Operations on the Service */
+
+static void s3_get_service_cb(struct http_request *req, const char *bucket,
+                             void *opaque)
+{
+       bool *print_header = opaque;
+
+       if (*print_header) {
+               *print_header = false;
+
+               http_request_writes(req,
+                       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+                       "<ListAllMyBucketsResult "
+                       "xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\";>"
+                       "<Buckets>");
+       }
+
+       /* FIXME: set the correct creation date */
+       http_request_writef(req, "<Bucket><Name>%s</Name><CreationDate>"
+                           "2009-02-03T16:45:09.000Z</CreationDate></Bucket>",
+                           xml_escape(bucket));
+}
+
+static void s3_get_service(struct http_request *req)
+{
+       bool print_header = true;
+
+       kvs_list_buckets(req, s3_get_service_cb, &print_header);
+
+       http_request_writes(req, "</Buckets></ListAllMyBucketsResult>\r\n");
+}
+
+/* Operations on Buckets */
+
+static void s3_head_bucket(struct http_request *req, const char *bucket)
+{
+       http_response_header(req, NOT_IMPLEMENTED);
+}
+
+static void s3_get_bucket_cb(struct http_request *req, const char *bucket,
+                            const char *object, void *opaque)
+{
+       bool *print_header = opaque;
+
+       if (*print_header) {
+               *print_header = false;
+
+               http_request_writef(req,
+                       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+                       "<ListBucketResult "
+                       "xmlns=\"http://s3.amazonaws.com/doc/2006-03-01\";>"
+                       "<Prefix></Prefix>"
+                       "<Marker></Marker>"
+                       "<Delimiter></Delimiter>"
+                       "<IsTruncated>false</IsTruncated>"
+                       "<MaxKeys>%d</MaxKeys>"
+                       "<Name>%s</Name>", MAX_BUCKET_LISTING,
+                       xml_escape(bucket));
+       }
+
+       /* FIXME: set the correct metadata info */
+       http_request_writef(req, "<Contents>"
+               "<Key>%s</Key>"
+               "<LastModified>2006-01-01T12:00:00.000Z</LastModified>"
+               "<ETag>&quot;828ef3fdfa96f00ad9f27c383fc9ac7f&quot;</ETag>"
+               "<Size>4</Size>"
+               "<StorageClass>STANDARD</StorageClass>"
+               "<Owner>"
+               "<ID>bcaf1ffd86a5fb16fd081034f</ID>"
+               "<DisplayName>webfile</DisplayName>"
+               "</Owner></Contents>", xml_escape(object));
+}
+
+static void s3_get_bucket(struct http_request *req, const char *bucket)
+{
+       bool print_header = true;
+
+       kvs_list_objects(req, bucket, s3_get_bucket_cb, &print_header);
+
+       switch (req->status) {
+       case OK:
+               http_request_writes(req, "</ListBucketResult>\r\n");
+               break;
+       case NOT_FOUND:
+               s3_write_err_response(req, "NoSuchBucket",
+                       "The specified bucket does not exist");
+               break;
+       default:
+               break;
+       }
+}
+
+static void s3_put_bucket(struct http_request *req, const char *bucket)
+{
+       kvs_create_bucket(req, bucket);
+
+       if (req->status == ACCEPTED)
+               s3_write_err_response(req, "BucketAlreadyExists",
+                       "The requested bucket name is not available");
+}
+
+static void s3_post_bucket(struct http_request *req, const char *bucket)
+{
+       http_response_header(req, NOT_IMPLEMENTED);
+}
+
+static void s3_delete_bucket(struct http_request *req, const char *bucket)
+{
+       kvs_delete_bucket(req, bucket);
+
+       switch (req->status) {
+       case NOT_FOUND:
+               s3_write_err_response(req, "NoSuchBucket",
+                       "The specified bucket does not exist");
+               break;
+       case CONFLICT:
+               s3_write_err_response(req, "BucketNotEmpty",
+                       "The bucket you tried to delete is not empty");
+               break;
+       default:
+               break;
+       }
+}
+
+/* Operations on Objects */
+
+static void s3_head_object(struct http_request *req, const char *bucket,
+                          const char *object)
+{
+       http_response_header(req, NOT_IMPLEMENTED);
+}
+
+static void s3_get_object(struct http_request *req, const char *bucket,
+                         const char *object)
+{
+       kvs_read_object(req, bucket, object);
+
+       if (req->status == NOT_FOUND)
+               s3_write_err_response(req, "NoSuchKey",
+                       "The resource you requested does not exist");
+}
+
+static void s3_put_object(struct http_request *req, const char *bucket,
+                         const char *object)
+{
+       kvs_create_object(req, bucket, object);
+
+       if (req->status == NOT_FOUND)
+               s3_write_err_response(req, "NoSuchBucket",
+                       "The specified bucket does not exist");
+}
+
+static void s3_post_object(struct http_request *req, const char *bucket,
+                          const char *object)
+{
+       http_response_header(req, NOT_IMPLEMENTED);
+}
+
+static void s3_delete_object(struct http_request *req, const char *bucket,
+                            const char *object)
+{
+       kvs_delete_object(req, bucket, object);
+
+       if (req->status == NOT_FOUND)
+               s3_write_err_response(req, "NoSuchKey",
+                       "The resource you requested does not exist");
+}
+
+/* S3 driver interfaces */
+
+static int s3_init(const char *option)
+{
+       return 0;
+}
+
+static void s3_handle_request(struct http_request *req,
+                             void (*s_handler)(struct http_request *req),
+                             void (*b_handler)(struct http_request *req,
+                                               const char *bucket),
+                             void (*o_handler)(struct http_request *req,
+                                               const char *bucket,
+                                               const char *object))
+{
+       char *args[2] = {};
+       char *bucket, *object;
+
+       split_path(req->uri, ARRAY_SIZE(args), args);
+
+       bucket = args[0];
+       object = args[1];
+
+       sd_info("%s", str_http_req(req));
+
+       if (bucket == NULL) {
+               if (s_handler) {
+                       sd_info("service operation");
+                       s_handler(req);
+               }
+       } else if (object == NULL) {
+               sd_info("bucket operation, %s", bucket);
+               b_handler(req, bucket);
+       } else {
+               sd_info("object operation, %s, %s", bucket, object);
+               o_handler(req, bucket, object);
+       }
+
+       sd_info("%s", str_http_req(req));
+
+       free(bucket);
+       free(object);
+}
+
+static void s3_head(struct http_request *req)
+{
+       s3_handle_request(req, NULL, s3_head_bucket, s3_head_object);
+}
+
+static void s3_get(struct http_request *req)
+{
+       s3_handle_request(req, s3_get_service, s3_get_bucket, s3_get_object);
+}
+
+static void s3_put(struct http_request *req)
+{
+       s3_handle_request(req, NULL, s3_put_bucket, s3_put_object);
+}
+
+static void s3_post(struct http_request *req)
+{
+       s3_handle_request(req, NULL, s3_post_bucket, s3_post_object);
+}
+
+static void s3_delete(struct http_request *req)
+{
+       s3_handle_request(req, NULL, s3_delete_bucket, s3_delete_object);
+}
+
+static struct http_driver hdrv_s3 = {
+       .name   = "s3",
+
+       .init   = s3_init,
+       .head   = s3_head,
+       .get    = s3_get,
+       .put    = s3_put,
+       .post   = s3_post,
+       .delete = s3_delete,
+};
+
+hdrv_register(hdrv_s3);
-- 
1.8.1.2

-- 
sheepdog mailing list
sheepdog@lists.wpkg.org
http://lists.wpkg.org/mailman/listinfo/sheepdog

Reply via email to