diff --git a/landerctl b/landerctl index f721091..acd9e48 100755 --- a/landerctl +++ b/landerctl @@ -11,5 +11,5 @@ if [ "$1" = add ]; then "$URL/$3" elif [ "$1" = get ]; then - curl -is "$URL/$2" | sed -En 's/^location: (.*)/\1/p' + curl -is "$URL/$2" | sed -En 's/^[lL]ocation: (.*)/\1/p' fi diff --git a/src/main.cpp b/src/main.cpp index bcc9636..85f8596 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,10 +49,11 @@ int main() { CROW_ROUTE(app, "/") .methods(crow::HTTPMethod::Get)( [trie](crow::response &res, std::string s) { - char *payload = ternarytrie_search(trie, s.c_str()); + Entry *entry = ternarytrie_search(trie, s.c_str()); - if (payload != NULL) { - res.redirect(payload); + // TODO check entry type + if (entry != NULL) { + res.redirect(entry->string); } else { res.code = 404; } @@ -63,7 +64,8 @@ int main() { [api_key, base_url, trie](const crow::request req) { AUTH(); - char *key = ternarytrie_add_random(trie, req.body.c_str()); + Entry *new_entry = entry_new(Redirect, req.body.c_str()); + char *key = ternarytrie_add_random(trie, new_entry); if (key == NULL) { return crow::response(crow::status::INTERNAL_SERVER_ERROR); @@ -76,11 +78,12 @@ int main() { }); CROW_ROUTE(app, "/") .methods(crow::HTTPMethod::Post)( - [api_key, base_url, trie](const crow::request &req, std::string s) { + [api_key, base_url, trie](const crow::request &req, std::string key) { AUTH(); - std::string key = req.body; - bool added = ternarytrie_add(trie, s.c_str(), req.body.c_str()); + Entry *new_entry = entry_new(Redirect, req.body.c_str()); + + bool added = ternarytrie_add(trie, key.c_str(), new_entry); if (!added) { return crow::response(crow::status::CONFLICT); diff --git a/tries/include/ternarytrie.h b/tries/include/ternarytrie.h index 85b6353..42773a0 100644 --- a/tries/include/ternarytrie.h +++ b/tries/include/ternarytrie.h @@ -23,6 +23,19 @@ static const size_t charset_len = sizeof(charset) - 1; */ typedef struct ttrie TernaryTrie; +typedef enum entry_type { + Redirect, + Paste, + Unknown +} EntryType; + +typedef struct entry { + EntryType type; + char *string; +} Entry; + +Entry *entry_new(EntryType type, const char *string); + /** * Allocate and initialize an empty Trie. * @@ -47,50 +60,47 @@ int ternarytrie_populate(TernaryTrie* trie, const char* file_path); void ternarytrie_free(TernaryTrie* trie); /** - * Search whether a string is contained in this trie. + * Search for an entry in the trie. * * @param trie - * @param key - * @return pointer to payload string; NULL if not found + * @param key key representing the entry + * @return pointer to entry; NULL if not found */ -char * ternarytrie_search(TernaryTrie* trie, const char* key); +Entry *ternarytrie_search(TernaryTrie* trie, const char* key); /** * Add a string to this trie. * * @param trie - * @param key - * @param payload payload to add + * @param key key to represent entry with + * @param entry entry to add * @return true if the trie was changed by this operation, false if it was already present */ -bool ternarytrie_add(TernaryTrie* trie, const char* key, const char *payload); +bool ternarytrie_add(TernaryTrie* trie, const char* key, Entry *entry); /** - * Add a payload by generating a random string as the key. + * Add an entry by generating a random string as the key. * * @param trie - * @param payload payload to add + * @param entry entry to add * @return the generated key */ -char *ternarytrie_add_random(TernaryTrie *trie, const char *payload); +char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry); /** - * Remove a string from this trie. - * - * Note: strings added to this trie are considered to be "owned" by the caller. - * Removing the string from the trie should not free the string's memory. + * Remove an entry from this trie given its key. * * @param trie - * @param key - * @return true if the string was present and has been removed, false if it was not present + * @param key key representing entry + * @return true if the entry was present and has been removed, false if it was not present */ -bool ternarytrie_remove(TernaryTrie* trie, const char* key); +bool ternarytrie_remove(TernaryTrie* trie, const char *key); /** - * Returns the number of strings in this trie. + * Returns the number of entries in this trie. * * @param trie - * @return the number of strings in this trie + * @return the number of entries in this trie */ size_t ternarytrie_size(TernaryTrie* trie); diff --git a/tries/src/ternarytrie.c b/tries/src/ternarytrie.c index df98316..93378d1 100644 --- a/tries/src/ternarytrie.c +++ b/tries/src/ternarytrie.c @@ -37,7 +37,32 @@ void ternarytrie_free(TernaryTrie *trie) { free(trie); } -bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, const char *payload); +bool ternarytrie_add_internal(TernaryTrie *trie, const char *key, Entry *entry); + +EntryType entry_type_from_char(char c) { + switch(c) { + case '0': return Redirect; + case '1': return Paste; + default: return Unknown; + } +} + +char entry_type_to_char(EntryType et) { + switch (et) { + case Redirect: return '0'; + case Paste: return '1'; + default: return '\0'; + } + +} + +Entry *entry_new(EntryType type, const char *string) { + Entry *entry = malloc(sizeof(Entry)); + entry->type = type; + entry->string = my_strdup(string); + + return entry; +} int ternarytrie_populate(TernaryTrie *trie, const char *file_path) { trie->file_path = my_strdup(file_path); @@ -51,13 +76,16 @@ int ternarytrie_populate(TernaryTrie *trie, const char *file_path) { // We read in lines of at most 8192 characters (sounds like enough) char buffer[8192]; + EntryType type; + Entry *entry; + char *string; int i, j; int entries = 0; while (fgets(buffer, 8192, fp)) { - // Find index of space character i = 0; + // Move index in buffer until we encounter first space character while (buffer[i] != ' ') { i++; } @@ -65,7 +93,10 @@ int ternarytrie_populate(TernaryTrie *trie, const char *file_path) { // Split the buffer into two strings, the key and the payload buffer[i] = '\0'; - j = i + 1; + type = entry_type_from_char(buffer[i + 1]); + + // Skip type character & its surrounding spaces + j = i + 3; // Now remove the newline character while (buffer[j] != '\n') { @@ -74,7 +105,9 @@ int ternarytrie_populate(TernaryTrie *trie, const char *file_path) { buffer[j] = '\0'; - ternarytrie_add_internal(trie, buffer, buffer + i + 1); + entry = entry_new(type, buffer + i + 3); + ternarytrie_add_internal(trie, buffer, entry); + entries++; } @@ -88,11 +121,11 @@ typedef struct searchresult { TernaryTrieNode *child; } SearchResult; -SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *string) { +SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *key) { SearchResult out = {NULL, NULL}; // Edge case for empty string - if (string[0] == DELIMITER) { + if (key[0] == DELIMITER) { if (trie->root->type == 1) { out.child = trie->root; } @@ -105,7 +138,7 @@ SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *string) { TernaryTrieNode **child_ptr; do { - child_ptr = ttnode_search(*node_ptr, string[i], false); + child_ptr = ttnode_search(*node_ptr, key[i], false); // We don't have to check whether *node_ptr is NULL, because if it was // NULL, it wouldn't be in the binary tree. @@ -115,7 +148,7 @@ SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *string) { i++; - if (string[i] == DELIMITER || (*child_ptr)->type == 2) { + if (key[i] == DELIMITER || (*child_ptr)->type == 2) { break; } @@ -123,8 +156,8 @@ SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *string) { } while (1); if ((*child_ptr)->type == 2) { - if (string[i] != DELIMITER && - strcmp(string + i, (*child_ptr)->ptr.string) == 0) { + if (key[i] != DELIMITER && + strcmp(key + i, (*child_ptr)->ptr.string) == 0) { out.child = *child_ptr; out.parent = *node_ptr; } @@ -146,15 +179,15 @@ SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *string) { * @param string string to look up * @return true if the string is present in the trie, false otherwise */ -char * ternarytrie_search(TernaryTrie *trie, const char *string) { +Entry *ternarytrie_search(TernaryTrie *trie, const char *key) { pthread_rwlock_rdlock(&trie->lock); - SearchResult res = ternarytrie_search_node(trie, string); + SearchResult res = ternarytrie_search_node(trie, key); - char* return_value = NULL; + Entry *return_value = NULL; if (res.child != NULL) { - return_value = res.child->payload; + return_value = res.child->entry; } pthread_rwlock_unlock(&trie->lock); @@ -170,12 +203,12 @@ char * ternarytrie_search(TernaryTrie *trie, const char *string) { * @return true if the string wasn't present in the trie and thus added, false * otherwise */ -bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, const char *payload) { +bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, Entry *entry) { // Edge case for empty string if (string[0] == DELIMITER) { if (trie->root->type == 0) { trie->root->type = 1; - trie->root->payload = my_strdup(payload); + trie->root->entry = entry; trie->size++; return true; @@ -222,7 +255,7 @@ bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, const char new_node->type = 1; } - new_node->payload = my_strdup(payload); + new_node->entry = entry; *node_ptr = new_node; @@ -246,21 +279,21 @@ bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, const char } (*node_ptr)->type = 1; - (*node_ptr)->payload = my_strdup(payload); + (*node_ptr)->entry = entry; trie->size++; return true; } -bool ternarytrie_add_persistent(TernaryTrie *trie, const char *string, const char *payload) { +bool ternarytrie_add_persistent(TernaryTrie *trie, const char *key, Entry *entry) { bool return_value = false; 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 (ternarytrie_search_node(trie, string).child != NULL) { + if (ternarytrie_search_node(trie, key).child != NULL) { return false; } @@ -270,9 +303,11 @@ bool ternarytrie_add_persistent(TernaryTrie *trie, const char *string, const cha return false; } - fputs(string, fp); + fputs(key, fp); fputs(" ", fp); - fputs(payload, fp); + fputc(entry_type_to_char(entry->type), fp); + fputs(" ", fp); + fputs(entry->string, fp); fputs("\n", fp); fclose(fp); @@ -280,20 +315,20 @@ bool ternarytrie_add_persistent(TernaryTrie *trie, const char *string, const cha // This function *should* always return true. Otherwise, the function would've // exited because the string was found in the trie. - return ternarytrie_add_internal(trie, string, payload); + return ternarytrie_add_internal(trie, key, entry); } -bool ternarytrie_add(TernaryTrie *trie, const char *string, const char *payload) { +bool ternarytrie_add(TernaryTrie *trie, const char *key, Entry *entry) { pthread_rwlock_wrlock(&trie->lock); - bool return_value = ternarytrie_add_persistent(trie, string, payload); + bool return_value = ternarytrie_add_persistent(trie, key, entry); pthread_rwlock_unlock(&trie->lock); return return_value; } -char* ternarytrie_add_random(TernaryTrie *trie, const char *payload) { +char* ternarytrie_add_random(TernaryTrie *trie, Entry *entry) { pthread_rwlock_wrlock(&trie->lock); // Generate random key @@ -312,7 +347,7 @@ char* ternarytrie_add_random(TernaryTrie *trie, const char *payload) { ok = ternarytrie_search_node(trie, key).child == NULL; } - bool res = ternarytrie_add_persistent(trie, key, payload); + bool res = ternarytrie_add_persistent(trie, key, entry); char *return_value; if (res) { diff --git a/tries/src/ternarytrie_node.c b/tries/src/ternarytrie_node.c index b6d355f..187ed5d 100644 --- a/tries/src/ternarytrie_node.c +++ b/tries/src/ternarytrie_node.c @@ -1,8 +1,10 @@ -#include "common.c" #include #include #include +#include "ternarytrie.h" +#include "common.c" + /** * Represents a node of the binary tree contained within each non-leaf * TernaryTrieNode. @@ -30,7 +32,7 @@ typedef struct ttnode { TernaryTrieInnerNode *root; char *string; } ptr; - char *payload; + Entry *entry; // What type of node this is // 0: regular non-representing node // 1: regular representing node @@ -101,9 +103,10 @@ void ttnode_free(TernaryTrieNode *node) { ttinode_free_cascade(node->ptr.root); } - if (node->payload != NULL) { - free(node->payload); - } + // TODO properly free entry + /* if (node->payload != NULL) { */ + /* free(node->payload); */ + /* } */ free(node); } @@ -218,11 +221,11 @@ void ttnode_split(TernaryTrieNode *node) { new_node->type = 1; } - new_node->payload = node->payload; + new_node->entry = node->entry; node->type = 0; node->size = 0; - node->payload = NULL; + node->entry = NULL; free(node->ptr.string); node->ptr.string = NULL;