web_main.c
author Tero Marttila <terom@fixme.fi>
Fri, 30 May 2008 14:24:23 +0300
changeset 0 5b010627d7ed
child 2 69f8c0acaac7
permissions -rw-r--r--
initial code, render_file(local+remote), render_node, web_main(local)

committer: Tero Marttila <terom@fixme.fi>
#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;
}