From c65fdedc7bedfc20da73cdbfc34c22bb80139896 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 28 Feb 2020 20:16:57 +0300 Subject: [magi] --- examples/Makefile | 2 +- examples/append.c | 33 ++++++------ examples/cookie.c | 43 +++++++-------- examples/echo.c | 135 +++++++++++++++++++++++------------------------- examples/fastcgi.c | 34 ++++++++++++ examples/fcgi.c | 46 ----------------- examples/upload.c | 51 +++++++++--------- include/magi.h | 10 +--- include/magi/cgi.h | 13 ++--- include/magi/cookie.h | 59 ++++++++++++--------- include/magi/file.h | 50 ++++++++++-------- include/magi/loadfile.h | 22 ++++---- include/magi/param.h | 23 ++++----- include/magi/urlenc.h | 2 +- readme | 4 +- 15 files changed, 259 insertions(+), 268 deletions(-) create mode 100644 examples/fastcgi.c delete mode 100644 examples/fcgi.c diff --git a/examples/Makefile b/examples/Makefile index 28e9bed..f2c366b 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -3,7 +3,7 @@ # Debug mode (allowing to debug the examples via gdb): # DEBUG = yes # Examples to build by default: -EXAMPLES = append cookie upload echo +EXAMPLES = append cookie echo upload fastcgi # Specify your favourite C compiler here (e.g. tcc): CC = gcc diff --git a/examples/append.c b/examples/append.c index 702f0fb..cafdf9c 100644 --- a/examples/append.c +++ b/examples/append.c @@ -1,23 +1,23 @@ #include #include -#include -void response_request(magi_request *req, magi_response *res) +void response(magi_request *r) { - char *data = magi_param_list_get(req->params, "addon"); + char *data = magi_request_param(r, "addon"); + magi_response_add(r, + "" + "" + "Append to File" + ""); if (data) { FILE *file = fopen("file_to_append", "a"); fputs(data, file); fclose(file); + magi_response_add(r, "

Appended!

"); } - - magi_response_add(res, - "" - "" - "Append to File" - "" + magi_response_add(r, "
" "" "" @@ -29,15 +29,12 @@ void response_request(magi_request *req, magi_response *res) int main(int argc, char const *argv[]) { magi_request request; - magi_request_setup(&request); - if (magi_request_full_cgi(&request)) { - magi_response response; - magi_response_setup(&response); - response_request(&request, &response); - magi_response_cgi_clear(&response); + magi_request_init(&request); + if (magi_cgi(&request)) { + response(&request); } else { - magi_error_cgi(request.error); + magi_response_error(&request); } - magi_request_destroy(&request); + magi_request_free(&request); return 0; } diff --git a/examples/cookie.c b/examples/cookie.c index 365f989..5bbade1 100644 --- a/examples/cookie.c +++ b/examples/cookie.c @@ -1,41 +1,38 @@ #include -#include -#include -void response_request(magi_request *req, magi_response *res) +void list_cookies(magi_request *r) { - magi_cookie_list *current; + magi_cookies *current; + magi_response_add(r, "Cookies:"); + for (current = r->cookies; current; current = current->next) { + magi_cookie *c = ¤t->item; + magi_response_format(r, "
[%s] = [%s]", c->name, c->data); + } +} - magi_response_add(res, +void response(magi_request *r) +{ + magi_response_cookie(r, "cookie", "monster"); + magi_response_add(r, "" "" "Cookie Listing and Setting" - ""); - - for (current = req->cookies; current; current = current->next) { - magi_response_add_format(res, - "[%s] = [%s]
", current->item.name, current->item.data); - } - - magi_response_add(res, ""); - - magi_response_cookie_easy(res, "cookie", "monster"); + "

"); + list_cookies(r); + magi_response_add(r, "

