aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Veresov <aleksey@veresov.pro>2020-03-09 20:17:28 +0300
committerAleksey Veresov <aleksey@veresov.pro>2020-03-09 20:17:28 +0300
commit5cfe6cdf6af2d630d21871f9193fc1b4a7db24ff (patch)
treeb50c9c0936a8dab87519dcd9e47ed40759d7eddc
parent18ce121d4243358bc55a0474a529efe2580a0610 (diff)
downloadmagi-5cfe6cdf6af2d630d21871f9193fc1b4a7db24ff.tar
magi-5cfe6cdf6af2d630d21871f9193fc1b4a7db24ff.tar.xz
magi-5cfe6cdf6af2d630d21871f9193fc1b4a7db24ff.zip
[magi]
-rw-r--r--include/magi/request.h3
-rw-r--r--include/magi/response.h18
-rw-r--r--src/cgi.c353
-rw-r--r--src/cookies.h4
-rw-r--r--src/loadfile.c37
-rw-r--r--src/multipart.h12
-rw-r--r--src/request.c31
-rw-r--r--src/response.c18
-rw-r--r--src/tools.c5
-rw-r--r--src/tools.h2
-rw-r--r--src/urlencoded.h2
11 files changed, 235 insertions, 250 deletions
diff --git a/include/magi/request.h b/include/magi/request.h
index 03e0c43..64e688d 100644
--- a/include/magi/request.h
+++ b/include/magi/request.h
@@ -39,9 +39,10 @@ typedef struct magi_request {
magi_params *body;
magi_files *files;
+ char *document_root;
char *method;
int is_secure;
- char *address;
+ char *host;
int port;
char *script;
char *path;
diff --git a/include/magi/response.h b/include/magi/response.h
index 4c6b788..52b1c9d 100644
--- a/include/magi/response.h
+++ b/include/magi/response.h
@@ -16,20 +16,24 @@
typedef void (*magi_response_method_head)(void *ud, magi_param *header);
+typedef void (*magi_response_method_start_body)(void *ud);
typedef void (*magi_response_method_body)(void *ud, const char *data, int len);
typedef void (*magi_response_method_file)(void *ud, FILE *file);
+typedef void (*magi_response_method_close)(void *ud);
typedef struct magi_response_methods {
- magi_response_method_head head;
- magi_response_method_body body;
- magi_response_method_file file;
+ magi_response_method_head head;
+ magi_response_method_start_body start_body;
+ magi_response_method_body body;
+ magi_response_method_file file;
+ magi_response_method_close close;
} magi_response_methods;
typedef struct magi_response_implementation {
- magi_response_methods *methods;
- void *userdata;
- magi_params *head[3];
- int head_done;
+ const magi_response_methods *methods;
+ void *userdata;
+ magi_params *head[3];
+ int head_done;
} magi_response_implementation;
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 <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, &param)) {
- 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);
}
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 <stdio.h>
+#include <stdlib.h>
#include <string.h>
@@ -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 <stdlib.h>
@@ -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,
+ "<!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>");
+ magi_response(r, magi_error_message(r->error));
+ magi_response(r, "</h2></body></html>");
+}
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 <string.h>
-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