bchs_tuto/examples/example3.c

228 lines
5.3 KiB
C
Raw Normal View History

/*
* Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "kcgi.h"
#include "kcgihtml.h"
enum page {
PAGE_INDEX, /* /index or just / */
PAGE_SENDDATA, /* /senddata */
PAGE__MAX
};
enum key {
KEY_INTEGER,
KEY_FILE,
KEY_PAGECOUNT,
KEY_PAGESIZE,
KEY__MAX
};
typedef void (*disp)(struct kreq *);
static void senddata(struct kreq *);
static void sendindex(struct kreq *);
static const disp disps[PAGE__MAX] = {
sendindex, /* PAGE_INDEX */
senddata, /* PAGE_SENDDATA */
};
static const struct kvalid keys[KEY__MAX] = {
{ kvalid_int, "integer" }, /* KEY_INTEGER */
{ NULL, "file" }, /* KEY_FILE */
{ kvalid_uint, "count" }, /* KEY_PAGECOUNT */
{ kvalid_uint, "size" }, /* KEY_PAGESIZE */
};
static const char *const pages[PAGE__MAX] = {
"index", /* PAGE_INDEX */
"senddata" /* PAGE_SENDDATA */
};
static void
resp_open(struct kreq *req, enum khttp http)
{
khttp_head(req, kresps[KRESP_STATUS],
"%s", khttps[http]);
khttp_head(req, kresps[KRESP_CONTENT_TYPE],
"%s", kmimetypes[req->mime]);
khttp_body(req);
}
static void
senddata(struct kreq *req)
{
int64_t i, j, k, nm, sz;
char *buf;
struct khtmlreq r;
nm = 1024 * 1024;
if (NULL != req->fieldmap[KEY_PAGECOUNT])
nm = req->fieldmap[KEY_PAGECOUNT]->parsed.i;
if (0 == nm)
nm = 1;
sz = 1;
if (NULL != req->fieldmap[KEY_PAGESIZE])
sz = req->fieldmap[KEY_PAGESIZE]->parsed.i;
if (0 == sz || (uint64_t)sz > SIZE_MAX)
sz = 1;
buf = kmalloc(sz);
resp_open(req, KHTTP_200);
khtml_open(&r, req);
khtml_elem(&r, KELEM_DOCTYPE);
khtml_elem(&r, KELEM_HTML);
khtml_elem(&r, KELEM_HEAD);
khtml_elem(&r, KELEM_TITLE);
khtml_puts(&r, "Have a banana.");
khtml_closeelem(&r, 2);
khtml_elem(&r, KELEM_BODY);
for (i = k = 0; i < nm; i++) {
for (j = 0; j < sz; j++) {
if (72 == k++) {
buf[j] = '\n';
k = 0;
} else
buf[j] = 65 + arc4random_uniform(24);
}
khtml_write(buf, sz, &r);
}
khtml_close(&r);
free(buf);
}
static void
sendindex(struct kreq *req)
{
char *page;
struct khtmlreq r;
const char *cp;
kasprintf(&page, "%s/%s", req->pname, pages[PAGE_INDEX]);
resp_open(req, KHTTP_200);
khtml_open(&r, req);
khtml_elem(&r, KELEM_DOCTYPE);
khtml_elem(&r, KELEM_HTML);
khtml_elem(&r, KELEM_HEAD);
khtml_elem(&r, KELEM_TITLE);
khtml_puts(&r, "Welcome!");
khtml_closeelem(&r, 2);
khtml_elem(&r, KELEM_BODY);
khtml_puts(&r, "Welcome!");
khtml_attr(&r, KELEM_FORM,
KATTR_METHOD, "post",
KATTR_ENCTYPE, "multipart/form-data",
KATTR_ACTION, page,
KATTR__MAX);
khtml_elem(&r, KELEM_FIELDSET);
khtml_elem(&r, KELEM_LEGEND);
khtml_puts(&r, "Post (multipart)");
khtml_closeelem(&r, 1);
khtml_elem(&r, KELEM_P);
cp = NULL == req->fieldmap[KEY_INTEGER] ?
"" : req->fieldmap[KEY_INTEGER]->val;
khtml_attr(&r, KELEM_INPUT,
KATTR_TYPE, "number",
KATTR_NAME, keys[KEY_INTEGER].name,
KATTR_VALUE, cp, KATTR__MAX);
khtml_closeelem(&r, 1);
khtml_elem(&r, KELEM_P);
khtml_attr(&r, KELEM_INPUT,
KATTR_TYPE, "file",
KATTR_MULTIPLE, "",
KATTR_NAME, keys[KEY_FILE].name,
KATTR__MAX);
if (NULL != req->fieldmap[KEY_FILE]) {
if (NULL != req->fieldmap[KEY_FILE]->file) {
khtml_puts(&r, "file: ");
khtml_puts(&r, req->fieldmap[KEY_FILE]->file);
khtml_puts(&r, " ");
}
if (NULL != req->fieldmap[KEY_FILE]->ctype) {
khtml_puts(&r, "ctype: ");
khtml_puts(&r, req->fieldmap[KEY_FILE]->ctype);
}
}
khtml_closeelem(&r, 1);
khtml_elem(&r, KELEM_P);
khtml_attr(&r, KELEM_INPUT,
KATTR_TYPE, "submit",
KATTR__MAX);
khtml_closeelem(&r, 0);
khtml_close(&r);
free(page);
}
int
main(void)
{
struct kreq r;
/*
* Set up our main HTTP context.
*/
if (KCGI_OK != khttp_parse
(&r, keys, KEY__MAX, pages, PAGE__MAX, PAGE_INDEX))
return(EXIT_FAILURE);
if (KMETHOD_OPTIONS == r.method) {
/*
* Indicate that we accept GET and POST methods.
* This isn't really needed.
*/
khttp_head(&r, kresps[KRESP_STATUS],
"%s", khttps[KHTTP_200]);
khttp_head(&r, kresps[KRESP_ALLOW],
"OPTIONS GET POST");
khttp_body(&r);
} else if (KMETHOD_GET != r.method &&
KMETHOD_POST != r.method) {
/*
* Don't accept non-GET and non-POST methods.
*/
resp_open(&r, KHTTP_405);
} else if (PAGE__MAX == r.page ||
KMIME_TEXT_HTML != r.mime) {
/*
* We've been asked for an unknown page or something
* with an unknown extension.
*/
resp_open(&r, KHTTP_404);
khttp_puts(&r, "Page not found.");
} else
/*
* Route to page handler.
*/
(*disps[r.page])(&r);
/*
* Clean up our context.
*/
khttp_free(&r);
return(EXIT_SUCCESS);
}