142 lines
4.1 KiB
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;
|
|
}
|