[sheepdog] [PATCH 8/9] sheep/http: add s3 driver

MORITA Kazutaka morita.kazutaka at gmail.com
Thu Oct 31 08:49:06 CET 2013


From: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>

Signed-off-by: MORITA Kazutaka <morita.kazutaka at 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.kazutaka at 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>"828ef3fdfa96f00ad9f27c383fc9ac7f"</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




More information about the sheepdog mailing list