diff --git a/.gitignore b/.gitignore index ab57ace..e274d0f 100644 --- a/.gitignore +++ b/.gitignore @@ -88,5 +88,7 @@ dkms.conf # Misc *.txt +*.avif CMakeFiles/ build/ +convert.sh \ No newline at end of file diff --git a/a.png b/a.png new file mode 100644 index 0000000..d32649d Binary files /dev/null and b/a.png differ diff --git a/include/DataType.h b/include/DataType.h index 822fd5e..03391bc 100644 --- a/include/DataType.h +++ b/include/DataType.h @@ -7,4 +7,9 @@ enum data_type { IMAGE }; +enum image_type { + PNG, + AVIF +}; + #endif \ No newline at end of file diff --git a/include/FileUtils.h b/include/FileUtils.h index 415a225..f1e24fa 100644 --- a/include/FileUtils.h +++ b/include/FileUtils.h @@ -8,6 +8,8 @@ using namespace std; struct FileUtils { static bool fileExists(const char *path); + static vector open_image(const string& path); + static vector get_image_list(const string& path); }; #endif \ No newline at end of file diff --git a/include/ServerUtils.h b/include/ServerUtils.h index 33721d8..d97ba4d 100644 --- a/include/ServerUtils.h +++ b/include/ServerUtils.h @@ -2,16 +2,7 @@ #define SERVERUTILS_H #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include "../include/DataType.h" using namespace std; @@ -22,9 +13,11 @@ class ServerUtils { private: static void process_request(int client_fd); static void send_header(int client_fd, data_type type); - static void send_chunked_html(int client_fd, unsigned int hash); + static void send_chunked_html(int client_fd, size_t hash); static void send_chunked_css(int client_fd); - static void send_data(int client_fd, string data); + static void send_data(int client_fd, const string& data); + static void send_image(int client_fd, const string& path, image_type type); + static size_t send_all(int sockfd, const char* data, size_t length); }; const string HTML_RESPONSE_HEADER = @@ -41,18 +34,12 @@ const string CSS_RESPONSE_HEADER = "Cache-control: max-age=12000\r\n" "Connection: close\r\n\r\n"; -const string PNG_RESPONSE_HEADER = - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/png; charset=utf-8\r\n" - "Transfer-Encoding: chunked\r\n" - "Cache-control: max-age=12000\r\n" - "Connection: close\r\n\r\n"; - const string HTML_BEGINNING = "\n\r\n" "Drip\r\n" + "\r\n" "\r\n" - "\r\n"; const string HTML_END = "\r\n"; diff --git a/include/WordUtils.h b/include/WordUtils.h index 4c5a92f..0062b76 100644 --- a/include/WordUtils.h +++ b/include/WordUtils.h @@ -4,21 +4,25 @@ #include #include #include -#include -#include #include "../include/DataType.h" using namespace std; struct WordUtils { - static map> load_data(const string& path); + static unordered_map> load_data(const string& path); static vector load_css(const string& path); - static vector predict_next_word(const string& input, const map>& word_frequencies, size_t count); + static vector predict_next_word(const string& input, const unordered_map>& word_frequencies, size_t count); static string load_file(const string& path); static vector split_string(const string& input, data_type type); static string extract_url(const string& input); - static string create_tag(const map>& word_frequencies, const char& hash); + static bool contains_image(const string& input); + static string extract_image_name(const string& input); + static string create_tag(const unordered_map>& word_frequencies, const char& hash); + static string create_link(const unordered_map>& word_frequencies, unsigned long hash); + static string create_image(const string& image); static unsigned int hash_url(const string& input); + static unsigned long djb2Hash(const string& str); + static unsigned long fnv1aHash(const string& str); }; #endif \ No newline at end of file diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index e66ddd7..b2a4afe 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -1,6 +1,40 @@ #include "../include/FileUtils.h" #include +#include +#include +#include bool FileUtils::fileExists(const char *path){ return filesystem::exists(path); +} + +vector FileUtils::open_image(const string& path) { + std::ifstream file(path, std::ios::binary); + if (!file) { + std::cerr << "Error opening file: " << path << std::endl; + return {}; // Return an empty vector on error + } + + std::vector data; + char c; + + while (file.get(c)) { + data.push_back(static_cast(c)); + } + + file.close(); + return data; +} + +vector FileUtils::get_image_list(const string& path) { + vector images; + const std::string ext(".avif"); + for (auto &p : filesystem::recursive_directory_iterator(path)) + { + if (p.path().extension() == ext) { + images.push_back(p.path().stem().string()); + } + } + + return images; } \ No newline at end of file diff --git a/src/ServerUtils.cpp b/src/ServerUtils.cpp index b743fa9..ed866c8 100644 --- a/src/ServerUtils.cpp +++ b/src/ServerUtils.cpp @@ -1,33 +1,37 @@ #include "../include/ServerUtils.h" #include "../include/WordUtils.h" #include "../include/DataType.h" +#include "../include/FileUtils.h" #include #include #include #include -#include #include #include #include #include +#include +#include -vector _css; -map> _word_frequencies; +vector css; +vector images; +unordered_map> word_frequencies; void ServerUtils::serve() { - _word_frequencies = WordUtils::load_data("/home/skingging/Documents/Projects/CPP/AI-Tarpit-Reimagined/wordlist/wordlist-Food.txt"); - _css = WordUtils::load_css("/home/skingging/Documents/Projects/CPP/AI-Tarpit-Reimagined/content/style.css"); + word_frequencies = WordUtils::load_data("/home/skingging/Documents/Projects/CPP/AI-Tarpit-Reimagined/wordlist/wordlist-Food.txt"); + css = WordUtils::load_css("/home/skingging/Documents/Projects/CPP/AI-Tarpit-Reimagined/content/style.css"); + images = FileUtils::get_image_list("/home/skingging/Documents/Projects/CPP/AI-Tarpit-Reimagined/content/"); // server_fd is a file descriptor. - int server_fd = socket(AF_INET, SOCK_STREAM, 0); + const int server_fd = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(8888); addr.sin_addr.s_addr = INADDR_ANY; - bind(server_fd, (sockaddr*)&addr, sizeof(addr)); + bind(server_fd, reinterpret_cast(&addr), sizeof(addr)); listen(server_fd, 15); cout << "Server is running on http://localhost:8888 \n"; @@ -41,9 +45,9 @@ void ServerUtils::serve() { close(server_fd); } -void ServerUtils::process_request(int client_fd) { +void ServerUtils::process_request(const int client_fd) { char buffer[1024]; - int bytes_received = recv(client_fd, buffer, sizeof(buffer) - 1, 0); + const int bytes_received = recv(client_fd, buffer, sizeof(buffer) - 1, 0); string url; @@ -51,7 +55,6 @@ void ServerUtils::process_request(int client_fd) { buffer[bytes_received] = '\0'; url = WordUtils::extract_url(string(buffer)); - } else { cerr << "AAAA \n"; } @@ -63,58 +66,70 @@ void ServerUtils::process_request(int client_fd) { } else if (url == "/favicon.png") { - // This sends the header, that instructs how the browser should interpret the data. - //send_header(client_fd, data_type::IMAGE); + send_image(client_fd, "/home/skingging/Documents/Projects/CPP/AI-Tarpit-Reimagined/a.png", image_type::PNG); + } + + else if (WordUtils::contains_image(url)) { + string p = "/home/skingging/Documents/Projects/CPP/AI-Tarpit-Reimagined/content/images/"; + p += WordUtils::extract_image_name(url); + cerr << p << endl; + send_image(client_fd, p, image_type::AVIF); } else { - unsigned int hash = WordUtils::hash_url(url); - send_header(client_fd, data_type::HTML); - send_chunked_html(client_fd, hash); + //unsigned int hash = WordUtils::hash_url(url); + //unsigned long hash2 = WordUtils::djb2Hash(url); + const unsigned long hash3 = WordUtils::fnv1aHash(url); + + send_header(client_fd, HTML); + send_chunked_html(client_fd, hash3); } - + // Send final zero-length chunk to end the response send(client_fd, "0\r\n\r\n", 5, 0); close(client_fd); } -void ServerUtils::send_header(int client_fd, data_type type) { - if (type == data_type::HTML) { - send(client_fd, HTML_RESPONSE_HEADER.c_str(), HTML_RESPONSE_HEADER.size(), 0); +void ServerUtils::send_header(const int client_fd, const data_type type) { + if (type == HTML) { + send_data(client_fd, HTML_RESPONSE_HEADER); } - else if (type == data_type::CSS) { - send(client_fd, CSS_RESPONSE_HEADER.c_str(), CSS_RESPONSE_HEADER.size(), 0); - } - - else { - send(client_fd, PNG_RESPONSE_HEADER.c_str(), PNG_RESPONSE_HEADER.size(), 0); + else if (type == CSS) { + send_data(client_fd, CSS_RESPONSE_HEADER); } } -void ServerUtils::send_chunked_html(int client_fd, unsigned int hash) { - string chunk; +void ServerUtils::send_chunked_html(const int client_fd, const size_t hash) { const string hashes = to_string(hash); unsigned short itr = 0; - unsigned short end = hashes.size(); + const unsigned short end = hashes.size(); send_data(client_fd, HTML_BEGINNING); send_data(client_fd, HTML_NAV); send_data(client_fd, HTML_MAIN_1); + minstd_rand generator(hash); + uniform_int_distribution distribution_1(0, end - 1); + uniform_int_distribution distribution_2(0, images.size() - 1); + + const int link = distribution_1(generator); + const int image = distribution_2(generator); + while (itr < end) { - ostringstream oss; + send_data(client_fd, WordUtils::create_tag(word_frequencies, hashes[itr])); - chunk = WordUtils::create_tag(_word_frequencies, hashes[itr]); + if (itr == link) { + send_data(client_fd, WordUtils::create_link(word_frequencies, hash)); + } - oss << hex << chunk.size() << "\r\n" << chunk << "\r\n"; - - string to_send = oss.str(); - - send(client_fd, to_send.c_str(), to_send.size(), 0); - //this_thread::sleep_for(chrono::milliseconds(0)); + if (itr == link) { + send_data(client_fd, WordUtils::create_image(images[image])); + } + + this_thread::sleep_for(chrono::milliseconds(25)); itr++; } @@ -124,22 +139,57 @@ void ServerUtils::send_chunked_html(int client_fd, unsigned int hash) { send_data(client_fd, HTML_END); } -void ServerUtils::send_chunked_css(int client_fd) { - for (size_t i = 0; i < _css.size(); i++) { - ostringstream oss; +void ServerUtils::send_chunked_css(const int client_fd) { + for (size_t i = 0; i < css.size(); i++) { + send_data(client_fd, css[i]); - oss << hex << _css[i].size() << "\r\n" << _css[i] << "\r\n"; - - string to_send = oss.str(); - - send(client_fd, to_send.c_str(), to_send.size(), 0); + this_thread::sleep_for(chrono::milliseconds(25)); } } -void ServerUtils::send_data(int client_fd, string data) { +void ServerUtils::send_image(const int client_fd, const string& path, const image_type type) { + const vector image = FileUtils::open_image(path); + + std::ostringstream oss; + oss << "HTTP/1.1 200 OK\r\n"; + if (type == PNG) { + oss << "Content-Type: image/png\r\n"; + } + + if (type == AVIF) { + oss << "Content-Type: image/avif\r\n"; + } + + oss << "Content-Length: " << image.size() << "\r\n"; + oss << "\r\n"; + + //send(client_fd, oss.str().c_str(), oss.str().size(), 0); + send_data(client_fd, oss.str()); + + send(client_fd, reinterpret_cast(image.data()), image.size(), 0); + //send_all(client_fd,reinterpret_cast(image.data()), image.size()); +} + +size_t ServerUtils::send_all(int sockfd, const char *data, const size_t length) { + size_t total_sent = 0; + while (total_sent < length) { + size_t sent = send(sockfd, data + total_sent, length - total_sent, 0); + if (sent <= 0) { + return sent; // Error or connection closed + } + total_sent += sent; + } + return total_sent; +} + +void ServerUtils::send_data(const int client_fd, const string& data) { ostringstream oss; oss << hex << data.size() << "\r\n" << data << "\r\n"; - send(client_fd, oss.str().c_str(), oss.str().size(), 0); + const int result = send(client_fd, oss.str().c_str(), oss.str().size(), 0); + + if (result == -1) { + return; + } } \ No newline at end of file diff --git a/src/WordUtils.cpp b/src/WordUtils.cpp index a675073..5d2ce8c 100644 --- a/src/WordUtils.cpp +++ b/src/WordUtils.cpp @@ -8,14 +8,15 @@ #include #include -map> WordUtils::load_data(const string& path) { +// We can just use a unordered_map> instead +unordered_map> WordUtils::load_data(const string& path) { vector data = split_string(load_file(path), data_type::HTML); - map> word_frequencies = {}; + unordered_map> word_frequencies = {}; for (long unsigned int i = 0; i + 1 < data.size(); i++) { - transform(data[i].begin(), data[i].end(), data[i].begin(), [](unsigned char c){ return tolower(c); }); - transform(data[i+1].begin(), data[i+1].end(), data[i+1].begin(), [](unsigned char c){ return tolower(c); }); + transform(data[i].begin(), data[i].end(), data[i].begin(), [](const unsigned char c){ return tolower(c); }); + transform(data[i+1].begin(), data[i+1].end(), data[i+1].begin(), [](const unsigned char c){ return tolower(c); }); word_frequencies[data[i]][data[i+1]]++; } @@ -26,12 +27,13 @@ vector WordUtils::load_css(const string& path) { return split_string(load_file(path), data_type::CSS); } -vector WordUtils::predict_next_word(const string& input, const map>& word_frequencies, size_t count) { - auto it = word_frequencies.find(input); +// We can just use a unordered_map> instead, since we're already sorting before counting. +vector WordUtils::predict_next_word(const string& input, const unordered_map>& word_frequencies, size_t count) { + const auto it = word_frequencies.find(input); if (it == word_frequencies.end()) return {input}; - const map nextWords = it->second; + const unordered_map nextWords = it->second; vector> sortedWords(nextWords.begin(), nextWords.end()); @@ -50,8 +52,8 @@ vector WordUtils::predict_next_word(const string& input, const map>& word_frequencies, const char& hash) { - unsigned char predict_num = 5; +string WordUtils::create_tag(const unordered_map>& word_frequencies, const char& hash) { + constexpr unsigned char predict_num = 5; const string start_words[3] = {"the", "but", "with"}; @@ -60,7 +62,7 @@ string WordUtils::create_tag(const map>& word_frequenci minstd_rand generator(hash); uniform_int_distribution outer_distribution(0, start_words->length() - 1); - + vector temp_words = predict_next_word(start_words[outer_distribution(generator)], word_frequencies, predict_num); uniform_int_distribution outer_2_distribution(0, temp_words.size() - 1); @@ -89,6 +91,60 @@ string WordUtils::create_tag(const map>& word_frequenci return temp_string; } +string WordUtils::create_link(const unordered_map>& word_frequencies, const unsigned long hash) { + constexpr unsigned char predict_num = 5; + + const string start_words[10] = {"the", "but", "with", "all", "over", "and", "our", "as", "a", "to"}; + + vector tags; + + minstd_rand generator(hash); + + uniform_int_distribution outer_distribution(0, start_words->length() - 1); + + vector temp_words = predict_next_word(start_words[outer_distribution(generator)], word_frequencies, predict_num); + + uniform_int_distribution outer_2_distribution(0, temp_words.size() - 1); + + tags.push_back(temp_words[outer_2_distribution(generator)]); + + // Words inside the

