From 07657b8a9f5c2fd9047594ec8604b9c439a999e4 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Sat, 4 Apr 2020 19:39:38 +0300 Subject: [magi] Finalization. --- src/cgi.c | 266 --------------------------------------------------------- src/error.c | 19 ++++- src/fastcgi.c | 23 ----- src/parse.c | 206 ++++++++++++++++++++++++++++++++++++++++++++ src/request.c | 11 --- src/response.c | 151 ++++++++++++++------------------ src/session.c | 58 ------------- 7 files changed, 287 insertions(+), 447 deletions(-) delete mode 100644 src/cgi.c delete mode 100644 src/fastcgi.c create mode 100644 src/parse.c delete mode 100644 src/session.c (limited to 'src') diff --git a/src/cgi.c b/src/cgi.c deleted file mode 100644 index 7b0551d..0000000 --- a/src/cgi.c +++ /dev/null @@ -1,266 +0,0 @@ -#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 "response.h" -#include "tools.h" -#include "urlencoded.h" -#include -#include -#include -#include - -extern char **const environ; - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * CGI Request - */ -static char *plain_env(char *env_name) -{ - const char *env = getenv(env_name); - if (!env) { - return 0; - } - return magi_str_create_copy(env, strlen(env)); -} - -static char *lower_env(char *env_name) -{ - char *env = plain_env(env_name); - magi_str_lowercase(env); - return env; -} - -static void cgi_http_env(magi_request *r) -{ - char **env; - int len = 0; - r->meta = 0; - for (env = environ; *env; ++env) { - magi_param meta; - char *name_end = strchr(*env, '='); - int nlen = name_end - *env; - int dlen = strlen(name_end + 1); - len += nlen + dlen; - if (len > r->limits.params_meta && r->limits.params_meta) { - r->error = magi_error_limit; - return; - } - meta.name = magi_str_create_copy(*env, nlen); - meta.data = magi_str_create_copy(name_end + 1, dlen); - magi_params_add(&r->meta, &meta); - } -} - -static void cgi_env(magi_request *r) -{ - 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; - } else { - r->port = 0; - r->is_secure = 0; - } - r->path = plain_env("PATH_INFO"); -} - -static void cgi_cookies(magi_request *r) -{ - const char *env = getenv("HTTP_COOKIE"); - if (!env || !*env) { - r->cookies = 0; - return; - } - if ((int)strlen(env) > r->limits.cookies && r->limits.cookies) { - r->error = magi_error_limit; - return; - } - magi_parse_cookies(r, env); -} - -static void cgi_input_get(magi_error *e, char **input, int max) -{ - 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_copy(env_input, len); - } -} - -static void cgi_url(magi_request *request) -{ - char *in = 0; - cgi_input_get(&request->error, &in, request->limits.params_head); - if (!request->error) { - magi_parse_urlencoded(&request->head, in); - free(in); - } -} - -static void cgi_input_post(magi_error *e, char **input, int max) -{ - 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 ((int)fread(*input, 1, input_len, stdin) != input_len) { - *e = magi_error_length; - return; - } -} - -static char *bound(const char *type) -{ - 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 magi_str_create_copy(type, strcspn(type, " \t")); -} - -static int next() -{ - return getchar(); -} - -static void mhead(void *any, magi_param *header) -{ - (void)any; - fputs(header->name, stdout); - fputs(": ", stdout); - fputs(header->data, stdout); - fputs("\r\n", stdout); -} - -static void mstart_body() -{ - fputs("\r\n", stdout); -} - -static void mbody(void *any, const char *data, int len) -{ - (void)any; - fwrite(data, 1, len, stdout); -} - -static void mformat(void *any, const char *format, va_list args) -{ - (void)any; - vprintf(format, args); -} - -static void mfile(void *any, FILE *file) -{ - (void)any; - while (!feof(file)) { - char buf[64]; - int len = fread(buf, 1, 64, file); - fwrite(buf, 1, len, stdout); - } -} - -static void mclose() {} - -static void setup_response(magi_request *r) -{ - static const magi_response_methods m = { - mhead, - mstart_body, - mbody, - mformat, - mfile, - mclose - }; - 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, "text/html"); - magi_response_status(r, 200, "OK"); -} - -/* 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_cgi_body(magi_request *request) -{ - 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); - if (boundary && *boundary) { - 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->limits.params_body); - if (!*e) { - magi_parse_urlencoded(&request->body, in); - } - free(in); - } else { - *e = magi_error_unknown; - return 0; - } - } - return !request->error; -} - -int magi_cgi(magi_request *request) -{ - return magi_cgi_head(request) && magi_cgi_body(request); -} diff --git a/src/error.c b/src/error.c index a1c3153..eb16eb6 100644 --- a/src/error.c +++ b/src/error.c @@ -1,9 +1,11 @@ #include "error.h" +#include + const char *magi_error_message(magi_error error) { - const char *const messages[] = { + static const char *const messages[] = { 0, /* magi_error_none */ "No boundary for multipart.", /* magi_error_nobound */ "Content-Type is unknown.", /* magi_error_unknown */ @@ -17,3 +19,18 @@ const char *magi_error_message(magi_error error) }; return messages[error]; } + +void magi_error_response(magi_error error) +{ + fputs("Status: 400 Bad Request\r\n" + "Content-Type: text/html\r\n\r\n" + "" + "" + "400 Bad Request" + "" + "

