summaryrefslogtreecommitdiff
path: root/datastore-leveldb/src/main.cpp
blob: 4fd95df4bfd40dc6840c9afacf7aa4465f75fa16 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
extern "C" {
#include "server_eh.h"
#include <unistd.h>
#include <signal.h>
#include <ev.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <fcntl.h>
}

#include <iostream>

#include "leveldb/db.h"
#include "leveldb/comparator.h"

// see http_parser.h
// char DELETE = 0;
// char GET = 1;
// char HEAD = 2;
// char POST = 3;
// char PUT = 4;

static inline void send_file(const char *path, int fd_out) {
    int fd_in;
    struct stat stat_buf;

    fd_in = open(path, O_RDONLY);
    fstat(fd_in, &stat_buf);
    sendfile(fd_out, fd_in, 0, stat_buf.st_size);
    close(fd_in);
}

static inline void http_ok(int fd, const char *content_type) {
#define write_const(fd, text) \
    write(fd, text, strlen(text));
 
    write_const(fd, "HTTP/1.1 200 OK\r\nContent-Type: ");
    write_const(fd, content_type);
    write_const(fd, "\r\n\r\n");
#undef write_const
}

static inline void http_fail(int fd) {
    write(fd, "HTTP/1.1 501 FAIL\r\n\r\n",25);
}

void handle_request(struct http_request *request, int fd) {
#define write_const(fd, text) \
    write(fd, text, strlen(text));
    
    if (request->url == NULL) { // happens only under high load
        std::cerr << "url is null" << std::endl;
        http_fail(fd);
        close(fd);
        return;
    }

    std::string url(request->url);

    if (url == "/") {
        http_ok(fd, "text/html; charset=UTF-8");
        send_file("index.html", fd);        
    } else if (url.find("/api/put") == 0) {
        http_ok(fd, "text/html; charset=UTF-8");
        std::cout << "put" << std::endl;
    } else if (url.find("/debug") == 0) {
        http_ok(fd, "text/html; charset=UTF-8");
        struct http_header *header = request->headers;
        write_const(fd, "<pre>Headers:\n");
        while (header != NULL) {
            write_const(fd, header->name);
            write_const(fd, ": ");
            write_const(fd, header->value);
            write_const(fd, "\n");
            header = header->next;
        }
        if (request->flags & F_HREQ_KEEPALIVE) {
             write_const(fd, "\nis keepalive.\n");
        }
        write_const(fd, "\r\n\r\n");
    } else {
        http_fail(fd);
    }
    close(fd);
#undef write_const
}

static struct http_server server;

void sigint_handler(int s) {
    struct ev_loop *loop = server.loop;
    ev_io_stop(EV_A_ server.ev_accept);
    exit(0);
}

int main(int argc, char **argv) {
    // configure server structures and desired listen address
    struct sockaddr_in listen_addr;
    memset(&listen_addr, 0, sizeof(listen_addr));
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_addr.s_addr = INADDR_ANY;
    listen_addr.sin_port = htons(5000);
    server.listen_addr = &listen_addr;
    server.handle_request = handle_request;

    // ignore SIGPIPE
    struct sigaction on_sigpipe;
    on_sigpipe.sa_handler = SIG_IGN;
    sigemptyset(&on_sigpipe.sa_mask);
    sigaction(SIGPIPE, &on_sigpipe, NULL);

    // handle C-c
    struct sigaction on_sigint;
    on_sigint.sa_handler = sigint_handler;
    sigemptyset(&on_sigint.sa_mask);
    on_sigint.sa_flags = 0;
    sigaction(SIGINT, &on_sigint, NULL);

    // start the server
    return http_server_loop(&server);
}