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 "http/types.h"
#include "trie.h" #include "trie.h"
#define HTTP_LOOP_MAX_STEPS 17
#define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(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; http_method method;
char *path; char *path;
regex_t *regex; regex_t *regex;
bool (*steps[5])(event_loop_conn *); bool (*steps[HTTP_LOOP_MAX_STEPS])(event_loop_conn *);
} http_route; } 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(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. * Add an entry by generating a random string as the key.
* *

View File

@ -11,9 +11,9 @@ http_route lander_routes[] = {
.method = http_get, .method = http_get,
.path = "^/\\([^/]\\+\\)$", .path = "^/\\([^/]\\+\\)$",
.steps = {lander_get_entry, NULL}}, .steps = {lander_get_entry, NULL}},
{.type = http_route_literal, {.type = http_route_regex,
.method = http_post, .method = http_post,
.path = "/s/", .path = "^/s\\(l\\?\\)/\\([^/]*\\)$",
.steps = {http_loop_step_auth, http_loop_step_body_to_buf, .steps = {http_loop_step_auth, http_loop_step_body_to_buf,
lander_post_redirect, NULL}}, lander_post_redirect, NULL}},
{.type = http_route_literal, {.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); sprintf(fname, "pastes/%.*s", key_len, key);
http_res_set_body_file(&ctx->res, fname); 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; conn->state = event_loop_conn_state_res;

View File

@ -5,14 +5,24 @@
bool lander_post_redirect(event_loop_conn *conn) { bool lander_post_redirect(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx; 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 // Allocate a new buffer to pass to the trie
char *url = malloc(ctx->req.body_len + 1); char *url = malloc(ctx->req.body_len + 1);
memcpy(url, ctx->req.body.buf, ctx->req.body_len); memcpy(url, ctx->req.body.buf, ctx->req.body_len);
url[ctx->req.body_len] = '\0'; url[ctx->req.body_len] = '\0';
char *key;
Entry *new_entry = entry_new(Redirect, url); 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) { if (res != Ok) {
error("trie_add_random failed with exit code %i", res); error("trie_add_random failed with exit code %i", res);
@ -23,15 +33,42 @@ bool lander_post_redirect(event_loop_conn *conn) {
return true; 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 // 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); char *buf = malloc(key_len + 2);
memcpy(&buf[1], key, key_len); memcpy(&buf[1], key, key_len);
buf[0] = '/'; buf[0] = '/';
buf[key_len + 1] = '\0'; buf[key_len + 1] = '\0';
if (random) {
free(key); free(key);
}
http_res_add_header(&ctx->res, http_header_location, buf, true); 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]; char buffer[8192];
EntryType type; EntryType type;
Entry *entry; Entry *entry;
char *string;
int i, j; int i, j;
TrieExitCode status; TrieExitCode status;
@ -109,7 +108,6 @@ SearchResult trie_search_node_len(Trie *trie, const char *key, size_t key_len) {
SearchResult out = {NULL, NULL}; SearchResult out = {NULL, NULL};
size_t i = 0; size_t i = 0;
size_t offset;
TrieNode **node_ptr = &(trie->root); TrieNode **node_ptr = &(trie->root);
TrieNode **child_ptr; 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 * @return true if the string wasn't present in the trie and thus added, false
* otherwise * 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; size_t i = 0;
uint8_t offset; uint8_t offset;
TrieNode **node_ptr = &(trie->root); TrieNode **node_ptr = &(trie->root);
@ -191,7 +190,7 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
do { do {
offset = 0; offset = 0;
child_node_ptr = tnode_search(*node_ptr, string[i], true); child_node_ptr = tnode_search(*node_ptr, key[i], true);
i++; i++;
@ -200,11 +199,11 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
if (*child_node_ptr == NULL) { if (*child_node_ptr == NULL) {
child_node = tnode_init(); 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++; offset++;
} }
memcpy(child_node->string, string + i, offset); memcpy(child_node->string, key + i, offset);
child_node->string_len = offset; child_node->string_len = offset;
*child_node_ptr = child_node; *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 // allowed skip length, we continue through the loop. The next iteration
// will enter this if statement again, and perform the same loop, until // will enter this if statement again, and perform the same loop, until
// the string is fully added to the trie. // the string is fully added to the trie.
if (string[i + offset] != DELIMITER) { if (i + offset < key_len) {
node_ptr = child_node_ptr; node_ptr = child_node_ptr;
i += offset; 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) { while (offset < (*child_node_ptr)->string_len) {
// String no longer aligns with edge, so we have to split // 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(); TrieNode *split_node = tnode_init();
child_node = *child_node_ptr; 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; node_ptr = child_node_ptr;
i += offset; i += offset;
} while (string[i] != DELIMITER); } while (i < key_len);
if ((*child_node_ptr)->represents) { if ((*child_node_ptr)->represents) {
return AlreadyPresent; return AlreadyPresent;
@ -284,12 +283,17 @@ TrieExitCode trie_add_no_lock(Trie *trie, const char *string, Entry *entry) {
return Ok; 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) { if (trie->file_path != NULL) {
// Easiest way to make sure we don't add duplicate entries // 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 // We use an internal function that doesn't require a read lock, as we're
// already inside a write lock // 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; 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 // This function *should* always return Ok. Otherwise, the function would've
// exited because the string was found in the trie. // 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, TrieExitCode trie_add_random(Trie *trie, char **key_ptr, Entry *entry,