400 Bad Request

" + "

", stdout); + fputs(magi_error_message(error), stdout); + fputs("

", stdout); +} diff --git a/src/fastcgi.c b/src/fastcgi.c deleted file mode 100644 index 8959c14..0000000 --- a/src/fastcgi.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "fastcgi.h" - - -int magi_fastcgi_head(magi_session *s, magi_request *r) -{ - (void)s; - (void)r; - return 1; -} - - -int magi_fastcgi_body(magi_session *s, magi_request *r) -{ - (void)s; - (void)r; - return 1; -} - - -int magi_fastcgi(magi_session *s, magi_request *r) -{ - return magi_fastcgi_head(s, r) && magi_fastcgi_body(s, r); -} diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..58ae001 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,206 @@ +#include "parse.h" + +#include "cookie.h" +#include "cookies.h" +#include "error.h" +#include "file.h" +#include "multipart.h" +#include "param.h" +#include "request.h" +#include "response.h" +#include "tools.h" +#include "urlencoded.h" +#include +#include +#include +#include + +extern char **const environ; + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * CGI Request + */ +static char *plain_env(char *env_name) +{ + const char *env = getenv(env_name); + if (!env) { + return 0; + } + return magi_str_create_copy(env, strlen(env)); +} + +static char *lower_env(char *env_name) +{ + char *env = plain_env(env_name); + magi_str_lowercase(env); + return env; +} + +static void cgi_http_env(magi_request *r) +{ + char **env; + int len = 0; + r->meta = 0; + for (env = environ; *env; ++env) { + magi_param meta; + char *name_end = strchr(*env, '='); + int nlen = name_end - *env; + int dlen = strlen(name_end + 1); + len += nlen + dlen; + if (len > r->limits.params_meta && r->limits.params_meta) { + r->error = magi_error_limit; + return; + } + meta.name = magi_str_create_copy(*env, nlen); + meta.data = magi_str_create_copy(name_end + 1, dlen); + magi_params_add(&r->meta, &meta); + } +} + +static void cgi_env(magi_request *r) +{ + 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; + } else { + r->port = 0; + r->is_secure = 0; + } + r->path = plain_env("PATH_INFO"); +} + +static void cgi_cookies(magi_request *r) +{ + const char *env = getenv("HTTP_COOKIE"); + if (!env || !*env) { + r->cookies = 0; + return; + } + if ((int)strlen(env) > r->limits.cookies && r->limits.cookies) { + r->error = magi_error_limit; + return; + } + magi_parse_cookies(r, env); +} + +static void cgi_input_get(magi_error *e, char **input, int max) +{ + 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_copy(env_input, len); + } +} + +static void cgi_url(magi_request *request) +{ + char *in = 0; + cgi_input_get(&request->error, &in, request->limits.params_head); + if (!request->error) { + magi_parse_urlencoded(&request->head, in); + free(in); + } +} + +static void cgi_input_post(magi_error *e, char **input, int max) +{ + 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 ((int)fread(*input, 1, input_len, stdin) != input_len) { + *e = magi_error_length; + return; + } +} + +static char *bound(const char *type) +{ + 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 magi_str_create_copy(type, strcspn(type, " \t")); +} + +static int next() +{ + return getchar(); +} + +/* Interfacial CGI Request Handling */ +int magi_parse_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); + return !request->error; +} + +int magi_parse_body(magi_request *request) +{ + 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); + if (boundary && *boundary) { + 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->limits.params_body); + if (!*e) { + magi_parse_urlencoded(&request->body, in); + } + free(in); + } else { + *e = magi_error_unknown; + return 0; + } + } + return !request->error; +} + +int magi_parse(magi_request *request) +{ + return magi_parse_head(request) && magi_parse_body(request); +} diff --git a/src/request.c b/src/request.c index d80bf20..bf8fc1d 100644 --- a/src/request.c +++ b/src/request.c @@ -1,6 +1,5 @@ #include "request.h" -#include "response.h" #include @@ -30,7 +29,6 @@ static void request_free(magi_request *request) free(request->host); free(request->script); free(request->path); - free(request->response); } static void request_annul(magi_request *request) @@ -44,7 +42,6 @@ static void request_annul(magi_request *request) request->host = 0; request->script = 0; request->path = 0; - request->response = 0; } void magi_request_free(magi_request *request) @@ -55,14 +52,6 @@ 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_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 dc36bb0..c5b7575 100644 --- a/src/response.c +++ b/src/response.c @@ -6,11 +6,55 @@ #include -void magi_response_status(magi_request *r, int code, const char *description) +void magi_response_init(magi_response *r) +{ + r->head_response = 0; + r->head_general = 0; + r->head_entity = 0; + magi_response_status(r, 200, "OK"); + magi_response_content_type(r, "text/html"); +} + +static void response_headers(magi_params *p) +{ + for (; p; p = p->next) { + fputs(p->item.name, stdout); + fputs(": ", stdout); + fputs(p->item.data, stdout); + fputs("\r\n", stdout); + } +} + +void magi_response_free(magi_response *r) +{ + response_headers(r->head_response); + response_headers(r->head_general); + response_headers(r->head_entity); + fputs("\r\n", stdout); + magi_params_free(r->head_response); + magi_params_free(r->head_general); + magi_params_free(r->head_entity); + free(r->head_response); + free(r->head_general); + free(r->head_entity); + r->head_response = 0; + r->head_general = 0; + r->head_entity = 0; +} + + +void magi_response_default() +{ + fputs("Status: 200 Ok\r\n" + "Content-Type: text/html\r\n\r\n", stdout); +} + + +void magi_response_status(magi_response *r, int code, const char *description) { int dlen; magi_param addon; - if (r->response->head_done || code <= 99 || 600 <= code) { + if (code <= 99 || 600 <= code) { return; } dlen = strlen(description); @@ -21,15 +65,15 @@ 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_response, &addon); + magi_params_set(&r->head_response, &addon); } -void magi_response_cookie(magi_request *r, const char *name, const char *data) +void magi_response_cookie(magi_response *r, const char *name, const char *data) { magi_param addon; int nlen; int dlen; - if (r->response->head_done || !name || !data) { + if (!name || !data) { return; } nlen = strlen(name); @@ -39,10 +83,10 @@ void magi_response_cookie(magi_request *r, const char *name, const char *data) memcpy(addon.data, name, nlen); addon.data[nlen] = '='; memcpy(addon.data + nlen + 1, data, dlen + 1); - magi_params_add(&r->response->head_general, &addon); + magi_params_add(&r->head_general, &addon); } -void magi_response_cookie_complex(magi_request *r, magi_cookie *c) +void magi_response_cookie_complex(magi_response *r, magi_cookie *c) { magi_param addon; char *pointer; @@ -50,7 +94,7 @@ void magi_response_cookie_complex(magi_request *r, magi_cookie *c) const int cdsize = 9; const int cpsize = 7; const int cmsize = 10; - if (r->response->head_done || !c->name) { + if (!c->name) { return; } nlen = strlen(c->name); @@ -83,14 +127,14 @@ void magi_response_cookie_complex(magi_request *r, magi_cookie *c) memcpy(pointer, "; Max-Age=", cmsize); memcpy(pointer + cmsize, c->max_age, msize - cmsize); } - magi_params_add(&r->response->head_general, &addon); + magi_params_add(&r->head_general, &addon); } -void magi_response_cookie_discard(magi_request *r, const char *name) +void magi_response_cookie_discard(magi_response *r, const char *name) { magi_param addon; int len; - if (r->response->head_done || !name) { + if (!name) { return; } len = strlen(name); @@ -98,29 +142,22 @@ void magi_response_cookie_discard(magi_request *r, const char *name) addon.data = malloc(len + 13); memcpy(addon.data, name, len); memcpy(addon.data + len, "=; Max-Age=1", 13); - magi_params_add(&r->response->head_general, &addon); + magi_params_add(&r->head_general, &addon); } -void magi_response_header(magi_request *r, const char *name, const char *data) +void magi_response_header(magi_response *r, const char *name, const char *data) { magi_param addon; - if (r->response->head_done) { - return; - } addon.name = magi_str_create_copy(name, strlen(name)); addon.data = magi_str_create_copy(data, strlen(data)); - magi_params_add(&r->response->head_general, &addon); + magi_params_add(&r->head_general, &addon); } -void magi_response_content_length(magi_request *r, int length) +void magi_response_content_length(magi_response *r, int length) { magi_param addon; - int len; - if (r->response->head_done) { - return; - } + int len = 1; addon.name = magi_str_create_copy("Content-Length", 14); - len = 1; addon.data = malloc(len + 1); *addon.data = '0' + length % 10; while (length /= 10) { @@ -129,75 +166,13 @@ void magi_response_content_length(magi_request *r, int length) ++len; } addon.data[len] = 0; - magi_params_set(&r->response->head_entity, &addon); + magi_params_set(&r->head_entity, &addon); } -void magi_response_content_type(magi_request *r, const char *type) +void magi_response_content_type(magi_response *r, const char *type) { magi_param addon; - if (r->response->head_done) { - 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_entity, &addon); -} - -static void response_headers(magi_response_implementation *r, magi_params *p) -{ - for (; p; p = p->next) { - r->methods->head(r->userdata, &p->item); - } -} - -void magi_response_head(magi_request *r) -{ - if (r->response->head_done) { - return; - } - 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; -} - -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)); -} - -void magi_response_format(magi_request *r, const char *format, ...) -{ - va_list args; - magi_response_head(r); - va_start(args, format); - r->response->methods->format(r->response->userdata, format, args); - va_end(args); -} - -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) -{ - 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, "