"); } int main(int argc, char const *argv[]) { magi_request request; - magi_request_setup(&request); - if (magi_request_full_cgi(&request)) { - magi_response response; - magi_response_setup(&response); - response_request(&request, &response); - magi_response_cgi_clear(&response); + magi_request_init(&request); + if (magi_cgi(&request)) { + response(&request); } else { - magi_error_cgi(request.error); + magi_response_error(&request); } - magi_request_destroy(&request); + magi_request_free(&request); return 0; } diff --git a/examples/echo.c b/examples/echo.c index f665cd0..89230de 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -1,118 +1,113 @@ #include -#include -#include -void proceed_cookies(magi_cookie_list *cookies, magi_response *response) +void list_cookies(magi_request *r) { - while (cookies) { - magi_response_add(response, "Cookie with name ["); - magi_response_add(response, cookies->item.name); - if (cookies->item.data) { - magi_response_add(response, "] is ["); - magi_response_add(response, cookies->item.data); + magi_cookies *current = r->cookies; + for (current = r->cookies; current; current = current->next) { + magi_cookie *c = ¤t->item; + magi_response_add(r, "Cookie with name ["); + magi_response_add(r, c->name); + if (c->data) { + magi_response_add(r, "] is ["); + magi_response_add(r, c->data); } - if (cookies->item.domain) { - magi_response_add(response, "] for domain ["); - magi_response_add(response, cookies->item.domain); + if (c->domain) { + magi_response_add(r, "] for domain ["); + magi_response_add(r, c->domain); } - if (cookies->item.path) { - magi_response_add(response, "] for path ["); - magi_response_add(response, cookies->item.path); + if (c->path) { + magi_response_add(r, "] for path ["); + magi_response_add(r, c->path); } - magi_response_add(response, "]
"); - cookies = cookies->next; + magi_response_add(r, "]
"); } } -void proceed_params(magi_param_list *params, magi_response *response) +void list_params(magi_request *r, magi_params *current) { - while (params) { - magi_response_add_format(response, - "[%s] is [%s]
", params->item.name, params->item.data); - params = params->next; + for (; current; current = current->next) { + magi_param *p = ¤t->item; + magi_response_format(r, "[%s] is [%s]
", p->name, p->data); } } -void proceed_files(magi_file_list *files, magi_response *response) +void list_files(magi_request *r) { - while (files) { - magi_file f = files->item; - magi_response_add_format(response, - "[%s] was [%s] on userside
", f.param_name, f.file_name); - files = files->next; + magi_files *current; + for (current = r->files; current; current = current->next) { + magi_file *f = ¤t->item; + magi_response_format(r, "[%s] was [%s] on clientside
", + f->param_name, f->file_name); } } -void process_meta(magi_request *req, magi_response *res) +void show_meta(magi_request *r) { - magi_response_add(res, "I was called with method ["); - magi_response_add(res, req->method); - if (req->uri) { - magi_response_add(res, "] with URL ["); - magi_response_add(res, req->uri); + magi_response_add(r, "I was called with method ["); + magi_response_add(r, r->method); + if (r->uri) { + magi_response_add(r, "] with URL ["); + magi_response_add(r, r->uri); } - if (req->server_name) { - magi_response_add(res, "] for server ["); - magi_response_add(res, req->server_name); + if (r->server_name) { + magi_response_add(r, "] for server ["); + magi_response_add(r, r->server_name); } - if (req->server_port) { - magi_response_add(res, "] on port ["); - magi_response_add(res, req->server_port); + if (r->server_port) { + magi_response_add(r, "] on port ["); + magi_response_add(r, r->server_port); } - if (req->server_protocol) { - magi_response_add(res, "] with protocol ["); - magi_response_add(res, req->server_protocol); + if (r->server_protocol) { + magi_response_add(r, "] with protocol ["); + magi_response_add(r, r->server_protocol); } - if (req->server_software) { - magi_response_add(res, "] and I am running on software ["); - magi_response_add(res, req->server_software); + if (r->server_software) { + magi_response_add(r, "] and I am running on software ["); + magi_response_add(r, r->server_software); } - magi_response_add(res, "]
"); + magi_response_add(r, "]
"); } -void response_request(magi_request *req, magi_response *res) +void response(magi_request *r) { - magi_response_add(res, + magi_response_add(r, "" "" "Echo" ""); - magi_response_add(res, "

Echo CGI Script

"); - process_meta(req, res); + magi_response_add(r, "

Echo CGI Script

