diff options
Diffstat (limited to 'src/cgi.c')
-rw-r--r-- | src/cgi.c | 353 |
1 files changed, 151 insertions, 202 deletions
@@ -7,6 +7,7 @@ #include "multipart.h" #include "param.h" #include "request.h" +#include "response.h" #include "tools.h" #include "urlencoded.h" #include <ctype.h> @@ -14,211 +15,230 @@ #include <stdlib.h> #include <string.h> -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, - "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' " - "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" - "<html xmlns='http://www.w3.org/1999/xhtml'>" - "<head><title>400 Bad Request</title></head>" - "<body>" - "<h1>400 <i>Bad Request</i></h1>" - "<h2>%s</h2>" - "</body>" - "</html>", - magi_error_message(error)); - return magi_response_cgi(&res); + return magi_cgi_head(request) && magi_cgi_body(request); } |