From 8f1e6faa7f548c9a8bcbcac71c8f239a6540b926 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 11 Mar 2020 17:54:19 +0300 Subject: [magi] --- examples/Makefile | 2 +- examples/append.c | 2 +- examples/cookie.c | 2 +- examples/echo.c | 44 ++++---- examples/upload.c | 11 +- include/magi.h | 1 + include/magi/response.h | 4 +- src/cgi.c | 19 ++-- src/cookies.c | 171 +++++++++++++------------------ src/multipart.c | 262 +++++++++++++++++++++--------------------------- src/param.c | 13 ++- src/request.c | 12 +-- src/response.c | 26 ++--- src/tools.c | 34 +++---- src/tools.h | 9 +- src/urlencoded.c | 83 +++++++-------- 16 files changed, 315 insertions(+), 380 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 991f936..88af46d 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 echo upload fastcgi +EXAMPLES = append cookie echo upload # Specify your favourite C compiler here (e.g. tcc): CC = gcc diff --git a/examples/append.c b/examples/append.c index 3a32287..c6cfb2b 100644 --- a/examples/append.c +++ b/examples/append.c @@ -26,7 +26,7 @@ void response(magi_request *r) ""); } -int main(int argc, char const *argv[]) +int main() { magi_request request; magi_request_init(&request); diff --git a/examples/cookie.c b/examples/cookie.c index 7c55ba8..601c901 100644 --- a/examples/cookie.c +++ b/examples/cookie.c @@ -24,7 +24,7 @@ void response(magi_request *r) magi_response(r, "

