X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-hreq.c;h=16114675a08001310630b132e0086bdf0b48261d;hb=1205c90cccd3144bab24b4b5fd8dcbf0d0e6b570;hp=e231b659be87569e035962ae5e155ff9ba376435;hpb=32b5e2069bca01ae176ed15e38b5616435bf396f;p=src%2Fapp-framework-binder.git diff --git a/src/afb-hreq.c b/src/afb-hreq.c index e231b659..16114675 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -23,10 +23,50 @@ #include "../include/local-def.h" #include "afb-method.h" +#include "afb-req-itf.h" #include "afb-hreq.h" +static char empty_string[] = ""; -static char empty_string[1] = ""; +struct hreq_data { + struct hreq_data *next; + char *key; + int file; + size_t length; + char *value; +}; + +static const struct afb_req_itf afb_hreq_itf = { + .argument = (void*)afb_hreq_get_argument, + .is_argument_file = (void*)afb_hreq_is_argument_a_file, + .iterate_arguments = (void*)afb_hreq_iterate_arguments +}; + +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) @@ -66,33 +106,33 @@ static int validsubpath(const char *subpath) } /* - * Removes the 'prefix' of 'length' frome the tail of 'request' + * Removes the 'prefix' of 'length' frome the tail of 'hreq' * if and only if the prefix exists and is terminated by a leading * slash */ -int afb_hreq_unprefix(struct afb_hreq *request, const char *prefix, size_t length) +int afb_hreq_unprefix(struct afb_hreq *hreq, const char *prefix, size_t length) { /* check the prefix ? */ - if (length > request->lentail || (request->tail[length] && request->tail[length] != '/') - || memcmp(prefix, request->tail, length)) + if (length > hreq->lentail || (hreq->tail[length] && hreq->tail[length] != '/') + || strncasecmp(prefix, hreq->tail, length)) return 0; /* removes successives / */ - while (length < request->lentail && request->tail[length + 1] == '/') + while (length < hreq->lentail && hreq->tail[length + 1] == '/') length++; /* update the tail */ - request->lentail -= length; - request->tail += length; + hreq->lentail -= length; + hreq->tail += length; return 1; } -int afb_hreq_valid_tail(struct afb_hreq *request) +int afb_hreq_valid_tail(struct afb_hreq *hreq) { - return validsubpath(request->tail); + return validsubpath(hreq->tail); } -void afb_hreq_reply_error(struct afb_hreq *request, unsigned int status) +void afb_hreq_reply_error(struct afb_hreq *hreq, unsigned int status) { char *buffer; int length; @@ -105,12 +145,12 @@ void afb_hreq_reply_error(struct afb_hreq *request, unsigned int status) buffer = "error"; response = MHD_create_response_from_buffer(strlen(buffer), buffer, MHD_RESPMEM_PERSISTENT); } - if (!MHD_queue_response(request->connection, status, response)) + if (!MHD_queue_response(hreq->connection, status, response)) fprintf(stderr, "Failed to reply error code %u", status); MHD_destroy_response(response); } -int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, const char *filename) +int afb_hreq_reply_file_if_exist(struct afb_hreq *hreq, int dirfd, const char *filename) { int rc; int fd; @@ -125,20 +165,29 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, const char if (fd < 0) { if (errno == ENOENT) return 0; - afb_hreq_reply_error(request, MHD_HTTP_FORBIDDEN); + afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN); return 1; } /* Retrieves file's status */ if (fstat(fd, &st) != 0) { close(fd); - afb_hreq_reply_error(request, MHD_HTTP_INTERNAL_SERVER_ERROR); + afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR); return 1; } - /* Don't serve directory */ + /* serve directory */ if (S_ISDIR(st.st_mode)) { - rc = afb_hreq_reply_file_if_exist(request, fd, "index.html"); + if (hreq->url[hreq->lenurl - 1] != '/') { + /* the redirect is needed for reliability of relative path */ + char *tourl = alloca(hreq->lenurl + 2); + memcpy(tourl, hreq->url, hreq->lenurl); + tourl[hreq->lenurl] = '/'; + tourl[hreq->lenurl + 1] = 0; + rc = afb_hreq_redirect_to(hreq, tourl); + } else { + rc = afb_hreq_reply_file_if_exist(hreq, fd, "index.html"); + } close(fd); return rc; } @@ -146,14 +195,14 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, const char /* Don't serve special files */ if (!S_ISREG(st.st_mode)) { close(fd); - afb_hreq_reply_error(request, MHD_HTTP_FORBIDDEN); + afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN); return 1; } /* Check the method */ - if ((request->method & (afb_method_get | afb_method_head)) == 0) { + if ((hreq->method & (afb_method_get | afb_method_head)) == 0) { close(fd); - afb_hreq_reply_error(request, MHD_HTTP_METHOD_NOT_ALLOWED); + afb_hreq_reply_error(hreq, MHD_HTTP_METHOD_NOT_ALLOWED); return 1; } @@ -161,7 +210,7 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, const char sprintf(etag, "%08X%08X", ((int)(st.st_mtim.tv_sec) ^ (int)(st.st_mtim.tv_nsec)), (int)(st.st_size)); /* checks the etag */ - inm = MHD_lookup_connection_value(request->connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_NONE_MATCH); + inm = MHD_lookup_connection_value(hreq->connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_NONE_MATCH); if (inm && 0 == strcmp(inm, etag)) { /* etag ok, return NOT MODIFIED */ close(fd); @@ -173,7 +222,7 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, const char /* check the size */ if (st.st_size != (off_t) (size_t) st.st_size) { close(fd); - afb_hreq_reply_error(request, MHD_HTTP_INTERNAL_SERVER_ERROR); + afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR); return 1; } @@ -183,8 +232,8 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, const char #if defined(USE_MAGIC_MIME_TYPE) /* set the type */ - if (request->session->magic) { - const char *mimetype = magic_descriptor(request->session->magic, fd); + if (hreq->session->magic) { + const char *mimetype = magic_descriptor(hreq->session->magic, fd); if (mimetype != NULL) MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mimetype); } @@ -192,31 +241,152 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, const char } /* fills the value and send */ - MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, request->session->cacheTimeout); + MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, hreq->session->cacheTimeout); MHD_add_response_header(response, MHD_HTTP_HEADER_ETAG, etag); - MHD_queue_response(request->connection, status, response); + MHD_queue_response(hreq->connection, status, response); MHD_destroy_response(response); return 1; } -int afb_hreq_reply_file(struct afb_hreq *request, int dirfd, const char *filename) +int afb_hreq_reply_file(struct afb_hreq *hreq, int dirfd, const char *filename) { - int rc = afb_hreq_reply_file_if_exist(request, dirfd, filename); + int rc = afb_hreq_reply_file_if_exist(hreq, dirfd, filename); if (rc == 0) - afb_hreq_reply_error(request, MHD_HTTP_NOT_FOUND); + afb_hreq_reply_error(hreq, MHD_HTTP_NOT_FOUND); return 1; } -int afb_hreq_redirect_to(struct afb_hreq *request, const char *url) +int afb_hreq_redirect_to(struct afb_hreq *hreq, const char *url) { struct MHD_Response *response; response = MHD_create_response_from_buffer(0, empty_string, MHD_RESPMEM_PERSISTENT); MHD_add_response_header(response, MHD_HTTP_HEADER_LOCATION, url); - MHD_queue_response(request->connection, MHD_HTTP_MOVED_PERMANENTLY, response); + MHD_queue_response(hreq->connection, MHD_HTTP_MOVED_PERMANENTLY, response); MHD_destroy_response(response); if (verbose) - fprintf(stderr, "redirect from [%s] to [%s]\n", request->url, url); + fprintf(stderr, "redirect from [%s] to [%s]\n", hreq->url, url); + return 1; +} + +const char *afb_hreq_get_cookie(struct afb_hreq *hreq, const char *name) +{ + return MHD_lookup_connection_value(hreq->connection, MHD_COOKIE_KIND, name); +} + +const char *afb_hreq_get_argument(struct afb_hreq *hreq, const char *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) +{ + return MHD_lookup_connection_value(hreq->connection, MHD_HEADER_KIND, name); +} + +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 }; +} + +struct iterator_data +{ + struct afb_hreq *hreq; + int (*iterator)(void *closure, const char *key, const char *value, int isfile); + void *closure; +}; + +static int itargs(struct iterator_data *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, key, value, 0); +} + +void afb_hreq_iterate_arguments(struct afb_hreq *hreq, int (*iterator)(void *closure, const char *key, const char *value, int isfile), void *closure) +{ + struct iterator_data id = { .hreq = hreq, .iterator = iterator, .closure = closure }; + struct hreq_data *data = hreq->data; + while (data) { + if (!iterator(closure, data->key, data->value, !!data->file)) + return; + data = data->next; + } + MHD_get_connection_values (hreq->connection, MHD_GET_ARGUMENT_KIND, (void*)itargs, &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; + } +} +