X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-hreq.c;h=e146bcb4ba2c24c3448f2abba0677fdfc75943aa;hb=dde70b62b09f49ad672c104a3f81714bf11047be;hp=7bee69b3e83abca16c27861a3e861c1019122372;hpb=4d603302535155ffe71208e86de14c7abc4e775d;p=src%2Fapp-framework-binder.git diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 7bee69b3..e146bcb4 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -16,18 +16,73 @@ */ #define _GNU_SOURCE -#include + +#include +#include +#include #include -#include +#include +#include #include -#include "../include/local-def.h" +#include + +#include "local-def.h" #include "afb-method.h" #include "afb-req-itf.h" #include "afb-hreq.h" -static char empty_string[1] = ""; +#define SIZE_RESPONSE_BUFFER 8000 + +static char empty_string[] = ""; +struct hreq_data { + struct hreq_data *next; + char *key; + int file; + size_t length; + char *value; +}; + +static struct afb_arg req_get(struct afb_hreq *hreq, const char *name); +static void req_iterate(struct afb_hreq *hreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure); +static void req_fail(struct afb_hreq *hreq, const char *status, const char *info); +static void req_success(struct afb_hreq *hreq, json_object *obj, const char *info); + +static const struct afb_req_itf afb_hreq_itf = { + .get = (void*)req_get, + .iterate = (void*)req_iterate, + .fail = (void*)req_fail, + .success = (void*)req_success +}; + void (*fail)(void *data, const char *status, const char *info); + void (*success)(void *data, json_object *obj, const char *info); + +static struct hreq_data *get_data(struct afb_hreq *hreq, const char *key, int create) +{ + struct hreq_data *data = hreq->data; + if (key == NULL) + key = empty_string; + while (data != NULL) { + if (!strcasecmp(data->key, key)) + return data; + data = data->next; + } + if (create) { + data = calloc(1, sizeof *data); + if (data != NULL) { + data->key = strdup(key); + if (data->key == NULL) { + free(data); + data = NULL; + } else { + data->next = hreq->data; + hreq->data = data; + } + } + } + return data; +} /* a valid subpath is a relative path not looking deeper than root using .. */ static int validsubpath(const char *subpath) @@ -75,7 +130,7 @@ int afb_hreq_unprefix(struct afb_hreq *hreq, const char *prefix, size_t length) { /* check the prefix ? */ if (length > hreq->lentail || (hreq->tail[length] && hreq->tail[length] != '/') - || memcmp(prefix, hreq->tail, length)) + || strncasecmp(prefix, hreq->tail, length)) return 0; /* removes successives / */ @@ -122,12 +177,20 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *hreq, int dirfd, const char *f struct MHD_Response *response; /* Opens the file or directory */ - fd = openat(dirfd, filename, O_RDONLY); - if (fd < 0) { - if (errno == ENOENT) - return 0; - afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN); - return 1; + if (filename[0]) { + fd = openat(dirfd, filename, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + return 0; + afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN); + return 1; + } + } else { + fd = dup(dirfd); + if (fd < 0) { + afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR); + return 1; + } } /* Retrieves file's status */ @@ -237,7 +300,8 @@ const char *afb_hreq_get_cookie(struct afb_hreq *hreq, const char *name) const char *afb_hreq_get_argument(struct afb_hreq *hreq, const char *name) { - return MHD_lookup_connection_value(hreq->connection, MHD_GET_ARGUMENT_KIND, name); + struct hreq_data *data = get_data(hreq, name, 0); + return data ? data->value : MHD_lookup_connection_value(hreq->connection, MHD_GET_ARGUMENT_KIND, name); } const char *afb_hreq_get_header(struct afb_hreq *hreq, const char *name) @@ -245,8 +309,171 @@ const char *afb_hreq_get_header(struct afb_hreq *hreq, const char *name) return MHD_lookup_connection_value(hreq->connection, MHD_HEADER_KIND, name); } -struct afb_req_itf afb_hreq_itf = { - .get_cookie = (void*)afb_hreq_get_cookie, - .get_argument = (void*)afb_hreq_get_argument +void afb_hreq_post_end(struct afb_hreq *hreq) +{ + struct hreq_data *data = hreq->data; + while(data) { + if (data->file > 0) { + close(data->file); + data->file = -1; + } + data = data->next; + } +} + +int afb_hreq_post_add(struct afb_hreq *hreq, const char *key, const char *data, size_t size) +{ + void *p; + struct hreq_data *hdat = get_data(hreq, key, 1); + if (hdat->file) { + return 0; + } + p = realloc(hdat->value, hdat->length + size + 1); + if (p == NULL) { + return 0; + } + hdat->value = p; + memcpy(&hdat->value[hdat->length], data, size); + hdat->length += size; + hdat->value[hdat->length] = 0; + return 1; +} + +int afb_hreq_post_add_file(struct afb_hreq *hreq, const char *key, const char *file, const char *data, size_t size) +{ + struct hreq_data *hdat = get_data(hreq, key, 1); + + /* continuation with reopening */ + if (hdat->file < 0) { + hdat->file = open(hdat->value, O_WRONLY|O_APPEND); + if (hdat->file == 0) { + hdat->file = dup(0); + close(0); + } + if (hdat->file <= 0) + return 0; + } + if (hdat->file > 0) { + write(hdat->file, data, size); + return 1; + } + + /* creation */ + /* TODO */ + return 0; + +} + +int afb_hreq_is_argument_a_file(struct afb_hreq *hreq, const char *key) +{ + struct hreq_data *hdat = get_data(hreq, key, 0); + return hdat != NULL && hdat->file != 0; +} + + +struct afb_req afb_hreq_to_req(struct afb_hreq *hreq) +{ + return (struct afb_req){ .itf = &afb_hreq_itf, .data = hreq }; +} + +static struct afb_arg req_get(struct afb_hreq *hreq, const char *name) +{ + struct hreq_data *hdat = get_data(hreq, name, 0); + if (hdat) + return (struct afb_arg){ + .name = hdat->key, + .value = hdat->value, + .size = hdat->length, + .is_file = (hdat->file != 0) + }; + + return (struct afb_arg){ + .name = name, + .value = MHD_lookup_connection_value(hreq->connection, MHD_GET_ARGUMENT_KIND, name), + .size = 0, + .is_file = 0 + }; +} + +struct iterdata +{ + struct afb_hreq *hreq; + int (*iterator)(void *closure, struct afb_arg arg); + void *closure; }; +static int _iterargs_(struct iterdata *id, enum MHD_ValueKind kind, const char *key, const char *value) +{ + if (get_data(id->hreq, key, 0)) + return 1; + return id->iterator(id->closure, (struct afb_arg){ + .name = key, + .value = value, + .size = 0, + .is_file = 0 + }); +} + +static void req_iterate(struct afb_hreq *hreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure) +{ + struct iterdata id = { .hreq = hreq, .iterator = iterator, .closure = closure }; + struct hreq_data *hdat = hreq->data; + while (hdat) { + if (!iterator(closure, (struct afb_arg){ + .name = hdat->key, + .value = hdat->value, + .size = hdat->length, + .is_file = (hdat->file != 0)})) + return; + hdat = hdat->next; + } + MHD_get_connection_values (hreq->connection, MHD_GET_ARGUMENT_KIND, (void*)_iterargs_, &id); +} + +void afb_hreq_drop_data(struct afb_hreq *hreq) +{ + struct hreq_data *data = hreq->data; + while (data) { + hreq->data = data->next; + free(data->key); + free(data->value); + free(data); + data = hreq->data; + } +} +static ssize_t send_json_cb(json_object *obj, uint64_t pos, char *buf, size_t max) +{ + ssize_t len = stpncpy(buf, json_object_to_json_string(obj)+pos, max) - buf; + return len ? : -1; +} + +static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *status, const char *info, json_object *resp) +{ + json_object *root, *request; + struct MHD_Response *response; + + root = json_object_new_object(); + json_object_object_add(root, "jtype", json_object_new_string("afb-reply")); + request = json_object_new_object(); + json_object_object_add(root, "request", request); + json_object_object_add(request, "status", json_object_new_string(status)); + if (info) + json_object_object_add(request, "info", json_object_new_string(info)); + if (resp) + json_object_object_add(root, "response", resp); + + response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, SIZE_RESPONSE_BUFFER, (void*)send_json_cb, root, (void*)json_object_put); + MHD_queue_response(hreq->connection, retcode, response); + MHD_destroy_response(response); +} + +static void req_fail(struct afb_hreq *hreq, const char *status, const char *info) +{ + req_reply(hreq, MHD_HTTP_OK, status, info, NULL); +} + +static void req_success(struct afb_hreq *hreq, json_object *obj, const char *info) +{ + req_reply(hreq, MHD_HTTP_OK, "success", info, obj); +} +