refactor(lander): clean up code a bit
parent
c026e13c44
commit
64af94ce7a
|
@ -7,7 +7,6 @@
|
|||
#include "http/req.h"
|
||||
#include "http/res.h"
|
||||
#include "http/types.h"
|
||||
#include "trie.h"
|
||||
|
||||
// Max amount of steps a route can use
|
||||
#define HTTP_LOOP_MAX_STEPS 17
|
||||
|
|
|
@ -5,17 +5,15 @@
|
|||
#include "lsm/store.h"
|
||||
|
||||
extern http_route lander_routes[6];
|
||||
extern const char lander_key_charset[];
|
||||
|
||||
typedef struct lander_gctx {
|
||||
const char *data_dir;
|
||||
Trie *trie;
|
||||
lsm_store *store;
|
||||
|
||||
} lander_gctx;
|
||||
|
||||
typedef struct lander_ctx {
|
||||
lsm_entry_handle *entry;
|
||||
uint64_t remaining_data;
|
||||
} lander_ctx;
|
||||
|
||||
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;
|
||||
|
||||
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 {
|
||||
lander_entry_type_redirect = 0,
|
||||
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_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_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_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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "http_loop.h"
|
||||
#include "lander.h"
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#include "lander.h"
|
||||
#include "lsm/store.h"
|
||||
|
||||
const char lander_key_charset[] =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
http_route lander_routes[] = {
|
||||
{.type = http_route_literal,
|
||||
.method = http_get,
|
||||
|
@ -16,7 +19,7 @@ http_route lander_routes[] = {
|
|||
.type = http_route_regex,
|
||||
.method = http_get,
|
||||
.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,
|
||||
NULL},
|
||||
},
|
||||
|
@ -32,7 +35,7 @@ http_route lander_routes[] = {
|
|||
.type = http_route_regex,
|
||||
.method = http_post,
|
||||
.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,
|
||||
NULL},
|
||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||
|
@ -42,27 +45,23 @@ http_route lander_routes[] = {
|
|||
.method = http_post,
|
||||
.path = "^/p(l?)/([^/]*)$",
|
||||
.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,
|
||||
NULL}},
|
||||
{.type = http_route_regex,
|
||||
.method = http_post,
|
||||
.path = "^/f(l?)/([^/]*)$",
|
||||
.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},
|
||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||
NULL}},
|
||||
};
|
||||
|
||||
struct {
|
||||
char *header;
|
||||
lander_attr_type attr_type;
|
||||
http_header header_type;
|
||||
} header_to_attr_type[] = {
|
||||
header_to_attr header_to_attrs[] = {
|
||||
{"X-Lander-Content-Type", lander_attr_type_content_type,
|
||||
http_header_content_type},
|
||||
{NULL, 0},
|
||||
{NULL, 0, 0},
|
||||
};
|
||||
|
||||
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->remaining_data = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool lander_get_entry_lsm(event_loop_conn *conn) {
|
||||
bool lander_get_entry(event_loop_conn *conn) {
|
||||
http_loop_ctx *ctx = conn->ctx;
|
||||
lander_ctx *c_ctx = ctx->c;
|
||||
http_loop_gctx *gctx = ctx->g;
|
||||
|
|
|
@ -5,71 +5,15 @@
|
|||
#include "lsm/store.h"
|
||||
|
||||
static void randomize_key(char *key, int len) {
|
||||
size_t charset_len = strlen(lander_key_charset);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
key[i] = charset[rand() % charset_len];
|
||||
key[i] = lander_key_charset[rand() % charset_len];
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -123,7 +67,7 @@ bool lander_insert_entry(http_loop_ctx *ctx) {
|
|||
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;
|
||||
lander_ctx *c_ctx = ctx->c;
|
||||
|
||||
|
@ -149,7 +93,7 @@ bool lander_post_redirect_body_to_attr(event_loop_conn *conn) {
|
|||
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;
|
||||
lander_ctx *c_ctx = ctx->c;
|
||||
|
||||
|
@ -164,7 +108,7 @@ bool lander_post_paste_lsm(event_loop_conn *conn) {
|
|||
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;
|
||||
lander_ctx *c_ctx = ctx->c;
|
||||
|
||||
|
@ -178,81 +122,3 @@ bool lander_post_file_lsm(event_loop_conn *conn) {
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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();
|
||||
c_gctx->data_dir = data_dir_s;
|
||||
|
||||
|
@ -60,7 +46,7 @@ int main() {
|
|||
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(
|
||||
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