diff --git a/CMakeLists.txt b/CMakeLists.txt index db34696..23b8e8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,36 +3,45 @@ cmake_minimum_required(VERSION 3.25) project(Rum VERSION 1.0) # compiler setup -set(CMAKE_CXX_COMPILER "clang++") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror") # warnings -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2b") # std c++23 +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) -if (STATIC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static") # static -endif() +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -if (DEBUG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") # debug symbols -endif() - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") # optimisations - -# IDE setup (clangd) set(CMAKE_EXPORT_COMPILE_COMMANDS true) -file(GLOB_RECURSE SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-variable -Wno-unused-private-field") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-variable -Wno-unused-private-field") -add_executable(server.bin ${SOURCES}) +file(GLOB_RECURSE SOURCES "${CMAKE_SOURCE_DIR}/src/rum/*.cpp") +set(HEADERS "${CMAKE_SOURCE_DIR}/inc/rum") +add_library(rum OBJECT ${SOURCES}) +set_target_properties(rum PROPERTIES POSITION_INDEPENDENT_CODE 1) +target_include_directories(rum PUBLIC "${CMAKE_SOURCE_DIR}/inc") -target_include_directories(server.bin PRIVATE "${CMAKE_SOURCE_DIR}/inc") +add_library(rum-static STATIC $) +set_target_properties(rum-static PROPERTIES OUTPUT_NAME rum) +target_include_directories(rum-static PUBLIC "${CMAKE_SOURCE_DIR}/inc") -add_custom_target(run - COMMAND $ - DEPENDS server.bin - COMMENT "Running server.bin" +add_library(rum-shared SHARED $) +set_target_properties(rum-shared PROPERTIES OUTPUT_NAME rum) +target_include_directories(rum-shared PUBLIC "${CMAKE_SOURCE_DIR}/inc") + +add_executable(example "${CMAKE_SOURCE_DIR}/src/server.cpp") +target_link_libraries(example rum-shared) +if(USE_FLAGS) + target_link_libraries(example flags-cpp) +endif() + +install(TARGETS + rum-static + rum-shared + RUNTIME + COMPONENT Runtime + LIBRARY + COMPONENT Runtime + ARCHIVE + COMPONENT Development ) - -add_custom_target(docker - COMMAND docker build -t dowerx/rum:${CMAKE_PROJECT_VERSION} .. - COMMENT "Building docker image" -) \ No newline at end of file +install(DIRECTORY ${HEADERS} DESTINATION include COMPONENT Development) \ No newline at end of file diff --git a/inc/rum/http/request.h b/inc/rum/http/request.h index 1b94676..bb0ef6f 100644 --- a/inc/rum/http/request.h +++ b/inc/rum/http/request.h @@ -13,6 +13,7 @@ class Request { Method get_method() const { return method; } URI& get_uri() { return uri; } + URI copy_uri() const { return uri; } const std::map& get_headers() const { return headers; } std::string get_header(std::string name) const { return headers.at(name); } diff --git a/inc/rum/http/uri.h b/inc/rum/http/uri.h index 325c398..d39dd74 100644 --- a/inc/rum/http/uri.h +++ b/inc/rum/http/uri.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include diff --git a/src/rum/http/server.cpp b/src/rum/http/server.cpp index 09be7bd..232cfa2 100644 --- a/src/rum/http/server.cpp +++ b/src/rum/http/server.cpp @@ -2,8 +2,11 @@ #include #include #include +#include +#include #include #include +#include #include namespace Rum::HTTP { @@ -28,8 +31,11 @@ Server::Server(unsigned int port, size_t worker_count, size_t buffer_size) : Rum tasks.pop(); } +#ifdef DEBUG std::cout << "Worker #" << i << " accepted a connection." << std::endl; - +#else + (void)i; +#endif handler(task.client_sock, task.sockaddr, buffer); if (int status = close(task.client_sock); status == TCP::Error::UNKNOWN) { std::cerr << TCP::to_string(task.sockaddr) << ": " << TCP::Error((TCP::Error::Type)status).what() << std::endl; @@ -37,7 +43,9 @@ Server::Server(unsigned int port, size_t worker_count, size_t buffer_size) : Rum } }); workers.emplace_back(std::move(worker)); +#ifdef DEBUG std::cout << "Worker #" << i << " created" << std::endl; +#endif } } @@ -88,8 +96,9 @@ Method string_to_method(std::string text) { void Server::handler(int client_sock, const sockaddr_in& client_address, char* buffer) { std::string address = TCP::to_string(client_address); +#ifdef DEBUG std::cout << address << ": connected" << std::endl; - +#endif Request request; enum Stage { METHOD, HEADER, BODY }; @@ -152,10 +161,13 @@ void Server::handler(int client_sock, const sockaddr_in& client_address, char* b } } } else { - request.set_header(it->str(1), it->str(2)); + std::string key(it->str(1)); + std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c) { return std::tolower(c); }); + request.set_header(key, it->str(2)); } } - message = message.substr(message.find("\r\n\r\n")); + + message = message.substr(message.find("\r\n\r\n") + 4); if (Method method = request.get_method(); method == POST || method == PUT) stage = BODY; @@ -164,6 +176,17 @@ void Server::handler(int client_sock, const sockaddr_in& client_address, char* b } if (stage == BODY) { + std::cout << "here" << std::endl; + + try { + size_t content_length = std::stoul(request.get_header("content-length")); + std::cout << message.size() << " " << content_length << std::endl; + if (message.size() < content_length) + continue; + } catch (std::out_of_range) { + } catch (std::invalid_argument e) { + std::cerr << "invlaid Content-Length header" << std::endl; + } request.set_body(message); break; } diff --git a/src/rum/http/uri.cpp b/src/rum/http/uri.cpp index 4a18eb5..a73d4f5 100644 --- a/src/rum/http/uri.cpp +++ b/src/rum/http/uri.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include namespace Rum::HTTP { @@ -27,11 +28,13 @@ URI::operator std::string() const { } URI::URI(const std::string& uri) { - std::regex uri_regex(R"((([\w\d]+):\/\/)?(([\w\d]+)(:([\w\d]+)?)@)?([\w\d\.]+)(:(\d+))?(\/?[\w\d\.\/]+)?(\?([\w\d\=\&]+))?(\#([\w\d]*))?)"); + std::regex uri_regex(R"((([\w\d]+):\/\/)?(([\w\d]+)(:([\w\d]+)?)@)?([\w\d\.]+)(:(\d+))?(\/?[\w\d\.\/]+)?(\?([^#]+))?(\#([\w\d]*))?)"); std::smatch match; +#ifdef DEBUG std::cout << uri << std::endl; +#endif if (std::regex_match(uri.cbegin(), uri.cend(), match, uri_regex)) { #define MATCH(var, i) \ diff --git a/src/server.cpp b/src/server.cpp index 7c4eacd..be2c420 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,4 +1,6 @@ -#include +#ifdef USE_FLAGS +#include +#endif #include #include #include @@ -7,6 +9,8 @@ Rum::HTTP::Server* server; int main(int argc, char** argv) { +#ifdef USE_FLAGS + Flags::Parser parser; int* port = parser.add("port", "tcp port number", false, 8080); unsigned long int* workers = parser.add("workers", "number of worker threads", false, 10); @@ -18,6 +22,11 @@ int main(int argc, char** argv) { return -1; } +#else + int* port = new int(argc >= 2 ? atoi(argv[1]) : 8080); + unsigned long* workers = new unsigned long(10); +#endif + std::cout << "Port: " << *port << std::endl; std::cout << "Workers: " << *workers << std::endl; @@ -37,10 +46,15 @@ int main(int argc, char** argv) { server->add_path("/cookie", [](const Rum::HTTP::Request& req, Rum::HTTP::Response& resp) { std::cout << "request accepted" << std::endl; - resp.cookies.push_back(Rum::HTTP::Cookie("testCookie", "valueOfCookie", "/", 60*60)); + resp.cookies.push_back(Rum::HTTP::Cookie("testCookie", "valueOfCookie", "/", 60 * 60)); resp.body = "

Cookie

" + (std::string)req + "
"; }); + server->add_path("/add", [](const Rum::HTTP::Request& req, Rum::HTTP::Response& resp) { + std::cout << (std::string)req << std::endl; + resp.body = "

Hello World

" + (std::string)req + "
"; + }); + server->add_path("/.*", [](const Rum::HTTP::Request& req, Rum::HTTP::Response& resp) { std::cout << "request accepted" << std::endl; resp.body = "

Hello World

" + (std::string)req + "
";