aboutsummaryrefslogtreecommitdiff
path: root/src/cgi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cgi.c')
-rw-r--r--src/cgi.c289
1 files changed, 189 insertions, 100 deletions
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 <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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, &param);
- } else {
- ok = 0;
+ if (!param.name || !param.data ||
+ !magi_param_list_add(&r->http_params, &param)) {
+ 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,
+ "<!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));
+ if (magi_response_cgi(&res)) {
+ magi_response_destroy(&res);
+ return 1;
+ } else {
+ magi_response_destroy(&res);
+ return 0;
+ }
+}