From 5cfe6cdf6af2d630d21871f9193fc1b4a7db24ff Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Mon, 9 Mar 2020 20:17:28 +0300 Subject: [magi] --- src/cgi.c | 353 ++++++++++++++++++++++++------------------------------- src/cookies.h | 4 +- src/loadfile.c | 37 +++--- src/multipart.h | 12 +- src/request.c | 31 +++-- src/response.c | 18 +++ src/tools.c | 5 +- src/tools.h | 2 +- src/urlencoded.h | 2 +- 9 files changed, 222 insertions(+), 242 deletions(-) (limited to 'src') diff --git a/src/cgi.c b/src/cgi.c index efb05c2..00b0a06 100644 --- a/src/cgi.c +++ b/src/cgi.c @@ -7,6 +7,7 @@ #include "multipart.h" #include "param.h" #include "request.h" +#include "response.h" #include "tools.h" #include "urlencoded.h" #include @@ -14,211 +15,230 @@ #include #include -extern char ** environ; +extern char **environ; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CGI Request */ -static int plain_env(char ** dest, char * env_name) +static char *plain_env(char *env_name) { - const char * env = getenv(env_name); - if (env) { - *dest = magi_str_create(strlen(env)); - if (!*dest) { - return 0; - } - strcpy(*dest, env); - } else { - *dest = 0; + const char *env = getenv(env_name); + if (!env) { + return 0; } - return 1; + return magi_str_create_copy(env, strlen(env)); } -static int lower_env(char ** dest, char * env_name) +static char *lower_env(char *env_name) { - if (plain_env(dest, env_name)) { - magi_str_lowercase(*dest); - return 1; - } - return 0; + return magi_str_lowercase(plain_env(env_name)); } -static int cgi_http_env(struct magi_request * r) +static void cgi_http_env(magi_request *r) { - char ** env = environ; - r->http_params = 0; - while (*env) { - if (!strncmp(*env, "HTTP_", 5) && strncmp(*env, "HTTP_COOKIE=", 12)) { - struct magi_param param; - /* At least one '=' must be in *env, according to format. */ - char * name_end = strchr(*env, '='); - param.name = magi_str_create(name_end - *env - 5); - if (param.name) { - memcpy(param.name, *env + 5, name_end - *env - 5); - param.data = magi_str_create(strlen(name_end + 1)); - if (param.data) { - strcpy(param.data, name_end + 1); - } else { - free(param.name); - } - } - if (!param.name || !param.data || - !magi_param_list_add(&r->http_params, ¶m)) { - r->error = magi_error_memory; - return 0; - } + char **env; + int len = 0; + r->meta = 0; + for (env = environ; *env; ++env) { + magi_param meta; + char *name_end; + int dlen; + if (!strncmp(*env, "HTTP_COOKIE=", 12) || + !strncmp(*env, "QUERY_STRING=", 13)) { + continue; + } + /* At least one '=' must be in *env, according to format. */ + name_end = strchr(*env, '='); + dlen = strlen(name_end + 1); + len += name_end - *env + dlen; + if (len > r->limits.params_meta && r->limits.params_meta) { + r->error = magi_error_limit; + return; } - ++env; + meta.name = magi_str_create_copy(*env, name_end - *env); + meta.data = magi_str_create_copy(name_end + 1, dlen); + magi_params_add(&r->meta, &meta); } - return 1; } -static void cgi_env(struct magi_request * r) +static void cgi_env(magi_request *r) { - if (!cgi_http_env(r) || !lower_env(&r->method, "REQUEST_METHOD") || - !plain_env(&r->uri, "REQUEST_URI") || - !plain_env(&r->document_root, "DOCUMENT_ROOT") || - !plain_env(&r->document_uri, "DOCUMENT_URI") || - !plain_env(&r->script_name, "SCRIPT_NAME") || - !plain_env(&r->script_filename, "SCRIPT_FILENAME") || - !plain_env(&r->remote_addr, "REMOTE_ADDR") || - !plain_env(&r->remote_port, "REMOTE_PORT") || - !plain_env(&r->server_addr, "SERVER_ADDR") || - !lower_env(&r->server_name, "SERVER_NAME") || - !plain_env(&r->server_port, "SERVER_PORT") || - !lower_env(&r->server_protocol, "SERVER_PROTOCOL") || - !plain_env(&r->server_software, "SERVER_SOFTWARE") || - !plain_env(&r->path_info, "PATH_INFO")) { - r->error = magi_error_memory; + cgi_http_env(r); + r->method = plain_env("REQUEST_METHOD"); + r->document_root = plain_env("DOCUMENT_ROOT"); + r->script = plain_env("SCRIPT_NAME"); + r->host = lower_env("HTTP_HOST"); + if (!r->host) { + r->host = lower_env("SERVER_NAME"); + } + if (getenv("SERVER_PORT")) { + r->port = atoi(getenv("SERVER_PORT")); + r->is_secure = r->port == 443; } + r->path = plain_env("PATH_INFO"); } -static int cgi_cookies(struct magi_request * r) +static void cgi_cookies(magi_request *r) { - const char * env = getenv("HTTP_COOKIE"); + const char *env = getenv("HTTP_COOKIE"); if (!env || !*env) { r->cookies = 0; - return 1; + return; } - if (strlen(env) < r->cookies_max && r->cookies_max) { - magi_cookies(r, env); - } else { + if (strlen(env) > r->limits.cookies && r->limits.cookies) { r->error = magi_error_limit; + return; } - return r->error; + magi_parse_cookies(r, env); } -static void cgi_input_get(enum magi_error * e, char ** input, int max) +static void cgi_input_get(magi_error *e, char **input, int max) { - const char * env_input = getenv("QUERY_STRING"); + const char *env_input = getenv("QUERY_STRING"); if (env_input) { int len = strlen(env_input); if (len >= max && max) { *e = magi_error_limit; return; } - *input = magi_str_create(len); - if (!*input) { - *e = magi_error_memory; - return; - } - strcpy(*input, env_input); + *input = magi_str_create_copy(env_input, len); } } -static void cgi_url(struct magi_request * request) +static void cgi_url(magi_request *request) { - char * in = 0; - cgi_input_get(&request->error, &in, request->url_params_max); + char *in = 0; + cgi_input_get(&request->error, &in, request->limits.params_head); if (!request->error) { - magi_urlencoded(&request->url_params, request, in); + magi_parse_urlencoded(&request->head, in); + free(in); } - free(in); } -static void cgi_input_post(enum magi_error * e, char ** input, int max) +static void cgi_input_post(magi_error *e, char **input, int max) { - if (!*e) { - int input_len = strtoul(getenv("CONTENT_LENGTH"), 0, 10); - if (!input_len) { - *e = magi_error_length; - return; - } - if (input_len >= max && max) { - *e = magi_error_limit; - return; - } - *input = magi_str_create(input_len); - if (!*input) { - *e = magi_error_memory; - return; - } - if (fread(*input, 1, input_len, stdin) != input_len) { - *e = magi_error_length; - return; - } + int input_len = strtoul(getenv("CONTENT_LENGTH"), 0, 10); + if (!input_len) { + *e = magi_error_length; + return; + } + if (input_len > max && max) { + *e = magi_error_limit; + return; + } + *input = magi_str_create(input_len); + if (fread(*input, 1, input_len, stdin) != input_len) { + *e = magi_error_length; + return; } } -static char * bound(const char * type) +static char *bound(const char *type) { - char * res = 0; - type = strchr(type, '='); - if (type) { - type += strspn(type, " \t") + 1; - if (*type == '"') { - ++type; - res = magi_str_create_copy(type, type - strchr(type, '"')); - } else { - res = magi_str_create_copy(type, strcspn(type, " \t")); - } + type = strchr(type, '='); + if (!type) { + return 0; + } + type += strspn(type, " \t") + 1; + if (*type == '"') { + ++type; + return magi_str_create_copy(type, type - strchr(type, '"')); } - return res; + return magi_str_create_copy(type, strcspn(type, " \t")); } -static int next(void * any) +static int next() { return getchar(); } -/* Interfacial CGI Request Handling */ -int magi_request_cgi(struct magi_request * request) +static void mhead(void *any, magi_param *header) +{ + fputs(header->name, stdout); + fputs(": ", stdout); + fputs(header->data, stdout); + fputs("\r\n", stdout); +} + +static void mstart_body(void *any) +{ + fputs("\r\n", stdout); +} + +static void mbody(void *any, const char *data, int len) +{ + fwrite(data, 1, len, stdout); +} + +static void mfile(void *any, FILE *file) +{ + while (!feof(file)) { + char buf[64]; + int len = fread(buf, 1, 64, file); + fwrite(buf, 1, len, stdout); + } +} + +static void mclose(void *any) {} + +static void setup_response(magi_request *r) { - request->files = 0; - request->params = 0; - request->url_params = 0; - request->http_params = 0; - request->error = magi_error_none; + static const magi_response_methods m = { + mhead, + mstart_body, + mbody, + 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; +} + +/* Interfacial CGI Request Handling */ +int magi_cgi_head(magi_request *request) +{ + request->cookies = 0; + request->files = 0; + request->meta = 0; + request->head = 0; + request->body = 0; + request->error = 0; cgi_env(request); cgi_cookies(request); cgi_url(request); + setup_response(request); return !request->error; } -int magi_request_resume_cgi(struct magi_request * request) +int magi_cgi_body(magi_request *request) { - enum magi_error * e = &request->error; - request->error = magi_error_none; - if (request->method && !strcmp(request->method, "post")) { - const char * t = getenv("CONTENT_TYPE"); + magi_error *e = &request->error; + request->error = magi_error_none; + if (request->method && !strcmp(request->method, "POST")) { + const char *t = getenv("CONTENT_TYPE"); if (!t) { *e = magi_error_notype; return 0; } if (!strncmp(t, "multipart/form-data", 19)) { - char * boundary = bound(t); + char *boundary = bound(t); if (boundary && *boundary) { - magi_multipart(request, boundary, next, 0); + magi_parse_multipart(request, boundary, next, 0); } else { *e = magi_error_nobound; } free(boundary); } else if (!strcmp(t, "application/x-www-form-urlencoded")) { - char * in = 0; - cgi_input_post(e, &in, request->params_max); + char *in = 0; + cgi_input_post(e, &in, request->limits.params_body); if (!*e) { - magi_urlencoded(&request->params, request, in); + magi_parse_urlencoded(&request->body, in); } free(in); } else { @@ -229,78 +249,7 @@ 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 - */ -void output_http_params(struct magi_param_list * list) -{ - while (list) { - fputs(list->item.name, stdout); - fputs(": ", stdout); - fputs(list->item.data, stdout); - fputs("\r\n", stdout); - list = list->next; - } -} - -void output_cookies(struct magi_cookie_list * list) -{ - while (list) { - fputs("Set-Cookie: ", stdout); - fputs(list->item.name, stdout); - fputs("=", stdout); - fputs(list->item.data, stdout); - if (list->item.path) { - fputs("; Path=", stdout); - fputs(list->item.path, stdout); - } - if (list->item.domain) { - fputs("; Domain=", stdout); - fputs(list->item.domain, stdout); - } - if (list->item.max_age) { - fputs("; Max-Age=", stdout); - fputs(list->item.max_age, stdout); - } - fputs("\r\n", stdout); - list = list->next; - } -} - - -int magi_response_cgi(struct magi_response *response) -{ - output_http_params(response->http_params); - output_cookies(response->cookies); - fputs(response->content_type, stdout); - fputs("\r\n\r\n", stdout); - fputs(response->content, stdout); - magi_response_destroy(response); - return 1; -} - - -int magi_error_cgi(enum magi_error error) +int magi_cgi(magi_request *request) { - struct magi_response res; - magi_response_setup(&res); - magi_response_http(&res, "Status", "400 Bad Request"); - magi_response_add_format(&res, - "" - "" - "400 Bad Request" - "" - "