"); + show_meta(r); - magi_response_add(res, "

Cookies:

"); - proceed_cookies(req->cookies, res); + magi_response_add(r, "

Cookies:

"); + list_cookies(r); - magi_response_add(res, "

Parameters:

"); - proceed_params(req->params, res); + magi_response_add(r, "

Parameters:

"); + list_params(r, r->params); - magi_response_add(res, "

URL Parameters:

"); - proceed_params(req->url_params, res); + magi_response_add(r, "

URL Parameters:

"); + list_params(r, r->url_params); - magi_response_add(res, "

HTTP Parameters:

"); - proceed_params(req->http_params, res); + magi_response_add(r, "

HTTP Parameters:

"); + list_params(r, r->http_params); - magi_response_add(res, "

Files:

"); - proceed_files(req->files, res); + magi_response_add(r, "

Files:

"); + list_files(r); - magi_response_add(res, ""); + magi_response_add(r, ""); } int main(int argc, char const *argv[]) { magi_request request; - magi_request_setup(&request); - if (magi_request_full_cgi(&request)) { - magi_response response; - magi_response_setup(&response); - response_request(&request, &response); - magi_response_cgi_clear(&response); + magi_request_init(&request); + if (magi_cgi(&request)) { + response(&request); } else { - magi_error_cgi(request.error); + magi_response_error(&request); } - magi_request_destroy(&request); + magi_request_free(&request); return 0; } diff --git a/examples/fastcgi.c b/examples/fastcgi.c new file mode 100644 index 0000000..2d68a3b --- /dev/null +++ b/examples/fastcgi.c @@ -0,0 +1,34 @@ +#include + + +void response(magi_request *r) +{ + magi_response_add(r, + "" + "" + "Fast CGI" + "Hi!" + ""); +} + +int main(int argc, char const *argv[]) +{ + magi_session session; + magi_request request; + magi_request_init(&request); + magi_session_init(&session); + magi_session_inet(&session, "localhost", "9973"); + magi_session_unix(&session, "unix.sock"); + while (magi_fastcgi(&session, &request)) { + if (request.error) { + magi_response_error(&request); + } else { + response(&request); + } + magi_request_free(&request); + } + magi_request_free(&request); + magi_session_free(&session); + return 0; +} diff --git a/examples/fcgi.c b/examples/fcgi.c deleted file mode 100644 index de2f525..0000000 --- a/examples/fcgi.c +++ /dev/null @@ -1,46 +0,0 @@ -/* * * TODO -- not valid yet * * */ -#include -#include -#include -#include - - -void response_request(struct magi_request * req, struct magi_resopnse * res) -{ - magi_response_content_type(res, magi_xhtml); - magi_response_add( - res, "" - "" - "Fast CGI" - "Hi!" - ""); -} - -int main(int argc, char const * argv[]) -{ - struct magi_session session; - int sock = magi_socket_inet("localhost", 9973); - /* E.g. also magi_socket_file("fcgi.sock") can be used. */ - if (magi_session_fcgi(&session, sock)) { - struct magi_request request; - magi_request_setup(&request); - while (magi_request_fcgi(&request, &session) && - magi_request_resume_fcgi(&request, &session)) { - if (!request.error) { - struct magi_response response; - magi_response_setup(&response); - response_request(&request, &response); - magi_response_fcgi(&response, &session); - magi_response_destroy(&response); - } else { - magi_error_fcgi(request.error, &session); - } - magi_request_destroy(&request); - } - } - fputs(magi_error_message(session.error), stderr); - magi_session_destroy(&session); - magi_socket_close(sock); - return 0; -} diff --git a/examples/upload.c b/examples/upload.c index 1877d39..158dcad 100644 --- a/examples/upload.c +++ b/examples/upload.c @@ -1,23 +1,22 @@ #include #include -#include -#include -void response_request(magi_request *req, magi_response *res) +void response(magi_request *r) { - char *name = magi_param_list_get(req->params, "name"); - magi_file *data = magi_file_list_get(req->files, "data"); - if (name && data) { - rename("data", name); - } - - magi_response_add(res, + char *name = magi_request_param(r, "name"); + magi_file *data = magi_request_file(r, "data"); + magi_response_add(r, "" "" "Upload File" - "" + ""); + if (name && data) { + rename("data", name); + magi_response_add(r, "

