#include <sys/types.h>
#include <sys/queue.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <event.h>
#include <evhttp.h>
#include "mandelbrot.h"
#include "common.h"
struct http_render_state {
struct evbuffer *buf;
} _http_render_state = { NULL };
int _http_render_cb (const unsigned char *data, size_t length, void *arg) {
// create a buffer
struct evbuffer *buf = evbuffer_new();
if (!buf) {
error("_http_render_cb: evbuffer_new failed");
return RENDER_CB_ERR;
}
// add the data to it
if (evbuffer_add(buf, data, length)) {
error("_http_render_cb: evbuffer_add(%d) failed", length);
return RENDER_CB_ERR;
}
// send it
evhttp_send_reply_chunk((struct evhttp_request *) arg, buf);
printf("_http_render_cb: sent chunk: %zu\n", length);
// free the buffer (!!!)
evbuffer_free(buf);
// return ok
return RENDER_CB_OK;
}
void http_render (struct evhttp_request *request, void *arg) {
// gather some info about the request
const char *uri = evhttp_request_uri(request);
char *peer_address;
u_short peer_port;
evhttp_connection_get_peer(request->evcon, &peer_address, &peer_port);
// request arguments
u_int32_t img_w = 256, img_h = 256;
struct evkeyval *qarg;
struct evkeyvalq qargs;
evhttp_parse_query(uri, &qargs);
TAILQ_FOREACH(qarg, &qargs, next) {
if (strcmp(qarg->key, "w") == 0)
img_w = strtol(qarg->value, NULL, 10);
else if (strcmp(qarg->key, "h") == 0)
img_h = strtol(qarg->value, NULL, 10);
}
// clean up the qargs (badly named functions :< )
evhttp_clear_headers(&qargs);
// request log
printf("REQ: [%s:%d] uri=%s, img_w=%d, img_h=%d\n", peer_address, peer_port, uri, img_w, img_h);
// set headers
evhttp_add_header(request->output_headers, "Content-Type", "image/png");
evhttp_send_reply_start(request, HTTP_OK, "OK");
// render
struct render_ctx ctx;
render_ctx_set(&ctx, &_http_render_cb, NULL, request);
int err = mandelbrot_render_full(&ctx, img_w, img_h);
if (err) {
fprintf(stderr, "ERR: mandelbrot_render_full(%d, %d): %d\n", img_w, img_h, err);
}
// reply end
evhttp_send_reply_end(request);
}
int main (void) {
// libevent/http init
struct event_base *ev_base = event_init();
if (!ev_base)
die("event_init");
struct evhttp *http_server = evhttp_new(ev_base);
if (!http_server)
die("evhttp_new");
// bind to the correct interface/port
if (evhttp_bind_socket(http_server, "0.0.0.0", 8117))
die("evhttp_bind_socket");
// add our http request handler
evhttp_set_cb(http_server, "/render", &http_render, NULL);
// we shall now run
printf("RUN 0.0.0.0:8117\n");
// run the libevent mainloop
if (event_dispatch())
die("event_dispatch");
// clean up
evhttp_free(http_server);
// successfull exit
return 0;
}