400 Bad Request

" - "

%s

" - "" - "", - magi_error_message(error)); - return magi_response_cgi(&res); + return magi_cgi_head(request) && magi_cgi_body(request); } diff --git a/src/cookies.h b/src/cookies.h index b83955d..30b9746 100644 --- a/src/cookies.h +++ b/src/cookies.h @@ -1,5 +1,5 @@ -#ifndef MAGI_INCLUDED_INNER_COOKIES -#define MAGI_INCLUDED_INNER_COOKIES +#ifndef MAGI_INCLUDED_COOKIES +#define MAGI_INCLUDED_COOKIES #include "request.h" diff --git a/src/loadfile.c b/src/loadfile.c index e8e0655..d76f562 100644 --- a/src/loadfile.c +++ b/src/loadfile.c @@ -1,6 +1,7 @@ #include "loadfile.h" #include +#include #include @@ -18,40 +19,40 @@ void magi_loadfiles_add(magi_loadfiles *table, } else { table->files = malloc(size); } - table->files[table->count].param_name = name; - table->files[table->count].location = path; - table->files[table->count].maximum = max; + table->files[table->count].name = name; + table->files[table->count].path = path; + table->files[table->count].max = max; table->count++; } -void magi_loadfiles_destroy(magi_loadfiles *table) +void magi_loadfiles_free(magi_loadfiles *table) { if (!table) { return; } - free(table->table); + free(table->files); + table->count = 0; } -static void loadfiles(magi_file *file, +static void loadfiles(void *userdata, + magi_file *file, char *addon, - int addon_len, - int is_addon_last, - void *userdata) + int addon_len) { magi_loadfiles *table = userdata; int pos; - if (!file->file_name || !strcmp(file->file_name, "")) { + if (!file->filename || !strcmp(file->filename, "")) { return; } for (pos = 0; pos != table->count; ++pos) { - if (!strcmp(table->files[pos].param_name, file->param_name)) { + if (!strcmp(table->files[pos].name, file->field)) { static FILE *f = 0; static int unlimited; static int left; if (!f) { - const char * loc = table->files[pos].location; - f = fopen(loc, "wb"); - left = table->files[pos].maximum; + const char *path = table->files[pos].path; + f = fopen(path, "wb"); + left = table->files[pos].max; unlimited = !left; } if (unlimited) { @@ -61,7 +62,7 @@ static void loadfiles(magi_file *file, fwrite(addon, 1, min, f); left -= min; } - if (is_addon_last) { + if (!addon_len) { fclose(f); f = 0; } @@ -70,8 +71,8 @@ static void loadfiles(magi_file *file, } } -void magi_request_setup_loadfiles(magi_request *request, magi_loadfiles *table) +void magi_loadfiles_set(magi_request *request, magi_loadfiles *table) { - request->file_callback = loadfiles; - request->file_callback_userdata = table; + request->callback.act = loadfiles; + request->callback.userdata = table; } diff --git a/src/multipart.h b/src/multipart.h index c3f7b65..617c3f8 100644 --- a/src/multipart.h +++ b/src/multipart.h @@ -1,13 +1,13 @@ -#ifndef MAGI_INCLUDED_INNER_MULTIPART -#define MAGI_INCLUDED_INNER_MULTIPART +#ifndef MAGI_INCLUDED_MULTIPART +#define MAGI_INCLUDED_MULTIPART #include "request.h" -void magi_multipart(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); #endif diff --git a/src/request.c b/src/request.c index 2917508..4132458 100644 --- a/src/request.c +++ b/src/request.c @@ -1,5 +1,6 @@ #include "request.h" +#include "response.h" #include @@ -25,22 +26,24 @@ static void request_free(magi_request *request) free(request->body); free(request->files); free(request->method); - free(request->address); + free(request->host); free(request->script); free(request->path); + free(request->response); } static void request_annul(magi_request *request) { - request->cookies = 0; - request->meta = 0; - request->head = 0; - request->body = 0; - request->files = 0; - request->method = 0; - request->address = 0; - request->script = 0; - request->path = 0; + request->cookies = 0; + request->meta = 0; + request->head = 0; + request->body = 0; + request->files = 0; + request->method = 0; + request->host = 0; + request->script = 0; + request->path = 0; + request->response = 0; } void magi_request_free(magi_request *request) @@ -51,6 +54,14 @@ void magi_request_free(magi_request *request) magi_params_free(request->head); magi_params_free(request->body); 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]); request_free(request); request_annul(request); } diff --git a/src/response.c b/src/response.c index 403e0fe..aea64b4 100644 --- a/src/response.c +++ b/src/response.c @@ -115,6 +115,7 @@ void magi_response_head(magi_request *r) response_headers(r->response, r->response->head[0]); response_headers(r->response, r->response->head[1]); response_headers(r->response, r->response->head[2]); + r->response->methods->start_body(r->response->userdata); r->response->head_done = 1; } @@ -135,3 +136,20 @@ void magi_response_file(magi_request *r, FILE *file) magi_response_head(r); r->response->methods->file(r->response->userdata, file); } + + +void magi_response_error(magi_request *r) +{ + /* TODO */ + magi_response_status(r, 400, "Bad Request"); + magi_response(r, + "" + "" + "400 Bad Request" + "" + "

