[sheepdog] [PATCH 2/2] http: add http transport
MORITA Kazutaka
morita.kazutaka at gmail.com
Wed Jul 3 02:46:01 CEST 2013
At Tue, 2 Jul 2013 00:35:28 +0800,
Liu Yuan wrote:
>
> This implement basic http transport via fastcgi. All the http operation are
> left empty and just return 'unplemented' notice back.
>
> Later if we write specific http handling as for swift or S3 service, we need
> just implement GET/PUT/POST/HEAD/DELETE handlers respectively.
>
> Signed-off-by: Liu Yuan <namei.unix at gmail.com>
> ---
> configure.ac | 13 +++
> sheep/Makefile.am | 3 +
> sheep/http.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> sheep/sheep.c | 10 +-
> sheep/sheep_priv.h | 16 +++
> 5 files changed, 355 insertions(+), 1 deletion(-)
> create mode 100644 sheep/http.c
>
> diff --git a/configure.ac b/configure.ac
> index 9e611eb..6b8d27d 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -218,6 +218,11 @@ AC_ARG_ENABLE([sheepfs],
> [ enable_sheepfs=$HAVE_FUSE ],)
> AM_CONDITIONAL(BUILD_SHEEPFS, test x$enable_sheepfs = xyes)
>
> +AC_ARG_ENABLE([http],
> + [ --enable-http : enable http request service (default no) ],,
> + [ enable_http="no" ],)
> +AM_CONDITIONAL(BUILD_HTTP, test x$enable_http = xyes)
> +
> CP=cp
> OS_LDL="-ldl"
> case "$host_os" in
> @@ -297,6 +302,14 @@ if test "x${enable_sheepfs}" = xyes; then
> PACKAGE_FEATURES="$PACKAGE_FEATURES sheepfs"
> fi
>
> +if test "x${enable_http}" = xyes; then
> + AC_CHECK_HEADERS([fcgiapp.h],,
> + AC_MSG_ERROR(fcgiapp.h header not found))
> + AC_CHECK_LIB([fcgi], [FCGX_Accept],,
> + AC_MSG_ERROR(libfcgi not found))
> + AC_DEFINE_UNQUOTED(HAVE_HTTP, 1, [have http])
> + PACKAGE_FEATURES="$PACKAGE_FEATURES http"
> +fi
>
> # extra warnings
> EXTRA_WARNINGS=""
> diff --git a/sheep/Makefile.am b/sheep/Makefile.am
> index 4916409..ebb8587 100644
> --- a/sheep/Makefile.am
> +++ b/sheep/Makefile.am
> @@ -30,6 +30,9 @@ sheep_SOURCES = sheep.c group.c request.c gateway.c store.c vdi.c \
> plain_store.c config.c migrate.c md.c \
> cluster/shepherd.c
>
> +if BUILD_HTTP
> +sheep_SOURCES += http.c
> +endif
> if BUILD_COROSYNC
> sheep_SOURCES += cluster/corosync.c
> endif
> diff --git a/sheep/http.c b/sheep/http.c
> new file mode 100644
> index 0000000..0560792
> --- /dev/null
> +++ b/sheep/http.c
> @@ -0,0 +1,314 @@
> +/*
> + * Copyright (C) 2013 Taobao Inc.
> + *
> + * Liu Yuan <namei.unix 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/>.
> + */
> +
> +/* This files implement RESTful interface to sheepdog storage via fastcig */
> +
> +#include <string.h>
> +#include <fcgiapp.h>
> +#include <errno.h>
> +#include <pthread.h>
> +
> +#include "util.h"
> +#include "sheep_priv.h"
> +
> +struct http_request {
> + FCGX_Request fcgx;
> + int opcode;
> + char *data;
> + size_t data_length;
> +};
> +
> +enum http_opcode {
> + HTTP_GET = 1,
> + HTTP_PUT,
> + HTTP_POST,
> + HTTP_DELETE,
> + HTTP_HEAD,
> +};
> +
> +enum http_status {
> + OK = 1, /* 200 */
> + CREATED, /* 201 */
> + PARTIAL_CONTENT, /* 206 */
> + BAD_REQUEST, /* 400 */
> + NOT_FOUND, /* 404 */
> + REQUEST_RANGE_NOT_SATISFIABLE, /* 416 */
> + INTERNAL_SERVER_ERROR, /* 500 */
> +};
> +
> +static inline const char *strstatus(int status)
> +{
> + static const char *const descs[] = {
> + [OK] = "200 OK",
> + [CREATED] = "201 CREATED",
> + [PARTIAL_CONTENT] = "206 Partial Content",
> + [BAD_REQUEST] = "400 Bad Request",
> + [NOT_FOUND] = "404 Not Found",
> + [REQUEST_RANGE_NOT_SATISFIABLE] =
> + "416 Requested Range Not Satisfiable",
> + [INTERNAL_SERVER_ERROR] = "500 Internal Server Error",
> + };
> +
> + if (descs[status] == NULL) {
> + static __thread char msg[32];
> + snprintf(msg, sizeof(msg), "Invalid Status %d", status);
> + return msg;
> + }
> +
> + return descs[status];
> +}
> +
> +struct http_work {
> + struct work work;
> + struct http_request *request;
> +};
> +
> +static inline int http_request_error(struct http_request *req)
> +{
> + int ret = FCGX_GetError(req->fcgx.out);
> +
> + if (ret == 0) {
> + return OK;
> + } else if (ret < 0) {
> + sd_eprintf("failed, FCGI error %d", ret);
> + return INTERNAL_SERVER_ERROR;
> + } else {
> + sd_eprintf("failed, %s", strerror(ret));
> + return INTERNAL_SERVER_ERROR;
> + }
> +}
> +
> +static inline int http_request_write(struct http_request *req,
> + const char *buf, int len)
> +{
> + int ret = FCGX_PutStr(buf, len, req->fcgx.out);
> + if (ret < 0)
> + return http_request_error(req);
> + return OK;
> +}
> +
> +static inline int http_request_read(struct http_request *req,
> + char *buf, int len)
> +{
> + int ret = FCGX_GetStr(buf, len, req->fcgx.in);
> + if (ret < 0)
> + return http_request_error(req);
> + return OK;
> +}
> +
> +static inline int http_request_writes(struct http_request *req, const char *str)
> +
> +{
> + int ret = FCGX_PutS(str, req->fcgx.out);
> + if (ret < 0)
> + return http_request_error(req);
> + return OK;
> +}
> +
> +__printf(2, 3)
> +static int http_request_writef(struct http_request *req, const char *fmt, ...)
> +
> +{
> + va_list ap;
> + int ret;
> +
> + va_start(ap, fmt);
> + ret = FCGX_VFPrintF(req->fcgx.out, fmt, ap);
> + va_end(ap);
> + if (ret < 0)
> + return http_request_error(req);
> + return OK;
> +}
> +
> +static int request_init_operation(struct http_request *req)
> +{
> + char **env = req->fcgx.envp;
> + char *p;
> +
> + p = FCGX_GetParam("REQUEST_METHOD", env);
> + if (!strcmp(p, "PUT")) {
> + req->opcode = HTTP_PUT;
> + p = FCGX_GetParam("CONTENT_LENGTH", env);
> + req->data_length = strtoll(p, NULL, 10);
> + req->data = xmalloc(req->data_length);
> + http_request_read(req, req->data, req->data_length);
> + } else if (!strcmp(p, "GET")) {
> + req->opcode = HTTP_GET;
> + } else if (!strcmp(p, "POST")) {
> + req->opcode = HTTP_POST;
> + } else if (!strcmp(p, "DELETE")) {
> + req->opcode = HTTP_DELETE;
> + } else if (!strcmp(p, "HEAD")) {
> + req->opcode = HTTP_HEAD;
> + } else {
> + return BAD_REQUEST;
> + }
> + return OK;
> +}
> +
> +static int http_init_request(struct http_request *req)
> +{
> + char *p;
> + int ret;
> +
> + for (int i = 0; (p = req->fcgx.envp[i]); ++i)
> + sd_dprintf("%s", p);
> +
> + ret = request_init_operation(req);
> + if (ret != OK)
> + return ret;
> + return OK;
> +}
> +
> +static void http_response_header(struct http_request *req, int status)
> +{
> + http_request_writef(req, "Status: %s\n", strstatus(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, OK);
> + http_request_writes(req, "not implemented\n");
> +}
> +
> +static void http_handle_put(struct http_request *req)
> +{
> + http_response_header(req, OK);
> + http_request_writes(req, "not implemented\n");
> +}
> +
> +static void http_handle_post(struct http_request *req)
> +{
> + http_response_header(req, OK);
> + http_request_writes(req, "not implemented\n");
> +}
> +
> +static void http_handle_delete(struct http_request *req)
> +{
> + http_response_header(req, OK);
> + http_request_writes(req, "not implemented\n");
> +}
> +
> +static void http_handle_head(struct http_request *req)
> +{
> + http_response_header(req, OK);
> + 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);
> + free(req->data);
> + free(req);
> +}
> +
> +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;
> +
> + if (op < http_max_request_handlers && http_request_handlers[op])
> + http_request_handlers[op](req);
> + else
> + panic("unhandled opcode %d", op);
> + http_end_request(req);
> +}
> +
> +static void http_queue_request(struct http_request *req)
> +{
> + struct http_work *hw = xzalloc(sizeof(*hw));
Seems that there is no one who frees this memory.
Thanks,
Kazutaka
More information about the sheepdog
mailing list