diff options
-rw-r--r-- | examples/append.c | 25 | ||||
-rw-r--r-- | examples/cookie.c | 37 | ||||
-rw-r--r-- | examples/echo.c | 69 | ||||
-rw-r--r-- | examples/fcgi.c | 6 | ||||
-rw-r--r-- | examples/upload.c | 53 | ||||
-rw-r--r-- | src/cgi.c | 38 | ||||
-rw-r--r-- | src/cgi.h | 15 | ||||
-rw-r--r-- | src/cookie.h | 34 | ||||
-rw-r--r-- | src/cookies.h | 10 | ||||
-rw-r--r-- | src/error.h | 6 | ||||
-rw-r--r-- | src/file.h | 25 | ||||
-rw-r--r-- | src/inner_cookies.c (renamed from src/cookies.c) | 2 | ||||
-rw-r--r-- | src/inner_cookies.h | 10 | ||||
-rw-r--r-- | src/inner_multipart.c (renamed from src/multipart.c) | 2 | ||||
-rw-r--r-- | src/inner_multipart.h | 13 | ||||
-rw-r--r-- | src/inner_urlencoded.c | 144 | ||||
-rw-r--r-- | src/inner_urlencoded.h | 13 | ||||
-rw-r--r-- | src/magi.h | 16 | ||||
-rw-r--r-- | src/multipart.h | 13 | ||||
-rw-r--r-- | src/param.h | 24 | ||||
-rw-r--r-- | src/request.h | 102 | ||||
-rw-r--r-- | src/response.c | 64 | ||||
-rw-r--r-- | src/response.h | 47 | ||||
-rw-r--r-- | src/urlenc.c | 135 | ||||
-rw-r--r-- | src/urlenc.h | 13 |
25 files changed, 475 insertions, 441 deletions
diff --git a/examples/append.c b/examples/append.c index cb49e50..702f0fb 100644 --- a/examples/append.c +++ b/examples/append.c @@ -1,22 +1,18 @@ -#include <cgi.h> -#include <request.h> -#include <response.h> +#include <magi.h> #include <stdio.h> #include <stdlib.h> -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res) { - char * data = magi_param_list_get(req->params, "addon"); + char *data = magi_param_list_get(req->params, "addon"); if (data) { - FILE * file = fopen("file_to_append", "a"); + FILE *file = fopen("file_to_append", "a"); fputs(data, file); fclose(file); } - magi_response_content_type(res, magi_xhtml); - magi_response_add( - res, + magi_response_add(res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" "<html xmlns='http://www.w3.org/1999/xhtml'>" @@ -30,16 +26,15 @@ void response_request(struct magi_request * req, struct magi_response * res) "</html>"); } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[]) { - struct magi_request request; + magi_request request; magi_request_setup(&request); - if (magi_request_cgi(&request) && magi_request_resume_cgi(&request)) { - struct magi_response response; + if (magi_request_full_cgi(&request)) { + magi_response response; magi_response_setup(&response); response_request(&request, &response); - magi_response_cgi(&response); - magi_response_destroy(&response); + magi_response_cgi_clear(&response); } else { magi_error_cgi(request.error); } diff --git a/examples/cookie.c b/examples/cookie.c index bb1e1d1..365f989 100644 --- a/examples/cookie.c +++ b/examples/cookie.c @@ -1,26 +1,22 @@ -#include <cgi.h> -#include <cookie.h> -#include <request.h> -#include <response.h> +#include <magi.h> #include <stdio.h> #include <stdlib.h> -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res) { - struct magi_cookie_list * current; + magi_cookie_list *current; - magi_response_content_type(res, magi_xhtml); - magi_response_add( - res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " - "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" - "<html xmlns='http://www.w3.org/1999/xhtml'>" - "<head><title>Cookie Listing and Setting</title></head>" - "<body>"); + magi_response_add(res, + "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " + "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" + "<html xmlns='http://www.w3.org/1999/xhtml'>" + "<head><title>Cookie Listing and Setting</title></head>" + "<body>"); for (current = req->cookies; current; current = current->next) { - magi_response_add_format(res, "[%s] = [%s]<br/>", current->item.name, - current->item.data); + magi_response_add_format(res, + "[%s] = [%s]<br/>", current->item.name, current->item.data); } magi_response_add(res, "</body></html>"); @@ -28,16 +24,15 @@ void response_request(struct magi_request * req, struct magi_response * res) magi_response_cookie_easy(res, "cookie", "monster"); } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[]) { - struct magi_request request; + magi_request request; magi_request_setup(&request); - if (magi_request_cgi(&request) && magi_request_resume_cgi(&request)) { - struct magi_response response; + if (magi_request_full_cgi(&request)) { + magi_response response; magi_response_setup(&response); response_request(&request, &response); - magi_response_cgi(&response); - magi_response_destroy(&response); + magi_response_cgi_clear(&response); } else { magi_error_cgi(request.error); } diff --git a/examples/echo.c b/examples/echo.c index e9807f0..81bdcf4 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -1,16 +1,10 @@ -#include <cgi.h> -#include <cookie.h> -#include <param.h> -#include <request.h> -#include <response.h> +#include <magi.h> #include <stdio.h> #include <stdlib.h> -void proceed_cookies(struct magi_cookie_list * cookies, - struct magi_response * response) +void proceed_cookies(magi_cookie_list *cookies, magi_response *response) { - magi_response_add(response, "<h2>Cookies:</h2>"); while (cookies) { magi_response_add(response, "Cookie with name ["); magi_response_add(response, cookies->item.name); @@ -33,36 +27,30 @@ void proceed_cookies(struct magi_cookie_list * cookies, magi_response_add(response, "]<br/>"); cookies = cookies->next; } - magi_response_add(response, "<hr/>"); } -void proceed_params(struct magi_param_list * params, - struct magi_response * response) +void proceed_params(magi_param_list *params, magi_response *response) { while (params) { - magi_response_add_format(response, "[%s] is [%s]<br/>", - params->item.name, params->item.data); + magi_response_add_format(response, + "[%s] is [%s]<br/>", params->item.name, params->item.data); params = params->next; } - magi_response_add(response, "<hr/>"); } -void proceed_files(struct magi_file_list * files, - struct magi_response * response) +void proceed_files(magi_file_list *files, magi_response *response) { while (files) { - magi_response_add_format(response, "[%s] was [%s] on userside<br/>", - files->item.param_name, - files->item.file_name); + magi_file f = files->item; + magi_response_add_format(response, + "[%s] was [%s] on userside<br/>", f.param_name, f.file_name); files = files->next; } - magi_response_add(response, "<hr/>"); } -void process_meta(struct magi_request * req, struct magi_response * res) +void process_meta(magi_request *req, magi_response *res) { - magi_response_add(res, - "<h1>Echo CGI Script</h1>I was called with method ["); + magi_response_add(res, "I was called with method ["); magi_response_add(res, req->method); if (req->uri) { magi_response_add(res, "] with URL ["); @@ -87,38 +75,45 @@ void process_meta(struct magi_request * req, struct magi_response * res) magi_response_add(res, "]<br/>"); } -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res) { - magi_response_content_type(res, magi_xhtml); - magi_response_add( - res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " - "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" - "<html xmlns='http://www.w3.org/1999/xhtml'>" - "<head><title>Echo</title></head>" - "<body>"); + magi_response_add(res, + "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " + "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" + "<html xmlns='http://www.w3.org/1999/xhtml'>" + "<head><title>Echo</title></head>" + "<body>"); + + magi_response_add(res, "<h1>Echo CGI Script</h1>"); process_meta(req, res); + + magi_response_add(res, "<h2>Cookies:</h2>"); proceed_cookies(req->cookies, res); + magi_response_add(res, "<h2>Parameters:</h2>"); proceed_params(req->params, res); + magi_response_add(res, "<h2>URL Parameters:</h2>"); proceed_params(req->url_params, res); + magi_response_add(res, "<h2>HTTP Parameters:</h2>"); proceed_params(req->http_params, res); + magi_response_add(res, "<h2>Files:</h2>"); proceed_files(req->files, res); + magi_response_add(res, "</body></html>"); } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[]) { - struct magi_request request; + magi_request request; magi_request_setup(&request); - if (magi_request_cgi(&request) && magi_request_resume_cgi(&request)) { - struct magi_response response; + if (magi_request_full_cgi(&request)) { + magi_response response; magi_response_setup(&response); response_request(&request, &response); - magi_response_cgi(&response); - magi_response_destroy(&response); + magi_response_cgi_clear(&response); } else { magi_error_cgi(request.error); } diff --git a/examples/fcgi.c b/examples/fcgi.c index 2790f9d..bb5645e 100644 --- a/examples/fcgi.c +++ b/examples/fcgi.c @@ -1,7 +1,5 @@ -#include <error.h> -#include <fastcgi.h> -#include <request.h> -#include <response.h> +/* * * TODO * * */ +#include <magi.h> #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/examples/upload.c b/examples/upload.c index 1947f93..6a3a7a4 100644 --- a/examples/upload.c +++ b/examples/upload.c @@ -1,50 +1,45 @@ -#include <cgi.h> -#include <multipart.h> -#include <request.h> -#include <response.h> +#include <magi.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -void response_request(struct magi_request * req, struct magi_response * res) +void response_request(magi_request *req, magi_response *res) { - char * name = magi_param_list_get(req->params, "name"); - struct magi_file * data = magi_file_list_get(req->files, "data"); + 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_content_type(res, magi_xhtml); - magi_response_add( - res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " - "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" - "<html xmlns='http://www.w3.org/1999/xhtml'>" - "<head><title>Upload File</title></head>" - "<body>" - "<form action='/cgi-bin/upload' method='post' " - "enctype='multipart/form-data'><fieldset>" - "<input type='text' name='name' value='filename'/>" - "<input type='file' name='data'/>" - "<input type='submit' value='Upload'/>" - "</fieldset></form>" - "</body>" - "</html>"); + magi_response_add(res, + "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " + "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" + "<html xmlns='http://www.w3.org/1999/xhtml'>" + "<head><title>Upload File</title></head>" + "<body>" + "<form action='/cgi-bin/upload' method='post' " + "enctype='multipart/form-data'><fieldset>" + "<input type='text' name='name' value='filename'/>" + "<input type='file' name='data'/>" + "<input type='submit' value='Upload'/>" + "</fieldset></form>" + "</body>" + "</html>"); } -int main(int argc, char const * argv[]) +int main(int argc, char const *argv[]) { - struct magi_request request; - struct magi_tempfiles tmps = { 0, 0, 0, 0 }; + 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_cgi(&request) && magi_request_resume_cgi(&request)) { - struct magi_response response; + if (magi_request_full_cgi(&request)) { + magi_response response; magi_response_setup(&response); response_request(&request, &response); - magi_response_cgi(&response); - magi_response_destroy(&response); + magi_response_cgi_clear(&response); } else { magi_error_cgi(request.error); } @@ -1,14 +1,14 @@ #include "cgi.h" #include "cookie.h" -#include "cookies.h" #include "error.h" #include "file.h" -#include "multipart.h" +#include "inner_cookies.h" +#include "inner_multipart.h" +#include "inner_tools.h" +#include "inner_urlencoded.h" #include "param.h" #include "request.h" -#include "urlenc.h" -#include "utils.h" #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -132,7 +132,7 @@ static void cgi_url(struct magi_request * request) char * in = 0; cgi_input_get(&request->error, &in, request->url_params_max); if (!request->error) { - magi_urlenc(&request->url_params, request, in); + magi_urlencoded(&request->url_params, request, in); } free(in); } @@ -218,7 +218,7 @@ int magi_request_resume_cgi(struct magi_request * request) char * in = 0; cgi_input_post(e, &in, request->params_max); if (!*e) { - magi_urlenc(&request->params, request, in); + magi_urlencoded(&request->params, request, in); } free(in); } else { @@ -229,6 +229,11 @@ int magi_request_resume_cgi(struct magi_request * request) return !request->error; } +int magi_request_full_cgi(magi_request *request) +{ + return magi_request_cgi(request) && magi_request_resume_cgi(request); +} + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CGI Response @@ -268,6 +273,7 @@ void output_cookies(struct magi_cookie_list * list) } } + int magi_response_cgi(struct magi_response * response) { output_http_params(response->http_params); @@ -278,14 +284,20 @@ int magi_response_cgi(struct magi_response * response) return 1; } +int magi_response_cgi_clear(magi_response *response) +{ + int ok = magi_response_cgi(response); + magi_response_destroy(response); + return ok; +} + + int magi_error_cgi(enum magi_error error) { struct magi_response res; magi_response_setup(&res); magi_response_http(&res, "Status", "400 Bad Request"); - magi_response_content_type(&res, magi_xhtml); - magi_response_add_format( - &res, + magi_response_add_format(&res, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" "<html xmlns='http://www.w3.org/1999/xhtml'>" @@ -296,11 +308,5 @@ int magi_error_cgi(enum magi_error error) "</body>" "</html>", magi_error_message(error)); - if (magi_response_cgi(&res)) { - magi_response_destroy(&res); - return 1; - } else { - magi_response_destroy(&res); - return 0; - } + return magi_response_cgi_clear(&res); } @@ -8,20 +8,27 @@ /* Constructs non-post part of request from environment; * Returns null only in case of error. */ -int magi_request_cgi(struct magi_request * request); +int magi_request_cgi(magi_request *request); /* Complete request with post data from standard input; * Returns null only in case of error. */ -int magi_request_resume_cgi(struct magi_request * request); +int magi_request_resume_cgi(magi_request *request); + +/* Shortcut for applying both previous. */ +int magi_request_full_cgi(magi_request *request); /* Sends response to standard output; * Returns null only in case of error. */ -int magi_response_cgi(struct magi_response * response); +int magi_response_cgi(magi_response *response); + +/* Shortcut for magi_response_cgi with desctruction after it. */ +int magi_response_cgi_clear(magi_response *response); + /* Sends a standart response of Bad Request error to standard output; * Returns null only in case of error. */ -int magi_error_cgi(enum magi_error error); +int magi_error_cgi(magi_error error); #endif diff --git a/src/cookie.h b/src/cookie.h index 82c914e..7eb3e9d 100644 --- a/src/cookie.h +++ b/src/cookie.h @@ -2,31 +2,31 @@ #define MAGI_INCLUDED_COOKIE -struct magi_cookie { +typedef struct magi_cookie { /* All pointers must be valid as 'free' arguments. */ - char * name; - char * data; - char * path; - char * domain; - char * port; -}; + 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. */ +} magi_cookie; -struct magi_cookie_list { - struct magi_cookie_list * next; /* Must be valid as 'free' arguments. */ - struct magi_cookie item; -}; +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(struct magi_cookie_list ** list, - struct magi_cookie * item); +int magi_cookie_list_add(magi_cookie_list **list, magi_cookie *item); -/* First node in list: node.name == name; else null. */ -struct magi_cookie * magi_cookie_list_get(struct magi_cookie_list * list, - const char * name); +/* 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(struct magi_cookie_list * list); +void magi_cookie_list_destroy(magi_cookie_list *list); #endif diff --git a/src/cookies.h b/src/cookies.h deleted file mode 100644 index 98b2ada..0000000 --- a/src/cookies.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MAGI_INCLUDED_COOKIES -#define MAGI_INCLUDED_COOKIES - -#include "request.h" - - -void magi_cookies(struct magi_request * request, const char * data); - - -#endif diff --git a/src/error.h b/src/error.h index f8f0aed..4a91962 100644 --- a/src/error.h +++ b/src/error.h @@ -2,7 +2,7 @@ #define MAGI_INCLUDED_ERROR -enum magi_error { +typedef enum magi_error { magi_error_none = 0, magi_error_nobound, magi_error_unknown, @@ -13,9 +13,9 @@ enum magi_error { magi_error_urlenc, magi_error_multipart, magi_error_limit -}; +} magi_error; -const char * magi_error_message(enum magi_error error); +const char *magi_error_message(magi_error error); #endif @@ -4,28 +4,27 @@ #include "param.h" -struct magi_file { +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 */ - struct magi_param_list * params; /* Multipart params (e.g. type) */ -}; + 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) */ +} magi_file; -struct magi_file_list { - struct magi_file_list * next; /* Must be valid as 'free' argument. */ - struct magi_file item; -}; +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(struct magi_file_list ** list, struct magi_file * item); +int magi_file_list_add(magi_file_list **list, magi_file *item); /* First node in list: node.param_name == name; else null. */ -struct magi_file * magi_file_list_get(struct magi_file_list * list, - const char * name); +magi_file *magi_file_list_get(magi_file_list *list, const char *name); /* Freeing and invalidation of list. */ -void magi_file_list_destroy(struct magi_file_list * list); +void magi_file_list_destroy(magi_file_list *list); #endif diff --git a/src/cookies.c b/src/inner_cookies.c index 4cbe659..d9035c4 100644 --- a/src/cookies.c +++ b/src/inner_cookies.c @@ -1,5 +1,5 @@ /* * * TODO * * */ -#include "cookies.h" +#include "inner_cookies.h" #include "utils.h" #include <stdlib.h> diff --git a/src/inner_cookies.h b/src/inner_cookies.h new file mode 100644 index 0000000..c336cf7 --- /dev/null +++ b/src/inner_cookies.h @@ -0,0 +1,10 @@ +#ifndef MAGI_INCLUDED_INNER_COOKIES +#define MAGI_INCLUDED_INNER_COOKIES + +#include "request.h" + + +void magi_cookies(magi_request *request, const char *data); + + +#endif diff --git a/src/multipart.c b/src/inner_multipart.c index 7b829d8..65252e5 100644 --- a/src/multipart.c +++ b/src/inner_multipart.c @@ -1,5 +1,5 @@ /* Support for multifile controls are not provided. */ -#include "multipart.h" +#include "inner_multipart.h" #include "error.h" #include "param.h" diff --git a/src/inner_multipart.h b/src/inner_multipart.h new file mode 100644 index 0000000..c3f7b65 --- /dev/null +++ b/src/inner_multipart.h @@ -0,0 +1,13 @@ +#ifndef MAGI_INCLUDED_INNER_MULTIPART +#define MAGI_INCLUDED_INNER_MULTIPART + +#include "request.h" + + +void magi_multipart(magi_request *request, + char *boundary, + int (*next)(void *userdata), + void *next_userdata); + + +#endif diff --git a/src/inner_urlencoded.c b/src/inner_urlencoded.c new file mode 100644 index 0000000..e3ea56a --- /dev/null +++ b/src/inner_urlencoded.c @@ -0,0 +1,144 @@ +#include "inner_urlencoded.h" + +#include "inner_tools.h" +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local Shortcuts + */ +/* Call only if is_hex(c). */ +static int from_hex(char c) +{ + if (isdigit(c)) { + return c - '0'; + } else { + return toupper(c) - 'A' + 10; + } +} + +static int is_hex(char c) +{ + return isdigit(c) || strchr("ABCDEF", toupper(c)); +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * URL Decoding + */ +static int deurl(char ** data) +{ + char * val = *data; + int ti; + int ci; + if (!val) { + *data = malloc(1); + **data = 0; + return 1; + } + for (ti = 0, ci = 0; 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]); /* 0000xxxx */ + val[ti] |= from_hex(val[ci + 1]) << 4; /* XXXXxxxx */ + ci += 2; /* Two extra characters are readed from code. */ + } else { + return 0; + } + } else if (val[ci] == '+') { + val[ti] = ' '; + } else { + val[ti] = val[ci]; + } + } + val[ti] = 0; + return 1; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Urlencoded Automata + */ +enum st { st_error = 0, st_name, st_data }; + +struct automata { + struct magi_param_list ** list; + struct magi_param param; + int size; + int len; +}; + + +static enum st parse_name(struct automata * a, char c) +{ + if (c == '&' || c == ';') { /* Impossible character means error. */ + return st_error; + } + if (c == '=') { /* Separator ends name. */ + a->size = 1; + a->len = 0; + return st_data; + } + + if (!magi_str_add(&a->param.name, &a->len, &a->size, c)) { + return st_error; + } + return st_name; +} + +static enum st end_data(struct automata * a) +{ + if (deurl(&a->param.name) && deurl(&a->param.data)) { + if (magi_param_list_add(a->list, &a->param)) { + a->size = 1; + a->len = 0; + a->param.name = 0; + a->param.data = 0; + return st_name; + } + } + return st_error; +} + +static enum st parse_data(struct automata * a, char c) +{ + if (c == '=') { /* Impossible character means error. */ + return st_error; + } + if (c == '&' || c == ';') { /* Separator ends data. */ + return end_data(a); + } + + if (!magi_str_add(&a->param.data, &a->len, &a->size, c)) { + return st_error; + } + return st_data; +} + +void magi_urlencoded(struct magi_param_list ** list, + struct magi_request * request, + const char * encoded) +{ + enum st state; + struct automata a = { 0, { 0, 0 }, 1, 0 }; + a.list = list; + *list = 0; + if (!encoded || !*encoded) { + return; + } + for (state = st_name; state && *encoded; ++encoded) { + if (state == st_name) { + state = parse_name(&a, *encoded); + } else { + state = parse_data(&a, *encoded); + } + } + if (state == st_name || !state || !end_data(&a)) { + free(a.param.name); + free(a.param.data); + request->error = magi_error_urlenc; + } +} diff --git a/src/inner_urlencoded.h b/src/inner_urlencoded.h new file mode 100644 index 0000000..e07ed6f --- /dev/null +++ b/src/inner_urlencoded.h @@ -0,0 +1,13 @@ +#ifndef MAGI_INCLUDED_INNER_URLENCODED +#define MAGI_INCLUDED_INNER_URLENCODED + +#include "request.h" + + +/* Fills request->url_params via parsing encoded data. */ +void magi_urlencoded(magi_param_list **list, + magi_request *request, + const char *encoded); + + +#endif diff --git a/src/magi.h b/src/magi.h new file mode 100644 index 0000000..b7df63c --- /dev/null +++ b/src/magi.h @@ -0,0 +1,16 @@ +#ifndef MAGI_INCLUDED +#define MAGI_INCLUDED +/* Magi Header Collection + * You can include this, if you don't want to think about headers. + */ +#include "cgi.h" +#include "cookie.h" +#include "error.h" +#include "fastcgi.h" +#include "file.h" +#include "param.h" +#include "request.h" +#include "response.h" +#include "urlenc.h" + +#endif diff --git a/src/multipart.h b/src/multipart.h deleted file mode 100644 index 47cfefe..0000000 --- a/src/multipart.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef MAGI_INCLUDED_MULTIPART -#define MAGI_INCLUDED_MULTIPART - -#include "request.h" - - -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 3f8cefe..bebacd7 100644 --- a/src/param.h +++ b/src/param.h @@ -2,27 +2,27 @@ #define MAGI_INCLUDED_PARAM -struct magi_param { +typedef struct magi_param { /* All pointers must be valid as 'free' arguments. */ - char * name; - char * data; -}; + char *name; + char *data; +} magi_param; -struct magi_param_list { - struct magi_param_list * next; /* Must be valid as 'free' argument. */ - struct magi_param item; -}; +typedef struct magi_param_list { + struct magi_param_list *next; /* Must be valid as 'free' argument. */ + magi_param item; +} magi_param_list; /* Addition of item to top of list. Null <=> error. */ -int magi_param_list_add(struct magi_param_list ** list, - struct magi_param * item); +int magi_param_list_add(magi_param_list **list, + magi_param *item); /* Data of the first node in list: node.name == name; else null. */ -char * magi_param_list_get(struct magi_param_list * list, const char * name); +char *magi_param_list_get(magi_param_list *list, const char *name); /* Freeing and invalidation of list. */ -void magi_param_list_destroy(struct magi_param_list * list); +void magi_param_list_destroy(magi_param_list *list); #endif diff --git a/src/request.h b/src/request.h index be92370..ffa239f 100644 --- a/src/request.h +++ b/src/request.h @@ -27,75 +27,91 @@ * document_uri: {script_name}{path_info} * /bin/script /article/magic */ -struct magi_request { +typedef struct magi_request { /* * * Results * * */ /* All pointers of this section must be valid as 'free' arguments. */ /* Parsed */ - struct magi_cookie_list * cookies; - 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; /* 'Post' multipart files */ + magi_cookie_list *cookies; + magi_param_list *http_params; /* HTTP Header parameters */ + magi_param_list *url_params; /* Paramteres from URL */ + magi_param_list *params; /* Parameters from 'post' body */ + magi_file_list *files; /* 'Post' multipart files */ /* 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 */ - char * server_name; /* SERVER_NAME */ + 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 */ + char *server_name; /* SERVER_NAME */ /* server_name can be not a domain name, even if request is done with it. * (Use http_params["HTTP_HOST"] instead.) */ - char * server_port; /* SERVER_PORT */ - char * server_protocol; /* SERVER_PROTOCOL */ - char * server_software; /* SERVER_COFTWARE */ - char * path_info; /* PATH_INFO */ + 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; + magi_error error; /* * * Settings * * */ /* 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_max; + void (*file_callback)(magi_file *file, + char *addon, + int addon_len, + int is_addon_last, + void *userdata); + void *file_callback_userdata; + int file_callback_addon_max; /* Limits for memory used (null <=> unlimitted) */ int cookies_max; int url_params_max; int http_params_max; int params_max; -}; +} magi_request; /* Setup request with default settings. */ -void magi_request_setup(struct magi_request * request); - -struct magi_tempfiles { - int count; - const char ** param_names; - const char ** locations; - int * maximums; /* Null maximums[i] <=> unlimited tempfiles[i]. */ -}; -void magi_tempfiles_add(struct magi_tempfiles * tmps, - const char * name, - const char * path, - int max); +void magi_request_setup(magi_request *request); + + +/* Destroys request. */ +void magi_request_destroy(magi_request *request); + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Tempfiles Callback + */ +typedef struct magi_tempfile { + const char *param_name; /* Form field name, in which file is expected. */ + const char *location; /* Location to load file in. */ + int maximum; /* Null <=> unlimited. */ +} magi_tempfile; + +typedef struct magi_tempfiles { + int count; + magi_tempfile *tmps; +} magi_tempfiles; + +void magi_tempfiles_add(magi_tempfiles *tmps, + const char *name, + const char *path, + int max); + +void magi_tempfiles_destroy(magi_tempfiles *tmps); + /* Setup request callback with files loaded into corresponding to their * parameter names locations; paths are in magi_tempfiles struct. */ -void magi_request_setup_tempfiles(struct magi_request * request, - struct magi_tempfiles * table); +void magi_request_setup_tempfiles(magi_request *request, + magi_tempfiles *table); /* Destroys request. */ void magi_request_destroy(struct magi_request * request); diff --git a/src/response.c b/src/response.c index 7e2ec0b..e4cd342 100644 --- a/src/response.c +++ b/src/response.c @@ -6,33 +6,33 @@ #include <stdlib.h> #include <string.h> -int vsnprintf(char * s, size_t n, const char * format, va_list arg); +/* TODO: realise vsnprintf or eliminate need of it. (see musl) */ +int vsnprintf(char *s, size_t n, const char *format, va_list arg); -void magi_response_setup(struct magi_response * response) +void magi_response_setup(magi_response *response) { 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; } - -void magi_response_content_type(struct magi_response * response, - enum magi_content_type type) +void magi_response_content_type(magi_response *response, const char *type) { - const char * const messages[] = { - "Content-Type: application/xhtml+xml", /* magi_xhtml */ - }; - if (!response->content_type) { - const char * end = messages[type] + strlen(messages[type]); - response->content_type = magi_str_create_copy(messages[type], end); - } + 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); } -void magi_response_add(struct magi_response * r, const char * addon) +void magi_response_add(magi_response *r, const char *addon) { int addon_len; if (!addon) { @@ -46,11 +46,9 @@ void magi_response_add(struct magi_response * r, const char * addon) r->len += addon_len; } -void magi_response_add_format(struct magi_response * response, - const char * addon, - ...) +void magi_response_add_format(magi_response *response, const char *addon, ...) { - char * act_addon; + char *act_addon; int n; va_list args; va_start(args, addon); @@ -66,34 +64,36 @@ void magi_response_add_format(struct magi_response * response, } } -void magi_response_cookie(struct magi_response * response, - struct magi_cookie * cookie) +void magi_response_cookie(magi_response *response, magi_cookie *cookie) { magi_cookie_list_add(&response->cookies, cookie); } -void magi_response_cookie_easy(struct magi_response * response, - const char * name, - const char * value) +void magi_response_cookie_easy(magi_response *response, + const char *name, + const char *value) +{ + +void magi_response_cookie_discard(magi_response *response, const char *name) { - struct magi_cookie cookie = { 0, 0, 0, 0, 0 }; - cookie.name = magi_str_create_copy(name, name + strlen(name)); - cookie.data = magi_str_create_copy(value, value + strlen(value)); + 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); } -void magi_response_http(struct magi_response * response, - const char * name, - const char * data) +void magi_response_http(magi_response *response, + const char *name, { - struct magi_param param = { 0, 0 }; - param.name = magi_str_create_copy(name, name + strlen(name)); - param.data = magi_str_create_copy(data, data + strlen(data)); + 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); } -void magi_response_destroy(struct magi_response * response) +void magi_response_destroy(magi_response *response) { if (!response) { return; diff --git a/src/response.h b/src/response.h index 95f6537..a51d4a4 100644 --- a/src/response.h +++ b/src/response.h @@ -5,42 +5,39 @@ #include "param.h" -enum magi_content_type { magi_xhtml = 0 }; +typedef struct magi_response { + magi_cookie_list *cookies; + magi_param_list *http_params; + char *content_type; + char *content; + int len; + int size; +} magi_response; -struct magi_response { - struct magi_cookie_list * cookies; - struct magi_param_list * http_params; - char * content_type; - char * content; - int len; - int size; -}; +void magi_response_setup(magi_response *response); -void magi_response_setup(struct magi_response * response); +void magi_response_content_type(magi_response *response, const char *type); -void magi_response_content_type(struct magi_response * response, - enum magi_content_type type); +void magi_response_add(magi_response *response, const char *addon); +void magi_response_add_format(magi_response *response, const char *addon, ...); -void magi_response_add(struct magi_response * response, const char * addon); -void magi_response_add_format(struct magi_response * response, - const char * addon, - ...); +void magi_response_cookie(magi_response *response, magi_cookie *cookie); -void magi_response_cookie(struct magi_response * response, - struct magi_cookie * cookie); +void magi_response_cookie_easy(magi_response *response, + const char *name, + const char *value); -void magi_response_cookie_easy(struct magi_response * response, - const char * name, - const char * value); +void magi_response_cookie_discard(magi_response *response, + const char *name); -void magi_response_http(struct magi_response * response, - const char * name, - const char * data); +void magi_response_http(magi_response *response, + const char *name, + const char *data); -void magi_response_destroy(struct magi_response * response); +void magi_response_destroy(magi_response *response); #endif diff --git a/src/urlenc.c b/src/urlenc.c index 8c38a0a..bb0bada 100644 --- a/src/urlenc.c +++ b/src/urlenc.c @@ -2,23 +2,12 @@ #include "utils.h" #include <ctype.h> -#include <stdlib.h> #include <string.h> /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Local Shortcuts */ -/* Call only if is_hex(c). */ -static int from_hex(char c) -{ - if (isdigit(c)) { - return c - '0'; - } else { - return toupper(c) - 'A' + 10; - } -} - /* Call only if 0 <= num && num <= 15. */ static char to_hex(int num) { @@ -26,11 +15,6 @@ static char to_hex(int num) return hex[num]; } -static int is_hex(char c) -{ - return isdigit(c) || strchr("ABCDEF", toupper(c)); -} - static int is_url(char c) { return isalnum(c) || strchr("$-_.+ !*'(),", c); @@ -38,125 +22,6 @@ static int is_url(char c) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * URL Decoding - */ -static int deurl(char ** data) -{ - char * val = *data; - int ti; - int ci; - if (!val) { - *data = malloc(1); - **data = 0; - return 1; - } - for (ti = 0, ci = 0; 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]); /* 0000xxxx */ - val[ti] |= from_hex(val[ci + 1]) << 4; /* XXXXxxxx */ - ci += 2; /* Two extra characters are readed from code. */ - } else { - return 0; - } - } else if (val[ci] == '+') { - val[ti] = ' '; - } else { - val[ti] = val[ci]; - } - } - val[ti] = 0; - return 1; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Urlencoded Automata - */ -enum st { st_error = 0, st_name, st_data }; - -struct automata { - struct magi_param_list ** list; - struct magi_param param; - int size; - int len; -}; - - -static enum st parse_name(struct automata * a, char c) -{ - if (c == '&' || c == ';') { /* Impossible character means error. */ - return st_error; - } - if (c == '=') { /* Separator ends name. */ - a->size = 1; - a->len = 0; - return st_data; - } - - if (!magi_str_add(&a->param.name, &a->len, &a->size, c)) { - return st_error; - } - return st_name; -} - -static enum st end_data(struct automata * a) -{ - if (deurl(&a->param.name) && deurl(&a->param.data)) { - if (magi_param_list_add(a->list, &a->param)) { - a->size = 1; - a->len = 0; - a->param.name = 0; - a->param.data = 0; - return st_name; - } - } - return st_error; -} - -static enum st parse_data(struct automata * a, char c) -{ - if (c == '=') { /* Impossible character means error. */ - return st_error; - } - if (c == '&' || c == ';') { /* Separator ends data. */ - return end_data(a); - } - - if (!magi_str_add(&a->param.data, &a->len, &a->size, c)) { - return st_error; - } - return st_data; -} - -void magi_urlenc(struct magi_param_list ** list, - struct magi_request * request, - const char * encoded) -{ - enum st state; - struct automata a = { 0, { 0, 0 }, 1, 0 }; - a.list = list; - *list = 0; - if (!encoded || !*encoded) { - return; - } - for (state = st_name; state && *encoded; ++encoded) { - if (state == st_name) { - state = parse_name(&a, *encoded); - } else { - state = parse_data(&a, *encoded); - } - } - if (state == st_name || !state || !end_data(&a)) { - free(a.param.name); - free(a.param.data); - request->error = magi_error_urlenc; - } -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * URL Encoding */ int magi_urlenc_size(const char * plain) diff --git a/src/urlenc.h b/src/urlenc.h index 5240109..edaec08 100644 --- a/src/urlenc.h +++ b/src/urlenc.h @@ -1,17 +1,10 @@ #ifndef MAGI_INCLUDED_URLENC #define MAGI_INCLUDED_URLENC -#include "request.h" - -/* Fills request->url_params via parsing encoded data. */ -void magi_urlenc(struct magi_param_list ** list, - struct magi_request * request, - const char * encoded); - -/* 'code' from urlencode must have size of at least magi_urlenc_size(plain). */ -int magi_urlenc_size(const char * plain); -void magi_urlencode(const char * plain, char * code); +/* 'code' from urlenc must have size of at least magi_urlenc_size(plain). */ +int magi_urlenc_size(const char *plain); +void magi_urlenc(const char *plain, char *code); #endif |