From 88081d9a4376b1ee4feed3bc843c46096e087b1e Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 22 Nov 2019 18:55:54 +0300 Subject: . --- examples/append.c | 18 +++--- examples/cookie.c | 21 +++--- examples/echo.c | 99 +++++++++++++---------------- examples/fcgi.c | 12 ++-- examples/upload.c | 28 ++++---- src/cgi.h | 22 +++---- src/cookie.h | 31 +++------ src/cookies.c | 0 src/cookies.h | 10 +++ src/error.c | 2 +- src/error.h | 2 +- src/fastcgi.h | 26 +++----- src/file.h | 11 ++++ src/multipart.c | 11 ++-- src/multipart.h | 19 ++---- src/param.h | 24 +++---- src/request.c | 86 +++++++++++++++++++------ src/request.h | 100 +++++++++++++++++------------ src/response.h | 36 +++++++++++ src/urlenc.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/urlenc.h | 13 ++++ src/urlencoded.c | 187 ------------------------------------------------------ src/urlencoded.h | 10 --- src/utils.c | 19 ++---- src/utils.h | 2 +- 25 files changed, 523 insertions(+), 453 deletions(-) create mode 100644 src/cookies.c create mode 100644 src/cookies.h create mode 100644 src/urlenc.c create mode 100644 src/urlenc.h delete mode 100644 src/urlencoded.c delete mode 100644 src/urlencoded.h diff --git a/examples/append.c b/examples/append.c index 30060fa..3320fe0 100644 --- a/examples/append.c +++ b/examples/append.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -7,7 +8,7 @@ void response_request(struct magi_request * req, struct magi_response * res) { magi_response_content_type(res, magi_xhtml); - magi_response_content( + magi_response_add( res, "" @@ -21,10 +22,10 @@ void response_request(struct magi_request * req, struct magi_response * res) "" ""); - struct magi_field * a = magi_field_list_get(req->fields, "addon"); - if (a && a->data) { + struct magi_param * addon = magi_param_list_get(req->url_params, "addon"); + if (addon && addon->data) { FILE * file = fopen("file_to_append", "a"); - fputs(a->data, file); + fputs(addon->data, file); fclose(file); } } @@ -32,13 +33,14 @@ void response_request(struct magi_request * req, struct magi_response * res) int main(int argc, char const * argv[]) { struct magi_request request; - if (magi_cgi(&request, 0, 0, 0)) { + magi_request_setup(&request); + if (magi_request_cgi(&request)) { struct magi_response response; response_request(&request, &response); - magi_cgi_response(&response); - magi_response_destroy(); + magi_response_cgi(&response); + magi_response_destroy(&response); } else { - magi_cgi_error(request.error); + magi_error_cgi(request.error); } magi_request_destroy(&request); return 0; diff --git a/examples/cookie.c b/examples/cookie.c index f99f07f..01d6dea 100644 --- a/examples/cookie.c +++ b/examples/cookie.c @@ -8,35 +8,38 @@ void response_request(struct magi_request * req, struct magi_response * res) { - struct magi_cookie_list * cookie; + struct magi_cookie_list * current; magi_response_content_type(res, magi_xhtml); - magi_response_content( + magi_response_add( res, "" "" "Cookie Listing and Setting" ""); - for (cookie = req->cookies; cookie; cookie = cookie->next) { - printf("[%s] = [%s]
", cookie->item.name, cookie->item.data); + for (current = req->cookies; current; current = current->next) { + magi_response_add_format(res, "[%s] = [%s]
", current->item.name, + current->item.data); } - magi_response_content(res, ""); + magi_response_add(res, ""); - magi_response_cookie_build(res, "cookie", "monstre", 0, 0, 0); + magi_response_cookie_easy(res, "cookie", "monster"); + magi_response_cookie_delete(res, "monster"); } int main(int argc, char const * argv[]) { struct magi_request request; - if (magi_cgi(&request, 0, 0, 0)) { + magi_request_setup(&request); + if (magi_request_cgi(&request)) { struct magi_response response; response_request(&request, &response); - magi_cgi_response(&response); + magi_response_cgi(&response); magi_response_destroy(); } else { - magi_cgi_error(request.error); + magi_error_cgi(request.error); } magi_request_destroy(&request); return 0; diff --git a/examples/echo.c b/examples/echo.c index 16e9d56..95219fc 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,94 +10,75 @@ void proceed_cookies(struct magi_cookie_list * cookies, struct magi_response * response) { - magi_response_content(response, "

Cookies:

"); + magi_response_add(response, "

Cookies:

"); while (cookies) { - magi_response_content(response, "Cookie with name ["); - magi_response_content(response, cookies->item.name); + magi_response_add(response, "Cookie with name ["); + magi_response_add(response, cookies->item.name); if (cookies->item.data) { - magi_response_content(response, "] is ["); - magi_response_content(response, cookies->item.data); + magi_response_add(response, "] is ["); + magi_response_add(response, cookies->item.data); } if (cookies->item.domain) { - magi_response_content(response, "] for domain ["); - magi_response_content(response, cookies->item.domain); + magi_response_add(response, "] for domain ["); + magi_response_add(response, cookies->item.domain); } if (cookies->item.port) { - magi_response_content(response, "] for port ["); - magi_response_content(response, cookies->item.port); + magi_response_add(response, "] for port ["); + magi_response_add(response, cookies->item.port); } if (cookies->item.path) { - magi_response_content(response, "] for path ["); - magi_response_content(response, cookies->item.path); + magi_response_add(response, "] for path ["); + magi_response_add(response, cookies->item.path); } - magi_response_content(response, "]
"); + magi_response_add(response, "]
"); cookies = cookies->next; } - magi_response_content(response, "
"); -} - -void proceed_fields(struct magi_field_list * fields, - struct magi_response * response) -{ - magi_response_content(response, "

Feilds:

"); - while (fields) { - magi_response_content(response, "Feild ["); - magi_response_content(response, fields->item.name); - magi_response_content(response, "] = ["); - magi_response_content(response, fields->item.data); - magi_response_content(response, "]
"); - fields = fields->next; - } - magi_response_content(response, "
"); + magi_response_add(response, "
"); } void proceed_params(struct magi_param_list * params, struct magi_response * response) { - magi_response_content(response, "

HTTP Parameters:

"); while (params) { - magi_response_content(response, "Param ["); - magi_response_content(response, params->item.name); - magi_response_content(response, "] is ["); - magi_response_content(response, params->item.data); - magi_response_content(response, "]
"); + magi_response_add_format(response, "[%s] is [%s]
", + params->item.name, params->item.data); params = params->next; } - magi_response_content(response, "
"); + magi_response_add(response, "
"); } void process_meta(struct magi_request * req, struct magi_response * res) { - magi_response_content(res, "

Echo CGI Script

" - "I was called with method ["); - magi_response_content(res, req->method); + magi_response_add(res, + "

Echo CGI Script

I was called with method [%s", + req->method); if (req->uri) { - magi_response_content(res, "] with URL ["); - magi_response_content(res, req->uri); + magi_response_add(res, "] with URL ["); + magi_response_add(res, req->uri); } if (req->server_name) { - magi_response_content(res, "] for server ["); - magi_response_content(res, req->server_name); + magi_response_add(res, "] for server ["); + magi_response_add(res, req->server_name); } if (req->server_port) { - magi_response_content(res, "] on port ["); - magi_response_content(res, req->server_port); + magi_response_add(res, "] on port ["); + magi_response_add(res, req->server_port); } if (req->server_protocol) { - magi_response_content(res, "] with protocol ["); - magi_response_content(res, req->server_protocol); + magi_response_add(res, "] with protocol ["); + magi_response_add(res, req->server_protocol); } if (req->server_software) { - magi_response_content(res, "] and I am running on software ["); - magi_response_content(res, req->server_software); + magi_response_add(res, "] and I am running on software ["); + magi_response_add(res, req->server_software); } - magi_response_content(res, "]
"); + magi_response_add(res, "]
"); } void response_request(struct magi_request * req, struct magi_response * res) { magi_response_content_type(res, magi_xhtml); - magi_response_content( + magi_response_add( res, "" "" @@ -104,21 +86,26 @@ void response_request(struct magi_request * req, struct magi_response * res) ""); process_meta(req, res); proceed_cookies(req->cookies, res); - proceed_fields(req->fields, res); + magi_response_add(res, "

Parameters:

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

URL Parameters:

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

HTTP Parameters:

"); proceed_params(req->http_params, res); - magi_response_content(res, ""); + magi_response_add(res, ""); } int main(int argc, char const * argv[]) { struct magi_request request; - if (magi_cgi(&request, 0, 0, 0)) { + magi_request_setup(&request); + if (magi_request_cgi(&request)) { struct magi_response response; response_request(&request, &response); - magi_cgi_response(&response); - magi_response_destroy(); + magi_response_cgi(&response); + magi_response_destroy(&response); } else { - magi_cgi_error(request.error); + magi_error_cgi(request.error); } magi_request_destroy(&request); return 0; diff --git a/examples/fcgi.c b/examples/fcgi.c index d6cc478..72fe83e 100644 --- a/examples/fcgi.c +++ b/examples/fcgi.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -9,7 +10,7 @@ void response_request(struct magi_request * req, struct magi_resopnse * res) { magi_response_content_type(res, magi_xhtml); - magi_response_content( + magi_response_add( res, "" "" @@ -23,16 +24,17 @@ 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_fcgi(&session, sock)) { + if (magi_session_fcgi(&session, sock)) { struct magi_request request; - while (magi_fcgi_accept(&request, &session)) { + magi_request_setup(&request); + while (magi_request_fcgi(&request, &session)) { if (!request.error) { struct magi_response response; response_request(&request, &response); - magi_fcgi_response(&response, &session); + magi_response_fcgi(&response, &session); magi_response_destroy(&response); } else { - magi_fcgi_error(request.error, &session); + magi_error_fcgi(request.error, &session); } magi_request_destroy(&request); } diff --git a/examples/upload.c b/examples/upload.c index 2ef8bc5..25fefaf 100644 --- a/examples/upload.c +++ b/examples/upload.c @@ -1,15 +1,17 @@ #include #include #include +#include #include #include #include void tempfile_callback(struct magi_file * file, - char * buffer, - int len, - void * _) + char * addon, + int addon_len, + int is_addon_last, + void * unused) { if (!strcmp(file->param_name, "data")) { static FILE * f = 0; @@ -17,10 +19,10 @@ void tempfile_callback(struct magi_file * file, remove(file->param_name); f = fopen(file->param_name, "wb"); } - if (len) { - fwrite(buffer, 1, len, f); + if (addon_len) { + fwrite(addon, 1, addon_len, f); } - if (len < magi_file_callback_portion_max) { + if (is_addon_last) { fclose(f); f = 0; } @@ -30,7 +32,7 @@ void tempfile_callback(struct magi_file * file, void response_request(struct magi_request * req, struct magi_response * res) { magi_response_content_type(res, magi_xhtml); - magi_response_content( + magi_response_add( res, "" "" @@ -45,8 +47,8 @@ void response_request(struct magi_request * req, struct magi_response * res) "" ""); - struct magi_field * name = magi_field_list_get(req->fields, "name"); - struct magi_field * data = magi_field_list_get(req->fields, "data"); + struct magi_param * name = magi_param_list_get(req->params, "name"); + struct magi_param * data = magi_param_list_get(req->params, "data"); if (name && name->data && data) { rename("data", name->data); } @@ -55,13 +57,15 @@ void response_request(struct magi_request * req, struct magi_response * res) int main(int argc, char const * argv[]) { struct magi_request request; - if (magi_cgi(&request, tempfile_callback, 0, 0)) { + magi_request_setup(&request); + request.file_callback = tempfile_callback; + if (magi_request_cgi(&request)) { struct magi_response response; response_request(&request, &response); - magi_cgi_response(&response); + magi_response_cgi(&response); magi_response_destroy(); } else { - magi_cgi_error(request.error); + magi_error_cgi(request.error); } magi_request_destroy(&request); return 0; diff --git a/src/cgi.h b/src/cgi.h index ee818ac..6cca424 100644 --- a/src/cgi.h +++ b/src/cgi.h @@ -1,23 +1,17 @@ #ifndef MAGI_INCLUDED_CGI #define MAGI_INCLUDED_CGI -#include "field.h" #include "request.h" -/* - * Constructs request using environment variables and standart I/O; - * Returns null if succeed, otherwise error code. - */ -int magi_cgi(struct magi_request * request, - /* Callback will be used only for fields loaded via multipart. */ - /* Null callback disables callback system. */ - void (*callback)(struct magi_field * field, - char * buffer, - int len, - void * thing), - void * thing, - int max_post); +/* Constructs request from environment and standard input; + * Returns null only in case of error. */ +int magi_request_cgi(struct magi_request * request); + + +/* Sends response to standard output; + * Returns null only in case of error. */ +int magi_response_cgi(struct magi_response * response); #endif diff --git a/src/cookie.h b/src/cookie.h index 7a7365e..479ab9f 100644 --- a/src/cookie.h +++ b/src/cookie.h @@ -6,40 +6,29 @@ * Cookie */ struct magi_cookie { - char * name; /* name: free(name) is valid. */ - char * data; /* data: free(data) is valid. */ - /* Following is used in Cookie2: */ - char * path; /* path: free(path) is valid. */ - char * domain; /* domain: free(domain) is valid. */ - char * port; /* port: free(port) is valid. */ + char * name; + char * data; + char * path; + char * domain; + char * port; }; -/* Null is valid "struct magi_cookie_list *" object. */ struct magi_cookie_list { struct magi_cookie_list * next; struct magi_cookie item; }; -/* Returns null in case of error. */ -int magi_parse_cookie(struct magi_cookie_list ** list, const char * input); -/* - * Adds *item to the begining of *list, item and list are dereferencable; - * Returns null in case of error. - */ +/* Returns null only in case of error. */ int magi_cookie_list_add(struct magi_cookie_list ** list, struct magi_cookie * item); -/* - * Searchs for first node in list: node.name == name, name is C-string; - * Returns node.data if succeed, otherwise result is null. - */ +/* Searchs for first node in list: node.name == name, name is C-string; + * Returns node.data if succeed, otherwise result is null. */ char * magi_cookie_list_get(struct magi_cookie_list * list, const char * name); -/* - * Destroys list; list is not valid after destruction. - */ -void magi_cookie_list_destroy(struct magi_cookie_list * list); +/* Destroys list. */ +void magi_cookie_list_free(struct magi_cookie_list * list); #endif diff --git a/src/cookies.c b/src/cookies.c new file mode 100644 index 0000000..e69de29 diff --git a/src/cookies.h b/src/cookies.h new file mode 100644 index 0000000..3da16e7 --- /dev/null +++ b/src/cookies.h @@ -0,0 +1,10 @@ +#ifndef MAGI_INCLUDED_COOKIES +#define MAGI_INCLUDED_COOKIES + +#include "cookie.h" + + +void magi_cookies(struct magi_request * request, const char * data); + + +#endif diff --git a/src/error.c b/src/error.c index 4b6f7c2..48c3c36 100644 --- a/src/error.c +++ b/src/error.c @@ -9,7 +9,7 @@ const char * magi_error_message(enum magi_error error) "Content-type is unknown.", /* magi_error_unknown */ "Content-type is not given.", /* magi_error_notype */ "Mismatch of content length.", /* magi_error_length */ - "Cannot allocate memmory.", /* magi_error_memmory */ + "Cannot allocate memory.", /* magi_error_memory */ "Cannot read cookies.", /* magi_error_cookies */ "Cannot decode URL.", /* magi_error_urlenc */ "Cannot read multipart body." /* magi_error_multipart */ diff --git a/src/error.h b/src/error.h index ee1c8a6..46a07cd 100644 --- a/src/error.h +++ b/src/error.h @@ -8,7 +8,7 @@ enum magi_error { magi_error_unknown, magi_error_notype, magi_error_length, - magi_error_memmory, + magi_error_memory, magi_error_cookies, magi_error_urlenc, magi_error_multipart diff --git a/src/fastcgi.h b/src/fastcgi.h index d2199b4..5410955 100644 --- a/src/fastcgi.h +++ b/src/fastcgi.h @@ -1,30 +1,22 @@ #ifndef MAGI_INCLUDED_FASTCGI #define MAGI_INCLUDED_FASTCGI -#include "field.h" +#include "error.h" +#include "file.h" #include "request.h" struct magi_session { - void (*callback)(struct magi_field * field, char * buffer, int len); - int max_post; struct magi_socket_list * sockets; + enum magi_error error; }; -int magi_fcgi(struct magi_session * session, int socket); - -/* - * Returns null if succeed, otherwise error code. - */ -int magi_fcgi_accept( - struct magi_request * request, - struct magi_session * session, - /* Callback will be used only for files loaded via multipart. */ - /* Null callback disables callback system. */ - void (*callback)( - struct magi_field * field, char * buffer, int len, void * thing), - void * thing, - int max_post); +int magi_session_fcgi(struct magi_session * session, int socket); + + +/* Returns null only in case of error. */ +int magi_request_fcgi(struct magi_request * request, + struct magi_session * session); #endif diff --git a/src/file.h b/src/file.h index e69de29..0994755 100644 --- a/src/file.h +++ b/src/file.h @@ -0,0 +1,11 @@ +#ifndef MAGI_INCLUDED_FILE +#define MAGI_INCLUDED_FILE + + +struct magi_file { + char * param_name; + struct magi_para_list * params; +}; + + +#endif diff --git a/src/multipart.c b/src/multipart.c index 6ab1258..c3e4a2d 100644 --- a/src/multipart.c +++ b/src/multipart.c @@ -485,13 +485,10 @@ static int run_automata(struct automata * a, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Automata Interfaces */ -int magi_parse_multipart(struct magi_field_list ** list, - int (*get_next)(void *), - void * get_next_arg, - char * boundary, - void (*callback)(struct magi_field * field, - char * buffer, - int len)) +int magi_parse_multipart(struct magi_request * request, + char * boundary, + int (*get_next)(void * userdata), + void * get_next_userdata) { struct automata a = { 0, { 0, 0, 0 }, { 0, 0 }, 0, 0, 1, 0, 0, 2, 0, 0, 0 diff --git a/src/multipart.h b/src/multipart.h index bb51d5c..47cfefe 100644 --- a/src/multipart.h +++ b/src/multipart.h @@ -1,22 +1,13 @@ #ifndef MAGI_INCLUDED_MULTIPART #define MAGI_INCLUDED_MULTIPART -#include "field.h" +#include "request.h" -enum { magi_parse_multipart_callback_size = 64 }; - - -int magi_parse_multipart( - struct magi_field_list ** list, - int (*get_next)(void *), - void * get_next_arg, - char * boundary, - /* End if size < magi_parse_multipart_callback_size. */ - /* Null callback means skipping. */ - void (*callback)( - struct magi_file * file, char * buffer, int size, void * thing), - void * thing); +void magi_multipart(struct magi_request * request, + char * boundary, + int (*next)(void * userdata), + void * next_userdata); #endif diff --git a/src/param.h b/src/param.h index 21e9538..6fd0ba0 100644 --- a/src/param.h +++ b/src/param.h @@ -5,36 +5,28 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Parameter */ -enum { magi_param_max = 1024 }; - struct magi_param { - char * name; /* name: free(name) is valid. */ - char * data; /* data: free(data) is valid. */ + char * name; + char * data; }; -/* Null is valid "struct magi_param_list *" object. */ struct magi_param_list { struct magi_param_list * next; struct magi_param item; }; -/* - * Adds *item to the begining of *list, item and list are dereferencable; - * Returns null in case of error. - */ + +/* Adds *item to the begining of *list, item and list are dereferencable; + * Returns null in case of error. */ int magi_param_list_add(struct magi_param_list ** list, struct magi_param * item); -/* - * Searchs for first node in list: node.name == name, name is C-string; - * Returns node itself if succeed, otherwise result is null. - */ +/* Searchs for first node in list: node.name == name, name is C-string; + * Returns node itself if succeed, otherwise result is null. */ struct magi_param * magi_param_list_get(struct magi_param_list * list, const char * name); -/* - * Destroys list; list is not valid after destruction. - */ +/* Destroys list; list is not valid after destruction. */ void magi_param_list_destroy(struct magi_param_list * list); diff --git a/src/request.c b/src/request.c index 73c4730..2d9625e 100644 --- a/src/request.c +++ b/src/request.c @@ -1,35 +1,79 @@ #include "request.h" #include "cookie.h" -#include "field.h" +#include "file.h" #include "param.h" #include -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Common Request Handling - */ +void magi_request_setup(struct magi_request * request) +{ + if (request) { + request->file_callback = 0; + request->file_callback_userdata = 0; + request->file_callback_addon_len_max = 64; + request->max_cookies_size = 0; + request->max_http_params_size = 0; + request->max_params_size = 0; + } +} + + +static void request_free(struct magi_request * request) +{ + free(request->cookies); + free(request->http_params); + free(request->url_params); + free(request->params); + 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); +} + +void magi_request_annul(struct 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; +} + void magi_request_destroy(struct magi_request * request) { if (request) { - magi_field_list_destroy(request->fields); magi_cookie_list_destroy(request->cookies); - free(request->fields); - free(request->cookies); - 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); magi_param_list_destroy(request->http_params); - free(request->http_params); + magi_param_list_destroy(request->url_params); + magi_param_list_destroy(request->params); + magi_file_list_destroy(request->files); + request_free(request); + request_annul(request); } } diff --git a/src/request.h b/src/request.h index d74dced..15a5da6 100644 --- a/src/request.h +++ b/src/request.h @@ -2,7 +2,8 @@ #define MAGI_INCLUDED_REQUEST #include "cookie.h" -#include "field.h" +#include "error.h" +#include "file.h" #include "param.h" @@ -10,52 +11,71 @@ * Request * * Can be generated via CGI handler (magi_cgi_request) or - * as session in Fast CGI (magi_fcgi_request). + * in a Fast CGI session (magi_fcgi_request). * - * Example: http://example.com/cgi-bin/script/foo/bar?var2=url%20enc - * method: get - * uri: /cgi-bin/script/foo/bar?var2=url%20enc - * document_root: { absolute path to root directory of domain } - * document_uri: /cgi-bin/script/foo/bar - * script_name: /cgi-bin/script - * script_filename: { absolute path to script on server machine } - * remote_addr: { client IP } - * remote_port: { client port } - * server_addr: { server IP } - * server_name: example.com - * (^ Better to use http_params["HTTP_HOST"] -- server_name can be IP too.) - * server_port: 80 - * server_protocol: http/1.1 - * server_software: { name of web server software } - * path_info: /foo/bar + * + * Request URL: http[s]://{server_name}[:{server_port}]{uri} + * example.com 80 + * uri: {document_uri}[?{urlencode(url_params)}] + * alfar=9973&veles=on + * document_uri: {script_name}{path_info} + * /bin/script /article/magic */ struct magi_request { - struct magi_param_list * url_params; - struct magi_param_list * params; - struct magi_file_list * files; + /* * * Results * * */ + + /* Parsed */ struct magi_cookie_list * cookies; - char * method; - char * uri; - char * document_root; - char * document_uri; - char * script_name; - char * script_filename; - char * remote_addr; - char * remote_port; - char * server_addr; - char * server_name; - char * server_port; - char * server_protocol; - char * server_software; - char * path_info; - struct magi_param_list * http_params; - enum magi_error error; + struct magi_param_list * http_params; /* HTTP Header parameters */ + struct magi_param_list * url_params; /* Urlencoded paramteres from URL */ + struct magi_param_list * params; /* Parameters from 'post' body */ + struct magi_file_list * files; /* Files loaded via multipart */ + + /* Environment Shortcuts */ + char * method; /* REQUEST_METHOD */ + char * uri; /* REQUEST_URI */ + char * document_root; /* DOCUMENT_ROOT */ + char * document_uri; /* DOCUMENT_URI */ + char * script_name; /* SCRIPT_NAME */ + char * script_filename; /* SCRIPT_FILENAME */ + char * remote_addr; /* REMOTE_ADDR */ + char * remote_port; /* REMOTE_PORT */ + char * server_addr; /* SERVER_ADDR */ + /* Following can be not a domain name, even if request is done with it. + * (Use http_params["HTTP_HOST"] instead.) */ + char * server_name; /* SERVER_NAME */ + char * server_port; /* SERVER_PORT */ + char * server_protocol; /* SERVER_PROTOCOL */ + char * server_software; /* SERVER_COFTWARE */ + char * path_info; /* PATH_INFO */ + + /* Request Error Code */ + enum magi_error error; + + + /* * * Internal Data (no need for user to analyse) * * */ + + /* Callback for processing files */ + void (*file_callback)(struct magi_file * file, + char * addon, + int addon_len, + int is_addon_last, + void * userdata); + void * file_callback_userdata; + int file_callback_addon_len_max; + + /* Limit for memory used (disables with zero) */ + int max_cookies_size; + int max_http_params_size; + int max_params_size; }; -/* - * Destroys request; request is not valid after destruction. - */ +/* Setup request with default settings. */ +void magi_request_setup(struct magi_request * request); + + +/* Destroys request. */ void magi_request_destroy(struct magi_request * request); diff --git a/src/response.h b/src/response.h index e69de29..04d7350 100644 --- a/src/response.h +++ b/src/response.h @@ -0,0 +1,36 @@ +#ifndef MAGI_INCLUDED_RESPONSE +#define MAGI_INCLUDED_RESPONSE + +#include "error.h" + + +enum magi_content_type { magi_xhtml }; + +struct magi_response { + struct magi_cookie_list * cookies; + struct magi_param_list * http_params; + struct magi_param_list * url_params; + char * content_type; + char * content; +}; + +void magi_response_content_type(struct magi_response * response, + enum magi_content_type type); + +void magi_reponse_add(struct magi_response * response, const char * addon); +void magi_reponse_add_format(struct magi_response * response, + const char * addon, + ...); + +void magi_response_cookie(struct magi_response * response, + const struct magi_cookie * cookie); + +void magi_response_cookie_easy(struct magi_response * response, + const char * name, + const char * value); + +void magi_response_cookie_delete(struct magi_response * response, + const char * name); + + +#endif diff --git a/src/urlenc.c b/src/urlenc.c new file mode 100644 index 0000000..336dde0 --- /dev/null +++ b/src/urlenc.c @@ -0,0 +1,187 @@ +#include "urlencoded.h" + +#include "error.h" +#include "field.h" +#include +#include +#include + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local Shortcuts + */ +/* Shouldn't be called with 'c' as not hex digit. */ +static char from_hex(char c) +{ + char num; + if (isdigit(c)) { + num = c - '0'; + } else { + num = toupper(c) - 'A' + 10; + } + return num; +} + +static int is_hex(char c) +{ + return isdigit(c) || strchr("ABCDEF", toupper(c)); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * URL Decoding + */ +static int deurl(char ** data) +{ + int ok = 1; + if (*data) { + char * val = *data; + int ti = 0; + int ci; + for (ci = 0; ok && val[ci]; ++ti, ++ci) { + if (val[ci] == '%') { + if (is_hex(val[ci + 1]) && is_hex(val[ci + 2])) { + /* Since chars can be signed, arithmetics are not safe. */ + val[ti] = from_hex(val[ci + 2]); /* 00xx */ + val[ti] |= from_hex(val[ci + 1]) << 4; /* XXxx */ + ci += 2; + } else { + ok = 0; + magi_error_set( + "[urlencoded] Waiting for two hex digits after '%%', " + "readed: \\%o\\%o (render: %c%c)", + val[ci + 1], val[ci + 2], val[ci + 1], val[ci + 2]); + } + } else if (val[ci] == '+') { + val[ti] = ' '; + } else { + val[ti] = val[ci]; + } + } + val[ti++] = 0; + } else { + *data = malloc(1); + **data = 0; + } + return ok; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Urlencoded Automata + */ +enum st { st_error = 0, st_name, st_data }; + +struct automata { + struct magi_field_list ** list; + struct magi_field field; + int size; + int len; +}; + + +static enum st parse_name(struct automata * a, char c) +{ + enum st state; + if (c != '&' && c != ';') { + if (c == '=') { + state = st_data; + a->size = 1; + a->len = 0; + } else { + if (a->len == a->size - 1) { + a->size *= 2; + a->field.name = realloc(a->field.name, a->size); + } + if (!a->field.name) { + state = st_error; + magi_error_set("[urlencoded] Cannot allocate field name."); + } else { + state = st_name; + a->len++; + a->field.name[a->len - 1] = c; + a->field.name[a->len] = 0; + } + } + } else { + state = st_error; + magi_error_set("[urlencoded] Reading name, readed: \\%o (render: %c).", + c, c); + } + return state; +} + +static enum st end_data(struct automata * a) +{ + enum st state = st_error; + if (deurl(&a->field.name) && deurl(&a->field.data)) { + a->field.len = strlen(a->field.data); + if (magi_field_list_add(a->list, &a->field)) { + state = st_name; + a->size = 1; + a->len = 0; + a->field.name = 0; + a->field.data = 0; + } + } + return state; +} + +static enum st parse_data(struct automata * a, char c) +{ + enum st state; + if (c != '=') { + if (c == '&' || c == ';') { + state = end_data(a); + } else { + if (a->len == a->size - 1) { + a->size *= 2; + a->field.data = realloc(a->field.data, a->size); + } + if (!a->field.data) { + state = st_error; + magi_error_set("[urlencoded] Cannot allocate field data."); + } else { + state = st_data; + a->len++; + a->field.data[a->len - 1] = c; + a->field.data[a->len] = 0; + } + } + } else { + state = st_error; + magi_error_set("[urlencoded] Reading data, readed: \\%o (render: %c).", + c, c); + } + return state; +} + +int magi_parse_urlencoded(struct magi_field_list ** list, const char * input) +{ + enum st state = st_name; + struct automata a = { 0, { 0, 0, 0 }, 1, 0 }; + if (input && *input) { + a.list = list; + while (state && *input) { + switch (state) { + case st_name: + state = parse_name(&a, *input); + break; + case st_data: + state = parse_data(&a, *input); + default: + break; + } + ++input; + } + if (state == st_data) { + state = end_data(&a); + } else if (state == st_name) { + state = st_error; + magi_error_set("[urlencoded] Input ended while reading name."); + } + free(a.field.name); + free(a.field.data); + } + return state != st_error; +} diff --git a/src/urlenc.h b/src/urlenc.h new file mode 100644 index 0000000..9c14ccb --- /dev/null +++ b/src/urlenc.h @@ -0,0 +1,13 @@ +#ifndef MAGI_INCLUDED_URLENC +#define MAGI_INCLUDED_URLENC + +#include "request.h" + + +void magi_urlenc(struct magi_request * request, const char * encoded); + +int magi_urlenc_size(const char * plain); +void magi_urlencode(const char * plain, char * code); + + +#endif diff --git a/src/urlencoded.c b/src/urlencoded.c deleted file mode 100644 index 336dde0..0000000 --- a/src/urlencoded.c +++ /dev/null @@ -1,187 +0,0 @@ -#include "urlencoded.h" - -#include "error.h" -#include "field.h" -#include -#include -#include - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Local Shortcuts - */ -/* Shouldn't be called with 'c' as not hex digit. */ -static char from_hex(char c) -{ - char num; - if (isdigit(c)) { - num = c - '0'; - } else { - num = toupper(c) - 'A' + 10; - } - return num; -} - -static int is_hex(char c) -{ - return isdigit(c) || strchr("ABCDEF", toupper(c)); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * URL Decoding - */ -static int deurl(char ** data) -{ - int ok = 1; - if (*data) { - char * val = *data; - int ti = 0; - int ci; - for (ci = 0; ok && val[ci]; ++ti, ++ci) { - if (val[ci] == '%') { - if (is_hex(val[ci + 1]) && is_hex(val[ci + 2])) { - /* Since chars can be signed, arithmetics are not safe. */ - val[ti] = from_hex(val[ci + 2]); /* 00xx */ - val[ti] |= from_hex(val[ci + 1]) << 4; /* XXxx */ - ci += 2; - } else { - ok = 0; - magi_error_set( - "[urlencoded] Waiting for two hex digits after '%%', " - "readed: \\%o\\%o (render: %c%c)", - val[ci + 1], val[ci + 2], val[ci + 1], val[ci + 2]); - } - } else if (val[ci] == '+') { - val[ti] = ' '; - } else { - val[ti] = val[ci]; - } - } - val[ti++] = 0; - } else { - *data = malloc(1); - **data = 0; - } - return ok; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Urlencoded Automata - */ -enum st { st_error = 0, st_name, st_data }; - -struct automata { - struct magi_field_list ** list; - struct magi_field field; - int size; - int len; -}; - - -static enum st parse_name(struct automata * a, char c) -{ - enum st state; - if (c != '&' && c != ';') { - if (c == '=') { - state = st_data; - a->size = 1; - a->len = 0; - } else { - if (a->len == a->size - 1) { - a->size *= 2; - a->field.name = realloc(a->field.name, a->size); - } - if (!a->field.name) { - state = st_error; - magi_error_set("[urlencoded] Cannot allocate field name."); - } else { - state = st_name; - a->len++; - a->field.name[a->len - 1] = c; - a->field.name[a->len] = 0; - } - } - } else { - state = st_error; - magi_error_set("[urlencoded] Reading name, readed: \\%o (render: %c).", - c, c); - } - return state; -} - -static enum st end_data(struct automata * a) -{ - enum st state = st_error; - if (deurl(&a->field.name) && deurl(&a->field.data)) { - a->field.len = strlen(a->field.data); - if (magi_field_list_add(a->list, &a->field)) { - state = st_name; - a->size = 1; - a->len = 0; - a->field.name = 0; - a->field.data = 0; - } - } - return state; -} - -static enum st parse_data(struct automata * a, char c) -{ - enum st state; - if (c != '=') { - if (c == '&' || c == ';') { - state = end_data(a); - } else { - if (a->len == a->size - 1) { - a->size *= 2; - a->field.data = realloc(a->field.data, a->size); - } - if (!a->field.data) { - state = st_error; - magi_error_set("[urlencoded] Cannot allocate field data."); - } else { - state = st_data; - a->len++; - a->field.data[a->len - 1] = c; - a->field.data[a->len] = 0; - } - } - } else { - state = st_error; - magi_error_set("[urlencoded] Reading data, readed: \\%o (render: %c).", - c, c); - } - return state; -} - -int magi_parse_urlencoded(struct magi_field_list ** list, const char * input) -{ - enum st state = st_name; - struct automata a = { 0, { 0, 0, 0 }, 1, 0 }; - if (input && *input) { - a.list = list; - while (state && *input) { - switch (state) { - case st_name: - state = parse_name(&a, *input); - break; - case st_data: - state = parse_data(&a, *input); - default: - break; - } - ++input; - } - if (state == st_data) { - state = end_data(&a); - } else if (state == st_name) { - state = st_error; - magi_error_set("[urlencoded] Input ended while reading name."); - } - free(a.field.name); - free(a.field.data); - } - return state != st_error; -} diff --git a/src/urlencoded.h b/src/urlencoded.h deleted file mode 100644 index 838ae57..0000000 --- a/src/urlencoded.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MAGI_INCLUDED_URLENCODED -#define MAGI_INCLUDED_URLENCODED - -#include "field.h" - - -int magi_parse_urlencoded(struct magi_field_list ** list, const char * input); - - -#endif diff --git a/src/utils.c b/src/utils.c index 01969a2..29e8219 100644 --- a/src/utils.c +++ b/src/utils.c @@ -22,8 +22,6 @@ char * magi_str_create_copy(const char * begin, const char * end) if (res) { memcpy(res, begin, end - begin); res[end - begin] = 0; - } else { - magi_error_set("Cannot allocate string."); } return res; } @@ -33,26 +31,21 @@ char * magi_str_create(int len) char * str = malloc(len + 1); if (str) { str[len] = 0; - } else { - magi_error_set("Cannot allocate string."); } return str; } -int magi_str_add(char ** dest, int * len, int * size, char c) +char * magi_str_add(char * dest, int * len, int * size, char c) { int ok = 1; if (*len + 1 == *size) { *size *= 2; - *dest = realloc(*dest, *size); + dest = realloc(dest, *size); } - if (*dest == 0) { - ok = 0; - magi_error_set("Cannot allocate string."); - } else { - (*dest)[*len] = c; + if (dest) { + dest[*len] = c; ++*len; - (*dest)[*len] = 0; + dest[*len] = 0; } - return ok; + return dest; } diff --git a/src/utils.h b/src/utils.h index fa7db40..15904d0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,7 +5,7 @@ void magi_str_lowercase(char * str); char * magi_str_create_copy(const char * begin, const char * end); char * magi_str_create(int len); -int magi_str_add(char ** dest, int * len, int * size, char c); +char * magi_str_add(char * dest, int * len, int * size, char c); #endif -- cgit v1.2.3