refactor(lander): clean up code a bit
parent
c026e13c44
commit
64af94ce7a
|
@ -7,7 +7,6 @@
|
||||||
#include "http/req.h"
|
#include "http/req.h"
|
||||||
#include "http/res.h"
|
#include "http/res.h"
|
||||||
#include "http/types.h"
|
#include "http/types.h"
|
||||||
#include "trie.h"
|
|
||||||
|
|
||||||
// Max amount of steps a route can use
|
// Max amount of steps a route can use
|
||||||
#define HTTP_LOOP_MAX_STEPS 17
|
#define HTTP_LOOP_MAX_STEPS 17
|
||||||
|
|
|
@ -5,17 +5,15 @@
|
||||||
#include "lsm/store.h"
|
#include "lsm/store.h"
|
||||||
|
|
||||||
extern http_route lander_routes[6];
|
extern http_route lander_routes[6];
|
||||||
|
extern const char lander_key_charset[];
|
||||||
|
|
||||||
typedef struct lander_gctx {
|
typedef struct lander_gctx {
|
||||||
const char *data_dir;
|
const char *data_dir;
|
||||||
Trie *trie;
|
|
||||||
lsm_store *store;
|
lsm_store *store;
|
||||||
|
|
||||||
} lander_gctx;
|
} lander_gctx;
|
||||||
|
|
||||||
typedef struct lander_ctx {
|
typedef struct lander_ctx {
|
||||||
lsm_entry_handle *entry;
|
lsm_entry_handle *entry;
|
||||||
uint64_t remaining_data;
|
|
||||||
} lander_ctx;
|
} lander_ctx;
|
||||||
|
|
||||||
typedef enum lander_attr_type : uint8_t {
|
typedef enum lander_attr_type : uint8_t {
|
||||||
|
@ -24,6 +22,14 @@ typedef enum lander_attr_type : uint8_t {
|
||||||
lander_attr_type_url = 2,
|
lander_attr_type_url = 2,
|
||||||
} lander_attr_type;
|
} lander_attr_type;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *header;
|
||||||
|
lander_attr_type attr_type;
|
||||||
|
http_header header_type;
|
||||||
|
} header_to_attr;
|
||||||
|
|
||||||
|
extern header_to_attr header_to_attrs[];
|
||||||
|
|
||||||
typedef enum lander_entry_type : uint8_t {
|
typedef enum lander_entry_type : uint8_t {
|
||||||
lander_entry_type_redirect = 0,
|
lander_entry_type_redirect = 0,
|
||||||
lander_entry_type_paste = 1,
|
lander_entry_type_paste = 1,
|
||||||
|
@ -46,21 +52,19 @@ bool lander_post_redirect(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_post_paste(event_loop_conn *conn);
|
bool lander_post_paste(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_post_paste_lsm(event_loop_conn *conn);
|
bool lander_post_paste(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_post_redirect_lsm(event_loop_conn *conn);
|
bool lander_post_redirect(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_stream_body_to_entry(event_loop_conn *conn);
|
bool lander_stream_body_to_entry(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_stream_body_to_client(event_loop_conn *conn);
|
bool lander_stream_body_to_client(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_get_entry_lsm(event_loop_conn *conn);
|
|
||||||
|
|
||||||
bool lander_post_redirect_body_to_attr(event_loop_conn *conn);
|
bool lander_post_redirect_body_to_attr(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_remove_entry(event_loop_conn *conn);
|
bool lander_remove_entry(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_post_file_lsm(event_loop_conn *conn);
|
bool lander_post_file(event_loop_conn *conn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse any custom headers and add them as attributes to the context's LSM
|
* Parse any custom headers and add them as attributes to the context's LSM
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "http_loop.h"
|
#include "http_loop.h"
|
||||||
#include "lander.h"
|
#include "lander.h"
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include "lander.h"
|
#include "lander.h"
|
||||||
#include "lsm/store.h"
|
#include "lsm/store.h"
|
||||||
|
|
||||||
|
const char lander_key_charset[] =
|
||||||
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
|
||||||
http_route lander_routes[] = {
|
http_route lander_routes[] = {
|
||||||
{.type = http_route_literal,
|
{.type = http_route_literal,
|
||||||
.method = http_get,
|
.method = http_get,
|
||||||
|
@ -16,7 +19,7 @@ http_route lander_routes[] = {
|
||||||
.type = http_route_regex,
|
.type = http_route_regex,
|
||||||
.method = http_get,
|
.method = http_get,
|
||||||
.path = "^/([^/]+)$",
|
.path = "^/([^/]+)$",
|
||||||
.steps = {lander_get_entry_lsm, lander_attrs_to_headers, NULL},
|
.steps = {lander_get_entry, lander_attrs_to_headers, NULL},
|
||||||
.steps_res = {http_loop_step_write_header, lander_stream_body_to_client,
|
.steps_res = {http_loop_step_write_header, lander_stream_body_to_client,
|
||||||
NULL},
|
NULL},
|
||||||
},
|
},
|
||||||
|
@ -32,7 +35,7 @@ http_route lander_routes[] = {
|
||||||
.type = http_route_regex,
|
.type = http_route_regex,
|
||||||
.method = http_post,
|
.method = http_post,
|
||||||
.path = "^/s(l?)/([^/]*)$",
|
.path = "^/s(l?)/([^/]*)$",
|
||||||
.steps = {http_loop_step_auth, lander_post_redirect_lsm,
|
.steps = {http_loop_step_auth, lander_post_redirect,
|
||||||
http_loop_step_body_to_buf, lander_post_redirect_body_to_attr,
|
http_loop_step_body_to_buf, lander_post_redirect_body_to_attr,
|
||||||
NULL},
|
NULL},
|
||||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||||
|
@ -42,27 +45,23 @@ http_route lander_routes[] = {
|
||||||
.method = http_post,
|
.method = http_post,
|
||||||
.path = "^/p(l?)/([^/]*)$",
|
.path = "^/p(l?)/([^/]*)$",
|
||||||
.steps = {http_loop_step_auth, http_loop_step_parse_content_length,
|
.steps = {http_loop_step_auth, http_loop_step_parse_content_length,
|
||||||
lander_post_paste_lsm, lander_stream_body_to_entry, NULL},
|
lander_post_paste, lander_stream_body_to_entry, NULL},
|
||||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||||
NULL}},
|
NULL}},
|
||||||
{.type = http_route_regex,
|
{.type = http_route_regex,
|
||||||
.method = http_post,
|
.method = http_post,
|
||||||
.path = "^/f(l?)/([^/]*)$",
|
.path = "^/f(l?)/([^/]*)$",
|
||||||
.steps = {http_loop_step_auth, http_loop_step_parse_content_length,
|
.steps = {http_loop_step_auth, http_loop_step_parse_content_length,
|
||||||
lander_post_file_lsm, lander_headers_to_attrs,
|
lander_post_file, lander_headers_to_attrs,
|
||||||
lander_stream_body_to_entry, NULL},
|
lander_stream_body_to_entry, NULL},
|
||||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||||
NULL}},
|
NULL}},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
header_to_attr header_to_attrs[] = {
|
||||||
char *header;
|
|
||||||
lander_attr_type attr_type;
|
|
||||||
http_header header_type;
|
|
||||||
} header_to_attr_type[] = {
|
|
||||||
{"X-Lander-Content-Type", lander_attr_type_content_type,
|
{"X-Lander-Content-Type", lander_attr_type_content_type,
|
||||||
http_header_content_type},
|
http_header_content_type},
|
||||||
{NULL, 0},
|
{NULL, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
void *lander_gctx_init() { return calloc(1, sizeof(lander_gctx)); }
|
void *lander_gctx_init() { return calloc(1, sizeof(lander_gctx)); }
|
||||||
|
@ -75,60 +74,6 @@ void lander_ctx_reset(lander_ctx *ctx) {
|
||||||
|
|
||||||
ctx->entry = NULL;
|
ctx->entry = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->remaining_data = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lander_ctx_free(lander_ctx *ctx) { free(ctx); }
|
void lander_ctx_free(lander_ctx *ctx) { free(ctx); }
|
||||||
|
|
||||||
bool lander_headers_to_attrs(event_loop_conn *conn) {
|
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
|
||||||
lander_ctx *c_ctx = ctx->c;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ctx->req.num_headers; i++) {
|
|
||||||
struct phr_header *header = &ctx->req.headers[i];
|
|
||||||
|
|
||||||
int j = 0;
|
|
||||||
|
|
||||||
while (header_to_attr_type[j].header != NULL) {
|
|
||||||
if (strncmp(header->name, header_to_attr_type[j].header,
|
|
||||||
header->name_len) == 0) {
|
|
||||||
lsm_str *value;
|
|
||||||
lsm_str_init_copy_n(&value, (char *)header->value, header->value_len);
|
|
||||||
|
|
||||||
lsm_entry_attr_insert(c_ctx->entry, header_to_attr_type[j].attr_type,
|
|
||||||
value);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lander_attrs_to_headers(event_loop_conn *conn) {
|
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
|
||||||
lander_ctx *c_ctx = ctx->c;
|
|
||||||
|
|
||||||
int j = 0;
|
|
||||||
lsm_str *value;
|
|
||||||
|
|
||||||
while (header_to_attr_type[j].header != NULL) {
|
|
||||||
if (lsm_entry_attr_get(&value, c_ctx->entry,
|
|
||||||
header_to_attr_type[j].attr_type) == lsm_error_ok) {
|
|
||||||
char *buf = malloc(lsm_str_len(value) + 1);
|
|
||||||
memcpy(buf, lsm_str_ptr(value), lsm_str_len(value));
|
|
||||||
buf[lsm_str_len(value)] = '\0';
|
|
||||||
|
|
||||||
http_res_add_header(&ctx->res, header_to_attr_type[j].header_type, buf,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ void lander_get_file(event_loop_conn *conn) {
|
||||||
ctx->res.body.expected_len = lsm_entry_data_len(c_ctx->entry);
|
ctx->res.body.expected_len = lsm_entry_data_len(c_ctx->entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lander_get_entry_lsm(event_loop_conn *conn) {
|
bool lander_get_entry(event_loop_conn *conn) {
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
lander_ctx *c_ctx = ctx->c;
|
lander_ctx *c_ctx = ctx->c;
|
||||||
http_loop_gctx *gctx = ctx->g;
|
http_loop_gctx *gctx = ctx->g;
|
||||||
|
|
|
@ -5,71 +5,15 @@
|
||||||
#include "lsm/store.h"
|
#include "lsm/store.h"
|
||||||
|
|
||||||
static void randomize_key(char *key, int len) {
|
static void randomize_key(char *key, int len) {
|
||||||
|
size_t charset_len = strlen(lander_key_charset);
|
||||||
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
key[i] = charset[rand() % charset_len];
|
key[i] = lander_key_charset[rand() % charset_len];
|
||||||
}
|
}
|
||||||
|
|
||||||
key[len] = '\0';
|
key[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO entry leaks if key is already present
|
|
||||||
static bool add_entry(char **key_ptr, int *key_len_ptr, http_loop_ctx *ctx,
|
|
||||||
Entry *entry, bool random) {
|
|
||||||
lander_gctx *c_gctx = ctx->g->c;
|
|
||||||
|
|
||||||
// The first match group matches the "long" path
|
|
||||||
bool secure =
|
|
||||||
(ctx->req.regex_groups[1].rm_eo - ctx->req.regex_groups[1].rm_so) == 1;
|
|
||||||
|
|
||||||
char *key;
|
|
||||||
int key_len = 0;
|
|
||||||
TrieExitCode res;
|
|
||||||
|
|
||||||
if (random) {
|
|
||||||
res = trie_add_random(c_gctx->trie, &key, entry, secure);
|
|
||||||
|
|
||||||
if (res == Ok) {
|
|
||||||
key_len = strlen(key);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
key = (char *)&ctx->req.path[ctx->req.regex_groups[2].rm_so];
|
|
||||||
key_len = ctx->req.regex_groups[2].rm_eo - ctx->req.regex_groups[2].rm_so;
|
|
||||||
|
|
||||||
res = trie_add_len(c_gctx->trie, key, key_len, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (res) {
|
|
||||||
case Ok:
|
|
||||||
break;
|
|
||||||
case AlreadyPresent:
|
|
||||||
ctx->res.status = http_conflict;
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
ctx->res.status = http_internal_server_error;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a slash to the key and add it as the location header
|
|
||||||
char *buf = malloc(key_len + 2);
|
|
||||||
|
|
||||||
memcpy(&buf[1], key, key_len);
|
|
||||||
buf[0] = '/';
|
|
||||||
buf[key_len + 1] = '\0';
|
|
||||||
|
|
||||||
http_res_add_header(&ctx->res, http_header_location, buf, true);
|
|
||||||
ctx->res.status = http_created;
|
|
||||||
|
|
||||||
if (key_ptr != NULL) {
|
|
||||||
*key_ptr = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key_len_ptr != NULL) {
|
|
||||||
*key_len_ptr = key_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a new entry into the store.
|
* Insert a new entry into the store.
|
||||||
*
|
*
|
||||||
|
@ -123,7 +67,7 @@ bool lander_insert_entry(http_loop_ctx *ctx) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lander_post_redirect_lsm(event_loop_conn *conn) {
|
bool lander_post_redirect(event_loop_conn *conn) {
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
lander_ctx *c_ctx = ctx->c;
|
lander_ctx *c_ctx = ctx->c;
|
||||||
|
|
||||||
|
@ -149,7 +93,7 @@ bool lander_post_redirect_body_to_attr(event_loop_conn *conn) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lander_post_paste_lsm(event_loop_conn *conn) {
|
bool lander_post_paste(event_loop_conn *conn) {
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
lander_ctx *c_ctx = ctx->c;
|
lander_ctx *c_ctx = ctx->c;
|
||||||
|
|
||||||
|
@ -164,7 +108,7 @@ bool lander_post_paste_lsm(event_loop_conn *conn) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lander_post_file_lsm(event_loop_conn *conn) {
|
bool lander_post_file(event_loop_conn *conn) {
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
lander_ctx *c_ctx = ctx->c;
|
lander_ctx *c_ctx = ctx->c;
|
||||||
|
|
||||||
|
@ -178,81 +122,3 @@ bool lander_post_file_lsm(event_loop_conn *conn) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lander_stream_body_to_entry(event_loop_conn *conn) {
|
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
|
||||||
lander_ctx *c_ctx = ctx->c;
|
|
||||||
|
|
||||||
uint64_t to_append =
|
|
||||||
MIN(conn->rbuf_size - conn->rbuf_read,
|
|
||||||
ctx->req.body.expected_len - lsm_entry_data_len(c_ctx->entry));
|
|
||||||
|
|
||||||
lsm_str *data;
|
|
||||||
lsm_str_init_copy_n(&data, (char *)&conn->rbuf[conn->rbuf_read], to_append);
|
|
||||||
lsm_entry_data_append(c_ctx->entry, data);
|
|
||||||
|
|
||||||
conn->rbuf_read += to_append;
|
|
||||||
|
|
||||||
lsm_str_free(data);
|
|
||||||
|
|
||||||
return lsm_entry_data_len(c_ctx->entry) == ctx->req.body.expected_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lander_post_redirect(event_loop_conn *conn) {
|
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
|
||||||
bool random =
|
|
||||||
ctx->req.regex_groups[2].rm_eo == ctx->req.regex_groups[2].rm_so;
|
|
||||||
|
|
||||||
// Allocate a new buffer to pass to the trie
|
|
||||||
char *url = malloc(ctx->req.body.len + 1);
|
|
||||||
memcpy(url, ctx->req.body.buf, ctx->req.body.len);
|
|
||||||
url[ctx->req.body.len] = '\0';
|
|
||||||
|
|
||||||
Entry *new_entry = entry_new(Redirect, url);
|
|
||||||
|
|
||||||
// The entry duplicates the string
|
|
||||||
free(url);
|
|
||||||
|
|
||||||
// We don't check the result here, because we would perform the same action
|
|
||||||
// either way
|
|
||||||
char *key;
|
|
||||||
add_entry(&key, NULL, ctx, new_entry, random);
|
|
||||||
|
|
||||||
if (random) {
|
|
||||||
free(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->state = event_loop_conn_state_res;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lander_post_paste(event_loop_conn *conn) {
|
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
|
||||||
lander_gctx *c_gctx = ctx->g->c;
|
|
||||||
|
|
||||||
bool random =
|
|
||||||
ctx->req.regex_groups[2].rm_eo == ctx->req.regex_groups[2].rm_so;
|
|
||||||
|
|
||||||
char *key;
|
|
||||||
int key_len;
|
|
||||||
Entry *new_entry = entry_new(Paste, "");
|
|
||||||
|
|
||||||
if (!add_entry(&key, &key_len, ctx, new_entry, random)) {
|
|
||||||
conn->state = event_loop_conn_state_res;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *fname = malloc(strlen(c_gctx->data_dir) + 8 + key_len + 1);
|
|
||||||
sprintf(fname, "%s/pastes/%.*s", c_gctx->data_dir, key_len, key);
|
|
||||||
|
|
||||||
ctx->req.body.fname = fname;
|
|
||||||
ctx->req.body.fname_owned = true;
|
|
||||||
|
|
||||||
if (random) {
|
|
||||||
free(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lander.h"
|
||||||
|
|
||||||
|
bool lander_stream_body_to_entry(event_loop_conn *conn) {
|
||||||
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
|
lander_ctx *c_ctx = ctx->c;
|
||||||
|
|
||||||
|
uint64_t to_append =
|
||||||
|
MIN(conn->rbuf_size - conn->rbuf_read,
|
||||||
|
ctx->req.body.expected_len - lsm_entry_data_len(c_ctx->entry));
|
||||||
|
|
||||||
|
lsm_str *data;
|
||||||
|
lsm_str_init_copy_n(&data, (char *)&conn->rbuf[conn->rbuf_read], to_append);
|
||||||
|
lsm_entry_data_append(c_ctx->entry, data);
|
||||||
|
|
||||||
|
conn->rbuf_read += to_append;
|
||||||
|
|
||||||
|
lsm_str_free(data);
|
||||||
|
|
||||||
|
return lsm_entry_data_len(c_ctx->entry) == ctx->req.body.expected_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lander_headers_to_attrs(event_loop_conn *conn) {
|
||||||
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
|
lander_ctx *c_ctx = ctx->c;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ctx->req.num_headers; i++) {
|
||||||
|
struct phr_header *header = &ctx->req.headers[i];
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
while (header_to_attrs[j].header != NULL) {
|
||||||
|
if (strncmp(header->name, header_to_attrs[j].header, header->name_len) ==
|
||||||
|
0) {
|
||||||
|
lsm_str *value;
|
||||||
|
lsm_str_init_copy_n(&value, (char *)header->value, header->value_len);
|
||||||
|
|
||||||
|
lsm_entry_attr_insert(c_ctx->entry, header_to_attrs[j].attr_type,
|
||||||
|
value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lander_attrs_to_headers(event_loop_conn *conn) {
|
||||||
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
|
lander_ctx *c_ctx = ctx->c;
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
lsm_str *value;
|
||||||
|
|
||||||
|
while (header_to_attrs[j].header != NULL) {
|
||||||
|
if (lsm_entry_attr_get(&value, c_ctx->entry,
|
||||||
|
header_to_attrs[j].attr_type) == lsm_error_ok) {
|
||||||
|
char *buf = malloc(lsm_str_len(value) + 1);
|
||||||
|
memcpy(buf, lsm_str_ptr(value), lsm_str_len(value));
|
||||||
|
buf[lsm_str_len(value)] = '\0';
|
||||||
|
|
||||||
|
http_res_add_header(&ctx->res, header_to_attrs[j].header_type, buf, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
16
src/main.c
16
src/main.c
|
@ -34,20 +34,6 @@ int main() {
|
||||||
critical(1, "Invalid TCP port %s", port_str);
|
critical(1, "Invalid TCP port %s", port_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* char file_path[strlen(data_dir) + 12 + 1]; */
|
|
||||||
/* sprintf(file_path, "%s/lander.data", data_dir); */
|
|
||||||
|
|
||||||
/* info("Initializing trie from file '%s'", file_path); */
|
|
||||||
|
|
||||||
/* Trie *trie; */
|
|
||||||
/* TrieExitCode res = trie_init(&trie, file_path); */
|
|
||||||
|
|
||||||
/* if (res != Ok) { */
|
|
||||||
/* critical(1, "An error occured while populating the trie."); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* info("Trie initialized and populated with %i entries", trie_size(trie)); */
|
|
||||||
|
|
||||||
lander_gctx *c_gctx = lander_gctx_init();
|
lander_gctx *c_gctx = lander_gctx_init();
|
||||||
c_gctx->data_dir = data_dir_s;
|
c_gctx->data_dir = data_dir_s;
|
||||||
|
|
||||||
|
@ -60,7 +46,7 @@ int main() {
|
||||||
critical(2, "Failed to load existing store.");
|
critical(2, "Failed to load existing store.");
|
||||||
}
|
}
|
||||||
|
|
||||||
info("Store loaded containing %lu entries.", lsm_store_size(c_gctx->store));
|
info("Store loaded containing %lu entries", lsm_store_size(c_gctx->store));
|
||||||
|
|
||||||
http_loop *hl = http_loop_init(
|
http_loop *hl = http_loop_init(
|
||||||
lander_routes, sizeof(lander_routes) / sizeof(lander_routes[0]), c_gctx,
|
lander_routes, sizeof(lander_routes) / sizeof(lander_routes[0]), c_gctx,
|
||||||
|
|
228
src/main.cpp
228
src/main.cpp
|
@ -1,228 +0,0 @@
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include "crow.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "trie.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string file_path = "lander.data";
|
|
||||||
static const std::string index_page = R"(
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
<h1>r8r.be</h1>
|
|
||||||
<p>This is the URL shortener and pastebin accompanying my site, <a href="https://rustybever.be">The Rusty Bever</a>.</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)";
|
|
||||||
|
|
||||||
#define ENV(var, env_var) \
|
|
||||||
const char *_##var = getenv(env_var); \
|
|
||||||
if (_##var == NULL) { \
|
|
||||||
printf("Missing environment variable %s.\n", env_var); \
|
|
||||||
return 1; \
|
|
||||||
} \
|
|
||||||
const std::string var = std::string(_##var);
|
|
||||||
|
|
||||||
#define AUTH() \
|
|
||||||
std::string provided_api_key = req.get_header_value("X-Api-Key"); \
|
|
||||||
if (api_key.compare(provided_api_key) != 0) { \
|
|
||||||
return crow::response(crow::status::UNAUTHORIZED); \
|
|
||||||
}
|
|
||||||
|
|
||||||
crow::response add_redirect(std::string base_url, Trie *trie, const char *url,
|
|
||||||
bool secure) {
|
|
||||||
Entry *new_entry = entry_new(Redirect, url);
|
|
||||||
|
|
||||||
// The key already gets copied into the trie, so this pointer is safe to use
|
|
||||||
// ever after unlocking the trie
|
|
||||||
trie_wlock(trie);
|
|
||||||
char *key;
|
|
||||||
TrieExitCode res = trie_add_random(trie, &key, new_entry, secure);
|
|
||||||
trie_unlock(trie);
|
|
||||||
|
|
||||||
if (res != Ok) {
|
|
||||||
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string out = base_url + key;
|
|
||||||
free(key);
|
|
||||||
|
|
||||||
return crow::response(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool store_paste(const char *key, const char *body) {
|
|
||||||
// Write paste contents to file
|
|
||||||
std::fstream file;
|
|
||||||
file.open(std::string("pastes/") + key, std::ios_base::out);
|
|
||||||
|
|
||||||
if (!file.is_open()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
file << body;
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
crow::response add_paste(std::string base_url, Trie *trie, const char *body,
|
|
||||||
bool secure) {
|
|
||||||
Entry *new_entry = entry_new(Paste, "");
|
|
||||||
|
|
||||||
trie_wlock(trie);
|
|
||||||
char *key;
|
|
||||||
TrieExitCode res = trie_add_random(trie, &key, new_entry, secure);
|
|
||||||
trie_unlock(trie);
|
|
||||||
|
|
||||||
if (res != Ok) {
|
|
||||||
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!store_paste(key, body)) {
|
|
||||||
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string out = base_url + key;
|
|
||||||
free(key);
|
|
||||||
|
|
||||||
return crow::response(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
// Initialize random seed for generating URLs
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
ENV(api_key, "LANDER_API_KEY");
|
|
||||||
ENV(base_url, "LANDER_BASE_URL");
|
|
||||||
|
|
||||||
std::cout << "Initializing trie from file '" << file_path << "'..."
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
// Initialize trie and populate from data file
|
|
||||||
Trie *trie;
|
|
||||||
int res = trie_init(&trie, file_path.c_str());
|
|
||||||
|
|
||||||
if (res != 0) {
|
|
||||||
std::cout << "An error occured while initializing the trie." << std::endl;
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Added " << trie_size(trie) << " entries to trie." << std::endl;
|
|
||||||
|
|
||||||
// Create pastes directory if not present
|
|
||||||
// TODO don't just ignore errors here
|
|
||||||
mkdir("pastes", 0700);
|
|
||||||
|
|
||||||
crow::SimpleApp app;
|
|
||||||
app.loglevel(crow::LogLevel::Info);
|
|
||||||
|
|
||||||
CROW_ROUTE(app, "/").methods(crow::HTTPMethod::Get)(
|
|
||||||
[]() { return crow::response("html", index_page); });
|
|
||||||
|
|
||||||
// Serve an entry
|
|
||||||
CROW_ROUTE(app, "/<string>")
|
|
||||||
.methods(crow::HTTPMethod::Get)(
|
|
||||||
[trie](crow::response &res, std::string key) {
|
|
||||||
trie_rlock(trie);
|
|
||||||
Entry *entry;
|
|
||||||
TrieExitCode status = trie_search(trie, &entry, key.c_str());
|
|
||||||
|
|
||||||
if (status == Ok) {
|
|
||||||
if (entry->type == Redirect) {
|
|
||||||
res.redirect(entry->string);
|
|
||||||
} else if (entry->type == Paste) {
|
|
||||||
res.set_static_file_info("pastes/" + key);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.code = 404;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.end();
|
|
||||||
trie_unlock(trie);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a new Redirect with a short randomly generated key
|
|
||||||
CROW_ROUTE(app, "/s/")
|
|
||||||
.methods(crow::HTTPMethod::Post)(
|
|
||||||
[api_key, base_url, trie](const crow::request req) {
|
|
||||||
AUTH();
|
|
||||||
|
|
||||||
return add_redirect(base_url, trie, req.body.c_str(), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a new Redirect with a long randomly generated key
|
|
||||||
CROW_ROUTE(app, "/sl/")
|
|
||||||
.methods(crow::HTTPMethod::Post)(
|
|
||||||
[api_key, base_url, trie](const crow::request req) {
|
|
||||||
AUTH();
|
|
||||||
|
|
||||||
return add_redirect(base_url, trie, req.body.c_str(), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a new Redirect with a given key
|
|
||||||
CROW_ROUTE(app, "/s/<string>")
|
|
||||||
.methods(crow::HTTPMethod::Post)(
|
|
||||||
[api_key, base_url, trie](const crow::request &req, std::string key) {
|
|
||||||
AUTH();
|
|
||||||
|
|
||||||
Entry *new_entry = entry_new(Redirect, req.body.c_str());
|
|
||||||
|
|
||||||
trie_wlock(trie);
|
|
||||||
TrieExitCode status = trie_add(trie, key.c_str(), new_entry);
|
|
||||||
trie_unlock(trie);
|
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case Ok:
|
|
||||||
return crow::response(base_url + key);
|
|
||||||
case AlreadyPresent:
|
|
||||||
return crow::response(crow::status::CONFLICT);
|
|
||||||
default:
|
|
||||||
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a new Paste with a short randomly generated key
|
|
||||||
CROW_ROUTE(app, "/p/")
|
|
||||||
.methods(crow::HTTPMethod::Post)(
|
|
||||||
[api_key, base_url, trie](const crow::request &req) {
|
|
||||||
AUTH();
|
|
||||||
|
|
||||||
return add_paste(base_url, trie, req.body.c_str(), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a new Paste with a long randomly generated key
|
|
||||||
CROW_ROUTE(app, "/pl/")
|
|
||||||
.methods(crow::HTTPMethod::Post)(
|
|
||||||
[api_key, base_url, trie](const crow::request &req) {
|
|
||||||
AUTH();
|
|
||||||
|
|
||||||
return add_paste(base_url, trie, req.body.c_str(), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a paste with a given key
|
|
||||||
CROW_ROUTE(app, "/p/<string>")
|
|
||||||
.methods(crow::HTTPMethod::Post)(
|
|
||||||
[api_key, base_url, trie](const crow::request &req, std::string key) {
|
|
||||||
AUTH();
|
|
||||||
|
|
||||||
Entry *new_entry = entry_new(Paste, "");
|
|
||||||
trie_wlock(trie);
|
|
||||||
TrieExitCode status = trie_add(trie, key.c_str(), new_entry);
|
|
||||||
trie_unlock(trie);
|
|
||||||
|
|
||||||
if (status != Ok) {
|
|
||||||
return crow::response(crow::status::CONFLICT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!store_paste(key.c_str(), req.body.c_str())) {
|
|
||||||
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return crow::response(base_url + key);
|
|
||||||
});
|
|
||||||
app.port(18080).multithreaded().run();
|
|
||||||
}
|
|
Loading…
Reference in New Issue