From 18ce121d4243358bc55a0474a529efe2580a0610 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Mon, 9 Mar 2020 18:06:10 +0300 Subject: [magi] --- Makefile | 2 +- examples/Makefile | 2 +- include/magi/cgi.h | 18 +----- include/magi/cookie.h | 13 ++-- include/magi/file.h | 11 ++++ include/magi/param.h | 6 ++ include/magi/request.h | 38 ++++++------ include/magi/response.h | 29 ++++++++- src/cookie.c | 43 +++++++------ src/cookies.h | 2 +- src/file.c | 38 ++++++------ src/param.c | 34 +++++------ src/request.c | 124 +++++++++++++++++++++----------------- src/response.c | 156 +++++++++++++++++++++++++++++++----------------- 14 files changed, 299 insertions(+), 217 deletions(-) diff --git a/Makefile b/Makefile index 93f4a2d..c3117d0 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ CC = gcc LIB = libmagi.a # Compile under the most strict conditions: -CFLAGS = -xc -ansi -pedantic -Wall +CFLAGS = -xc -ansi -pedantic -Wall -Wextra # Debug and optimisation are not compatible: ifeq '$(DEBUG)' 'yes' CFLAGS += -g -O0 diff --git a/examples/Makefile b/examples/Makefile index f2c366b..991f936 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -11,7 +11,7 @@ CC = gcc # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Preparations # Compile under the most strict conditions: -CFLAGS = -xc -ansi -pedantic -Wall +CFLAGS = -xc -ansi -pedantic -Wall -Wextra # Debug and optimisation are not compatible: ifeq '$(DEBUG)' 'yes' CFLAGS += -g -O0 diff --git a/include/magi/cgi.h b/include/magi/cgi.h index 9b29a98..8a13240 100644 --- a/include/magi/cgi.h +++ b/include/magi/cgi.h @@ -5,32 +5,20 @@ * * blah-blah... */ -#include "error.h" #include "request.h" -#include "response.h" /** Analyses non-post part of request from environment. * @return 1 if ok, 0 if error. */ -int magi_request_cgi_head(magi_request *request); +int magi_cgi_head(magi_request *request); /** Complete request with post body from standard input. * @return 1 if ok, 0 if error. */ -int magi_request_cgi_body(magi_request *request); +int magi_cgi_body(magi_request *request); /** Shortcut for analysing both head and body of request. * @return 1 if ok, 0 if error. */ -int magi_request_cgi(magi_request *request); - - -/** Sends response to standard output and destroys it. - * @return 1 if ok, 0 if error. */ -int magi_response_cgi(magi_response *response); - - -/** Sends a standard response of Bad Request error. - * @return 1 if ok, 0 if error. */ -int magi_error_cgi(magi_error error); +int magi_cgi(magi_request *request); #endif diff --git a/include/magi/cookie.h b/include/magi/cookie.h index 8a92a82..8e1c6fc 100644 --- a/include/magi/cookie.h +++ b/include/magi/cookie.h @@ -25,19 +25,20 @@ typedef struct magi_cookies { magi_cookie item; /**< Cookie on top. */ } magi_cookies; + /** Add @p newitem to @p cookies. * @param[in,out] cookies to add into. * @param[in] newitem to add onto top of @p cookies. */ void magi_cookies_add(magi_cookies **cookies, magi_cookie *newitem); -/** Get data of cookie from @p cookies with @p name. +/** Get cookie from @p cookies with @p name. * @note Cookies in @p cookies are in reverse request order, and first cookie * from request is the most accurate in terms of domain and path. - * @param[in] params to search in. - * @param[in] name of needed parameter. - * @return data of the last from top of @p cookies cookie with @p name, - * null only if no such parameter. */ -char *magi_cookies_get(magi_cookies *cookies, const char *name); + * @param[in] cookies to search in. + * @param[in] name of needed cookie. + * @return the last from top of @p cookies cookie with @p name, + * null only if no such cookie. */ +magi_cookie *magi_cookies_get(magi_cookies *cookies, const char *name); /** Free memory used by @p cookies. * @param[in,out] cookies to be destructed. */ diff --git a/include/magi/file.h b/include/magi/file.h index 07baadc..1b1fb35 100644 --- a/include/magi/file.h +++ b/include/magi/file.h @@ -38,4 +38,15 @@ magi_file *magi_files_get(magi_files *files, const char *name); void magi_files_free(magi_files *files); +typedef void (*magi_file_callback_act)(void *userdata, + magi_file *file_to_add_into, + char *addon, + int addon_len); +typedef struct magi_file_callback { + magi_file_callback_act act; + void *userdata; + int addon_max; +} magi_file_callback; + + #endif diff --git a/include/magi/param.h b/include/magi/param.h index 0ad1919..b9dbde1 100644 --- a/include/magi/param.h +++ b/include/magi/param.h @@ -24,6 +24,12 @@ typedef struct magi_params { * @param[in] newitem to add onto top of @p params. */ void magi_params_add(magi_params **params, magi_param *newitem); +/** Set @p newitem in @p params. + * @param[in,out] params to add into. + * @param[in] newitem to replace item in @p params with same name + or to add, if no param with same name is in @p params. */ +void magi_params_set(magi_params **params, magi_param *newitem); + /** Get data of parameter from @p params with @p name. * @param[in] params to search in. * @param[in] name of needed parameter. diff --git a/include/magi/request.h b/include/magi/request.h index 4e04989..03e0c43 100644 --- a/include/magi/request.h +++ b/include/magi/request.h @@ -10,29 +10,26 @@ #include "file.h" #include "param.h" -typedef void (*magi_file_callback_act)(void *, magi_file *, char *, int); -typedef struct magi_file_callback { - magi_file_callback_act act; - void *userdata; - int addon_max; -} magi_file_callback; typedef struct magi_request_limits { int cookies; - int params_http; + int params_meta; int params_head; int params_body; } magi_request_limits; + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** - * Request and response handler. + * Request handler. * - * Can be created via 'magi_request_{gateway interface name}', but will have - * nullified 'post'-related fields ('params' & 'files'). Reason is unlimited - * 'post' body size, with possible dependence of wanted limits from data of + * Can be created via 'magi_{gateway interface name}_head', but will have + * nullified 'POST'-related fields ('params' & 'files'). Reason is unlimited + * 'POST' body size, with possible dependence of wanted limits from data of * headers (e.g. session id from cookies, enabling some users to load more). - * To proceed 'post' use 'magi_request_resume_{gateway interface name}', - * specifying settings if necessary. */ + * To proceed 'post' use 'magi_{gateway interface name}_body', specifying + * settings if necessary. + * + * Or just use shortcut 'magi_{gateway interface_name}' to do both parts. */ typedef struct magi_request { magi_error error; @@ -42,12 +39,12 @@ typedef struct magi_request { magi_params *body; magi_files *files; - magi_method method; - int is_secure; - char *domain; - int port; - char *script; - char *path; + char *method; + int is_secure; + char *address; + int port; + char *script; + char *path; magi_file_callback callback; magi_request_limits limits; @@ -60,8 +57,7 @@ void magi_request_init(magi_request *r); void magi_request_free(magi_request *r); -char *magi_request_meta(magi_request *r, magi_meta code); -char *magi_request_meta_custom(magi_request *r, const char *name); +char *magi_request_meta(magi_request *r, const char *name); char *magi_request_param(magi_request *r, const char *name); char *magi_request_urlparam(magi_request *r, const char *name); diff --git a/include/magi/response.h b/include/magi/response.h index a623da1..4c6b788 100644 --- a/include/magi/response.h +++ b/include/magi/response.h @@ -12,21 +12,46 @@ * all headers should be sent before anything from the body.) */ #include "request.h" +#include -void magi_response_status(magi_request *r, magi_status code); -void magi_response_status_custom(magi_request *r, int code, const char *desc); +typedef void (*magi_response_method_head)(void *ud, magi_param *header); +typedef void (*magi_response_method_body)(void *ud, const char *data, int len); +typedef void (*magi_response_method_file)(void *ud, FILE *file); + +typedef struct magi_response_methods { + magi_response_method_head head; + magi_response_method_body body; + magi_response_method_file file; +} magi_response_methods; + +typedef struct magi_response_implementation { + magi_response_methods *methods; + void *userdata; + magi_params *head[3]; + int head_done; +} magi_response_implementation; + + +void magi_response_status(magi_request *r, int code, const char *description); void magi_response_cookie(magi_request *r, const char *name, const char *data); void magi_response_cookie_complex(magi_request *r, magi_cookie *c); void magi_response_cookie_discard(magi_request *r, const char *name); +void magi_response_header(magi_request *r, const char *name, const char *data); + void magi_response_content_length(magi_request *r, int length); void magi_response_content_type(magi_request *r, const char *type); +void magi_response_head(magi_request *r); + void magi_response(magi_request *r, const char *addon); void magi_response_format(magi_request *r, const char *format, ...); void magi_response_file(magi_request *r, FILE *file); +void magi_response_error(magi_request *r); + + #endif diff --git a/src/cookie.c b/src/cookie.c index d1d82b3..7b40f1a 100644 --- a/src/cookie.c +++ b/src/cookie.c @@ -4,42 +4,39 @@ #include -int magi_cookie_list_add(struct magi_cookie_list ** list, - struct magi_cookie * item) +void magi_cookies_add(magi_cookies **cookies, magi_cookie *newitem) { - struct magi_cookie_list * node = malloc(sizeof(*node)); + magi_cookies *node = malloc(sizeof(*node)); if (node) { - node->next = *list; - node->item = *item; - *list = node; + node->next = *cookies; + node->item = *newitem; + *cookies = node; } - return !!node; } -char * magi_cookie_list_get(struct magi_cookie_list * list, const char * name) +magi_cookie *magi_cookies_get(magi_cookies *cookies, const char *name) { - char * res = 0; - if (!list || !name) { + magi_cookie *res = 0; + if (!cookies || !name) { return 0; } - while (list) { - if (!strcmp(list->item.name, name)) { - res = list->item.data; + for (; cookies; cookies = cookies->next) { + if (!strcmp(cookies->item.name, name)) { + res = &cookies->item; } - list = list->next; } return res; } -void magi_cookie_list_destroy(struct magi_cookie_list * list) +void magi_cookies_free(magi_cookies *cookies) { - if (list) { - magi_cookie_list_destroy(list->next); - free(list->next); - free(list->item.name); - free(list->item.data); - free(list->item.path); - free(list->item.domain); - free(list->item.max_age); + if (cookies) { + magi_cookies_free(cookies->next); + free(cookies->next); + free(cookies->item.name); + free(cookies->item.data); + free(cookies->item.path); + free(cookies->item.domain); + free(cookies->item.max_age); } } diff --git a/src/cookies.h b/src/cookies.h index c336cf7..b83955d 100644 --- a/src/cookies.h +++ b/src/cookies.h @@ -4,7 +4,7 @@ #include "request.h" -void magi_cookies(magi_request *request, const char *data); +void magi_parse_cookies(magi_request *request, const char *data); #endif diff --git a/src/file.c b/src/file.c index 9bf70c4..dd4802a 100644 --- a/src/file.c +++ b/src/file.c @@ -4,37 +4,35 @@ #include -int magi_file_list_add(struct magi_file_list ** list, struct magi_file * item) +void magi_files_add(magi_files **files, magi_file *newitem) { - struct magi_file_list * node = malloc(sizeof(*node)); + magi_files *node = malloc(sizeof(*node)); if (node) { - node->next = *list; - node->item = *item; - *list = node; + node->next = *files; + node->item = *newitem; + *files = node; } - return !!node; } -struct magi_file * magi_file_list_get(struct magi_file_list * list, - const char * name) +magi_file *magi_files_get(magi_files *files, const char *name) { - if (!list || !name) { + if (!files || !name) { return 0; - } else if (!strcmp(list->item.param_name, name)) { - return &list->item; + } else if (!strcmp(files->item.field, name)) { + return &files->item; } else { - return magi_file_list_get(list->next, name); + return magi_files_get(files->next, name); } } -void magi_file_list_destroy(struct magi_file_list * list) +void magi_files_free(magi_files *files) { - if (list) { - magi_file_list_destroy(list->next); - free(list->next); - free(list->item.param_name); - free(list->item.file_name); - magi_param_list_destroy(list->item.params); - free(list->item.params); + if (files) { + magi_files_free(files->next); + free(files->next); + free(files->item.field); + free(files->item.filename); + magi_params_free(files->item.params); + free(files->item.params); } } diff --git a/src/param.c b/src/param.c index e9f43f8..42785fc 100644 --- a/src/param.c +++ b/src/param.c @@ -4,35 +4,33 @@ #include -int magi_param_list_add(struct magi_param_list ** list, - struct magi_param * item) +void magi_params_add(magi_params **params, magi_param *newitem) { - struct magi_param_list * node = malloc(sizeof(*node)); + magi_params *node = malloc(sizeof(*node)); if (node) { - node->next = *list; - node->item = *item; - *list = node; + node->next = *params; + node->item = *newitem; + *params = node; } - return !!node; } -char * magi_param_list_get(struct magi_param_list * list, const char * name) +char *magi_params_get(magi_params *params, const char *name) { - if (!list || !name) { + if (!params || !name) { return 0; - } else if (!strcmp(list->item.name, name)) { - return list->item.data; + } else if (!strcmp(params->item.name, name)) { + return params->item.data; } else { - return magi_param_list_get(list->next, name); + return magi_params_get(params->next, name); } } -void magi_param_list_destroy(struct magi_param_list * list) +void magi_params_free(magi_params *params) { - if (list) { - magi_param_list_destroy(list->next); - free(list->next); - free(list->item.name); - free(list->item.data); + if (params) { + magi_params_free(params->next); + free(params->next); + free(params->item.name); + free(params->item.data); } } diff --git a/src/request.c b/src/request.c index 3677eb7..2917508 100644 --- a/src/request.c +++ b/src/request.c @@ -1,80 +1,96 @@ #include "request.h" -#include "cookie.h" -#include "file.h" -#include "param.h" #include -void magi_request_setup(struct magi_request * request) +void magi_request_init(magi_request *request) { if (request) { - request->file_callback = 0; - request->file_callback_userdata = 0; - request->file_callback_addon_max = 64; - request->cookies_max = 1024 * 8; - request->url_params_max = 1024 * 2; - request->http_params_max = 1024 * 16; - request->params_max = 0; + request->callback.act = 0; + request->callback.userdata = 0; + request->callback.addon_max = 1024; + request->limits.cookies = 1024 * 16; + request->limits.params_meta = 1024 * 16; + request->limits.params_head = 1024 * 16; + request->limits.params_body = 1024 * 16; } } -static void request_free(struct magi_request * request) +static void request_free(magi_request *request) { free(request->cookies); - free(request->http_params); - free(request->url_params); - free(request->params); + free(request->meta); + free(request->head); + free(request->body); free(request->files); free(request->method); - free(request->uri); - free(request->document_root); - free(request->document_uri); - free(request->script_name); - free(request->script_filename); - free(request->remote_addr); - free(request->remote_port); - free(request->server_addr); - free(request->server_name); - free(request->server_port); - free(request->server_protocol); - free(request->server_software); - free(request->path_info); + free(request->address); + free(request->script); + free(request->path); } -static void request_annul(struct magi_request * request) +static void request_annul(magi_request *request) { - request->cookies = 0; - request->http_params = 0; - request->url_params = 0; - request->params = 0; - request->files = 0; - request->method = 0; - request->uri = 0; - request->document_root = 0; - request->document_uri = 0; - request->script_name = 0; - request->script_filename = 0; - request->remote_addr = 0; - request->remote_port = 0; - request->server_addr = 0; - request->server_name = 0; - request->server_port = 0; - request->server_protocol = 0; - request->server_software = 0; - request->path_info = 0; + request->cookies = 0; + request->meta = 0; + request->head = 0; + request->body = 0; + request->files = 0; + request->method = 0; + request->address = 0; + request->script = 0; + request->path = 0; } -void magi_request_destroy(struct magi_request * request) +void magi_request_free(magi_request *request) { if (request) { - magi_cookie_list_destroy(request->cookies); - magi_param_list_destroy(request->http_params); - magi_param_list_destroy(request->url_params); - magi_param_list_destroy(request->params); - magi_file_list_destroy(request->files); + magi_cookies_free(request->cookies); + magi_params_free(request->meta); + magi_params_free(request->head); + magi_params_free(request->body); + magi_files_free(request->files); request_free(request); request_annul(request); } } + + +char *magi_request_meta(magi_request *r, const char *name) +{ + return magi_params_get(r->meta, name); +} + +char *magi_request_param(magi_request *r, const char *name) +{ + char *res = magi_params_get(r->body, name); + if (!res) { + return magi_params_get(r->head, name); + } + return res; +} + +char *magi_request_urlparam(magi_request *r, const char *name) +{ + return magi_params_get(r->head, name); +} + +magi_file *magi_request_file(magi_request *r, const char *name) +{ + return magi_files_get(r->files, name); +} + +char *magi_request_cookie(magi_request *r, const char *name) +{ + magi_cookie *res = magi_cookies_get(r->cookies, name); + if (!res) { + return 0; + } + return res->data; +} + +magi_cookie *magi_request_cookie_complex(magi_request *r, const char *name) +{ + return magi_cookies_get(r->cookies, name); +} diff --git a/src/response.c b/src/response.c index 904b855..403e0fe 100644 --- a/src/response.c +++ b/src/response.c @@ -6,86 +6,132 @@ #include -void magi_response_setup(magi_response *response) +void magi_response_status(magi_request *r, int code, const char *description) { - response->cookies = 0; - response->http_params = 0; - response->content_type = 0; - magi_response_content_type(response, "application/xhtml+xml"); - response->content = magi_str_create(0); - response->len = 0; - response->size = 1; + int dlen; + magi_param addon; + if (r->response->head_done || code <= 99 || 600 <= code) { + return; + } + dlen = strlen(description); + addon.name = magi_str_create_copy("Status", 6); + addon.data = malloc(5 + dlen); + addon.data[0] = '0' + code / 100; + addon.data[1] = '0' + code / 10 % 10; + addon.data[2] = '0' + code % 10; + addon.data[3] = ' '; + memcpy(addon.data + 4, description, dlen + 1); + magi_params_set(r->response->head, &addon); } -void magi_response_content_type(magi_response *response, const char *type) +void magi_response_cookie(magi_request *r, const char *name, const char *data) { - static const char *const ct = "Content-Type: "; - static const int ctlen = 15; - const int len = strlen(type); - free(response->content_type); - response->content_type = malloc(ctlen + len + 1); - memcpy(response->content_type, ct, ctlen); - memcpy(response->content_type + ctlen, type, len + 1); + magi_param addon; + if (r->response->head_done) { + return; + } + addon.name = magi_str_create_copy("Set-Cookie", 10); + /* TODO */ + magi_params_add(r->response->head + 1, &addon); } -void magi_response_add(magi_response *r, const char *addon) +void magi_response_cookie_complex(magi_request *r, magi_cookie *c) { - int addon_len; - if (!addon) { + magi_param addon; + if (r->response->head_done) { return; } - addon_len = strlen(addon); - if (r->len + addon_len + 1 >= r->size) { - r->content = realloc(r->content, r->len + addon_len + 1); - } - memcpy(r->content + r->len, addon, addon_len + 1); - r->len += addon_len; + addon.name = magi_str_create_copy("Set-Cookie", 10); + /* TODO */ + magi_params_add(r->response->head + 1, &addon); } -void magi_response_cookie(magi_response *response, magi_cookie *cookie) +void magi_response_cookie_discard(magi_request *r, const char *name) { - magi_cookie_list_add(&response->cookies, cookie); + magi_param addon; + if (r->response->head_done) { + return; + } + addon.name = magi_str_create_copy("Set-Cookie", 10); + /* TODO */ + magi_params_add(r->response->head + 1, &addon); } -void magi_response_cookie_easy(magi_response *response, - const char *name, - const char *value) +void magi_response_header(magi_request *r, const char *name, const char *data) { - magi_cookie cookie = { 0, 0, 0, 0, 0 }; - cookie.name = magi_str_create_copy(name, strlen(name)); - cookie.data = magi_str_create_copy(value, strlen(value)); - magi_cookie_list_add(&response->cookies, &cookie); + magi_param addon; + if (r->response->head_done) { + return; + } + addon.name = magi_str_create_copy(name, strlen(name)); + addon.data = magi_str_create_copy(data, strlen(data)); + magi_params_add(r->response->head + 1, &addon); } -void magi_response_cookie_discard(magi_response *response, const char *name) +void magi_response_content_length(magi_request *r, int length) { - magi_cookie cookie = { 0, 0, 0, 0, 0 }; - cookie.name = magi_str_create_copy(name, strlen(name)); - cookie.max_age = magi_str_create(1); - cookie.max_age[0] = '0'; - magi_cookie_list_add(&response->cookies, &cookie); + magi_param addon; + int len; + if (r->response->head_done) { + return; + } + addon.name = magi_str_create_copy("Content-Length", 14); + len = 1; + addon.data = malloc(len + 1); + *addon.data = '0' + length % 10; + while (length /= 10) { + addon.data = realloc(addon.data, len + 2); + addon.data[len] = '0' + length % 10; + ++len; + } + addon.data[len] = 0; + magi_params_set(r->response->head + 2, &addon); } -void magi_response_http(magi_response *response, - const char *name, - const char *data) +void magi_response_content_type(magi_request *r, const char *type) { - magi_param param = { 0, 0 }; - param.name = magi_str_create_copy(name, strlen(name)); - param.data = magi_str_create_copy(data, strlen(data)); - magi_param_list_add(&response->http_params, ¶m); + magi_param addon; + if (r->response->head_done) { + return; + } + addon.name = magi_str_create_copy("Content-Type", 12); + addon.data = magi_str_create_copy(type, strlen(type)); + magi_params_set(r->response->head + 2, &addon); } +static void response_headers(magi_response_implementation *r, magi_params *p) +{ + for (; p; p = p->next) { + r->methods->head(r->userdata, &p->item); + } +} -void magi_response_destroy(magi_response *response) +void magi_response_head(magi_request *r) { - if (!response) { + magi_params *current; + if (r->response->head_done) { return; } - magi_cookie_list_destroy(response->cookies); - magi_param_list_destroy(response->http_params); - free(response->cookies); - free(response->http_params); - free(response->content_type); - free(response->content); + response_headers(r->response, r->response->head[0]); + response_headers(r->response, r->response->head[1]); + response_headers(r->response, r->response->head[2]); + r->response->head_done = 1; +} + +void magi_response(magi_request *r, const char *addon) +{ + magi_response_head(r); + r->response->methods->body(r->response->userdata, addon, strlen(addon)); +} + +void magi_response_format(magi_request *r, const char *format, ...) +{ + magi_response_head(r); + /* TODO */ +} + +void magi_response_file(magi_request *r, FILE *file) +{ + magi_response_head(r); + r->response->methods->file(r->response->userdata, file); } -- cgit v1.2.3