aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cgi.c14
-rw-r--r--src/cgi.h12
-rw-r--r--src/cookie.c369
-rw-r--r--src/cookie.h18
-rw-r--r--src/cookies.c329
-rw-r--r--src/fastcgi.c1
-rw-r--r--src/fastcgi.h16
-rw-r--r--src/file.c40
-rw-r--r--src/file.h22
-rw-r--r--src/param.c38
-rw-r--r--src/param.h17
-rw-r--r--src/request.c51
-rw-r--r--src/request.h40
-rw-r--r--src/response.h3
14 files changed, 530 insertions, 440 deletions
diff --git a/src/cgi.c b/src/cgi.c
index cf74f14..48b2a93 100644
--- a/src/cgi.c
+++ b/src/cgi.c
@@ -2,11 +2,11 @@
#include "cookie.h"
#include "error.h"
-#include "field.h"
+#include "file.h"
#include "multipart.h"
#include "param.h"
#include "request.h"
-#include "urlencoded.h"
+#include "urlenc.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -16,9 +16,8 @@ extern char ** environ;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * CGI Request Handling
+ * CGI Request
*/
-/* Helpers for CGI Request Handling */
static int plain_env(char ** dest, char * env_name)
{
int ok = 1;
@@ -160,7 +159,7 @@ static int intput_getter(void * any)
}
/* Interfacial CGI Request Handling */
-int magi_cgi_request(struct magi_request * request,
+int magi_request_cgi(struct magi_request * request,
void (*callback)(struct magi_field * field,
char * buffer,
int len),
@@ -205,3 +204,8 @@ int magi_cgi_request(struct magi_request * request,
}
return request->error == magi_error_none;
}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * CGI Response
+ */
diff --git a/src/cgi.h b/src/cgi.h
index 6cca424..6101de6 100644
--- a/src/cgi.h
+++ b/src/cgi.h
@@ -1,17 +1,27 @@
#ifndef MAGI_INCLUDED_CGI
#define MAGI_INCLUDED_CGI
+#include "error.h"
#include "request.h"
+#include "response.h"
-/* Constructs request from environment and standard input;
+/* Constructs non-post part of request from environment;
* Returns null only in case of error. */
int magi_request_cgi(struct magi_request * request);
+/* Complete request with post data from standard input;
+ * Returns null only in case of error. */
+int magi_request_resume_cgi(struct magi_request * request);
+
/* Sends response to standard output;
* Returns null only in case of error. */
int magi_response_cgi(struct magi_response * response);
+/* Sends a standart response of Bad Request error to standard output;
+ * Returns null only in case of error. */
+int magi_error_cgi(enum magi_error error);
+
#endif
diff --git a/src/cookie.c b/src/cookie.c
index d04eccf..506e4ef 100644
--- a/src/cookie.c
+++ b/src/cookie.c
@@ -1,370 +1,31 @@
#include "cookie.h"
-#include "error.h"
#include <stdlib.h>
#include <string.h>
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Cookie Parse
- */
-enum st {
- st_error = 0,
- st_pre_name,
- st_name,
- st_post_name,
- st_pre_data,
- st_data,
- st_post_data
-};
-
-enum data_type { dt_plain = 0, dt_version, dt_path, dt_domain, dt_port };
-
-struct automata {
- struct magi_cookie_list ** list;
- struct magi_cookie cookie;
- char * buf;
- int buf_len;
- int buf_size;
- int is_first;
- int is_cookie2;
- int is_quoted;
- enum data_type data_t;
-};
-
-static void nulify_cookie(struct automata * a)
-{
- a->cookie.name = 0;
- a->cookie.data = 0;
- a->cookie.path = 0;
- a->cookie.domain = 0;
- a->cookie.port = 0;
-}
-
-static void buf_new(struct automata * a)
-{
- a->buf = 0;
- a->buf_len = 0;
- a->buf_size = 1;
-}
-
-static int buf_add(struct automata * a, char c)
-{
- int ok = 1;
- if (a->buf_len == a->buf_size - 1) {
- a->buf_size *= 2;
- a->buf = realloc(a->buf, a->buf_size);
- }
- if (a->buf) {
- a->buf_len++;
- a->buf[a->buf_len - 1] = c;
- a->buf[a->buf_len] = 0;
- } else {
- ok = 0;
- magi_error_set("[cookie] Cannot allocate automata buffer.");
- }
- return ok;
-}
-
-static enum data_type what_is_name(const struct automata * a)
-{
- enum data_type data_t = dt_plain;
- if (a->is_first && !strcmp(a->buf, "$Version")) {
- data_t = dt_version;
- } else if (a->is_cookie2) {
- if (!strcmp(a->buf, "$Path")) {
- data_t = dt_path;
- } else if (!strcmp(a->buf, "$Domain")) {
- data_t = dt_domain;
- } else if (!strcmp(a->buf, "$Port")) {
- data_t = dt_port;
- }
- }
- return data_t;
-}
-
-static int end_name(struct automata * a)
-{
- int ok = 1;
- a->data_t = what_is_name(a);
- if (a->data_t == dt_plain) {
- if (a->cookie.name) {
- ok = magi_cookie_list_add(a->list, &a->cookie);
- }
- nulify_cookie(a);
- a->cookie.name = a->buf;
- } else {
- free(a->buf);
- }
- buf_new(a);
- return ok;
-}
-
-static int end_data(struct automata * a)
-{
- int ok = 1;
- switch (a->data_t) {
- case dt_plain:
- a->cookie.data = a->buf;
- break;
- case dt_path:
- a->cookie.path = a->buf;
- break;
- case dt_domain:
- a->cookie.domain = a->buf;
- break;
- case dt_port:
- a->cookie.port = a->buf;
- break;
- case dt_version:
- if (strcmp(a->buf, "1")) {
- ok = 0;
- magi_error_set("[cookie] Version must be '1', readed: %s.",
- a->buf);
- }
- }
- buf_new(a);
- return ok;
-}
-
-static enum st parse_pre_name(struct automata * a, char c)
-{
- enum st state;
- if (c == ' ' || c == '\t') {
- state = st_name;
- } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
- state = st_name;
- if (!buf_add(a, c)) {
- state = st_error;
- }
- } else {
- state = st_error;
- magi_error_set("[cookie] Pre-name, readed: \\%o (render: %c).", c, c);
- }
- return state;
-}
-
-static enum st parse_name(struct automata * a, char c)
-{
- enum st state;
- if (c == '=') {
- state = st_pre_data;
- if (!end_name(a)) {
- state = st_error;
- }
- } else if (c == ' ' || c == '\t') {
- state = st_post_name;
- if (!end_name(a)) {
- state = st_error;
- }
- } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
- state = st_name;
- if (!buf_add(a, c)) {
- state = st_error;
- }
- } else {
- state = st_error;
- magi_error_set("[cookie] Reading name, readed: \\%o (render: %c).", c,
- c);
- }
- return state;
-}
-
-static enum st parse_post_name(struct automata * a, char c)
-{
- enum st state;
- if (c == '=') {
- state = st_pre_data;
- } else if (c == ' ' || c == '\t') {
- state = st_post_name;
- } else {
- state = st_error;
- magi_error_set("[cookie] Waiting for name-value separator, "
- "readed: \\%o (render: %c).",
- c, c);
- }
- return state;
-}
-
-static enum st parse_pre_data(struct automata * a, char c)
-{
- enum st state;
- if (c == ' ' || c == '\t') {
- state = st_pre_data;
- } else if (c == '"') {
- state = st_data;
- a->is_quoted = 1;
- } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
- state = st_data;
- if (!buf_add(a, c)) {
- state = st_error;
- }
- } else {
- state = st_error;
- magi_error_set("[cookie] Pre-value, readed: \\%o (render: %c).", c, c);
- }
- return state;
-}
-
-static enum st parse_not_quoted_data(struct automata * a, char c)
-{
- enum st state;
- if (c == ';' || (c == ',' && a->is_first)) {
- state = st_pre_name;
- a->is_first = 0;
- if (!end_data(a)) {
- state = st_error;
- }
- } else if (c == ' ' || c == '\t') {
- state = st_post_data;
- if (!end_data(a)) {
- state = st_error;
- }
- } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
- state = st_data;
- if (!buf_add(a, c)) {
- state = st_error;
- }
- } else {
- state = st_error;
- magi_error_set("[cookie] Reading not-quoted value, "
- "readed: \\%o (render: %c).",
- c, c);
- }
- return state;
-}
-
-static enum st parse_data(struct automata * a, char c)
-{
- enum st state;
- if (a->is_quoted) {
- if (c == '"') {
- state = st_post_data;
- a->is_quoted = 0;
- if (!end_data(a)) {
- state = st_error;
- }
- } else {
- state = st_data;
- }
- } else {
- state = parse_not_quoted_data(a, c);
- }
- return state;
-}
-
-static enum st parse_post_data(struct automata * a, char c)
-{
- enum st state;
- if (c == ';' || (c == ',' && a->is_first)) {
- state = st_pre_name;
- } else if (c == ' ' || c == '\t') {
- state = st_post_data;
- } else {
- state = st_error;
- magi_error_set(
- "[cookie] Waiting for separator between name-value pairs, "
- "readed: \\%o (render: %c).",
- c, c);
- }
- return state;
-}
-
-static int parse_end(struct automata * a, enum st s)
-{
- int ok = 0;
- if (s == st_post_data) {
- ok = 1;
- } else if (s == st_data) {
- if (!a->is_quoted) {
- if (a->cookie.name) {
- if (end_data(a) && magi_cookie_list_add(a->list, &a->cookie)) {
- ok = 1;
- nulify_cookie(a);
- buf_new(a);
- }
- } else {
- magi_error_set("[cookie] No cookies set.");
- }
- } else {
- magi_error_set("[cookie] In quotation when reached input end.");
- }
- } else if (s != st_error) {
- magi_error_set("[cookie] Input ended in not correct state.");
- }
- free(a->cookie.name);
- free(a->cookie.data);
- free(a->cookie.path);
- free(a->cookie.domain);
- free(a->cookie.port);
- free(a->buf);
- return ok;
-}
-
-int magi_parse_cookie(struct magi_cookie_list ** list, const char * input)
-{
- struct automata a = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 1, 1, 0, 0, 0 };
- enum st state = st_pre_name;
- a.list = list;
- while (*input && state) {
- char c = *input++;
- switch (state) {
- case st_pre_name:
- state = parse_pre_name(&a, c);
- break;
- case st_name:
- state = parse_name(&a, c);
- break;
- case st_post_name:
- state = parse_post_name(&a, c);
- break;
- case st_pre_data:
- state = parse_pre_data(&a, c);
- break;
- case st_data:
- state = parse_data(&a, c);
- break;
- case st_post_data:
- state = parse_post_data(&a, c);
- default:
- break;
- }
- }
- return parse_end(&a, state);
-}
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Cookie List
- */
int magi_cookie_list_add(struct magi_cookie_list ** list,
struct magi_cookie * item)
{
- struct magi_cookie_list * old = *list;
- int ok = 1;
- *list = malloc(sizeof(**list));
- if (*list) {
- (*list)->next = old;
- (*list)->item = *item;
- } else {
- ok = 0;
- magi_error_set("[cookie:list] Cannot allocate new list node.");
- *list = old;
+ struct magi_cookie_list * node = malloc(sizeof(*node));
+ if (node) {
+ node->next = *list;
+ node->item = *item;
+ *list = node;
}
- return ok;
+ return node;
}
-char * magi_cookie_list_get(struct magi_cookie_list * list, const char * name)
+struct magi_cookie * magi_cookie_list_get(struct magi_cookie_list * list,
+ const char * name)
{
- char * data = 0;
- if (list && name) {
- if (!strcmp(list->item.name, name)) {
- data = list->item.data;
- } else {
- data = magi_cookie_list_get(list->next, name);
- }
+ if (!list || !name) {
+ return 0;
+ } else if (!strcmp(list->item.name, name)) {
+ return &list->item;
+ } else {
+ return magi_cookie_list_get(list->next, name);
}
- return data;
}
void magi_cookie_list_destroy(struct magi_cookie_list * list)
@@ -374,8 +35,8 @@ void magi_cookie_list_destroy(struct magi_cookie_list * list)
free(list->next);
free(list->item.name);
free(list->item.data);
- free(list->item.domain);
free(list->item.path);
+ free(list->item.domain);
free(list->item.port);
}
}
diff --git a/src/cookie.h b/src/cookie.h
index 479ab9f..82c914e 100644
--- a/src/cookie.h
+++ b/src/cookie.h
@@ -2,10 +2,8 @@
#define MAGI_INCLUDED_COOKIE
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Cookie
- */
struct magi_cookie {
+ /* All pointers must be valid as 'free' arguments. */
char * name;
char * data;
char * path;
@@ -14,21 +12,21 @@ struct magi_cookie {
};
struct magi_cookie_list {
- struct magi_cookie_list * next;
+ struct magi_cookie_list * next; /* Must be valid as 'free' arguments. */
struct magi_cookie item;
};
-/* Returns null only in case of error. */
+/* Addition of item to top of list. Null <=> error. */
int magi_cookie_list_add(struct magi_cookie_list ** list,
struct magi_cookie * item);
-/* Searchs for first node in list: node.name == name, name is C-string;
- * Returns node.data if succeed, otherwise result is null. */
-char * magi_cookie_list_get(struct magi_cookie_list * list, const char * name);
+/* First node in list: node.name == name; else null. */
+struct magi_cookie * magi_cookie_list_get(struct magi_cookie_list * list,
+ const char * name);
-/* Destroys list. */
-void magi_cookie_list_free(struct magi_cookie_list * list);
+/* Freeing and invalidation of list. */
+void magi_cookie_list_destroy(struct magi_cookie_list * list);
#endif
diff --git a/src/cookies.c b/src/cookies.c
index e69de29..f690ccc 100644
--- a/src/cookies.c
+++ b/src/cookies.c
@@ -0,0 +1,329 @@
+#include "cookies.h"
+
+#include <string.h>
+
+
+enum st {
+ st_error = 0,
+ st_pre_name,
+ st_name,
+ st_post_name,
+ st_pre_data,
+ st_data,
+ st_post_data
+};
+
+enum data_type { dt_plain = 0, dt_version, dt_path, dt_domain, dt_port };
+
+struct automata {
+ struct magi_cookie_list ** list;
+ struct magi_cookie cookie;
+ char * buf;
+ int buf_len;
+ int buf_size;
+ int is_first;
+ int is_cookie2;
+ int is_quoted;
+ enum data_type data_t;
+};
+
+static void nulify_cookie(struct automata * a)
+{
+ a->cookie.name = 0;
+ a->cookie.data = 0;
+ a->cookie.path = 0;
+ a->cookie.domain = 0;
+ a->cookie.port = 0;
+}
+
+static void buf_new(struct automata * a)
+{
+ a->buf = 0;
+ a->buf_len = 0;
+ a->buf_size = 1;
+}
+
+static int buf_add(struct automata * a, char c)
+{
+ int ok = 1;
+ if (a->buf_len == a->buf_size - 1) {
+ a->buf_size *= 2;
+ a->buf = realloc(a->buf, a->buf_size);
+ }
+ if (a->buf) {
+ a->buf_len++;
+ a->buf[a->buf_len - 1] = c;
+ a->buf[a->buf_len] = 0;
+ } else {
+ ok = 0;
+ magi_error_set("[cookie] Cannot allocate automata buffer.");
+ }
+ return ok;
+}
+
+static enum data_type what_is_name(const struct automata * a)
+{
+ enum data_type data_t = dt_plain;
+ if (a->is_first && !strcmp(a->buf, "$Version")) {
+ data_t = dt_version;
+ } else if (a->is_cookie2) {
+ if (!strcmp(a->buf, "$Path")) {
+ data_t = dt_path;
+ } else if (!strcmp(a->buf, "$Domain")) {
+ data_t = dt_domain;
+ } else if (!strcmp(a->buf, "$Port")) {
+ data_t = dt_port;
+ }
+ }
+ return data_t;
+}
+
+static int end_name(struct automata * a)
+{
+ int ok = 1;
+ a->data_t = what_is_name(a);
+ if (a->data_t == dt_plain) {
+ if (a->cookie.name) {
+ ok = magi_cookie_list_add(a->list, &a->cookie);
+ }
+ nulify_cookie(a);
+ a->cookie.name = a->buf;
+ } else {
+ free(a->buf);
+ }
+ buf_new(a);
+ return ok;
+}
+
+static int end_data(struct automata * a)
+{
+ int ok = 1;
+ switch (a->data_t) {
+ case dt_plain:
+ a->cookie.data = a->buf;
+ break;
+ case dt_path:
+ a->cookie.path = a->buf;
+ break;
+ case dt_domain:
+ a->cookie.domain = a->buf;
+ break;
+ case dt_port:
+ a->cookie.port = a->buf;
+ break;
+ case dt_version:
+ if (strcmp(a->buf, "1")) {
+ ok = 0;
+ magi_error_set("[cookie] Version must be '1', readed: %s.",
+ a->buf);
+ }
+ }
+ buf_new(a);
+ return ok;
+}
+
+static enum st parse_pre_name(struct automata * a, char c)
+{
+ enum st state;
+ if (c == ' ' || c == '\t') {
+ state = st_name;
+ } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
+ state = st_name;
+ if (!buf_add(a, c)) {
+ state = st_error;
+ }
+ } else {
+ state = st_error;
+ magi_error_set("[cookie] Pre-name, readed: \\%o (render: %c).", c, c);
+ }
+ return state;
+}
+
+static enum st parse_name(struct automata * a, char c)
+{
+ enum st state;
+ if (c == '=') {
+ state = st_pre_data;
+ if (!end_name(a)) {
+ state = st_error;
+ }
+ } else if (c == ' ' || c == '\t') {
+ state = st_post_name;
+ if (!end_name(a)) {
+ state = st_error;
+ }
+ } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
+ state = st_name;
+ if (!buf_add(a, c)) {
+ state = st_error;
+ }
+ } else {
+ state = st_error;
+ magi_error_set("[cookie] Reading name, readed: \\%o (render: %c).", c,
+ c);
+ }
+ return state;
+}
+
+static enum st parse_post_name(struct automata * a, char c)
+{
+ enum st state;
+ if (c == '=') {
+ state = st_pre_data;
+ } else if (c == ' ' || c == '\t') {
+ state = st_post_name;
+ } else {
+ state = st_error;
+ magi_error_set("[cookie] Waiting for name-value separator, "
+ "readed: \\%o (render: %c).",
+ c, c);
+ }
+ return state;
+}
+
+static enum st parse_pre_data(struct automata * a, char c)
+{
+ enum st state;
+ if (c == ' ' || c == '\t') {
+ state = st_pre_data;
+ } else if (c == '"') {
+ state = st_data;
+ a->is_quoted = 1;
+ } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
+ state = st_data;
+ if (!buf_add(a, c)) {
+ state = st_error;
+ }
+ } else {
+ state = st_error;
+ magi_error_set("[cookie] Pre-value, readed: \\%o (render: %c).", c, c);
+ }
+ return state;
+}
+
+static enum st parse_not_quoted_data(struct automata * a, char c)
+{
+ enum st state;
+ if (c == ';' || (c == ',' && a->is_first)) {
+ state = st_pre_name;
+ a->is_first = 0;
+ if (!end_data(a)) {
+ state = st_error;
+ }
+ } else if (c == ' ' || c == '\t') {
+ state = st_post_data;
+ if (!end_data(a)) {
+ state = st_error;
+ }
+ } else if (32 <= c && c <= 126 && !strchr("()<>@,;:\\\"/[]?={}", c)) {
+ state = st_data;
+ if (!buf_add(a, c)) {
+ state = st_error;
+ }
+ } else {
+ state = st_error;
+ magi_error_set("[cookie] Reading not-quoted value, "
+ "readed: \\%o (render: %c).",
+ c, c);
+ }
+ return state;
+}
+
+static enum st parse_data(struct automata * a, char c)
+{
+ enum st state;
+ if (a->is_quoted) {
+ if (c == '"') {
+ state = st_post_data;
+ a->is_quoted = 0;
+ if (!end_data(a)) {
+ state = st_error;
+ }
+ } else {
+ state = st_data;
+ }
+ } else {
+ state = parse_not_quoted_data(a, c);
+ }
+ return state;
+}
+
+static enum st parse_post_data(struct automata * a, char c)
+{
+ enum st state;
+ if (c == ';' || (c == ',' && a->is_first)) {
+ state = st_pre_name;
+ } else if (c == ' ' || c == '\t') {
+ state = st_post_data;
+ } else {
+ state = st_error;
+ magi_error_set(
+ "[cookie] Waiting for separator between name-value pairs, "
+ "readed: \\%o (render: %c).",
+ c, c);
+ }
+ return state;
+}
+
+static int parse_end(struct automata * a, enum st s)
+{
+ int ok = 0;
+ if (s == st_post_data) {
+ ok = 1;
+ } else if (s == st_data) {
+ if (!a->is_quoted) {
+ if (a->cookie.name) {
+ if (end_data(a) && magi_cookie_list_add(a->list, &a->cookie)) {
+ ok = 1;
+ nulify_cookie(a);
+ buf_new(a);
+ }
+ } else {
+ magi_error_set("[cookie] No cookies set.");
+ }
+ } else {
+ magi_error_set("[cookie] In quotation when reached input end.");
+ }
+ } else if (s != st_error) {
+ magi_error_set("[cookie] Input ended in not correct state.");
+ }
+ free(a->cookie.name);
+ free(a->cookie.data);
+ free(a->cookie.path);
+ free(a->cookie.domain);
+ free(a->cookie.port);
+ free(a->buf);
+ return ok;
+}
+
+int magi_parse_cookie(struct magi_cookie_list ** list, const char * input)
+{
+ struct automata a = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 1, 1, 0, 0, 0 };
+ enum st state = st_pre_name;
+ a.list = list;
+ while (*input && state) {
+ char c = *input++;
+ switch (state) {
+ case st_pre_name:
+ state = parse_pre_name(&a, c);
+ break;
+ case st_name:
+ state = parse_name(&a, c);
+ break;
+ case st_post_name:
+ state = parse_post_name(&a, c);
+ break;
+ case st_pre_data:
+ state = parse_pre_data(&a, c);
+ break;
+ case st_data:
+ state = parse_data(&a, c);
+ break;
+ case st_post_data:
+ state = parse_post_data(&a, c);
+ default:
+ break;
+ }
+ }
+ return parse_end(&a, state);
+}
diff --git a/src/fastcgi.c b/src/fastcgi.c
index e69de29..39c57ca 100644
--- a/src/fastcgi.c
+++ b/src/fastcgi.c
@@ -0,0 +1 @@
+#include "fastcgi.h"
diff --git a/src/fastcgi.h b/src/fastcgi.h
index 5410955..d701fe0 100644
--- a/src/fastcgi.h
+++ b/src/fastcgi.h
@@ -1,22 +1,8 @@
#ifndef MAGI_INCLUDED_FASTCGI
#define MAGI_INCLUDED_FASTCGI
-#include "error.h"
-#include "file.h"
-#include "request.h"
-
-struct magi_session {
- struct magi_socket_list * sockets;
- enum magi_error error;
-};
-
-int magi_session_fcgi(struct magi_session * session, int socket);
-
-
-/* Returns null only in case of error. */
-int magi_request_fcgi(struct magi_request * request,
- struct magi_session * session);
+/* TODO */
#endif
diff --git a/src/file.c b/src/file.c
index e69de29..df6c978 100644
--- a/src/file.c
+++ b/src/file.c
@@ -0,0 +1,40 @@
+#include "file.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+int magi_file_list_add(struct magi_file_list ** list, struct magi_file * item)
+{
+ struct magi_file_list * node = malloc(sizeof(*node));
+ if (node) {
+ node->next = *list;
+ node->item = *item;
+ *list = node;
+ }
+ return node;
+}
+
+struct magi_file * magi_file_list_get(struct magi_file_list * list,
+ const char * name)
+{
+ if (!list || !name) {
+ return 0;
+ } else if (!strcmp(list->item.param_name, name)) {
+ return &list->item;
+ } else {
+ return magi_file_list_get(list->next, name);
+ }
+}
+
+void magi_file_list_destroy(struct magi_file_list * list)
+{
+ if (list) {
+ magi_file_list_destroy(list->next);
+ free(list->next);
+ free(list->item.param_name);
+ free(list->item.file_name);
+ magi_param_list_destroy(list->item.params);
+ free(list->item.params);
+ }
+}
diff --git a/src/file.h b/src/file.h
index 0994755..a677e2f 100644
--- a/src/file.h
+++ b/src/file.h
@@ -3,9 +3,27 @@
struct magi_file {
- char * param_name;
- struct magi_para_list * params;
+ /* All pointers must be valid as 'free' arguments. */
+ char * param_name; /* Name of corresponding form field */
+ char * file_name; /* File name on user's computer */
+ struct magi_param_list * params; /* Multipart params (e.g. type) */
};
+struct magi_file_list {
+ struct magi_file_list * next; /* Must be valid as 'free' argument. */
+ struct magi_file item;
+};
+
+
+/* Addition of item to top of list. Null <=> error. */
+int magi_file_list_add(struct magi_file_list ** list, struct magi_file * item);
+
+/* First node in list: node.param_name == name; else null. */
+struct magi_file * magi_file_list_get(struct magi_file_list * list,
+ const char * name);
+
+/* Freeing and invalidation of list. */
+void magi_file_list_destroy(struct magi_file_list * list);
+
#endif
diff --git a/src/param.c b/src/param.c
index d87a610..73005af 100644
--- a/src/param.c
+++ b/src/param.c
@@ -1,42 +1,30 @@
#include "param.h"
-#include "error.h"
#include <stdlib.h>
#include <string.h>
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Parameter
- */
int magi_param_list_add(struct magi_param_list ** list,
struct magi_param * item)
{
- struct magi_param_list * old = *list;
- int ok = 1;
- *list = malloc(sizeof(**list));
- if (*list) {
- (*list)->next = old;
- (*list)->item = *item;
- } else {
- ok = 0;
- magi_error_set("[param:list] Cannot allocate new list node.");
- *list = old;
+ struct magi_param_list * node = malloc(sizeof(*node));
+ if (node) {
+ node->next = *list;
+ node->item = *item;
+ *list = node;
}
- return ok;
+ return node;
}
-struct magi_param * magi_param_list_get(struct magi_param_list * list,
- const char * name)
+char * magi_param_list_get(struct magi_param_list * list, const char * name)
{
- struct magi_param * item = 0;
- if (list && name) {
- if (!strcmp(list->item.name, name)) {
- item = &list->item;
- } else {
- item = magi_param_list_get(list->next, name);
- }
+ if (!list || !name) {
+ return 0;
+ } else if (!strcmp(list->item.name, name)) {
+ return &list->item.data;
+ } else {
+ return magi_param_list_get(list->next, name);
}
- return item;
}
void magi_param_list_destroy(struct magi_param_list * list)
diff --git a/src/param.h b/src/param.h
index 6fd0ba0..3f8cefe 100644
--- a/src/param.h
+++ b/src/param.h
@@ -2,31 +2,26 @@
#define MAGI_INCLUDED_PARAM
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Parameter
- */
struct magi_param {
+ /* All pointers must be valid as 'free' arguments. */
char * name;
char * data;
};
struct magi_param_list {
- struct magi_param_list * next;
+ struct magi_param_list * next; /* Must be valid as 'free' argument. */
struct magi_param item;
};
-/* Adds *item to the begining of *list, item and list are dereferencable;
- * Returns null in case of error. */
+/* Addition of item to top of list. Null <=> error. */
int magi_param_list_add(struct magi_param_list ** list,
struct magi_param * item);
-/* Searchs for first node in list: node.name == name, name is C-string;
- * Returns node itself if succeed, otherwise result is null. */
-struct magi_param * magi_param_list_get(struct magi_param_list * list,
- const char * name);
+/* Data of the first node in list: node.name == name; else null. */
+char * magi_param_list_get(struct magi_param_list * list, const char * name);
-/* Destroys list; list is not valid after destruction. */
+/* Freeing and invalidation of list. */
void magi_param_list_destroy(struct magi_param_list * list);
diff --git a/src/request.c b/src/request.c
index 2d9625e..4a1464a 100644
--- a/src/request.c
+++ b/src/request.c
@@ -3,21 +3,60 @@
#include "cookie.h"
#include "file.h"
#include "param.h"
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
void magi_request_setup(struct magi_request * request)
{
if (request) {
- request->file_callback = 0;
- request->file_callback_userdata = 0;
- request->file_callback_addon_len_max = 64;
- request->max_cookies_size = 0;
- request->max_http_params_size = 0;
- request->max_params_size = 0;
+ request->file_callback = 0;
+ request->file_callback_userdata = 0;
+ request->file_callback_addon_max = 64;
+ request->cookies_max = 1024 * 8;
+ request->url_params_max = 1024 * 2;
+ request->http_params_max = 1024 * 16;
+ request->params_max = 0;
}
}
+static void tempfiles(struct magi_file * file,
+ char * addon,
+ int addon_len,
+ int is_addon_last,
+ struct magi_tempfiles * table)
+{
+ int pos;
+ for (pos = 0; pos != table->count; ++pos) {
+ if (!strcmp(table->param_names[pos], file->param_name)) {
+ static FILE * f = 0;
+ static int left;
+ int min;
+ if (!f) {
+ const char * loc = table->locations[pos];
+ f = fopen(loc, "wb");
+ left = table->maximums[pos];
+ }
+ min = left < addon_len ? left : addon_len;
+ fwrite(addon, 1, min, f);
+ left -= min;
+ if (is_addon_last) {
+ fclose(f);
+ f = 0;
+ }
+ return;
+ }
+ }
+}
+
+void magi_request_setup_tempfiles(struct magi_request * request,
+ struct magi_tempfiles * table)
+{
+ request->file_callback = tempfiles;
+ request->file_callback_userdata = table;
+}
+
static void request_free(struct magi_request * request)
{
diff --git a/src/request.h b/src/request.h
index 15a5da6..5bb2070 100644
--- a/src/request.h
+++ b/src/request.h
@@ -10,10 +10,16 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Request
*
- * Can be generated via CGI handler (magi_cgi_request) or
- * in a Fast CGI session (magi_fcgi_request).
+ * Can be created via 'magi_request_{gateway interface name}', but will have
+ * nullified 'post'-related fields ('params' & 'files'). Reason is unlimited
+ * 'post' body size, with possible dependence of wanted limits from data of
+ * headers (e.g. session id from cookies, enabling some users to load more).
+ * To proceed 'post' use 'magi_request_resume_{gateway interface name}',
+ * specifying settings if necessary.
*
*
+ * Cheatsheet on environment:
+ *
* Request URL: http[s]://{server_name}[:{server_port}]{uri}
* example.com 80
* uri: {document_uri}[?{urlencode(url_params)}]
@@ -23,13 +29,14 @@
*/
struct magi_request {
/* * * Results * * */
+ /* All pointers of this section must be valid as 'free' arguments. */
/* Parsed */
struct magi_cookie_list * cookies;
struct magi_param_list * http_params; /* HTTP Header parameters */
struct magi_param_list * url_params; /* Urlencoded paramteres from URL */
struct magi_param_list * params; /* Parameters from 'post' body */
- struct magi_file_list * files; /* Files loaded via multipart */
+ struct magi_file_list * files; /* 'Post' multipart files */
/* Environment Shortcuts */
char * method; /* REQUEST_METHOD */
@@ -41,9 +48,9 @@ struct magi_request {
char * remote_addr; /* REMOTE_ADDR */
char * remote_port; /* REMOTE_PORT */
char * server_addr; /* SERVER_ADDR */
- /* Following can be not a domain name, even if request is done with it.
- * (Use http_params["HTTP_HOST"] instead.) */
char * server_name; /* SERVER_NAME */
+ /* server_name can be not a domain name, even if request is done with it.
+ * (Use http_params["HTTP_HOST"] instead.) */
char * server_port; /* SERVER_PORT */
char * server_protocol; /* SERVER_PROTOCOL */
char * server_software; /* SERVER_COFTWARE */
@@ -53,7 +60,7 @@ struct magi_request {
enum magi_error error;
- /* * * Internal Data (no need for user to analyse) * * */
+ /* * * Settings * * */
/* Callback for processing files */
void (*file_callback)(struct magi_file * file,
@@ -62,18 +69,29 @@ struct magi_request {
int is_addon_last,
void * userdata);
void * file_callback_userdata;
- int file_callback_addon_len_max;
+ int file_callback_addon_max;
- /* Limit for memory used (disables with zero) */
- int max_cookies_size;
- int max_http_params_size;
- int max_params_size;
+ /* Limits for memory used (null <=> unlimitted) */
+ int cookies_max;
+ int url_params_max;
+ int http_params_max;
+ int params_max;
};
/* Setup request with default settings. */
void magi_request_setup(struct magi_request * request);
+struct magi_tempfiles {
+ int count;
+ const char ** param_names;
+ const char ** locations;
+ int * maximums; /* Null maximums[i] <=> unlimited tempfiles[i]. */
+};
+/* Setup request callback with files loaded into corresponding to their
+ * parameter names locations; paths are in magi_tempfiles struct. */
+void magi_request_setup_tempfiles(struct magi_request * request,
+ struct magi_tempfiles * table);
/* Destroys request. */
void magi_request_destroy(struct magi_request * request);
diff --git a/src/response.h b/src/response.h
index 04d7350..346ce3d 100644
--- a/src/response.h
+++ b/src/response.h
@@ -33,4 +33,7 @@ void magi_response_cookie_delete(struct magi_response * response,
const char * name);
+void magi_response_destroy(struct magi_response * response);
+
+
#endif