diff --git a/include/http_loop.h b/include/http_loop.h index e1049ac..9a588c5 100644 --- a/include/http_loop.h +++ b/include/http_loop.h @@ -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; /* diff --git a/include/trie.h b/include/trie.h index 912e438..9662ed4 100644 --- a/include/trie.h +++ b/include/trie.h @@ -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. * diff --git a/src/lander/lander.c b/src/lander/lander.c index 7a66082..2fa379b 100644 --- a/src/lander/lander.c +++ b/src/lander/lander.c @@ -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, diff --git a/src/lander/lander_get.c b/src/lander/lander_get.c index 39a5004..40d6db7 100644 --- a/src/lander/lander_get.c +++ b/src/lander/lander_get.c @@ -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; diff --git a/src/lander/lander_post.c b/src/lander/lander_post.c index ea271ee..cd66152 100644 --- a/src/lander/lander_post.c +++ b/src/lander/lander_post.c @@ -5,33 +5,70 @@ 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); - if (res != Ok) { - error("trie_add_random failed with exit code %i", res); + char *key; + int key_len; - ctx->res.status = http_internal_server_error; - conn->state = event_loop_conn_state_res; + if (random) { + TrieExitCode res = trie_add_random(ctx->g->trie, &key, new_entry, secure); - return true; + if (res != Ok) { + error("trie_add_random failed with exit code %i", res); + + ctx->res.status = http_internal_server_error; + conn->state = event_loop_conn_state_res; + + 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'; - free(key); + if (random) { + free(key); + } http_res_add_header(&ctx->res, http_header_location, buf, true); diff --git a/src/trie/trie.c b/src/trie/trie.c index 926e37c..b1262a7 100644 --- a/src/trie/trie.c +++ b/src/trie/trie.c @@ -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,