tag + for (unsigned short j = 0; j < 7; j++) + { + temp_words = predict_next_word(tags[j], word_frequencies, predict_num); + + uniform_int_distribution inner_distribution(0, temp_words.size() - 1); + + tags.push_back(temp_words[inner_distribution(generator)]); + } + + string temp_string_2 = ""; + + temp_string_2 += temp_string; + + temp_string_2 += ".\n"; + + return temp_string_2; +} + +string WordUtils::create_image(const string& image) { + + string temp_1 = ""; + return temp_1; +} + vector WordUtils::split_string(const string& input, data_type type) { vector data; @@ -98,13 +154,11 @@ vector WordUtils::split_string(const string& input, data_type type) { // Create a string from the delimiters array string delimiter_string; - if (type == data_type::HTML) - { + if (type == data_type::HTML) { delimiter_string = " .,!?;:()\n\r\t"; } - else if (type == data_type::CSS) - { + else if (type == data_type::CSS) { delimiter_string = "}\n\r\t"; } @@ -140,26 +194,72 @@ string WordUtils::load_file(const string& path) { } string WordUtils::extract_url(const string& input) { - unsigned short first_line_end = input.find("\n"); + const unsigned short first_line_end = input.find('\n'); if (first_line_end == string::npos) return ""; string first_line = input.substr(0, first_line_end); - unsigned short method_end = first_line.find(' '); + const unsigned short method_end = first_line.find(' '); if (method_end == string::npos) return ""; - unsigned short path_end = first_line.find(' ', method_end + 1); + const unsigned short path_end = first_line.find(' ', method_end + 1); if (path_end == string::npos) return ""; return first_line.substr(method_end + 1, path_end - method_end - 1); } +string WordUtils::extract_image_name(const string& input) { + const unsigned short first_line_end = input.find("f"); + if (first_line_end == string::npos) return ""; + + string first_line = input.substr(1, first_line_end); + + return first_line; +} + +bool WordUtils::contains_image(const string& input) { + const unsigned short first_line_end = input.find('.'); + + if (first_line_end == 65535) return false; + + cerr << first_line_end; + + string type = input.substr(first_line_end, 3); + cerr << type << endl; + + if (first_line_end != string::npos) return true; + return false; +} + unsigned int WordUtils::hash_url(const string& input) { + // A very little modified version of simple hash. + unsigned int hash = 0; - for (char c : input) { + for (const char c : input) { hash += static_cast(c) * 597301; } + return hash; +} + +unsigned long WordUtils::djb2Hash(const string& str) { + unsigned long hash = 5381; + for (const char c : str) { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + } + + return hash; +} + +unsigned long WordUtils::fnv1aHash(const std::string& str) { + const unsigned long prime = 16777619; // A commonly used prime + unsigned long hash = 2166136261; // Initial prime value + + for (const char c : str) { + hash ^= c; + hash *= prime; + } + return hash; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 426febe..92004e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,5 @@ +#include + #include "../include/FileUtils.h" #include "../include/WordUtils.h" #include "../include/ServerUtils.h" @@ -33,11 +35,10 @@ int main(int argc, const char* argv[]) { cout << "Next word is: " << out << endl; } }*/ - //argv[1] - ServerUtils server; - server.serve(); - + signal(SIGPIPE, SIG_IGN); + ServerUtils::serve(); + return 0; } \ No newline at end of file