Uploaded!

"); + } + magi_response_add(r, "
" "" @@ -28,22 +27,26 @@ void response_request(magi_request *req, magi_response *res) ""); } +void get(magi_request *r) +{ + magi_loadfiles rules; + magi_loadfiles_init(&rules); + magi_loadfiles_add(&rules, "data", "data", 0); + magi_loadfiles_set(&r, &rules); + magi_cgi(&r); + magi_loadfiles_free(&rules); +} + int main(int argc, char const *argv[]) { - magi_request request; - magi_tempfiles tmps = { 0, 0 }; - magi_request_setup(&request); - magi_tempfiles_add(&tmps, "data", "data", 0); - magi_request_setup_tempfiles(&request, &tmps); - if (magi_request_full_cgi(&request)) { - magi_response response; - magi_response_setup(&response); - response_request(&request, &response); - magi_response_cgi(&response); + magi_request request; + magi_request_init(request); + get(&request); + if (request.error) { + magi_response_error(&request); } else { - magi_error_cgi(request.error); + response(&request); } - magi_tempfiles_destroy(&tmps); - magi_request_destroy(&request); + magi_request_free(&request); return 0; } diff --git a/include/magi.h b/include/magi.h index 60f0cc9..c14f8b6 100644 --- a/include/magi.h +++ b/include/magi.h @@ -1,5 +1,5 @@ -#ifndef MAGI_INCLUDED -#define MAGI_INCLUDED +#ifndef MAGI_INCLUDED_EVERYTHING +#define MAGI_INCLUDED_EVERYTHING /** @file magi.h * @brief All headers are included here. * @@ -14,10 +14,4 @@ #include "magi/request.h" #include "magi/response.h" #include "magi/urlenc.h" - - -/** @mainpage Magi Gateway Interfaces Library - */ - - #endif diff --git a/include/magi/cgi.h b/include/magi/cgi.h index c365f2f..4d182b7 100644 --- a/include/magi/cgi.h +++ b/include/magi/cgi.h @@ -11,24 +11,25 @@ /** @brief Analyses non-post part of request from environment. - * @return Returns null only in case of error. */ + * @return 1 if ok, 0 if error. */ int magi_request_cgi_head(magi_request *request); -/** @brief Complete request with post data from standard input. - * @return Returns null only in case of error. */ +/** @brief Complete request with post body from standard input. + * @return 1 if ok, 0 if error. */ int magi_request_cgi_body(magi_request *request); -/** @brief Shortcut for analysing both head and body of request. */ +/** @brief Shortcut for analysing both head and body of request. + * @return 1 if ok, 0 if error. */ int magi_request_cgi(magi_request *request); /** @brief Sends response to standard output and destroys it. - * @return Returns null only in case of error. */ + * @return 1 if ok, 0 if error. */ int magi_response_cgi(magi_response *response); /** @brief Sends a standard response of Bad Request error. - * @return Returns null only in case of error. */ + * @return 1 if ok, 0 if error. */ int magi_error_cgi(magi_error error); diff --git a/include/magi/cookie.h b/include/magi/cookie.h index 485b6d9..e6a5c4f 100644 --- a/include/magi/cookie.h +++ b/include/magi/cookie.h @@ -1,37 +1,48 @@ #ifndef MAGI_INCLUDED_COOKIE #define MAGI_INCLUDED_COOKIE /** @file cookie.h - * @brief blah... + * @brief HTTP Cookie. * - * blah-blah... + * Described in RFC 6265. */ +/** @brief HTTP Cookie. */ typedef struct magi_cookie { - /* All pointers must be valid as 'free' arguments. */ - char *name; - char *data; - char *path; /* Without '/' at the end. */ - char *domain; /* With dot at the begining. */ - char *max_age; /* In seconds until discard, used only in response. */ + char *name; /**<@brief Cookie name. */ + char *data; /**<@brief Cookie value. */ + char *path; /**<@brief Path on wich cookie is set. + * Without '/' at the end. */ + char *domain; /**<@brief Domain in wich cookie is set. + * With dot at the begining. */ + char *max_age; /**<@brief In seconds until discard (response only). */ } magi_cookie; -typedef struct magi_cookie_list { - struct magi_cookie_list *next; /* Must be valid as 'free' arguments. */ - magi_cookie item; -} magi_cookie_list; - - -/* Addition of item to top of list. Null <=> error. */ -int magi_cookie_list_add(magi_cookie_list **list, magi_cookie *item); - -/* Data of last cookie in list: cookie.name == name, returns null if no such; - * Last cookie in list is first from request, and from RFC 2109 we know that - * first cookie is the most accurate for request's domain and path. */ -char *magi_cookie_list_get(magi_cookie_list *list, const char *name); - -/* Freeing and invalidation of list. */ -void magi_cookie_list_destroy(magi_cookie_list *list); +/** @ brief HTTP cookies collection. + * + * Implemented as a linked list. */ +typedef struct magi_cookies { + struct magi_cookies *next; /**<@brief Pointer to next cookies. */ + magi_cookie item; /**<@brief Cookie on top. */ +} magi_cookies; + +/** @brief 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); + +/** @brief Get data of 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); + +/** @brief Free memory used by @p cookies. + * @param[in,out] cookies to be destructed. */ +void magi_cookies_free(magi_cookies *cookies); #endif diff --git a/include/magi/file.h b/include/magi/file.h index 57b88f0..474913d 100644 --- a/include/magi/file.h +++ b/include/magi/file.h @@ -1,34 +1,42 @@ #ifndef MAGI_INCLUDED_FILE #define MAGI_INCLUDED_FILE /** @file file.h - * @brief blah... - * - * blah-blah... + * @brief Form field of file with its parameters. */ #include "param.h" +/** @brief Form field of file with its parameters. */ typedef struct magi_file { - /* All pointers must be valid as 'free' arguments. */ - char *param_name; /* Name of corresponding form field */ - char *file_name; /* File name on user's computer */ - magi_param_list *params; /* Multipart params (e.g. type) */ + char *field; /**<@brief Name of form field. */ + char *filename; /**<@brief File name on user's computer. */ + magi_params *params; /**<@brief Multipart params (e.g. type). */ } magi_file; -typedef struct magi_file_list { - struct magi_file_list *next; /* Must be valid as 'free' argument. */ - magi_file item; -} magi_file_list; - - -/* Addition of item to top of list. Null <=> error. */ -int magi_file_list_add(magi_file_list **list, magi_file *item); - -/* First node in list: node.param_name == name; else null. */ -magi_file *magi_file_list_get(magi_file_list *list, const char *name); - -/* Freeing and invalidation of list. */ -void magi_file_list_destroy(magi_file_list *list); +/** @brief Form files collection. + * + * Implemented as a linked list. */ +typedef struct magi_files { + struct magi_files *next; /**<@brief Pointer to next files. */ + magi_file item; /**<@brief File on top. */ +} magi_files; + + +/** @brief Add @p newitem to @p files. + * @param[in,out] files to add into. + * @param[in] newitem to add onto top of @p files. */ +void magi_files_add(magi_files **files, magi_file *newitem); + +/** @brief Get file with @p name from @p files. + * @param[in] files to search in. + * @param[in] name of needed file. + * @return first from top of @p files file with @p name, + null only if no such file. */ +magi_file *magi_files_get(magi_files *files, const char *name); + +/** @brief Free memory used by @p files. + * @param[in,out] files to be destructed. */ +void magi_files_free(magi_files *files); #endif diff --git a/include/magi/loadfile.h b/include/magi/loadfile.h index b485ea1..41622d8 100644 --- a/include/magi/loadfile.h +++ b/include/magi/loadfile.h @@ -14,23 +14,22 @@ /** @brief Rule of loading single file. - * + * * There is no need to form or edit it directly. */ -struct magi_loadfile { +typedef struct magi_loadfile { const char *name; /**<@brief Form field to load file from. */ const char *path; /**<@brief Path to load file in. */ int max; /**<@brief Limit in bytes. Null means unlimited. */ -}; -typedef struct magi_loadfile magi_loadfile; +} magi_loadfile; /** @brief Table of rules for loading files. - * + * * Set @c count and @c files as null to initialize. */ -struct magi_loadfiles { - int count; /**<@brief Size of @c files.*/ - magi_loadfile *files; /**<@brief Dynamic array of rules to load files. */ -}; -typedef struct magi_loadfiles magi_loadfiles; +typedef struct magi_loadfiles { + int count; /**<@brief Size of @c files.*/ + magi_loadfile *files; /**<@brief Dynamic array of rules to load files. */ +} magi_loadfiles; + /** @brief Add entity into @p table. * @param[in,out] table is the table to add into. @@ -50,8 +49,7 @@ void magi_loadfiles_free(magi_loadfiles *table); /** @brief Setup @p request to use loadfiles callback with @p table. * @param[in,out] request to setup using loadfiles callback. * @param[in] table to use in loadfiles callback. */ -void magi_request_setup_loadfiles(magi_request *request, - magi_loadfiles *table); +void magi_loadfiles_set(magi_request *request, magi_loadfiles *table); #endif diff --git a/include/magi/param.h b/include/magi/param.h index de39ff6..7e1262b 100644 --- a/include/magi/param.h +++ b/include/magi/param.h @@ -6,20 +6,18 @@ /** @brief Parameter as name-value pair. */ -struct magi_param { +typedef struct magi_param { char *name; /**<@brief Cannot be null. */ char *data; /**<@brief Cannot be null. */ -}; -typedef struct magi_param magi_param; +} magi_param; /** @brief Parameters collection. * - * Implemented as linked list. */ -struct magi_params { - struct magi_params *next; /**<@brief Pointer to next parameter. */ - magi_param item; /**<@brief Top parameter. */ -}; -typedef struct magi_params magi_params; + * Implemented as a linked list. */ +typedef struct magi_params { + struct magi_params *next; /**<@brief Pointer to next parameters. */ + magi_param item; /**<@brief Parameter on top. */ +} magi_params; /** @brief Add @p newitem to @p params. @@ -31,10 +29,11 @@ void magi_params_add(magi_params **params, magi_param *newitem); * @param[in] params to search in. * @param[in] name of needed parameter. * @return data of the first from top of @p params parameter with @p name, - * null only if no parameter with @p name is in @p params. */ -char *magi_params_get(magi_param_list *params, const char *name); + * null only if no such parameter. */ +char *magi_params_get(magi_params *params, const char *name); -/* Freeing and invalidation of list. */ +/** @brief Free memory used by @p params. + * @param[in,out] params to be destructed. */ void magi_params_free(magi_params *params); diff --git a/include/magi/urlenc.h b/include/magi/urlenc.h index aa21f3e..99f7bbe 100644 --- a/include/magi/urlenc.h +++ b/include/magi/urlenc.h @@ -10,7 +10,7 @@ * RFC 3986 describes URL-encoding. Briefly it is changing every space into * plus sign and every not alpha-numerical and not @c "~-._" character into * percent sign followed by hexadecimal representation of given character. - * + * * @note This module is optional. */ diff --git a/readme b/readme index 3160155..cf90f06 100644 --- a/readme +++ b/readme @@ -33,7 +33,7 @@ magi_request analyses incoming request, general workflow is to: 3. Process post part of the CGI request via 'magi_request_resume_cgi'; 4. Now you have the full request analysed, so do your work; 5. And finally, free memory via 'magi_request_destroy'. -For more see 'src/request.h'. +For more see 'include/magi/request.h'. magi_response provides output capabilities. You can form the response with 'magi_response_setup' used to setup defaults, and the following functions to @@ -46,7 +46,7 @@ fill in your data ('...' means 'magi_response_'): ...add_format: add comething to the body, using format (similar to printf); Outputting itself can be done with 'magi_response_cgi'. To correctly free all occupied memory call 'magi_response_destroy'. -For more see 'src/response.h'. +For more see 'include/magi/response.h'. Motivation Web must be fun. -- cgit v1.2.3