[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