[sheepdog] [PATCH 6/9] sheep: add framework for http drivers
MORITA Kazutaka
morita.kazutaka at gmail.com
Thu Oct 31 08:49:04 CET 2013
From: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
This introduces a framework of http driver for object storage feature.
We can specify several http drivers to control http requests. The
drivers are stackable and work like a WSGI pipeline of Python.
Usage
$ sheep -r [host=<hostname>,][port=<port>,]<http driver>[,<http driver>][,...]
Example:
- Enable object storage service with Swift API
$ sheep -r swift /store
- Enable object storage service with S3 API and S3 authorization
$ sheep -r s3_auth,s3 /store
- Enable Swift API and use localhost:7001 to communicate with http
server.
$ sheep -r host=localhost,port=7001,s3 /store
Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
sheep/http.c | 142 ++++++++++++++++++++++++++++++++++++-----------------
sheep/http.h | 51 +++++++++++++++++++
sheep/sheep.c | 16 +++---
sheep/sheep_priv.h | 4 +-
4 files changed, 160 insertions(+), 53 deletions(-)
diff --git a/sheep/http.c b/sheep/http.c
index 2585daa..74c9432 100644
--- a/sheep/http.c
+++ b/sheep/http.c
@@ -15,6 +15,13 @@
#include "http.h"
#include "sheep_priv.h"
+#include "option.h"
+
+static const char *http_host = "localhost";
+static const char *http_port = "8000";
+
+LIST_HEAD(http_drivers);
+static LIST_HEAD(http_enabled_drivers);
static inline const char *stropcode(enum http_opcode opcode)
{
@@ -182,46 +189,6 @@ void http_response_header(struct http_request *req, enum http_status status)
http_request_writes(req, "Content-type: text/plain;\r\n\r\n");
}
-static void http_handle_get(struct http_request *req)
-{
- http_response_header(req, NOT_IMPLEMENTED);
- http_request_writes(req, "not implemented\n");
-}
-
-static void http_handle_put(struct http_request *req)
-{
- http_response_header(req, NOT_IMPLEMENTED);
- http_request_writes(req, "not implemented\n");
-}
-
-static void http_handle_post(struct http_request *req)
-{
- http_response_header(req, NOT_IMPLEMENTED);
- http_request_writes(req, "not implemented\n");
-}
-
-static void http_handle_delete(struct http_request *req)
-{
- http_response_header(req, NOT_IMPLEMENTED);
- http_request_writes(req, "not implemented\n");
-}
-
-static void http_handle_head(struct http_request *req)
-{
- http_response_header(req, NOT_IMPLEMENTED);
- http_request_writes(req, "not implemented\n");
-}
-
-static void (*const http_request_handlers[])(struct http_request *req) = {
- [HTTP_GET] = http_handle_get,
- [HTTP_PUT] = http_handle_put,
- [HTTP_POST] = http_handle_post,
- [HTTP_DELETE] = http_handle_delete,
- [HTTP_HEAD] = http_handle_head,
-};
-
-static const int http_max_request_handlers = ARRAY_SIZE(http_request_handlers);
-
static void http_end_request(struct http_request *req)
{
FCGX_Finish_r(&req->fcgx);
@@ -233,11 +200,40 @@ static void http_run_request(struct work *work)
struct http_work *hw = container_of(work, struct http_work, work);
struct http_request *req = hw->request;
int op = req->opcode;
+ struct http_driver *hdrv;
+
+ list_for_each_entry(hdrv, &http_enabled_drivers, list) {
+ void (*method)(struct http_request *req);
+
+ switch (op) {
+ case HTTP_HEAD:
+ method = hdrv->head;
+ break;
+ case HTTP_GET:
+ method = hdrv->get;
+ break;
+ case HTTP_PUT:
+ method = hdrv->put;
+ break;
+ case HTTP_POST:
+ method = hdrv->post;
+ break;
+ case HTTP_DELETE:
+ method = hdrv->delete;
+ break;
+ default:
+ break;
+ }
- if (op < http_max_request_handlers && http_request_handlers[op])
- http_request_handlers[op](req);
- else
- panic("unhandled opcode %d", op);
+ if (method != NULL) {
+ method(req);
+ if (req->status != UNKNOWN)
+ goto out;
+ }
+ }
+
+ http_response_header(req, METHOD_NOT_ALLOWED);
+out:
http_end_request(req);
}
@@ -295,10 +291,65 @@ out:
pthread_exit(NULL);
}
-int http_init(const char *address)
+static int http_opt_host_parser(const char *s)
+{
+ http_host = s;
+ return 0;
+}
+
+static int http_opt_port_parser(const char *s)
+{
+ http_port = s;
+ return 0;
+}
+
+static int http_opt_default_parser(const char *s)
+{
+ struct http_driver *hdrv;
+
+ hdrv = find_hdrv(&http_enabled_drivers, s);
+ if (hdrv != NULL) {
+ sd_err("%s driver is already enabled", hdrv->name);
+ return -1;
+ }
+
+ hdrv = find_hdrv(&http_drivers, s);
+ if (hdrv == NULL) {
+ sd_err("'%s' is not a valid driver name", s);
+ return -1;
+ }
+
+ if (hdrv->init(get_hdrv_option(hdrv, s)) < 0) {
+ sd_err("failed to initialize %s driver", hdrv->name);
+ return -1;
+ }
+
+ list_move_tail(&hdrv->list, &http_enabled_drivers);
+
+ return 0;
+}
+
+static struct option_parser http_opt_parsers[] = {
+ { "host=", http_opt_host_parser },
+ { "port=", http_opt_port_parser },
+ { "", http_opt_default_parser },
+ { NULL, NULL },
+};
+
+int http_init(const char *options)
{
pthread_t t;
int err;
+ char *s, address[HOST_NAME_MAX + 8];
+
+ s = strdup(options);
+ if (s == NULL) {
+ sd_emerg("OOM");
+ return -1;
+ }
+
+ if (option_parse(s, ",", http_opt_parsers) < 0)
+ return -1;
sys->http_wqueue = create_work_queue("http", WQ_DYNAMIC);
if (!sys->http_wqueue)
@@ -307,6 +358,7 @@ int http_init(const char *address)
FCGX_Init();
#define LISTEN_QUEUE_DEPTH 1024 /* No rationale */
+ snprintf(address, sizeof(address), "%s:%s", http_host, http_port);
http_sockfd = FCGX_OpenSocket(address, LISTEN_QUEUE_DEPTH);
if (http_sockfd < 0) {
sd_err("open socket failed, address %s", address);
diff --git a/sheep/http.h b/sheep/http.h
index 0f30ea4..495a66c 100644
--- a/sheep/http.h
+++ b/sheep/http.h
@@ -49,6 +49,57 @@ struct http_request {
size_t data_length;
};
+struct http_driver {
+ const char *name;
+
+ /* Returns zero on success, -1 on error. */
+ int (*init)(const char *option);
+
+ void (*head)(struct http_request *req);
+ void (*get)(struct http_request *req);
+ void (*put)(struct http_request *req);
+ void (*post)(struct http_request *req);
+ void (*delete)(struct http_request *req);
+
+ struct list_node list;
+};
+
+extern struct list_head http_drivers;
+
+#define hdrv_register(driver) \
+static void __attribute__((constructor)) register_ ## driver(void) \
+{ \
+ list_add(&driver.list, &http_drivers); \
+}
+
+static inline struct http_driver *find_hdrv(struct list_head *drivers,
+ const char *name)
+{
+ struct http_driver *hdrv;
+ int len;
+
+ list_for_each_entry(hdrv, drivers, list) {
+ len = strlen(hdrv->name);
+
+ if (strncmp(hdrv->name, name, len) == 0 &&
+ (name[len] == ':' || name[len] == '\0'))
+ return hdrv;
+ }
+
+ return NULL;
+}
+
+static inline const char *get_hdrv_option(const struct http_driver *hdrv,
+ const char *arg)
+{
+ int len = strlen(hdrv->name);
+
+ if (arg[len] == ':')
+ return strdup(arg + len + 1);
+ else
+ return NULL;
+}
+
const char *str_http_req(const struct http_request *req);
void http_response_header(struct http_request *req, enum http_status status);
int http_request_read(struct http_request *req, void *buf, int len);
diff --git a/sheep/sheep.c b/sheep/sheep.c
index 27713d2..306432d 100644
--- a/sheep/sheep.c
+++ b/sheep/sheep.c
@@ -58,9 +58,13 @@ static const char loglevel_help[] =
"This only allows logs with level smaller than SDOG_WARNING to be logged\n";
static const char http_help[] =
-"Example:\n\t$ sheep -r localhost:7001 ...\n"
-"This tries to enable sheep as http service backend and use localhost:7001 to\n"
-"communicate with http server. Not fully implemented yet.\n";
+"Available arguments:\n"
+"\thost=: specify a host to communicate with http server (default: localhost)\n"
+"\tport=: specify a port to communicate with http server (default: 8000)\n"
+"\tswift: enable swift API\n"
+"Example:\n\t$ sheep -r host=localhost,port=7001,swift ...\n"
+"This tries to enable Swift API and use localhost:7001 to\n"
+"communicate with http server.\n";
static const char myaddr_help[] =
"Example:\n\t$ sheep -y 192.168.1.1:7000 ...\n"
@@ -548,7 +552,7 @@ int main(int argc, char **argv)
int64_t zone = -1;
struct cluster_driver *cdrv;
struct option *long_options;
- const char *log_format = "server", *http_address = NULL;
+ const char *log_format = "server", *http_options = NULL;
static struct logger_user_info sheep_info;
install_crash_handler(crash_handler);
@@ -573,7 +577,7 @@ int main(int argc, char **argv)
pid_file = optarg;
break;
case 'r':
- http_address = optarg;
+ http_options = optarg;
break;
case 'f':
is_daemon = false;
@@ -818,7 +822,7 @@ int main(int argc, char **argv)
if (ret)
exit(1);
- if (http_address && http_init(http_address) != 0)
+ if (http_options && http_init(http_options) != 0)
exit(1);
if (pid_file && (create_pidfile(pid_file) != 0)) {
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index 20ec2be..83b461c 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -460,9 +460,9 @@ uint64_t md_get_size(uint64_t *used);
/* http.c */
#ifdef HAVE_HTTP
-int http_init(const char *address);
+int http_init(const char *options);
#else
-static inline int http_init(const char *address)
+static inline int http_init(const char *options)
{
sd_notice("http service is not complied");
return 0;
--
1.8.1.2
More information about the sheepdog
mailing list