diff --git a/.gitignore b/.gitignore index 35f41da..6f9958c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ lander.data* pastes/ .cache/ vgcore.* +data/ diff --git a/include/lander.h b/include/lander.h index 0579a65..0ffca46 100644 --- a/include/lander.h +++ b/include/lander.h @@ -49,4 +49,8 @@ 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_entry_sync(event_loop_conn *conn); + #endif diff --git a/lsm/include/lsm/store.h b/lsm/include/lsm/store.h index 72334c6..16798f2 100644 --- a/lsm/include/lsm/store.h +++ b/lsm/include/lsm/store.h @@ -17,7 +17,8 @@ */ typedef enum lsm_attr_type : uint64_t { lsm_attr_type_entry_type = 1 << 0, - lsm_attr_type_content_type = 1 << 1 + lsm_attr_type_content_type = 1 << 1, + lsm_attr_type_url = 1 << 2, } lsm_attr_type; /** diff --git a/lsm/src/store/lsm_store_disk_write.c b/lsm/src/store/lsm_store_disk_write.c index 9813f40..07034a1 100644 --- a/lsm/src/store/lsm_store_disk_write.c +++ b/lsm/src/store/lsm_store_disk_write.c @@ -100,6 +100,9 @@ lsm_error lsm_entry_sync(lsm_store *store, lsm_entry_handle *handle) { res = lsm_entry_write_uint64_t(store->idx_file, new_block_count); if (res == lsm_error_ok) { + // Only if we successfully updated the on-disk counter do we make the code + // aware that the file's size has increased. This way, if a write to the + // counter fails, the code will simply reuse the already written content. store->idx_file_size += entry_size; store->idx_file_block_count = new_block_count; } diff --git a/src/lander/lander.c b/src/lander/lander.c index c4c4ca7..8045f28 100644 --- a/src/lander/lander.c +++ b/src/lander/lander.c @@ -23,8 +23,9 @@ http_route lander_routes[] = { .type = http_route_regex, .method = http_post, .path = "^/s(l?)/([^/]*)$", - .steps = {http_loop_step_auth, http_loop_step_parse_content_length, - lander_post_redirect_lsm, lander_stream_body_to_entry, NULL}, + .steps = {http_loop_step_auth, lander_post_redirect_lsm, + http_loop_step_body_to_buf, lander_post_redirect_body_to_attr, + lander_entry_sync, NULL}, .steps_res = {http_loop_step_write_header, http_loop_step_write_body, NULL}, }, @@ -32,7 +33,8 @@ 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_lsm, lander_stream_body_to_entry, + lander_entry_sync, NULL}, .steps_res = {http_loop_step_write_header, http_loop_step_write_body, NULL}}, }; diff --git a/src/lander/lander_get.c b/src/lander/lander_get.c index d2fee1e..026f449 100644 --- a/src/lander/lander_get.c +++ b/src/lander/lander_get.c @@ -3,6 +3,7 @@ #include "event_loop.h" #include "http/types.h" #include "lander.h" +#include "log.h" #include "lsm/store.h" static const char index_page[] = @@ -82,19 +83,25 @@ bool lander_get_entry_lsm(event_loop_conn *conn) { lsm_attr_type_entry_type); if (t == lander_entry_type_redirect) { - // Stream entire redirect data into buffer to set as header - uint64_t data_len = lsm_entry_data_len(c_ctx->entry); - char *buf = malloc(data_len + 1); - uint64_t read = 0; - uint64_t total_read = 0; + // For redirects, the URL is stored as an in-memory attribute + lsm_str *url_attr_val; - while (total_read < data_len) { - lsm_entry_data_read(&read, &buf[total_read], c_ctx->entry, - data_len - total_read); - total_read += read; + // This shouldn't be able to happen + if (lsm_entry_attr_get(&url_attr_val, c_ctx->entry, lsm_attr_type_url) != + lsm_error_ok) { + error("Entry of type redirect detected without URL attribute"); + + ctx->res.status = http_internal_server_error; + lsm_entry_close(c_ctx->entry); + c_ctx->entry = NULL; + + return true; } - buf[data_len] = '\0'; + char *buf = malloc(lsm_str_len(url_attr_val) + 1); + memcpy(buf, lsm_str_ptr(url_attr_val), lsm_str_len(url_attr_val)); + + buf[lsm_str_len(url_attr_val)] = '\0'; ctx->res.status = http_moved_permanently; http_res_add_header(&ctx->res, http_header_location, buf, true); diff --git a/src/lander/lander_post.c b/src/lander/lander_post.c index da9d1c4..b03cd53 100644 --- a/src/lander/lander_post.c +++ b/src/lander/lander_post.c @@ -138,6 +138,30 @@ bool lander_post_redirect_lsm(event_loop_conn *conn) { return true; } +bool lander_post_redirect_body_to_attr(event_loop_conn *conn) { + http_loop_ctx *ctx = conn->ctx; + lander_ctx *c_ctx = ctx->c; + + lsm_str *attr_value; + lsm_str_init_copy_n(&attr_value, ctx->req.body.buf, ctx->req.body.len); + lsm_entry_attr_insert(c_ctx->entry, lsm_attr_type_url, attr_value); + + return true; +} + +bool lander_entry_sync(event_loop_conn *conn) { + http_loop_ctx *ctx = conn->ctx; + http_loop_gctx *gctx = ctx->g; + lander_gctx *c_gctx = gctx->c; + lander_ctx *c_ctx = ctx->c; + + if (lsm_entry_sync(c_gctx->store, c_ctx->entry) != lsm_error_ok) { + ctx->res.status = http_internal_server_error; + } + + return true; +} + bool lander_post_paste_lsm(event_loop_conn *conn) { http_loop_ctx *ctx = conn->ctx; lander_ctx *c_ctx = ctx->c; diff --git a/src/main.c b/src/main.c index f552081..f854f3e 100644 --- a/src/main.c +++ b/src/main.c @@ -23,7 +23,7 @@ int main() { ENV(api_key, "LANDER_API_KEY"); ENV_OPT(port_str, "LANDER_PORT", "18080"); - ENV_OPT(data_dir, "LANDER_DATA_DIR", "."); + ENV_OPT(data_dir_s, "LANDER_DATA_DIR", "."); int port = atoi(port_str); @@ -46,12 +46,14 @@ int main() { /* info("Trie initialized and populated with %i entries", trie_size(trie)); */ lander_gctx *c_gctx = lander_gctx_init(); - c_gctx->data_dir = data_dir; + c_gctx->data_dir = data_dir_s; /* c_gctx->trie = trie; */ - lsm_str *data_dir2; - lsm_str_init_copy(&data_dir2, "data"); - lsm_store_load(&c_gctx->store, data_dir2); + lsm_str *data_dir; + lsm_str_init_copy(&data_dir, (char *)data_dir_s); + if (lsm_store_load(&c_gctx->store, data_dir) != lsm_error_ok) { + critical(2, "Failed to load existing store."); + } http_loop *hl = http_loop_init( lander_routes, sizeof(lander_routes) / sizeof(lander_routes[0]), c_gctx,