From ea25abb295d9b4fbaf0ac23af8ffe71247970f1b Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 27 Nov 2019 21:33:06 +0300 Subject: . --- examples/fcgi.c | 2 +- src/cgi.c | 14 ++- src/cgi.h | 12 +- src/cookie.c | 369 +++----------------------------------------------------- src/cookie.h | 18 ++- src/cookies.c | 329 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/fastcgi.c | 1 + src/fastcgi.h | 16 +-- src/file.c | 40 ++++++ src/file.h | 22 +++- src/param.c | 38 ++---- src/param.h | 17 +-- src/request.c | 51 +++++++- src/request.h | 40 ++++-- src/response.h | 3 + 15 files changed, 531 insertions(+), 441 deletions(-) diff --git a/examples/fcgi.c b/examples/fcgi.c index 72fe83e..7d93614 100644 --- a/examples/fcgi.c +++ b/examples/fcgi.c @@ -39,7 +39,7 @@ int main(int argc, char const * argv[]) magi_request_destroy(&request); } } - puts(magi_error_message(session.error)); + fputs(magi_error_message(session.error), stderr); magi_session_destroy(&session); magi_socket_close(sock); return 0; diff --git a/src/cgi.c b/src/cgi.c index cf74f14..48b2a93 100644 --- a/src/cgi.c +++ b/src/cgi.c @@ -2,11 +2,11 @@ #include "cookie.h" #include "error.h" -#include "field.h" +#include "file.h" #include "multipart.h" #include "param.h" #include "request.h" -#include "urlencoded.h" +#include "urlenc.h" #include #include #include @@ -16,9 +16,8 @@ extern char ** environ; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * CGI Request Handling + * CGI Request */ -/* Helpers for CGI Request Handling */ static int plain_env(char ** dest, char * env_name) { int ok = 1; @@ -160,7 +159,7 @@ static int intput_getter(void * any) } /* Interfacial CGI Request Handling */ -int magi_cgi_request(struct magi_request * request, +int magi_request_cgi(struct magi_request * request, void (*callback)(struct magi_field * field, char * buffer, int len), @@ -205,3 +204,8 @@ int magi_cgi_request(struct magi_request * request, } return request->error == magi_error_none; } + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * CGI Response + */ diff --git a/src/cgi.h b/src/cgi.h index 6cca424..6101de6 100644 --- a/src/cgi.h +++ b/src/cgi.h @@ -1,17 +1,27 @@ #ifndef MAGI_INCLUDED_CGI #define MAGI_INCLUDED_CGI +#include "error.h" #include "request.h" +#include "response.h" -/* Constructs request from environment and standard input; +/* Constructs non-post part of request from environment; * Returns null only in case of error. */ int magi_request_cgi(struct 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); + /* Sends response to standard output; * Returns null only in case of error. */ int magi_response_cgi(struct 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); + #endif diff --git a/src/cookie.c b/src/cookie.c index d04eccf..506e4ef 100644 --- a/src/cookie.c +++ b/src/cookie.c @@ -1,370 +1,31 @@ #include "cookie.h" -#include "error.h" #include #include -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Cookie Parse - */ -enum st { - st_error = 0, - st_pre_name, - st_name, - st_post_name, - st_pre_data, - st_data, - st_post_data -}; - -enum data_type { dt_plain = 0, dt_version, dt_path, dt_domain, dt_port }; - -struct automata { - struct magi_cookie_list ** list; - struct magi_cookie cookie; - char * buf; - int buf_len; - int buf_size; - int is_first; - int is_cookie2; - int is_quoted; - enum data_type data_t; -}; - -static void nulify_cookie(struct automata * a) -{ - a->cookie.name = 0; - a->cookie.data = 0; - a->cookie.path = 0; - a->cookie.domain = 0; - a->cookie.port = 0; -} - -static void buf_new(struct automata * a) -{ - a->buf = 0; - a->buf_len = 0; - a->buf_size = 1; -} - -static int buf_add(struct automata * a, char c) -{ - int ok = 1; - if (a->buf_len == a->buf_size - 1) { - a->buf_size *= 2; - a->buf = realloc(a->buf, a->buf_size); - } - if (a->buf) { - a->buf_len++; - a->buf[a->buf_len - 1] = c; - a->buf[a->buf_len] = 0; - } else { - ok = 0; - magi_error_set("[cookie] Cannot allocate automata buffer."); - } - return ok; -} - -static enum data_type what_is_name(const struct automata * a) -{ - enum data_type data_t = dt_plain; - if (a->is_first && !strcmp(a->buf, "$Version")) { - data_t = dt_version; - } else if (a->is_cookie2) { - if (!strcmp(a->buf, "$Path")) { - data_t = dt_path; - } else if (!strcmp(a->buf, "$Domain")) { - data_t = dt_domain; - } else if (!strcmp(a->buf, "$Port")) { - data_t = dt_port; - } - } - return data_t; -} - -static int end_name(struct automata * a) -{ - int ok = 1; - a->data_t = what_is_name(a); - if (a->data_t == dt_plain) { - if (a->cookie.name) { - ok = magi_cookie_list_add(a->list, &a->cookie); - } - nulify_cookie(a); - a->cookie.name = a->buf; - } else { - free(a->buf); - } - buf_new(a); - return ok; -} - -static int end_data(struct 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_port: - a->cookie.port = a->buf; - break; - case dt_version: - if (strcmp(a->buf, "1")) { - ok = 0; - magi_error_set("[cookie] Version must be '1', readed: %s.", - a->buf); - } - } - buf_new(a); - return ok; -} - -static enum st parse_pre_name(struct automata * a, char c) -{ - enum st state; - if (c == ' ' || c == '\t') { - state = st_name; - } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { - state = st_name; - if (!buf_add(a, c)) { - state = st_error; - } - } else { - state = st_error; - magi_error_set("[cookie] Pre-name, readed: \\%o (render: %c).", c, c); - } - return state; -} - -static enum st parse_name(struct automata * a, char c) -{ - enum st state; - if (c == '=') { - state = st_pre_data; - if (!end_name(a)) { - state = st_error; - } - } else if (c == ' ' || c == '\t') { - state = st_post_name; - if (!end_name(a)) { - state = st_error; - } - } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { - state = st_name; - if (!buf_add(a, c)) { - state = st_error; - } - } else { - state = st_error; - magi_error_set("[cookie] Reading name, readed: \\%o (render: %c).", c, - c); - } - return state; -} - -static enum st parse_post_name(struct automata * a, char c) -{ - enum st state; - if (c == '=') { - state = st_pre_data; - } else if (c == ' ' || c == '\t') { - state = st_post_name; - } else { - state = st_error; - magi_error_set("[cookie] Waiting for name-value separator, " - "readed: \\%o (render: %c).", - c, c); - } - return state; -} - -static enum st parse_pre_data(struct automata * a, char c) -{ - enum st state; - if (c == ' ' || c == '\t') { - state = st_pre_data; - } else if (c == '"') { - state = st_data; - a->is_quoted = 1; - } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { - state = st_data; - if (!buf_add(a, c)) { - state = st_error; - } - } else { - state = st_error; - magi_error_set("[cookie] Pre-value, readed: \\%o (render: %c).", c, c); - } - return state; -} - -static enum st parse_not_quoted_data(struct automata * a, char c) -{ - enum st state; - if (c == ';' || (c == ',' && a->is_first)) { - state = st_pre_name; - a->is_first = 0; - if (!end_data(a)) { - state = st_error; - } - } else if (c == ' ' || c == '\t') { - state = st_post_data; - if (!end_data(a)) { - state = st_error; - } - } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { - state = st_data; - if (!buf_add(a, c)) { - state = st_error; - } - } else { - state = st_error; - magi_error_set("[cookie] Reading not-quoted value, " - "readed: \\%o (render: %c).", - c, c); - } - return state; -} - -static enum st parse_data(struct automata * a, char c) -{ - enum st state; - if (a->is_quoted) { - if (c == '"') { - state = st_post_data; - a->is_quoted = 0; - if (!end_data(a)) { - state = st_error; - } - } else { - state = st_data; - } - } else { - state = parse_not_quoted_data(a, c); - } - return state; -} - -static enum st parse_post_data(struct automata * a, char c) -{ - enum st state; - if (c == ';' || (c == ',' && a->is_first)) { - state = st_pre_name; - } else if (c == ' ' || c == '\t') { - state = st_post_data; - } else { - state = st_error; - magi_error_set( - "[cookie] Waiting for separator between name-value pairs, " - "readed: \\%o (render: %c).", - c, c); - } - return state; -} - -static int parse_end(struct automata * a, enum st s) -{ - int ok = 0; - if (s == st_post_data) { - ok = 1; - } else if (s == st_data) { - if (!a->is_quoted) { - if (a->cookie.name) { - if (end_data(a) && magi_cookie_list_add(a->list, &a->cookie)) { - ok = 1; - nulify_cookie(a); - buf_new(a); - } - } else { - magi_error_set("[cookie] No cookies set."); - } - } else { - magi_error_set("[cookie] In quotation when reached input end."); - } - } else if (s != st_error) { - magi_error_set("[cookie] Input ended in not correct state."); - } - free(a->cookie.name); - free(a->cookie.data); - free(a->cookie.path); - free(a->cookie.domain); - free(a->cookie.port); - free(a->buf); - return ok; -} - -int magi_parse_cookie(struct magi_cookie_list ** list, const char * input) -{ - struct automata a = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 1, 1, 0, 0, 0 }; - enum st state = st_pre_name; - a.list = list; - while (*input && state) { - char c = *input++; - switch (state) { - case st_pre_name: - state = parse_pre_name(&a, c); - break; - case st_name: - state = parse_name(&a, c); - break; - case st_post_name: - state = parse_post_name(&a, c); - break; - case st_pre_data: - state = parse_pre_data(&a, c); - break; - case st_data: - state = parse_data(&a, c); - break; - case st_post_data: - state = parse_post_data(&a, c); - default: - break; - } - } - return parse_end(&a, state); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Cookie List - */ int magi_cookie_list_add(struct magi_cookie_list ** list, struct magi_cookie * item) { - struct magi_cookie_list * old = *list; - int ok = 1; - *list = malloc(sizeof(**list)); - if (*list) { - (*list)->next = old; - (*list)->item = *item; - } else { - ok = 0; - magi_error_set("[cookie:list] Cannot allocate new list node."); - *list = old; + struct magi_cookie_list * node = malloc(sizeof(*node)); + if (node) { + node->next = *list; + node->item = *item; + *list = node; } - return ok; + return node; } -char * magi_cookie_list_get(struct magi_cookie_list * list, const char * name) +struct magi_cookie * magi_cookie_list_get(struct magi_cookie_list * list, + const char * name) { - char * data = 0; - if (list && name) { - if (!strcmp(list->item.name, name)) { - data = list->item.data; - } else { - data = magi_cookie_list_get(list->next, name); - } + if (!list || !name) { + return 0; + } else if (!strcmp(list->item.name, name)) { + return &list->item; + } else { + return magi_cookie_list_get(list->next, name); } - return data; } void magi_cookie_list_destroy(struct magi_cookie_list * list) @@ -374,8 +35,8 @@ void magi_cookie_list_destroy(struct magi_cookie_list * list) free(list->next); free(list->item.name); free(list->item.data); - free(list->item.domain); free(list->item.path); + free(list->item.domain); free(list->item.port); } } diff --git a/src/cookie.h b/src/cookie.h index 479ab9f..82c914e 100644 --- a/src/cookie.h +++ b/src/cookie.h @@ -2,10 +2,8 @@ #define MAGI_INCLUDED_COOKIE -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Cookie - */ struct magi_cookie { + /* All pointers must be valid as 'free' arguments. */ char * name; char * data; char * path; @@ -14,21 +12,21 @@ struct magi_cookie { }; struct magi_cookie_list { - struct magi_cookie_list * next; + struct magi_cookie_list * next; /* Must be valid as 'free' arguments. */ struct magi_cookie item; }; -/* Returns null only in case of error. */ +/* Addition of item to top of list. Null <=> 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. */ -char * magi_cookie_list_get(struct magi_cookie_list * list, const char * name); +/* First node in list: node.name == name; else null. */ +struct magi_cookie * magi_cookie_list_get(struct magi_cookie_list * list, + const char * name); -/* Destroys list. */ -void magi_cookie_list_free(struct magi_cookie_list * list); +/* Freeing and invalidation of list. */ +void magi_cookie_list_destroy(struct magi_cookie_list * list); #endif diff --git a/src/cookies.c b/src/cookies.c index e69de29..f690ccc 100644 --- a/src/cookies.c +++ b/src/cookies.c @@ -0,0 +1,329 @@ +#include "cookies.h" + +#include + + +enum st { + st_error = 0, + st_pre_name, + st_name, + st_post_name, + st_pre_data, + st_data, + st_post_data +}; + +enum data_type { dt_plain = 0, dt_version, dt_path, dt_domain, dt_port }; + +struct automata { + struct magi_cookie_list ** list; + struct magi_cookie cookie; + char * buf; + int buf_len; + int buf_size; + int is_first; + int is_cookie2; + int is_quoted; + enum data_type data_t; +}; + +static void nulify_cookie(struct automata * a) +{ + a->cookie.name = 0; + a->cookie.data = 0; + a->cookie.path = 0; + a->cookie.domain = 0; + a->cookie.port = 0; +} + +static void buf_new(struct automata * a) +{ + a->buf = 0; + a->buf_len = 0; + a->buf_size = 1; +} + +static int buf_add(struct automata * a, char c) +{ + int ok = 1; + if (a->buf_len == a->buf_size - 1) { + a->buf_size *= 2; + a->buf = realloc(a->buf, a->buf_size); + } + if (a->buf) { + a->buf_len++; + a->buf[a->buf_len - 1] = c; + a->buf[a->buf_len] = 0; + } else { + ok = 0; + magi_error_set("[cookie] Cannot allocate automata buffer."); + } + return ok; +} + +static enum data_type what_is_name(const struct automata * a) +{ + enum data_type data_t = dt_plain; + if (a->is_first && !strcmp(a->buf, "$Version")) { + data_t = dt_version; + } else if (a->is_cookie2) { + if (!strcmp(a->buf, "$Path")) { + data_t = dt_path; + } else if (!strcmp(a->buf, "$Domain")) { + data_t = dt_domain; + } else if (!strcmp(a->buf, "$Port")) { + data_t = dt_port; + } + } + return data_t; +} + +static int end_name(struct automata * a) +{ + int ok = 1; + a->data_t = what_is_name(a); + if (a->data_t == dt_plain) { + if (a->cookie.name) { + ok = magi_cookie_list_add(a->list, &a->cookie); + } + nulify_cookie(a); + a->cookie.name = a->buf; + } else { + free(a->buf); + } + buf_new(a); + return ok; +} + +static int end_data(struct 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_port: + a->cookie.port = a->buf; + break; + case dt_version: + if (strcmp(a->buf, "1")) { + ok = 0; + magi_error_set("[cookie] Version must be '1', readed: %s.", + a->buf); + } + } + buf_new(a); + return ok; +} + +static enum st parse_pre_name(struct automata * a, char c) +{ + enum st state; + if (c == ' ' || c == '\t') { + state = st_name; + } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { + state = st_name; + if (!buf_add(a, c)) { + state = st_error; + } + } else { + state = st_error; + magi_error_set("[cookie] Pre-name, readed: \\%o (render: %c).", c, c); + } + return state; +} + +static enum st parse_name(struct automata * a, char c) +{ + enum st state; + if (c == '=') { + state = st_pre_data; + if (!end_name(a)) { + state = st_error; + } + } else if (c == ' ' || c == '\t') { + state = st_post_name; + if (!end_name(a)) { + state = st_error; + } + } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { + state = st_name; + if (!buf_add(a, c)) { + state = st_error; + } + } else { + state = st_error; + magi_error_set("[cookie] Reading name, readed: \\%o (render: %c).", c, + c); + } + return state; +} + +static enum st parse_post_name(struct automata * a, char c) +{ + enum st state; + if (c == '=') { + state = st_pre_data; + } else if (c == ' ' || c == '\t') { + state = st_post_name; + } else { + state = st_error; + magi_error_set("[cookie] Waiting for name-value separator, " + "readed: \\%o (render: %c).", + c, c); + } + return state; +} + +static enum st parse_pre_data(struct automata * a, char c) +{ + enum st state; + if (c == ' ' || c == '\t') { + state = st_pre_data; + } else if (c == '"') { + state = st_data; + a->is_quoted = 1; + } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { + state = st_data; + if (!buf_add(a, c)) { + state = st_error; + } + } else { + state = st_error; + magi_error_set("[cookie] Pre-value, readed: \\%o (render: %c).", c, c); + } + return state; +} + +static enum st parse_not_quoted_data(struct automata * a, char c) +{ + enum st state; + if (c == ';' || (c == ',' && a->is_first)) { + state = st_pre_name; + a->is_first = 0; + if (!end_data(a)) { + state = st_error; + } + } else if (c == ' ' || c == '\t') { + state = st_post_data; + if (!end_data(a)) { + state = st_error; + } + } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) { + state = st_data; + if (!buf_add(a, c)) { + state = st_error; + } + } else { + state = st_error; + magi_error_set("[cookie] Reading not-quoted value, " + "readed: \\%o (render: %c).", + c, c); + } + return state; +} + +static enum st parse_data(struct automata * a, char c) +{ + enum st state; + if (a->is_quoted) { + if (c == '"') { + state = st_post_data; + a->is_quoted = 0; + if (!end_data(a)) { + state = st_error; + } + } else { + state = st_data; + } + } else { + state = parse_not_quoted_data(a, c); + } + return state; +} + +static enum st parse_post_data(struct automata * a, char c) +{ + enum st state; + if (c == ';' || (c == ',' && a->is_first)) { + state = st_pre_name; + } else if (c == ' ' || c == '\t') { + state = st_post_data; + } else { + state = st_error; + magi_error_set( + "[cookie] Waiting for separator between name-value pairs, " + "readed: \\%o (render: %c).", + c, c); + } + return state; +} + +static int parse_end(struct automata * a, enum st s) +{ + int ok = 0; + if (s == st_post_data) { + ok = 1; + } else if (s == st_data) { + if (!a->is_quoted) { + if (a->cookie.name) { + if (end_data(a) && magi_cookie_list_add(a->list, &a->cookie)) { + ok = 1; + nulify_cookie(a); + buf_new(a); + } + } else { + magi_error_set("[cookie] No cookies set."); + } + } else { + magi_error_set("[cookie] In quotation when reached input end."); + } + } else if (s != st_error) { + magi_error_set("[cookie] Input ended in not correct state."); + } + free(a->cookie.name); + free(a->cookie.data); + free(a->cookie.path); + free(a->cookie.domain); + free(a->cookie.port); + free(a->buf); + return ok; +} + +int magi_parse_cookie(struct magi_cookie_list ** list, const char * input) +{ + struct automata a = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 1, 1, 0, 0, 0 }; + enum st state = st_pre_name; + a.list = list; + while (*input && state) { + char c = *input++; + switch (state) { + case st_pre_name: + state = parse_pre_name(&a, c); + break; + case st_name: + state = parse_name(&a, c); + break; + case st_post_name: + state = parse_post_name(&a, c); + break; + case st_pre_data: + state = parse_pre_data(&a, c); + break; + case st_data: + state = parse_data(&a, c); + break; + case st_post_data: + state = parse_post_data(&a, c); + default: + break; + } + } + return parse_end(&a, state); +} diff --git a/src/fastcgi.c b/src/fastcgi.c index e69de29..39c57ca 100644 --- a/src/fastcgi.c +++ b/src/fastcgi.c @@ -0,0 +1 @@ +#include "fastcgi.h" diff --git a/src/fastcgi.h b/src/fastcgi.h index 5410955..d701fe0 100644 --- a/src/fastcgi.h +++ b/src/fastcgi.h @@ -1,22 +1,8 @@ #ifndef MAGI_INCLUDED_FASTCGI #define MAGI_INCLUDED_FASTCGI -#include "error.h" -#include "file.h" -#include "request.h" - -struct magi_session { - struct magi_socket_list * sockets; - enum magi_error error; -}; - -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); +/* TODO */ #endif diff --git a/src/file.c b/src/file.c index e69de29..df6c978 100644 --- a/src/file.c +++ b/src/file.c @@ -0,0 +1,40 @@ +#include "file.h" + +#include +#include + + +int magi_file_list_add(struct magi_file_list ** list, struct magi_file * item) +{ + struct magi_file_list * node = malloc(sizeof(*node)); + if (node) { + node->next = *list; + node->item = *item; + *list = node; + } + return node; +} + +struct magi_file * magi_file_list_get(struct magi_file_list * list, + const char * name) +{ + if (!list || !name) { + return 0; + } else if (!strcmp(list->item.param_name, name)) { + return &list->item; + } else { + return magi_file_list_get(list->next, name); + } +} + +void magi_file_list_destroy(struct magi_file_list * list) +{ + if (list) { + magi_file_list_destroy(list->next); + free(list->next); + free(list->item.param_name); + free(list->item.file_name); + magi_param_list_destroy(list->item.params); + free(list->item.params); + } +} diff --git a/src/file.h b/src/file.h index 0994755..a677e2f 100644 --- a/src/file.h +++ b/src/file.h @@ -3,9 +3,27 @@ struct magi_file { - char * param_name; - struct magi_para_list * params; + /* 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) */ }; +struct magi_file_list { + struct magi_file_list * next; /* Must be valid as 'free' argument. */ + struct magi_file item; +}; + + +/* Addition of item to top of list. Null <=> error. */ +int magi_file_list_add(struct magi_file_list ** list, struct 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); + +/* Freeing and invalidation of list. */ +void magi_file_list_destroy(struct magi_file_list * list); + #endif diff --git a/src/param.c b/src/param.c index d87a610..73005af 100644 --- a/src/param.c +++ b/src/param.c @@ -1,42 +1,30 @@ #include "param.h" -#include "error.h" #include #include -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Parameter - */ int magi_param_list_add(struct magi_param_list ** list, struct magi_param * item) { - struct magi_param_list * old = *list; - int ok = 1; - *list = malloc(sizeof(**list)); - if (*list) { - (*list)->next = old; - (*list)->item = *item; - } else { - ok = 0; - magi_error_set("[param:list] Cannot allocate new list node."); - *list = old; + struct magi_param_list * node = malloc(sizeof(*node)); + if (node) { + node->next = *list; + node->item = *item; + *list = node; } - return ok; + return node; } -struct magi_param * magi_param_list_get(struct magi_param_list * list, - const char * name) +char * magi_param_list_get(struct magi_param_list * list, const char * name) { - struct magi_param * item = 0; - if (list && name) { - if (!strcmp(list->item.name, name)) { - item = &list->item; - } else { - item = magi_param_list_get(list->next, name); - } + if (!list || !name) { + return 0; + } else if (!strcmp(list->item.name, name)) { + return &list->item.data; + } else { + return magi_param_list_get(list->next, name); } - return item; } void magi_param_list_destroy(struct magi_param_list * list) diff --git a/src/param.h b/src/param.h index 6fd0ba0..3f8cefe 100644 --- a/src/param.h +++ b/src/param.h @@ -2,31 +2,26 @@ #define MAGI_INCLUDED_PARAM -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Parameter - */ struct magi_param { + /* All pointers must be valid as 'free' arguments. */ char * name; char * data; }; struct magi_param_list { - struct magi_param_list * next; + struct magi_param_list * next; /* Must be valid as 'free' argument. */ struct magi_param item; }; -/* Adds *item to the begining of *list, item and list are dereferencable; - * Returns null in case of error. */ +/* Addition of item to top of list. Null <=> 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. */ -struct magi_param * magi_param_list_get(struct magi_param_list * list, - const char * name); +/* 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); -/* Destroys list; list is not valid after destruction. */ +/* Freeing and invalidation of list. */ void magi_param_list_destroy(struct magi_param_list * list); diff --git a/src/request.c b/src/request.c index 2d9625e..4a1464a 100644 --- a/src/request.c +++ b/src/request.c @@ -3,21 +3,60 @@ #include "cookie.h" #include "file.h" #include "param.h" +#include #include +#include 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; + request->file_callback = 0; + request->file_callback_userdata = 0; + request->file_callback_addon_max = 64; + request->cookies_max = 1024 * 8; + request->url_params_max = 1024 * 2; + request->http_params_max = 1024 * 16; + request->params_max = 0; } } +static void tempfiles(struct magi_file * file, + char * addon, + int addon_len, + int is_addon_last, + struct magi_tempfiles * table) +{ + int pos; + for (pos = 0; pos != table->count; ++pos) { + if (!strcmp(table->param_names[pos], file->param_name)) { + static FILE * f = 0; + static int left; + int min; + if (!f) { + const char * loc = table->locations[pos]; + f = fopen(loc, "wb"); + left = table->maximums[pos]; + } + min = left < addon_len ? left : addon_len; + fwrite(addon, 1, min, f); + left -= min; + if (is_addon_last) { + fclose(f); + f = 0; + } + return; + } + } +} + +void magi_request_setup_tempfiles(struct magi_request * request, + struct magi_tempfiles * table) +{ + request->file_callback = tempfiles; + request->file_callback_userdata = table; +} + static void request_free(struct magi_request * request) { diff --git a/src/request.h b/src/request.h index 15a5da6..5bb2070 100644 --- a/src/request.h +++ b/src/request.h @@ -10,10 +10,16 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Request * - * Can be generated via CGI handler (magi_cgi_request) or - * in a Fast CGI session (magi_fcgi_request). + * Can be created via 'magi_request_{gateway interface name}', but will have + * nullified 'post'-related fields ('params' & 'files'). Reason is unlimited + * 'post' body size, with possible dependence of wanted limits from data of + * headers (e.g. session id from cookies, enabling some users to load more). + * To proceed 'post' use 'magi_request_resume_{gateway interface name}', + * specifying settings if necessary. * * + * Cheatsheet on environment: + * * Request URL: http[s]://{server_name}[:{server_port}]{uri} * example.com 80 * uri: {document_uri}[?{urlencode(url_params)}] @@ -23,13 +29,14 @@ */ 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; /* Files loaded via multipart */ + struct magi_file_list * files; /* 'Post' multipart files */ /* Environment Shortcuts */ char * method; /* REQUEST_METHOD */ @@ -41,9 +48,9 @@ struct magi_request { 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 */ + /* 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 */ @@ -53,7 +60,7 @@ struct magi_request { enum magi_error error; - /* * * Internal Data (no need for user to analyse) * * */ + /* * * Settings * * */ /* Callback for processing files */ void (*file_callback)(struct magi_file * file, @@ -62,18 +69,29 @@ struct magi_request { int is_addon_last, void * userdata); void * file_callback_userdata; - int file_callback_addon_len_max; + int file_callback_addon_max; - /* Limit for memory used (disables with zero) */ - int max_cookies_size; - int max_http_params_size; - int max_params_size; + /* Limits for memory used (null <=> unlimitted) */ + int cookies_max; + int url_params_max; + int http_params_max; + int params_max; }; /* 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]. */ +}; +/* 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); /* Destroys request. */ void magi_request_destroy(struct magi_request * request); diff --git a/src/response.h b/src/response.h index 04d7350..346ce3d 100644 --- a/src/response.h +++ b/src/response.h @@ -33,4 +33,7 @@ void magi_response_cookie_delete(struct magi_response * response, const char * name); +void magi_response_destroy(struct magi_response * response); + + #endif -- cgit v1.2.3