lander/src/lander/lander_get.c

142 lines
4.1 KiB
C

#include <stdio.h>
#include "event_loop.h"
#include "http/types.h"
#include "lander.h"
#include "log.h"
#include "lsm/store.h"
static const char index_page[] =
"<!DOCTYPE html>\n"
"<html>\n"
" <body>\n"
" <h1>r8r.be</h1>\n"
" <p>This is the URL shortener and pastebin accompanying my site, <a "
"href=\"https://rustybever.be\">The Rusty Bever</a>.</p>\n"
" </body>\n"
"</html>\n";
bool lander_get_index(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
http_res_set_body_buf(&ctx->res, index_page, sizeof(index_page) - 1, false);
http_res_set_mime_type(&ctx->res, http_mime_html);
conn->state = event_loop_conn_state_res;
return true;
}
bool lander_get_entry(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
lander_gctx *c_gctx = ctx->g->c;
const char *key = &ctx->req.path[ctx->req.regex_groups[1].rm_so];
int key_len = ctx->req.regex_groups[1].rm_eo - ctx->req.regex_groups[1].rm_so;
Entry *entry;
TrieExitCode res = trie_search_len(c_gctx->trie, &entry, key, key_len);
if (res == NotFound) {
ctx->res.status = http_not_found;
} else if (entry->type == Redirect) {
ctx->res.status = http_moved_permanently;
http_res_add_header(&ctx->res, http_header_location, entry->string, false);
} else if (entry->type == Paste) {
char fname[strlen(c_gctx->data_dir) + 8 + key_len + 1];
sprintf(fname, "%s/pastes/%.*s", c_gctx->data_dir, key_len, key);
http_res_set_body_file(&ctx->res, fname);
// TODO don't call everything a text file
http_res_set_mime_type(&ctx->res, http_mime_txt);
}
conn->state = event_loop_conn_state_res;
return true;
}
bool lander_get_entry_lsm(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
lander_ctx *c_ctx = ctx->c;
http_loop_gctx *gctx = ctx->g;
lander_gctx *c_gctx = gctx->c;
const char *key_s = &ctx->req.path[ctx->req.regex_groups[1].rm_so];
int key_len = ctx->req.regex_groups[1].rm_eo - ctx->req.regex_groups[1].rm_so;
lsm_str *key;
lsm_str_init_copy_n(&key, (char *)key_s, key_len);
switch (lsm_store_open_read(&c_ctx->entry, c_gctx->store, key)) {
case lsm_error_ok:
break;
case lsm_error_not_found:
ctx->res.status = http_not_found;
return true;
default:
ctx->res.status = http_internal_server_error;
return true;
}
lander_entry_type t;
lsm_entry_attr_get_num((uint64_t *)&t, c_ctx->entry,
lsm_attr_type_entry_type);
if (t == lander_entry_type_redirect) {
// For redirects, the URL is stored as an in-memory attribute
lsm_str *url_attr_val;
// 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;
}
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);
// We no longer need the entry at this point, so we can unlock it early
// This will also signal to the response code not to read any data from
// the entry
lsm_entry_close(c_ctx->entry);
c_ctx->entry = NULL;
} else {
ctx->res.body.expected_len = lsm_entry_data_len(c_ctx->entry);
}
return true;
}
bool lander_stream_body_to_client(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
lander_ctx *c_ctx = ctx->c;
if ((c_ctx->entry == NULL) ||
(ctx->res.body.expected_len == ctx->res.body.len)) {
return true;
}
uint64_t to_write = MIN(EVENT_LOOP_BUFFER_SIZE - conn->wbuf_size,
ctx->res.body.expected_len - ctx->res.body.len);
uint64_t read = 0;
lsm_entry_data_read(&read, (char *)&conn->wbuf[conn->wbuf_size], c_ctx->entry,
to_write);
ctx->res.body.len += read;
conn->wbuf_size += read;
return false;
}