aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Veresov <aleksey@veresov.pro>2020-07-29 07:51:41 +0300
committerAleksey Veresov <aleksey@veresov.pro>2020-07-29 07:51:41 +0300
commit0ac3b187dff09b67bd4551e0124e6fad8884adda (patch)
tree5ef93190b12ec1e778ccc56f1b511c8ae3632739
parentc5aa29ffc0a82864f5155427634a9ed7c40b3d06 (diff)
downloadmagi-0ac3b187dff09b67bd4551e0124e6fad8884adda.tar
magi-0ac3b187dff09b67bd4551e0124e6fad8884adda.tar.xz
magi-0ac3b187dff09b67bd4551e0124e6fad8884adda.zip
Docs completed.
-rw-r--r--examples/upload.c9
-rw-r--r--include/magi/file.h4
-rw-r--r--include/magi/loadfiles.h29
-rw-r--r--include/magi/response.h10
-rw-r--r--man/magi.3195
-rw-r--r--src/file.c6
-rw-r--r--src/loadfiles.c82
7 files changed, 274 insertions, 61 deletions
diff --git a/examples/upload.c b/examples/upload.c
index c9752b6..6349118 100644
--- a/examples/upload.c
+++ b/examples/upload.c
@@ -36,12 +36,13 @@ void response(struct magi_request *r)
void get(struct magi_request *r)
{
- struct magi_loadfiles rules = { 0, 0 };
+ struct magi_loadfiles *cb;
+ magi_loadfiles_init(&cb);
/* Setup callback to load file from "data" field into file "data": */
- magi_loadfiles_add(&rules, "data", "data", 0);
- magi_loadfiles_set(r, &rules); /* Setup request to use the callback. */
+ magi_loadfiles_add(&cb, "data", "data", 0);
+ magi_loadfiles_set(r, &cb); /* Setup request to use the callback. */
magi_parse(r);
- magi_loadfiles_free(&rules); /* Free data of callback. */
+ magi_loadfiles_free(&cb); /* Free data of callback. */
}
int main()
diff --git a/include/magi/file.h b/include/magi/file.h
index a655855..0623644 100644
--- a/include/magi/file.h
+++ b/include/magi/file.h
@@ -30,6 +30,10 @@ const struct magi_file *magi_files_get(const struct magi_files *files,
const char *name);
+/* Get value of parameter with name from file->params. */
+char *magi_file_param(struct magi_file *file, const char *name);
+
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Callback to load files while analysing request.
* addon_len is not null if something to add is in addon
diff --git a/include/magi/loadfiles.h b/include/magi/loadfiles.h
index 9d7978f..85aeefc 100644
--- a/include/magi/loadfiles.h
+++ b/include/magi/loadfiles.h
@@ -18,30 +18,31 @@ struct magi_loadfile {
int max; /* Limit in bytes. Null means unlimited. */
};
-/* Table of rules for loading files.
- * Set count and files as null to initialize. */
+/* Table of rules for loading files as linked list. */
struct magi_loadfiles {
- int count; /* Size of files array.*/
- struct magi_loadfile *files; /* Dynamic array of rules to load files. */
+ struct magi_loadfile *item;
+ struct magi_loadfiles *next;
};
-/* Free memory used by table. Request using table will become invalid. */
-void magi_loadfiles_free(struct magi_loadfiles *table);
+/* Initialise loadfiles. */
+void magi_loadfiles_init(struct magi_loadfiles **loadfiles);
+/* Free memory used by loadfiles. Request using table will become invalid. */
+void magi_loadfiles_free(struct magi_loadfiles **loadfiles);
-/* Add entity into table.
+/* Add entity into loadfiles.
* Specify form field to load file from with name,
* wnated loaction to load file with path,
* and file size limit in bytes with max (pass null to unlimit). */
-void magi_loadfiles_add(struct magi_loadfiles *table,
- const char *name,
- const char *path,
- int max);
+void magi_loadfiles_add(struct magi_loadfiles **loadfiles,
+ const char *name,
+ const char *path,
+ int max);
-/* Setup request to use loadfiles callback with table. */
-void magi_loadfiles_set(struct magi_request *request,
- struct magi_loadfiles *table);
+/* Setup request to use loadfiles callback. */
+void magi_loadfiles_set(struct magi_request *request,
+ struct magi_loadfiles **loadfiles);
#endif
diff --git a/include/magi/response.h b/include/magi/response.h
index 6a49a0c..10c5c1c 100644
--- a/include/magi/response.h
+++ b/include/magi/response.h
@@ -37,19 +37,19 @@ void magi_response_status(struct magi_response *r,
/* Add cookie to response. */
void magi_response_cookie(struct magi_response *r,
- const char *n,
- const char *d);
+ const char *name,
+ const char *data);
/* Add cookie with additional information to response. */
void magi_response_cookie_complex(struct magi_response *r,
const struct magi_cookie *c);
/* Add request to discard cookie to response. */
void magi_response_cookie_discard(struct magi_response *r,
- const char *name);
+ const char *name);
/* Just add some general custom header. */
void magi_response_header(struct magi_response *r,
- const char *n,
- const char *d);
+ const char *name,
+ const char *data);
/* Change Content-Length header. */
void magi_response_content_length(struct magi_response *r, int length);
diff --git a/man/magi.3 b/man/magi.3
index 7efbcd5..786b692 100644
--- a/man/magi.3
+++ b/man/magi.3
@@ -218,7 +218,197 @@ structure. If no cookie is found, result is null. It has fields
.I max_age
(the last one is used only in response).
.SS Files in request
+While ordinary parameters are not very big and don't need special processing,
+files can be huge and need specail processing.
+Due to their size, files shouldn't be loaded into memory in general.
+The
+.B magi
+library allows you to setup your own callback for file loading,
+or use predefined one,
+.BR magi_loadfiles .
+.P
+You can load file from field
+.I to_load
+into
+.I ./uploaded
+with limits on its size of 1MB as following:
+.P
+.RS
+.nf
+struct magi_loadfiles cb;
+magi_loadfiles_init(&cb);
+magi_loadfiles_add(&cb, "to_load", "./uploaded", 1024 * 1024);
+magi_loadfiles_set(&request, &cb);
+magi_parse_body(&request);
+magi_loadfiles_free(&rules);
+/* Use file ./uploaded */
+.fi
+.RE
+.P
+There
+.I request
+is initialised
+.B magi_request
+with parsed head and not parsed body.
+.P
+To access information about file, use
+.B magi_request_file .
+It will get your
+.B magi_file
+structure for file loaded from field with passed name.
+This structure have file name on user host in
+.I filename
+field.
+Other parameters (as Content-Type) are in
+.I params
+field, accessible with
+.BR magi_file_param .
+.P
+For example, we can get user feedback, returning Content-Type of loaded file:
+.P
+.RS
+.nf
+struct magi_file *loaded = magi_request_file(&request, "to_load");
+if (loaded) {
+ char *type = magi_file_param(loaded, "Content-Type");
+ if (type_to_response) {
+ /* Report the user that file of 'type' was loaded. */
+ } else {
+ /* Report the user that file was loaded without
+ specified Content-Type. */
+ }
+} else {
+ /* Report the user that file wasn't loaded. */
+}
+.SS File processing callback
+In some cases
+.B magi_loadfiles
+can be not enough.
+Then you can specify your own
+.BR magi_file_callback .
+The
+.I act
+field contains the callback function itself.
+The
+.I userdata
+field has type
+.I "void *"
+allowing you to exchange state across different calls of callback.
+The
+.I addon_max
+field specify how much bytes can be passed to your callback with one call.
+.P
+Callback function has type
+.BR magi_file_callback_act ,
+which is function returning void, with
+.IR userdata ,
+.I newfile
+flag,
+.I file
+.B magi_file
+structure,
+.I addon
+and
+.IR addon_len .
+.P
+Files are passed sequantially addon by addon.
+At the file end callback will be called with
+.I addon
+and
+.I addon_len
+as nulls.
+If current
+.I addon
+is first in current
+.I file
+.I newfile
+flag will be setted up.
+.P
+You can load file from field 'file' into current directory with name,
+as specified by
+.I filename
+field as:
+.P
+.RS
+.nf
+static void cb(void *userdata,
+ int newfile,
+ const struct magi_file *file,
+ const char *addon,
+ int addon_len)
+{
+ static FILE *f = 0;
+ if (!strcmp("file", file->field)) {
+ if (newfile) {
+ f = fopen(file->filename, "wb");
+ }
+ fwrite(addon, 1, addon_len, f);
+ if (!addon) {
+ fclose(f);
+ }
+ }
+}
+.fi
+.RE
+.P
+Set it as callback for processing files for initialised
+.I request
+with parsed head and not parsed body, and then parse the body:
+.P
+.RS
+.nf
+request.callback.act = cb;
+magi_parse_body(&request);
+/* Now file is loaded into filename */
+.fi
+.RE
.SH RESPONSE
+Response headers are formed with
+.B magi_response
+structure.
+It is initiated with
+.BR magi_response_init ,
+sent with
+.BR magi_response_send ,
+and freed with
+.BR magi_response_free .
+The only defaults are
+.I text/html
+as Content-Type and
+.I 200 Ok
+as status.
+You can send them with
+.BR magi_response_default .
+.P
+.BR magi_response_content_type ,
+.B magi_reponse_content_length
+and
+.B magi_response_status
+are used to change corresponding headers.
+Any other header can be only added, not changed with
+.BR magi_response_header .
+Don't use it in cases above.
+.P
+For cookies use
+.B magi_response_cookie
+to set cookies and
+.B magi_response_cookie_discard
+to discrad them.
+In case of Cookie2 use
+.BR magi_response_cookie_complex .
+.P
+Lets send headers for XHTML body, setting cookie 'monster' as 'cookie':
+.P
+.RS
+.nf
+struct magi_response response;
+magi_response_init(&response);
+magi_response_content_type(&response, "application/xhtml+xml");
+magi_response_cookie(&response, "monster", "cookie");
+magi_response_send(&response);
+magi_response_free(&response);
+.fi
+.RE
.SS URL encoding
It is described in
.IR "RFC 3986" .
@@ -271,6 +461,11 @@ code is in
field of
.B magi_request
structure. For other modules error codes seem to be overkill.
+.P
+You can access default error message with
+.B magi_error_message
+or send default error page with
+.BR magi_error_response .
.SH DEBUGGING
To debug your CGI scripts with
.I gdb
diff --git a/src/file.c b/src/file.c
index b3727f1..10e5b07 100644
--- a/src/file.c
+++ b/src/file.c
@@ -38,3 +38,9 @@ void magi_files_free(struct magi_files *files)
free(files->item.params);
}
}
+
+
+char *magi_file_param(struct magi_file *file, const char *name)
+{
+ return file ? magi_params_get(file->params, name) : 0;
+}
diff --git a/src/loadfiles.c b/src/loadfiles.c
index 49cf503..9d7043c 100644
--- a/src/loadfiles.c
+++ b/src/loadfiles.c
@@ -5,55 +5,25 @@
#include <string.h>
-void magi_loadfiles_add(struct magi_loadfiles *table,
- const char *name,
- const char *path,
- int max)
-{
- static const int size = sizeof(*table->files);
- if (!table) {
- return;
- }
- if (table->count) {
- table->files = realloc(table->files, size * table->count + size);
- } else {
- table->files = malloc(size);
- }
- table->files[table->count].name = name;
- table->files[table->count].path = path;
- table->files[table->count].max = max;
- table->count++;
-}
-
-void magi_loadfiles_free(struct magi_loadfiles *table)
-{
- if (!table) {
- return;
- }
- free(table->files);
- table->count = 0;
-}
-
static void loadfiles_callback(void *userdata,
int newfile,
const struct magi_file *file,
const char *addon,
int addon_len)
{
- int pos;
- struct magi_loadfiles *table = userdata;
+ struct magi_loadfiles *loadfiles = *(struct magi_loadfiles **)userdata;
if (!file->filename || !*file->filename) {
return;
}
- for (pos = 0; pos != table->count; ++pos) {
- if (!strcmp(table->files[pos].name, file->field)) {
+ for (; loadfiles; loadfiles = loadfiles->next) {
+ if (!strcmp(loadfiles->item->name, file->field)) {
static FILE *f = 0;
static int unlimited;
static int left;
if (newfile) {
- const char *path = table->files[pos].path;
+ const char *path = loadfiles->item->path;
f = fopen(path, "wb");
- left = table->files[pos].max;
+ left = loadfiles->item->max;
unlimited = !left;
}
if (unlimited) {
@@ -71,9 +41,45 @@ static void loadfiles_callback(void *userdata,
}
}
-void magi_loadfiles_set(struct magi_request *request,
- struct magi_loadfiles *table)
+
+void magi_loadfiles_init(struct magi_loadfiles **loadfiles)
+{
+ *loadfiles = 0;
+}
+
+void magi_loadfiles_free(struct magi_loadfiles **loadfiles)
+{
+ if (!loadfiles || !*loadfiles) {
+ return;
+ }
+ free((*loadfiles)->item);
+ magi_loadfiles_free(&(*loadfiles)->next);
+ free(*loadfiles);
+}
+
+
+void magi_loadfiles_add(struct magi_loadfiles **loadfiles,
+ const char *name,
+ const char *path,
+ int max)
+{
+ struct magi_loadfiles *next;
+ if (!loadfiles) {
+ return;
+ }
+ next = *loadfiles ? (*loadfiles)->next : 0;
+ *loadfiles = malloc(sizeof(**loadfiles));
+ (*loadfiles)->item = malloc(sizeof(struct magi_loadfile));
+ (*loadfiles)->item->name = name;
+ (*loadfiles)->item->path = path;
+ (*loadfiles)->item->max = max;
+ (*loadfiles)->next = next;
+}
+
+
+void magi_loadfiles_set(struct magi_request *request,
+ struct magi_loadfiles **loadfiles)
{
request->callback.act = loadfiles_callback;
- request->callback.userdata = table;
+ request->callback.userdata = loadfiles;
}