feat: add long & custom redirect urls

c-web-server
Jef Roosens 2023-05-30 19:36:58 +02:00
parent f07042e798
commit 58e2d8a02e
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
6 changed files with 76 additions and 24 deletions

View File

@ -9,6 +9,8 @@
#include "http/types.h"
#include "trie.h"
#define HTTP_LOOP_MAX_STEPS 17
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
@ -22,7 +24,7 @@ typedef struct http_route {
http_method method;
char *path;
regex_t *regex;
bool (*steps[5])(event_loop_conn *);
bool (*steps[HTTP_LOOP_MAX_STEPS])(event_loop_conn *);
} http_route;
/*

View File

@ -88,6 +88,9 @@ TrieExitCode trie_search_len(Trie *trie, Entry **entry_ptr, const char *key,
*/
TrieExitCode trie_add(Trie *trie, const char *key, Entry *entry);
TrieExitCode trie_add_len(Trie *trie, const char *key, size_t key_len,
Entry *entry);
/**
* Add an entry by generating a random string as the key.
*

View File

@ -11,9 +11,9 @@ http_route lander_routes[] = {
.method = http_get,
.path = "^/\\([^/]\\+\\)$",
.steps = {lander_get_entry, NULL}},
{.type = http_route_literal,
{.type = http_route_regex,
.method = http_post,
.path = "/s/",
.path = "^/s\\(l\\?\\)/\\([^/]*\\)$",
.steps = {http_loop_step_auth, http_loop_step_body_to_buf,
lander_post_redirect, NULL}},
{.type = http_route_literal,

View File

@ -41,6 +41,8 @@ bool lander_get_entry(event_loop_conn *conn) {
sprintf(fname, "pastes/%.*s", 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;

View File

@ -5,14 +5,24 @@
bool lander_post_redirect(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
// 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;
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';
char *key;
Entry *new_entry = entry_new(Redirect, url);
TrieExitCode res = trie_add_random(ctx->g->trie, &key, new_entry, false);
char *key;
int key_len;
if (random) {
TrieExitCode res = trie_add_random(ctx->g->trie, &key, new_entry, secure);
if (res != Ok) {
error("trie_add_random failed with exit code %i", res);
@ -23,15 +33,42 @@ bool lander_post_redirect(event_loop_conn *conn) {
return true;
}
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;
TrieExitCode res = trie_add_len(ctx->g->trie, key, key_len, new_entry);
switch (res) {
case Ok:
break;
case AlreadyPresent:
ctx->res.status = http_conflict;
break;
default:
ctx->res.status = http_internal_server_error;
}
if (res != Ok) {
error("trie_add_len failed with exit code %i", res);
conn->state = event_loop_conn_state_res;
return true;
}
}
// Add a slash to the key and add it as the location header
size_t key_len = strlen(key);
char *buf = malloc(key_len + 2);
memcpy(&buf[1], key, key_len);
buf[0] = '/';
buf[key_len + 1] = '\0';
if (random) {
free(key);
}
http_res_add_header(&ctx->res, http_header_location, buf, true);

View File

@ -47,7 +47,6 @@ TrieExitCode trie_init(Trie **trie_ptr, const char *file_path) {
char buffer[8192];
EntryType type;
Entry *entry;
char *string;
int i, j;
TrieExitCode status;
@ -109,7 +108,6 @@ SearchResult trie_search_node_len(Trie *trie, const char *key, size_t key_len) {
SearchResult out = {NULL, NULL};
size_t i = 0;
size_t offset;
TrieNode **node_ptr = &(trie->root);
TrieNode **child_ptr;
@ -182,7 +180,8 @@ TrieExitCode trie_search(Trie *trie, Entry **entry_ptr, const char *key) {
* @return true if the string wasn't present in the trie and thus added, false
* otherwise
*/
TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
TrieExitCode trie_add_len_no_lock(Trie *trie, const char *key, size_t key_len,
Entry *entry) {
size_t i = 0;
uint8_t offset;
TrieNode **node_ptr = &(trie->root);
@ -191,7 +190,7 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
do {
offset = 0;
child_node_ptr = tnode_search(*node_ptr, string[i], true);
child_node_ptr = tnode_search(*node_ptr, key[i], true);
i++;
@ -200,11 +199,11 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
if (*child_node_ptr == NULL) {
child_node = tnode_init();
while (offset < TRIE_MAX_SKIP_SIZE && string[i + offset] != DELIMITER) {
while (offset < TRIE_MAX_SKIP_SIZE && i + offset < key_len) {
offset++;
}
memcpy(child_node->string, string + i, offset);
memcpy(child_node->string, key + i, offset);
child_node->string_len = offset;
*child_node_ptr = child_node;
@ -213,7 +212,7 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
// allowed skip length, we continue through the loop. The next iteration
// will enter this if statement again, and perform the same loop, until
// the string is fully added to the trie.
if (string[i + offset] != DELIMITER) {
if (i + offset < key_len) {
node_ptr = child_node_ptr;
i += offset;
@ -229,7 +228,7 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
while (offset < (*child_node_ptr)->string_len) {
// String no longer aligns with edge, so we have to split
if (string[i + offset] != (*child_node_ptr)->string[offset]) {
if (key[i + offset] != (*child_node_ptr)->string[offset]) {
TrieNode *split_node = tnode_init();
child_node = *child_node_ptr;
@ -272,7 +271,7 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
node_ptr = child_node_ptr;
i += offset;
} while (string[i] != DELIMITER);
} while (i < key_len);
if ((*child_node_ptr)->represents) {
return AlreadyPresent;
@ -284,12 +283,17 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
return Ok;
}
TrieExitCode trie_add(Trie *trie, const char *key, Entry *entry) {
TrieExitCode trie_add_no_lock(Trie *trie, const char *key, Entry *entry) {
return trie_add_len_no_lock(trie, key, strlen(key), entry);
}
TrieExitCode trie_add_len(Trie *trie, const char *key, size_t key_len,
Entry *entry) {
if (trie->file_path != NULL) {
// Easiest way to make sure we don't add duplicate entries
// We use an internal function that doesn't require a read lock, as we're
// already inside a write lock
if (trie_search_node(trie, key).child != NULL) {
if (trie_search_node_len(trie, key, key_len).child != NULL) {
return AlreadyPresent;
}
@ -311,7 +315,11 @@ TrieExitCode trie_add(Trie *trie, const char *key, Entry *entry) {
// This function *should* always return Ok. Otherwise, the function would've
// exited because the string was found in the trie.
return trie_add_no_lock(trie, key, entry);
return trie_add_len_no_lock(trie, key, key_len, entry);
}
TrieExitCode trie_add(Trie *trie, const char *key, Entry *entry) {
return trie_add_len(trie, key, strlen(key), entry);
}
TrieExitCode trie_add_random(Trie *trie, char **key_ptr, Entry *entry,