"); + magi_params_set(&r->head_entity, &addon); } diff --git a/src/session.c b/src/session.c deleted file mode 100644 index aec0e6d..0000000 --- a/src/session.c +++ /dev/null @@ -1,58 +0,0 @@ -#include "session.h" - -#include -#include -#include -#include - - -enum { listen_backlog = 64 }; - -void magi_session_init(magi_session *s) -{ - s->socket = 0; -} - -void magi_session_free(magi_session *s) -{ - if (s->socket) { - shutdown(s->socket, SHUT_RDWR); - s->socket = 0; - } -} - - -int magi_session_inet(magi_session *s, const char *address, int port) -{ - struct sockaddr_in addr; - if (s->socket) { - return 0; - } - s->socket = socket(AF_INET, SOCK_STREAM, 0); - if (s->socket == -1) { - s->socket = 0; - return 0; - } - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(address); - return !bind(s->socket, (struct sockaddr *)&addr, sizeof(addr)) && - !listen(s->socket, listen_backlog); -} - -int magi_session_unix(magi_session *s, const char *path) -{ - struct sockaddr_un addr; - if (s->socket) { - return 0; - } - s->socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (s->socket == -1) { - s->socket = 0; - return 0; - } - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); - return !bind(s->socket, (struct sockaddr *)&addr, sizeof(addr)) && - !listen(s->socket, listen_backlog); -} -- cgit v1.2.3