"); } -int main(int argc, char const *argv[]) +int main() { magi_request request; magi_request_init(&request); diff --git a/examples/echo.c b/examples/echo.c index e3b90c7..7c840e2 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -38,33 +38,29 @@ void list_files(magi_request *r) 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); + f->field, f->filename); } } void show_meta(magi_request *r) { - magi_response(r, "I was called with method ["); - magi_response(r, r->method); - if (r->uri) { - magi_response(r, "] with URL ["); - magi_response(r, r->uri); - } - if (r->server_name) { - magi_response(r, "] for server ["); - magi_response(r, r->server_name); + magi_response(r, "I was called "); + if (r->is_secure) { + magi_response(r, "securely "); } - if (r->server_port) { - magi_response(r, "] on port ["); - magi_response(r, r->server_port); + magi_response(r, "with method ["); + magi_response(r, r->method); + if (r->host) { + magi_response(r, "] on server ["); + magi_response(r, r->host); } - if (r->server_protocol) { - magi_response(r, "] with protocol ["); - magi_response(r, r->server_protocol); + if (r->script) { + magi_response(r, "] being script on ["); + magi_response(r, r->script); } - if (r->server_software) { - magi_response(r, "] and I am running on software ["); - magi_response(r, r->server_software); + if (r->path) { + magi_response(r, "] with requested path ["); + magi_response(r, r->path); } magi_response(r, "]
"); } @@ -85,13 +81,13 @@ void response(magi_request *r) list_cookies(r); magi_response(r, "

Parameters:

"); - list_params(r, r->params); + list_params(r, r->meta); magi_response(r, "

URL Parameters:

"); - list_params(r, r->url_params); + list_params(r, r->head); - magi_response(r, "

HTTP Parameters:

"); - list_params(r, r->http_params); + magi_response(r, "

Body Parameters:

"); + list_params(r, r->body); magi_response(r, "

Files:

"); list_files(r); @@ -99,7 +95,7 @@ void response(magi_request *r) magi_response(r, ""); } -int main(int argc, char const *argv[]) +int main() { magi_request request; magi_request_init(&request); diff --git a/examples/upload.c b/examples/upload.c index 54d3a48..a8503ea 100644 --- a/examples/upload.c +++ b/examples/upload.c @@ -29,18 +29,17 @@ void response(magi_request *r) void get(magi_request *r) { - magi_loadfiles rules; - magi_loadfiles_init(&rules); + magi_loadfiles rules = { 0, 0 }; magi_loadfiles_add(&rules, "data", "data", 0); - magi_loadfiles_set(&r, &rules); - magi_cgi(&r); + magi_loadfiles_set(r, &rules); + magi_cgi(r); magi_loadfiles_free(&rules); } -int main(int argc, char const *argv[]) +int main() { magi_request request; - magi_request_init(request); + magi_request_init(&request); get(&request); if (request.error) { magi_response_error(&request); diff --git a/include/magi.h b/include/magi.h index 0089878..a5b047d 100644 --- a/include/magi.h +++ b/include/magi.h @@ -8,6 +8,7 @@ #include "magi/error.h" #include "magi/fastcgi.h" #include "magi/file.h" +#include "magi/loadfile.h" #include "magi/param.h" #include "magi/request.h" #include "magi/response.h" diff --git a/include/magi/response.h b/include/magi/response.h index 52b1c9d..a9854d4 100644 --- a/include/magi/response.h +++ b/include/magi/response.h @@ -32,7 +32,9 @@ typedef struct magi_response_methods { typedef struct magi_response_implementation { const magi_response_methods *methods; void *userdata; - magi_params *head[3]; + magi_params *head_response; + magi_params *head_general; + magi_params *head_entity; int head_done; } magi_response_implementation; diff --git a/src/cgi.c b/src/cgi.c index 00b0a06..291a57f 100644 --- a/src/cgi.c +++ b/src/cgi.c @@ -75,6 +75,9 @@ static void cgi_env(magi_request *r) if (getenv("SERVER_PORT")) { r->port = atoi(getenv("SERVER_PORT")); r->is_secure = r->port == 443; + } else { + r->port = 0; + r->is_secure = 0; } r->path = plain_env("PATH_INFO"); } @@ -191,13 +194,15 @@ static void setup_response(magi_request *r) mfile, mclose }; - r->response = malloc(sizeof(*r->response)); - r->response->methods = &m; - r->response->userdata = 0; - r->response->head[0] = 0; - r->response->head[1] = 0; - r->response->head[2] = 0; - r->response->head_done = 0; + r->response = malloc(sizeof(*r->response)); + r->response->methods = &m; + r->response->userdata = 0; + r->response->head_response = 0; + r->response->head_general = 0; + r->response->head_entity = 0; + r->response->head_done = 0; + magi_response_content_type(r, "application/xhtml+xml"); + magi_response_status(r, 200, "OK"); } /* Interfacial CGI Request Handling */ diff --git a/src/cookies.c b/src/cookies.c index 8b610d4..7e8248b 100644 --- a/src/cookies.c +++ b/src/cookies.c @@ -6,7 +6,7 @@ #include -enum st { +typedef enum st { st_error = 0, st_pre_name, st_name, @@ -14,24 +14,24 @@ enum st { st_pre_data, st_data, st_post_data -}; +} st; -enum data_type { dt_plain = 0, dt_version, dt_path, dt_domain }; +typedef enum dt { dt_plain = 0, dt_version, dt_path, dt_domain } dt; -struct automata { - struct magi_cookie_list ** list; - struct magi_cookie cookie; - char * buf; - int buf_len; - int buf_size; - int is_first; - int is_advanced; - int is_quoted; - enum data_type data_t; -}; +typedef struct automata { + magi_cookies **list; + magi_cookie cookie; + char *buf; + int buf_len; + int buf_size; + int is_first; + int is_advanced; + int is_quoted; + dt datatype; +} automata; -static void nulify_cookie(struct automata * a) +static void nulify_cookie(automata *a) { a->cookie.name = 0; a->cookie.data = 0; @@ -40,7 +40,7 @@ static void nulify_cookie(struct automata * a) a->cookie.max_age = 0; } -static void buf_new(struct automata * a) +static void buf_new(automata *a) { a->buf = 0; a->buf_len = 0; @@ -48,29 +48,28 @@ static void buf_new(struct automata * a) } -static enum data_type what_is_name(const struct automata * a) +static dt what_is_name(const automata *a) { - enum data_type data_t = dt_plain; + dt datatype = dt_plain; if (a->is_first && !strcmp(a->buf, "$Version")) { - data_t = dt_version; + datatype = dt_version; } else if (a->is_advanced) { if (!strcmp(a->buf, "$Path")) { - data_t = dt_path; + datatype = dt_path; } else if (!strcmp(a->buf, "$Domain")) { - data_t = dt_domain; + datatype = dt_domain; } } - return data_t; + return datatype; } -static int end_name(struct automata * a) +static void end_name(automata *a) { - int ok = 1; - a->data_t = what_is_name(a); - if (a->data_t == dt_plain) { + a->datatype = what_is_name(a); + if (a->datatype == dt_plain) { if (a->cookie.name) { - ok = magi_cookie_list_add(a->list, &a->cookie); + magi_cookies_add(a->list, &a->cookie); } nulify_cookie(a); a->cookie.name = a->buf; @@ -78,75 +77,56 @@ static int end_name(struct automata * a) free(a->buf); } buf_new(a); - return ok; } -static int end_data(struct automata * a) +static int end_data(automata *a) { - int ok = 1; - switch (a->data_t) { - case dt_plain: - a->cookie.data = a->buf; - break; - case dt_path: - a->cookie.path = a->buf; - break; - case dt_domain: - a->cookie.domain = a->buf; - break; - case dt_version: - if (strcmp(a->buf, "1")) { - ok = 0; - } + switch (a->datatype) { + case dt_plain: a->cookie.data = a->buf; break; + case dt_path: a->cookie.path = a->buf; break; + case dt_domain: a->cookie.domain = a->buf; break; + case dt_version: if (strcmp(a->buf, "1")) { return 0; } } buf_new(a); - return ok; + return 1; } -static enum st parse_pre_name(struct automata * a, char c) +static st parse_pre_name(automata *a, char c) { - enum st state; + st state; if (c == ' ' || c == '\t') { state = st_name; } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { state = st_name; - if (!magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c)) { - state = st_error; - } + magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c); } else { state = st_error; } return state; } -static enum st parse_name(struct automata * a, char c) +static st parse_name(automata *a, char c) { - enum st state; + st state; if (c == '=') { state = st_pre_data; - if (!end_name(a)) { - state = st_error; - } + end_name(a); } else if (c == ' ' || c == '\t') { state = st_post_name; - if (!end_name(a)) { - state = st_error; - } + end_name(a); } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { state = st_name; - if (!magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c)) { - state = st_error; - } + magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c); } else { state = st_error; } return state; } -static enum st parse_post_name(struct automata * a, char c) +static st parse_post_name(automata *a, char c) { - enum st state; + st state; if (c == '=') { state = st_pre_data; } else if (c == ' ' || c == '\t') { @@ -157,9 +137,9 @@ static enum st parse_post_name(struct automata * a, char c) return state; } -static enum st parse_pre_data(struct automata * a, char c) +static st parse_pre_data(automata *a, char c) { - enum st state; + st state; if (c == ' ' || c == '\t') { state = st_pre_data; } else if (c == '"') { @@ -167,18 +147,16 @@ static enum st parse_pre_data(struct automata * a, char c) a->is_quoted = 1; } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { state = st_data; - if (!magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c)) { - state = st_error; - } + magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c); } else { state = st_error; } return state; } -static enum st parse_not_quoted_data(struct automata * a, char c) +static st parse_not_quoted_data(automata *a, char c) { - enum st state; + st state; if (c == ';' || (c == ',' && a->is_first)) { state = st_pre_name; a->is_first = 0; @@ -192,18 +170,16 @@ static enum st parse_not_quoted_data(struct automata * a, char c) } } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { state = st_data; - if (!magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c)) { - state = st_error; - } + magi_str_add(&a->buf, &a->buf_len, &a->buf_size, c); } else { state = st_error; } return state; } -static enum st parse_data(struct automata * a, char c) +static st parse_data(automata *a, char c) { - enum st state; + st state; if (a->is_quoted) { if (c == '"') { state = st_post_data; @@ -220,9 +196,9 @@ static enum st parse_data(struct automata * a, char c) return state; } -static enum st parse_post_data(struct automata * a, char c) +static st parse_post_data(automata *a, char c) { - enum st state; + st state; if (c == ';' || (c == ',' && a->is_first)) { state = st_pre_name; } else if (c == ' ' || c == '\t') { @@ -234,14 +210,15 @@ static enum st parse_post_data(struct automata * a, char c) } -static void parse_end(enum magi_error * e, struct automata * a, enum st s) +static void parse_end(magi_error *e, automata *a, st s) { if (s == st_data) { if (a->is_quoted || !a->cookie.name) { *e = magi_error_cookies; return; } - if (end_data(a) && magi_cookie_list_add(a->list, &a->cookie)) { + if (end_data(a)) { + magi_cookies_add(a->list, &a->cookie); nulify_cookie(a); } else { *e = magi_error_cookies; @@ -252,33 +229,21 @@ static void parse_end(enum magi_error * e, struct automata * a, enum st s) } -void magi_cookies(struct magi_request * request, const char * data) +void magi_parse_cookies(magi_request *request, const char *data) { - enum st state; - struct automata a = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 1, 1, 0, 0, 0 }; - a.list = &request->cookies; - request->cookies = 0; + st state; + automata a = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0, 1, 0, 0, 0 }; + a.list = &request->cookies; + request->cookies = 0; for (state = st_pre_name; state && *data; ++data) { switch (state) { - case st_pre_name: - state = parse_pre_name(&a, *data); - break; - case st_name: - state = parse_name(&a, *data); - break; - case st_post_name: - state = parse_post_name(&a, *data); - break; - case st_pre_data: - state = parse_pre_data(&a, *data); - break; - case st_data: - state = parse_data(&a, *data); - break; - case st_post_data: - state = parse_post_data(&a, *data); - default: - break; + case st_pre_name: state = parse_pre_name(&a, *data); break; + case st_name: state = parse_name(&a, *data); break; + case st_post_name: state = parse_post_name(&a, *data); break; + case st_pre_data: state = parse_pre_data(&a, *data); break; + case st_data: state = parse_data(&a, *data); break; + case st_post_data: state = parse_post_data(&a, *data); break; + default: break; } } parse_end(&request->error, &a, state); diff --git a/src/multipart.c b/src/multipart.c index 001b4d1..72fe607 100644 --- a/src/multipart.c +++ b/src/multipart.c @@ -18,7 +18,7 @@ static int is_token(char c) return 32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={} \t", c); } -static int is_str_token(char * str) +static int is_str_token(char *str) { int is = str && *str; /* Empty string is not valid. */ while (is && *str) { @@ -32,7 +32,7 @@ static int is_str_token(char * str) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Automata for multipart/form-data */ -enum st { +typedef enum st { st_error = 0, st_begin, st_pname_pre, @@ -41,31 +41,31 @@ enum st { st_pdata, st_data, st_end -}; - -struct automata { - struct magi_request * request; - struct magi_file file; - struct magi_param param; - struct magi_param subparam; - char * buf; - int buf_size; - int size; - int len; - char * boundary; - int boundary_pos; - int boundary_len; - int is_end_suspected; - int is_CR_readed; - int is_quoted; - int readed; -}; +} st; + +typedef struct automata { + magi_request *request; + magi_file file; + magi_param param; + magi_param subparam; + char *buf; + int buf_size; + int size; + int len; + char *boundary; + int boundary_pos; + int boundary_len; + int is_end_suspected; + int is_CR_readed; + int is_quoted; + int readed; +} automata; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Automata Shortcuts */ -static char * extract_filename(char * n) +static char *extract_filename(char *n) { n = strchr(n, '='); if (!n) { @@ -80,9 +80,9 @@ static char * extract_filename(char * n) } } -static int content_disposition(struct automata * a) +static int content_disposition(automata *a) { - char * n = strchr(a->subparam.data, '='); + char *n = strchr(a->subparam.data, '='); if (!n) { return 0; } @@ -99,11 +99,11 @@ static int content_disposition(struct automata * a) return 0; } } - a->file.file_name = extract_filename(n); - if (a->file.file_name) { - a->file.param_name = a->param.name; - a->file.params = 0; - a->param.name = 0; + a->file.filename = extract_filename(n); + if (a->file.filename) { + a->file.field = a->param.name; + a->file.params = 0; + a->param.name = 0; } free(a->subparam.name); free(a->subparam.data); @@ -112,53 +112,42 @@ static int content_disposition(struct automata * a) return 1; } -static int subparam_end(struct automata * a) +static int subparam_end(automata *a) { a->size = 1; a->len = 0; magi_str_lowercase(a->subparam.name); if (!strcmp(a->subparam.name, "content-disposition")) { return content_disposition(a); - } else if (magi_param_list_add(&a->file.params, &a->subparam)) { - a->subparam.name = 0; - a->subparam.data = 0; - return 1; } - return 0; + magi_params_add(&a->file.params, &a->subparam); + a->subparam.name = 0; + a->subparam.data = 0; + return 1; } -static int param_end(struct automata * a) +static int param_end(automata *a) { - if (a->file.file_name) { - a->request->file_callback(&a->file, a->buf, a->buf_size, 1, - a->request->file_callback_userdata); - a->readed -= a->buf_size; + if (a->file.filename) { + a->request->callback.act(a->request->callback.userdata, + &a->file, a->buf, a->buf_size); + a->request->callback.act(a->request->callback.userdata, + &a->file, 0, 0); + a->readed -= a->buf_size; a->buf_size = 0; - if (!magi_file_list_add(&a->request->files, &a->file)) { - free(a->file.file_name); - free(a->file.param_name); - magi_param_list_destroy(a->file.params); - free(a->file.params); - a->request->error = magi_error_multipart; - return 0; - } - a->file.file_name = 0; - a->file.param_name = 0; - a->file.params = 0; - a->size = 1; - a->len = 0; + magi_files_add(&a->request->files, &a->file); + a->file.filename = 0; + a->file.field = 0; + a->file.params = 0; + a->size = 1; + a->len = 0; return 1; } if (!a->param.name) { a->request->error = magi_error_multipart; return 0; } - if (!magi_param_list_add(&a->request->params, &a->param)) { - free(a->param.name); - free(a->param.data); - a->request->error = magi_error_multipart; - return 0; - } + magi_params_add(&a->request->body, &a->param); a->param.name = 0; a->param.data = 0; a->size = 1; @@ -170,7 +159,7 @@ static int param_end(struct automata * a) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Boundary Interfaces */ -static char sepget(const struct automata * a) +static char sepget(const automata *a) { char c; const int pos_after = a->boundary_pos - 4 - a->boundary_len; @@ -192,12 +181,9 @@ static char sepget(const struct automata * a) return c; } -static int seplen(const struct automata * a) -{ - return a->boundary_len + 6; -} +static int seplen(const automata *a) { return a->boundary_len + 6; } -static char endget(const struct automata * a) +static char endget(const automata *a) { char c; const int pos_after = a->boundary_pos - 4 - a->boundary_len; @@ -221,13 +207,13 @@ static char endget(const struct automata * a) return c; } -static int endlen(const struct automata * a) +static int endlen(const automata *a) { return a->boundary_len + 8; } -static int is_semiend(const struct automata * a) -{ /* Is end readed, expect last two chars, which are CR LF? */ +static int is_semiend(const automata *a) +{ /* Is end readed, expect last two chars, which are CR LF? */ return a->is_end_suspected && (a->boundary_pos == endlen(a) - 2); } @@ -235,19 +221,18 @@ static int is_semiend(const struct automata * a) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Data Reading */ -static void apply_callback(struct automata * a) +static void apply_callback(automata *a) { - int full = a->buf_size == a->request->file_callback_addon_max; - if (a->file.file_name && full) { - a->request->file_callback(&a->file, a->buf, a->buf_size, 0, - a->request->file_callback_userdata); - a->readed -= a->buf_size; + int full = a->buf_size == a->request->callback.addon_max; + if (a->file.filename && full) { + a->request->callback.act(a->request->callback.userdata, + &a->file, a->buf, a->buf_size); + a->readed -= a->buf_size; a->buf_size = 0; } } -static enum st data_add_act( - struct automata * a, char c, char ** dest, int * len, int * size) +static st data_add_act(automata *a, char c, char **dest, int *len, int *size) { int pos = a->boundary_pos; for (a->boundary_pos = 0; a->boundary_pos < pos; ++a->boundary_pos) { @@ -275,10 +260,10 @@ static enum st data_add_act( } } -static enum st data_add(struct automata * a, char c) +static st data_add(automata *a, char c) { - if (a->file.file_name) { - int max = a->request->file_callback_addon_max + 1; + if (a->file.filename) { + int max = a->request->callback.addon_max + 1; return data_add_act(a, c, &a->buf, &a->buf_size, &max); } else { return data_add_act(a, c, &a->param.data, &a->len, &a->size); @@ -289,20 +274,20 @@ static enum st data_add(struct automata * a, char c) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * State analysers */ -static enum st parse_begin(struct automata * a, char c) +static st parse_begin(automata *a, char c) { - if (sepget(a) != c) { /* 'c' is not wanted character from separator; */ - a->boundary_pos = 0; /* so nullify progress in reading separator. */ + if (sepget(a) != c) { /* 'c' is not wanted character from separator; */ + a->boundary_pos = 0; /* so nullify progress in reading separator. */ } else { a->boundary_pos++; if (a->boundary_pos == seplen(a)) { - return st_pname_pre; /* Separator is completed, so move on. */ + return st_pname_pre; /* Separator is completed, so move on. */ } } return st_begin; } -static enum st parse_pname_pre(struct automata * a, char c) +static st parse_pname_pre(automata *a, char c) { if (a->is_CR_readed) { if (c != '\n') { @@ -314,14 +299,15 @@ static enum st parse_pname_pre(struct automata * a, char c) } else if (c == '\r') { a->is_CR_readed = 1; return st_pname_pre; - } else if (is_token(c) && - magi_str_add(&a->subparam.name, &a->len, &a->size, c)) { - return st_pname; } - return st_error; + if (!is_token(c)) { + return st_error; + } + magi_str_add(&a->subparam.name, &a->len, &a->size, c); + return st_pname; } -static enum st parse_pname(struct automata * a, char c) +static st parse_pname(automata *a, char c) { if (c == ':') { a->len = 0; @@ -329,14 +315,15 @@ static enum st parse_pname(struct automata * a, char c) return st_pdata; } else if (c == ' ' || c == '\t') { return st_pname_end; - } else if (is_token(c) && - magi_str_add(&a->subparam.name, &a->len, &a->size, c)) { - return st_pname; } - return st_error; + if (!is_token(c)) { + return st_error; + } + magi_str_add(&a->subparam.name, &a->len, &a->size, c); + return st_pname; } -static enum st parse_pname_end(struct automata * a, char c) +static st parse_pname_end(automata *a, char c) { if (c == ':') { a->len = 0; @@ -348,7 +335,7 @@ static enum st parse_pname_end(struct automata * a, char c) return st_error; } -static enum st parse_pdata(struct automata * a, char c) +static st parse_pdata(automata *a, char c) { if (a->is_CR_readed) { a->is_CR_readed = 0; @@ -357,21 +344,19 @@ static enum st parse_pdata(struct automata * a, char c) return st_pname_pre; } return st_error; - } else if (magi_str_add(&a->subparam.data, &a->len, &a->size, '\r') && - magi_str_add(&a->subparam.data, &a->len, &a->size, c)) { - return st_pdata; } - return st_error; + magi_str_add(&a->subparam.data, &a->len, &a->size, '\r'); + magi_str_add(&a->subparam.data, &a->len, &a->size, c); + return st_pdata; } else if (c == '\r') { a->is_CR_readed = 1; return st_pdata; - } else if (magi_str_add(&a->subparam.data, &a->len, &a->size, c)) { - return st_pdata; } - return st_error; + magi_str_add(&a->subparam.data, &a->len, &a->size, c); + return st_pdata; } -static enum st parse_data(struct automata * a, char c) +static st parse_data(automata *a, char c) { if (a->is_end_suspected) { if (endget(a) != c) { @@ -398,51 +383,35 @@ static enum st parse_data(struct automata * a, char c) return data_add(a, c); } -static enum st parse_end(struct automata * a, char c) -{ - return st_end; -} +static st parse_end(automata *a, char c) { return st_end; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Automata Runner */ -static void run_automata(struct automata * a, - int (*next)(void * next_userdata), - void * next_userdata) +static void run_automata(automata *a, + int (*next)(void *next_userdata), + void *next_userdata) { - enum st state = st_begin; - int c = next(next_userdata); + st state = st_begin; + int c = next(next_userdata); + int maxr = a->request->limits.params_body; while (state && state != st_end && c != EOF && - (!a->request->params_max || a->readed != a->request->params_max)) { + (!maxr || a->readed != maxr)) { switch (state) { - case st_begin: - state = parse_begin(a, c); - break; - case st_pname_pre: - state = parse_pname_pre(a, c); - break; - case st_pname: - state = parse_pname(a, c); - break; - case st_pname_end: - state = parse_pname_end(a, c); - break; - case st_pdata: - state = parse_pdata(a, c); - break; - case st_data: - state = parse_data(a, c); - break; - case st_end: - state = parse_end(a, c); - default: - break; + case st_begin: state = parse_begin(a, c); break; + case st_pname_pre: state = parse_pname_pre(a, c); break; + case st_pname: state = parse_pname(a, c); break; + case st_pname_end: state = parse_pname_end(a, c); break; + case st_pdata: state = parse_pdata(a, c); break; + case st_data: state = parse_data(a, c); break; + case st_end: state = parse_end(a, c); break; + default: break; } c = next(next_userdata); ++a->readed; } - if (a->request->params_max && a->readed == a->request->params_max) { + if (maxr && a->readed == maxr) { a->request->error = magi_error_limit; return; } @@ -461,17 +430,18 @@ static void run_automata(struct automata * a, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Automata Interfaces */ -void magi_multipart(struct magi_request * request, - char * boundary, - int (*next)(void * userdata), - void * next_userdata) +void magi_parse_multipart(magi_request *request, + char *boundary, + int (*next)(void *userdata), + void *next_userdata) { - struct automata a = { 0, { 0, 0, 0 }, { 0, 0 }, { 0, 0 }, 0, 0, 1, - 0, 0, 2, 0, 0, 0, 0 }; - a.request = request; - a.boundary = boundary; - a.boundary_len = strlen(boundary); - a.buf = malloc(request->file_callback_addon_max + 1); + automata a = { + 0, { 0, 0, 0 }, { 0, 0 }, { 0, 0 }, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0 + }; + a.request = request; + a.boundary = boundary; + a.boundary_len = strlen(boundary); + a.buf = malloc(request->callback.addon_max + 1); if (a.buf) { run_automata(&a, next, next_userdata); free(a.buf); diff --git a/src/param.c b/src/param.c index 42785fc..dd89a48 100644 --- a/src/param.c +++ b/src/param.c @@ -10,7 +10,18 @@ void magi_params_add(magi_params **params, magi_param *newitem) if (node) { node->next = *params; node->item = *newitem; - *params = node; + *params = node; + } +} + +void magi_params_set(magi_params **params, magi_param *newitem) +{ + if (!*params) { + magi_params_add(params, newitem); + } else if (!strcmp((*params)->item.name, newitem->name)) { + (*params)->item.data = newitem->data; + } else { + magi_params_set(&(*params)->next, newitem); } } diff --git a/src/request.c b/src/request.c index 4132458..41b77fe 100644 --- a/src/request.c +++ b/src/request.c @@ -56,12 +56,12 @@ void magi_request_free(magi_request *request) magi_files_free(request->files); request->response->methods->close(request->response->userdata); free(request->response->userdata); - magi_params_free(request->response->head[0]); - magi_params_free(request->response->head[1]); - magi_params_free(request->response->head[2]); - free(request->response->head[0]); - free(request->response->head[1]); - free(request->response->head[2]); + magi_params_free(request->response->head_response); + magi_params_free(request->response->head_general); + magi_params_free(request->response->head_entity); + free(request->response->head_response); + free(request->response->head_general); + free(request->response->head_entity); request_free(request); request_annul(request); } diff --git a/src/response.c b/src/response.c index aea64b4..d7d2c86 100644 --- a/src/response.c +++ b/src/response.c @@ -21,7 +21,7 @@ void magi_response_status(magi_request *r, int code, const char *description) addon.data[2] = '0' + code % 10; addon.data[3] = ' '; memcpy(addon.data + 4, description, dlen + 1); - magi_params_set(r->response->head, &addon); + magi_params_set(&r->response->head_response, &addon); } void magi_response_cookie(magi_request *r, const char *name, const char *data) @@ -32,7 +32,7 @@ void magi_response_cookie(magi_request *r, const char *name, const char *data) } addon.name = magi_str_create_copy("Set-Cookie", 10); /* TODO */ - magi_params_add(r->response->head + 1, &addon); + magi_params_add(&r->response->head_general, &addon); } void magi_response_cookie_complex(magi_request *r, magi_cookie *c) @@ -43,7 +43,7 @@ void magi_response_cookie_complex(magi_request *r, magi_cookie *c) } addon.name = magi_str_create_copy("Set-Cookie", 10); /* TODO */ - magi_params_add(r->response->head + 1, &addon); + magi_params_add(&r->response->head_general, &addon); } void magi_response_cookie_discard(magi_request *r, const char *name) @@ -54,7 +54,7 @@ void magi_response_cookie_discard(magi_request *r, const char *name) } addon.name = magi_str_create_copy("Set-Cookie", 10); /* TODO */ - magi_params_add(r->response->head + 1, &addon); + magi_params_add(&r->response->head_general, &addon); } void magi_response_header(magi_request *r, const char *name, const char *data) @@ -65,7 +65,7 @@ void magi_response_header(magi_request *r, const char *name, const char *data) } addon.name = magi_str_create_copy(name, strlen(name)); addon.data = magi_str_create_copy(data, strlen(data)); - magi_params_add(r->response->head + 1, &addon); + magi_params_add(&r->response->head_general, &addon); } void magi_response_content_length(magi_request *r, int length) @@ -85,18 +85,18 @@ void magi_response_content_length(magi_request *r, int length) ++len; } addon.data[len] = 0; - magi_params_set(r->response->head + 2, &addon); + magi_params_set(&r->response->head_entity, &addon); } void magi_response_content_type(magi_request *r, const char *type) { magi_param addon; - if (r->response->head_done) { + if (r->response->head_done || !type) { return; } addon.name = magi_str_create_copy("Content-Type", 12); addon.data = magi_str_create_copy(type, strlen(type)); - magi_params_set(r->response->head + 2, &addon); + magi_params_set(&r->response->head_entity, &addon); } static void response_headers(magi_response_implementation *r, magi_params *p) @@ -108,13 +108,12 @@ static void response_headers(magi_response_implementation *r, magi_params *p) void magi_response_head(magi_request *r) { - magi_params *current; if (r->response->head_done) { return; } - response_headers(r->response, r->response->head[0]); - response_headers(r->response, r->response->head[1]); - response_headers(r->response, r->response->head[2]); + response_headers(r->response, r->response->head_response); + response_headers(r->response, r->response->head_general); + response_headers(r->response, r->response->head_entity); r->response->methods->start_body(r->response->userdata); r->response->head_done = 1; } @@ -122,6 +121,9 @@ void magi_response_head(magi_request *r) void magi_response(magi_request *r, const char *addon) { magi_response_head(r); + if (!addon) { + return; + } r->response->methods->body(r->response->userdata, addon, strlen(addon)); } diff --git a/src/tools.c b/src/tools.c index d7a90ce..d6170bc 100644 --- a/src/tools.c +++ b/src/tools.c @@ -19,37 +19,27 @@ char *magi_str_lowercase(char *str) char *magi_str_create_copy(const char *first, int len) { char *copy = magi_str_create(len); - if (copy) { - memcpy(copy, first, len); - } + memcpy(copy, first, len); return copy; } char *magi_str_create(int len) { char *str = malloc(len + 1); - if (str) { - str[len] = 0; - } + str[len] = 0; return str; } -int magi_str_add(magi_str *str, char c) +void magi_str_add(char **str, int *len, int *size, char c) { - if (!str->data) { - str->len = 0; - str->size = 2; - str->data = malloc(2); - } else if (str->len + 1 == str->size) { - str->size *= 2; - str->data = realloc(str->data, str->size); - } - if (!str->dest) { - str->len = 0; - str->size = 0; - return 0; + if (!*str) { + *len = 0; + *size = 2; + *str = malloc(2); + } else if (*len + 1 == *size) { + *size *= 2; + *str = realloc(*str, *size); } - str->data[str->len++] = c; - str->data[str->len] = 0; - return 1; + *str[*len] = c; + *str[++*len] = 0; } diff --git a/src/tools.h b/src/tools.h index 49513e8..0152f35 100644 --- a/src/tools.h +++ b/src/tools.h @@ -8,14 +8,7 @@ char *magi_str_lowercase(char *str); char *magi_str_create_copy(const char *first, int len); char *magi_str_create(int len); - -typedef struct magi_str { - char *data; - int size; - int len; -} magi_str; - -int magi_str_add(magi_str *str, char c); +void magi_str_add(char **str, int *len, int *size, char c); #endif diff --git a/src/urlencoded.c b/src/urlencoded.c index 9d596ed..4f9efe8 100644 --- a/src/urlencoded.c +++ b/src/urlencoded.c @@ -61,76 +61,77 @@ static int deurl(char **data) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Urlencoded Automata */ -typedef struct automata { - magi_param_list **list; - magi_str name; - magi_str data; -} automata; -typedef void *(*state)(automata *a, char c); +typedef struct automata automata; +typedef void (*state)(automata *a, char c); +struct automata { + state s; + magi_params **list; + char *name; + int nlen; + int nsize; + char *data; + int dlen; + int dsize; +}; -static void *state_parse_data(automata *a, char c); -static void *state_parse_name(automata *a, char c) +static void state_parse_data(automata *a, char c); +static void state_parse_name(automata *a, char c) { if (c == '&' || c == ';') { - return 0; + a->s = 0; + return; } if (c == '=') { - if (!deurl(&a->name.data)) { - return 0; + if (!deurl(&a->name)) { + a->s = 0; + return; } - return state_parse_name; + a->s = state_parse_data; } - magi_str_add(&a->name, c); - return a->name.size ? state_parse_name : 0; + magi_str_add(&a->name, &a->nlen, &a->nsize, c); } -static int add_to_list(automata *a) +static void add_to_list(automata *a) { magi_param param; - param.name = a->name.data; - param.data = a->data.data; - if (!magi_param_list_add(a->list, param)) { - return 0; - } - a->name.data = 0; - a->data.data = 0; - return 1; + param.name = a->name; + param.data = a->data; + magi_params_add(a->list, ¶m); + a->name = 0; + a->data = 0; } static void state_parse_data(automata *a, char c) { if (c == '=') { - return 0; + a->s = 0; + return; } if (c == '&' || c == ';') { - if (!deurl(&a->data.data) || !add_to_list(a)) { - return 0; + if (!deurl(&a->data)) { + a->s = 0; + return; } - return state_parse_name; + add_to_list(a); + a->s = state_parse_name; } - magi_str_add(&a->data, c); - return a->data.size ? state_parse_data : 0; + magi_str_add(&a->data, &a->dlen, &a->dsize, c); } -magi_error magi_urlencoded(magi_param_list **list, const char *encoded) +magi_error magi_parse_urlencoded(magi_params **list, const char *encoded) { - st state; - automata a = { 0, { 0, 0 }, 1, 0 }; + automata a = { state_parse_name, 0, 0, 0, 0, 0, 0, 0 }; a.list = list; *list = 0; if (!encoded || !*encoded) { return 0; } - for (; *encoded; ++encoded) { - s = s(&a, *encoded); - if (!s) { - return auto_free(a); - } + for (; *encoded && a.s; ++encoded) { + a.s(&a, *encoded); } - if (state == st_name || !state || !end_data(&a)) { - free(a.param.name); - free(a.param.data); - return auto_free(a); + if (a.s == state_parse_name || !a.s || !deurl(&a.data)) { + return magi_error_urlenc; } + add_to_list(&a); return 0; } -- cgit v1.2.3