From b08db17162fddda97e6ee1ac625eae1430d22b64 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 29 Nov 2019 18:50:04 +0300 Subject: [magi] Almost done! --- src/cgi.c | 289 ++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 189 insertions(+), 100 deletions(-) (limited to 'src/cgi.c') diff --git a/src/cgi.c b/src/cgi.c index 48b2a93..d410873 100644 --- a/src/cgi.c +++ b/src/cgi.c @@ -1,12 +1,14 @@ #include "cgi.h" #include "cookie.h" +#include "cookies.h" #include "error.h" #include "file.h" #include "multipart.h" #include "param.h" #include "request.h" #include "urlenc.h" +#include "utils.h" #include #include #include @@ -20,31 +22,30 @@ extern char ** environ; */ static int plain_env(char ** dest, char * env_name) { - int ok = 1; const char * env = getenv(env_name); if (env) { - *dest = str_alloc(strlen(env)); - if (*dest) { - strcpy(*dest, env); - } else { - ok = 0; + *dest = magi_str_create(strlen(env)); + if (!*dest) { + return 0; } + strcpy(*dest, env); } else { *dest = 0; } - return ok; + return 1; } static int lower_env(char ** dest, char * env_name) { - int ok = plain_env(dest, env_name); - lowercase(*dest); - return ok; + if (plain_env(dest, env_name)) { + magi_str_lowercase(*dest); + return 1; + } + return 0; } static int cgi_http_env(struct magi_request * r) { - int ok = 1; char ** env = environ; r->http_params = 0; while (*env) { @@ -52,87 +53,110 @@ static int cgi_http_env(struct magi_request * r) struct magi_param param; /* At least one '=' must be in *env, according to format. */ char * name_end = strchr(*env, '='); - param.name = str_alloc(name_end - *env - 5); + param.name = magi_str_create(name_end - *env - 5); if (param.name) { memcpy(param.name, *env + 5, name_end - *env - 5); - param.data = str_alloc(strlen(name_end + 1)); + 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) { - ok = magi_param_list_add(&r->http_params, ¶m); - } else { - ok = 0; + if (!param.name || !param.data || + !magi_param_list_add(&r->http_params, ¶m)) { + r->error = magi_error_memory; + return 0; } } ++env; } - return ok; + return 1; } -static void cgi_env(enum magi_error * e, struct magi_request * r) +static void cgi_env(struct magi_request * r) { - cgi_http_env(e, r); - lower_env(e, &r->method, "REQUEST_METHOD"); - plain_env(e, &r->uri, "REQUEST_URI"); - plain_env(e, &r->document_root, "DOCUMENT_ROOT"); - plain_env(e, &r->document_uri, "DOCUMENT_URI"); - plain_env(e, &r->script_name, "SCRIPT_NAME"); - plain_env(e, &r->script_filename, "SCRIPT_FILENAME"); - plain_env(e, &r->remote_addr, "REMOTE_ADDR"); - plain_env(e, &r->remote_port, "REMOTE_PORT"); - plain_env(e, &r->server_addr, "SERVER_ADDR"); - lower_env(e, &r->server_name, "SERVER_NAME"); - plain_env(e, &r->server_port, "SERVER_PORT"); - lower_env(e, &r->server_protocol, "SERVER_PROTOCOL"); - plain_env(e, &r->server_software, "SERVER_SOFTWARE"); - plain_env(e, &r->path_info, "PATH_INFO"); + 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; + } } -static void cgi_cookies(enum magi_error * e, struct magi_cookie_list ** list) +static int cgi_cookies(struct magi_request * r) { - if (!*e) { - const char * env = getenv("HTTP_COOKIE"); - *list = 0; - if (env && *env) { - magi_parse_cookie(e, list, env); - } else { - *list = 0; - } + const char * env = getenv("HTTP_COOKIE"); + if (!env || !*env) { + r->cookies = 0; + return 1; + } + if (strlen(env) < r->cookies_max && r->cookies_max) { + magi_cookies(r, env); + } else { + r->error = magi_error_limit; } + return r->error; } -static int cgi_input_get(char ** input) +static void cgi_input_get(enum magi_error * e, char ** input, int max) { - int ok = 1; const char * env_input = getenv("QUERY_STRING"); if (env_input) { - *input = str_alloc(strlen(env_input)); - if (*input) { - strcpy(*input, env_input); - } else { - ok = 0; + 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); } - return ok; +} + +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); + } + free(in); } static void cgi_input_post(enum magi_error * e, char ** input, int max) { if (!*e) { int input_len = strtoul(getenv("CONTENT_LENGTH"), 0, 10); - if (input_len && (input_len < max || !max)) { - *input = str_alloc(input_len); - if (*input) { - if (fread(*input, 1, input_len, stdin) != input_len) { - *e = magi_error_length; - } - } else { - *e = magi_error_input; - } + 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; } } } @@ -145,67 +169,132 @@ static char * bound(const char * type) type += strspn(type, " \t") + 1; if (*type == '"') { ++type; - res = create_str(type, strchr(type, '"')); + res = magi_str_create_copy(type, strchr(type, '"')); } else { - res = create_str(type, type + strcspn(type, " \t")); + res = magi_str_create_copy(type, type + strcspn(type, " \t")); } } return res; } -static int intput_getter(void * any) +static int next(void * any) { return getchar(); } /* Interfacial CGI Request Handling */ -int magi_request_cgi(struct magi_request * request, - void (*callback)(struct magi_field * field, - char * buffer, - int len), - int max_post) +int magi_request_cgi(struct magi_request * request) { - request->fields = 0; - request->error = magi_error_none; - enum magi_error * e = &request->error; - cgi_env(e, request); - cgi_cookies(e, &request->cookies); - if (request->method) { - if (!strcmp(request->method, "post")) { - const char * t = getenv("CONTENT_TYPE"); - if (t) { - if (!strncmp(t, "multipart/form-data", 19)) { - char * boundary = bound(t); - if (boundary && *boundary) { - magi_parse_multipart(e, &request->fields, - intput_getter, 0, boundary, - callback); - } else { - *e = magi_error_nobound; - } - free(boundary); - } else if (!strcmp(t, "application/x-www-form-urlencoded")) { - char * in = 0; - cgi_input_post(e, &in, max_post); - magi_parse_urlencoded(e, &request->fields, in); - free(in); - } else { - *e = magi_error_unknown; - } + enum magi_error * e = &request->error; + request->files = 0; + request->params = 0; + request->url_params = 0; + request->http_params = 0; + request->error = magi_error_none; + cgi_env(request); + cgi_cookies(request); + cgi_url(request); + 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); + if (boundary && *boundary) { + magi_multipart(request, boundary, next, 0); } else { - *e = magi_error_notype; + *e = magi_error_nobound; } - } else if (!strcmp(request->method, "get")) { + free(boundary); + } else if (!strcmp(t, "application/x-www-form-urlencoded")) { char * in = 0; - cgi_input_get(e, &in); - magi_parse_urlencoded(e, &request->fields, in); + cgi_input_post(e, &in, request->params_max); + if (!*e) { + magi_urlenc(&request->params, request, in); + } free(in); + } else { + *e = magi_error_unknown; + return 0; } } - return request->error == magi_error_none; + return !request->error; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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.port) { + fputs("; Port=", stdout); + fputs(list->item.port, 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); + return 1; +} + +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, + "" + "" + "400 Bad Request" + "" + "

400 Bad Request

" + "

%s

" + "" + "", + magi_error_message(error)); + if (magi_response_cgi(&res)) { + magi_response_destroy(&res); + return 1; + } else { + magi_response_destroy(&res); + return 0; + } +} -- cgit v1.2.3