400 Bad Request

" + "

"); + magi_response(r, magi_error_message(r->error)); + magi_response(r, "

"); +} diff --git a/src/tools.c b/src/tools.c index ecfcd6c..d7a90ce 100644 --- a/src/tools.c +++ b/src/tools.c @@ -5,14 +5,15 @@ #include -void magi_str_lowercase(char *str) +char *magi_str_lowercase(char *str) { if (!str) { - return; + return str; } for (; *str; ++str) { *str = tolower(*str); } + return str; } char *magi_str_create_copy(const char *first, int len) diff --git a/src/tools.h b/src/tools.h index f7e701d..49513e8 100644 --- a/src/tools.h +++ b/src/tools.h @@ -2,7 +2,7 @@ #define MAGI_INCLUDED_TOOLS -void magi_str_lowercase(char *str); +char *magi_str_lowercase(char *str); /* Results of both create functions are malloced, so need to be freed. */ char *magi_str_create_copy(const char *first, int len); diff --git a/src/urlencoded.h b/src/urlencoded.h index 319f01e..df33fe4 100644 --- a/src/urlencoded.h +++ b/src/urlencoded.h @@ -6,7 +6,7 @@ /* Add decoded params from 'encoded' to 'list'. */ -magi_error magi_urlencoded(magi_param_list **list, const char *encoded); +magi_error magi_parse_urlencoded(magi_params **list, const char *encoded); #endif -- cgit v1.2.3