From fae621ef4acdd728cf7888192aa2f91c2cac8c7d Mon Sep 17 00:00:00 2001 From: Vinicius Pereira <130008311+0bvim@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:02:29 -0300 Subject: [PATCH 01/16] Create feature.yml --- .github/workflows/feature.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/feature.yml diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml new file mode 100644 index 0000000..e9f6ad8 --- /dev/null +++ b/.github/workflows/feature.yml @@ -0,0 +1,33 @@ +name: Feature CI + +on: + push: + branches: + - 'feature/*' + pull_request: + branches: [main, develop] + +jobs: + feature-ci: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Clang 12 + uses: actions/setup-tool@v3 + with: + url: https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/clang+llvm-12.0.0-linux-x86_64.tar.xz + extract: 'clang+llvm-12.0.0-linux-x86_64' + + - name: Configure Clang 12 + run: | + export PATH=$PATH:$PWD/clang+llvm-12.0.0-linux-x86_64/bin + clang++ --version + + - name: Compile Webserv + run: make + + - name: Run Code + run: make run From 1779cd75b3c367f458a4fc2bf0d829d20ec8bf3c Mon Sep 17 00:00:00 2001 From: Vinicius Pereira <130008311+0bvim@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:06:14 -0300 Subject: [PATCH 02/16] Update feature.yml --- .github/workflows/feature.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml index e9f6ad8..3f3ea64 100644 --- a/.github/workflows/feature.yml +++ b/.github/workflows/feature.yml @@ -2,8 +2,7 @@ name: Feature CI on: push: - branches: - - 'feature/*' + branches: feature/* pull_request: branches: [main, develop] From e4f01f045e1b2d964f36ecacd706d5807dd7cb90 Mon Sep 17 00:00:00 2001 From: Vinicius Pereira <130008311+0bvim@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:21:26 -0300 Subject: [PATCH 03/16] Update feature.yml --- .github/workflows/feature.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml index 3f3ea64..c52e1c6 100644 --- a/.github/workflows/feature.yml +++ b/.github/workflows/feature.yml @@ -2,7 +2,7 @@ name: Feature CI on: push: - branches: feature/* + branches: [feature/*] pull_request: branches: [main, develop] @@ -15,10 +15,9 @@ jobs: uses: actions/checkout@v3 - name: Setup Clang 12 - uses: actions/setup-tool@v3 + uses: actions/setup-cpp@v1 with: - url: https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/clang+llvm-12.0.0-linux-x86_64.tar.xz - extract: 'clang+llvm-12.0.0-linux-x86_64' + cpp-version: '11' - name: Configure Clang 12 run: | From 53b83ab67b466458226aa92ba46f599ddf9d9c7b Mon Sep 17 00:00:00 2001 From: Vinicius Pereira <130008311+0bvim@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:26:58 -0300 Subject: [PATCH 04/16] Update feature.yml last try? --- .github/workflows/feature.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml index c52e1c6..8e92709 100644 --- a/.github/workflows/feature.yml +++ b/.github/workflows/feature.yml @@ -14,15 +14,12 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - - name: Setup Clang 12 - uses: actions/setup-cpp@v1 - with: - cpp-version: '11' + - name: Set up C++ environment + uses: aminya/setup-cpp@v1 - - name: Configure Clang 12 - run: | - export PATH=$PATH:$PWD/clang+llvm-12.0.0-linux-x86_64/bin - clang++ --version + # start test coverage using this tool or gcov + - name: Install gcovr + run: sudo apt-get install -y gcovr - name: Compile Webserv run: make From cb91db81a566dc4abf2f8afaf41b1055cc27610e Mon Sep 17 00:00:00 2001 From: Vinicius Pereira <130008311+0bvim@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:34:37 -0300 Subject: [PATCH 05/16] Update feature.yml --- .github/workflows/feature.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml index 8e92709..61f8b08 100644 --- a/.github/workflows/feature.yml +++ b/.github/workflows/feature.yml @@ -25,4 +25,10 @@ jobs: run: make - name: Run Code - run: make run + run: | + make run & + SERVER_PID=$! + sleep 3 # just to certify that test will run... + + - name: Stop Webserv + run: kill -SIGINT $SERVER_PID From f0269db6ec6c497861da4946ec0322da3a524631 Mon Sep 17 00:00:00 2001 From: Vinicius Pereira <130008311+0bvim@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:39:43 -0300 Subject: [PATCH 06/16] Update feature.yml --- .github/workflows/feature.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml index 61f8b08..2c76c26 100644 --- a/.github/workflows/feature.yml +++ b/.github/workflows/feature.yml @@ -28,7 +28,7 @@ jobs: run: | make run & SERVER_PID=$! - sleep 3 # just to certify that test will run... + sleep 3 - name: Stop Webserv - run: kill -SIGINT $SERVER_PID + run: kill -SIGINT $SERVER_PID || true From ef2eaef762f274bf74e223ac27760f9dd75192de Mon Sep 17 00:00:00 2001 From: Vinicius Pereira <130008311+0bvim@users.noreply.github.com> Date: Sun, 8 Sep 2024 19:04:54 -0300 Subject: [PATCH 07/16] Update README.md --- README.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/README.md b/README.md index 4e3e892..f90d289 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,41 @@ # webserv This is when you finally understand why a URL starts with HTTP + + +```mermaid +flowchart TD + A[Introduction to HTTP] --> B[Overview of HTTP server] + B --> C[Primary function of a web server] + C --> D[Request/Response model] + D --> E[Role of client and server] + + A1[General rules] --> F[Program Stability] + F --> G[No crashing or unexpected quit] + F --> H[Makefile structure] + F --> I[Use C++ 98 standard] + F --> J[Forbidden libraries] + + A2[Mandatory Part] --> K[Program name: webserv] + K --> L[HTTP server in C++ 98] + L --> M[Command to run: ./webserv config_file] + L --> N[Requirements] + N --> O[Non-blocking I/O using poll or equivalent] + N --> P[Configuration file handling] + N --> Q[GET, POST, DELETE methods support] + N --> R[Serve static content] + N --> S[Handle file uploads] + N --> T[Multiple ports support] + + A3[For MacOS only] --> U[Use of fcntl] + + A4[Configuration File] --> V[Define server host and port] + V --> W[Set up server_names] + W --> X[Configure routes for files] + X --> Y[Enable CGI execution] + X --> Z[Handle uploads and directory listing] + + A5[Bonus Part] --> AA[Support cookies and session management] + AA --> AB[Handle multiple CGI scripts] + + A6[Submission and Peer Evaluation] --> AC[Submit via Git repository] +``` From c6d706ac343d7049769fdf1938651557c2a8068b Mon Sep 17 00:00:00 2001 From: vinicius Date: Sat, 2 Nov 2024 16:40:14 -0300 Subject: [PATCH 08/16] refactor: exclude old files and start new project from almost brand new scratch --- .gdb_history | 18 -- .gitignore | 1 + .vscode/launch.json | 43 ---- .vscode/settings.json | 76 ------ CMakeLists.txt | 30 --- Makefile | 3 +- arquivo.conf | 60 ----- config/default.conf | 49 ++++ empty.conf => config/empty.conf | 0 default.conf | 24 -- include/Client.hpp | 34 --- include/Config.hpp | 54 ----- include/Events.hpp | 33 --- include/Request.hpp | 53 ----- include/Response.hpp | 90 -------- include/Server.hpp | 56 ----- include/common.hpp | 50 +--- server.conf | 5 - src/Client.cpp | 50 ---- src/Config.cpp | 223 ------------------ src/ConfigUtils.cpp | 13 -- src/Events.cpp | 71 ------ src/InitServer.cpp | 29 --- src/Request.cpp | 82 ------- src/Response.cpp | 233 ------------------- src/ResponseUtils.cpp | 16 -- src/Server.cpp | 112 --------- src/ServerUtils.cpp | 40 ---- src/main.cpp | 35 +-- src/parser_config_file/check_file.cpp | 26 +++ src/parser_config_file/check_file.h | 11 + src/utils.cpp | 38 --- tests/alternativeConfParser.cpp | 124 ---------- tests/main.cpp | 8 - tests/monolito.cpp | 321 -------------------------- tests/nonblk.cpp | 150 ------------ tests/server.conf | 5 - tests/testConfig.cpp | 14 -- tests/testItoa.cpp | 23 -- tests/testParser.cpp | 63 ----- tests/testRequest.cpp | 25 -- tests/testResponse.hpp | 28 --- tests/testServer.cpp | 246 -------------------- tests/test_default.conf | 14 -- 44 files changed, 110 insertions(+), 2569 deletions(-) delete mode 100644 .gdb_history delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json delete mode 100644 CMakeLists.txt delete mode 100644 arquivo.conf create mode 100644 config/default.conf rename empty.conf => config/empty.conf (100%) delete mode 100644 default.conf delete mode 100644 include/Client.hpp delete mode 100644 include/Config.hpp delete mode 100644 include/Events.hpp delete mode 100644 include/Request.hpp delete mode 100644 include/Response.hpp delete mode 100644 include/Server.hpp delete mode 100644 server.conf delete mode 100644 src/Client.cpp delete mode 100644 src/Config.cpp delete mode 100644 src/ConfigUtils.cpp delete mode 100644 src/Events.cpp delete mode 100644 src/InitServer.cpp delete mode 100644 src/Request.cpp delete mode 100644 src/Response.cpp delete mode 100644 src/ResponseUtils.cpp delete mode 100644 src/Server.cpp delete mode 100644 src/ServerUtils.cpp create mode 100644 src/parser_config_file/check_file.cpp create mode 100644 src/parser_config_file/check_file.h delete mode 100644 src/utils.cpp delete mode 100644 tests/alternativeConfParser.cpp delete mode 100644 tests/main.cpp delete mode 100644 tests/monolito.cpp delete mode 100644 tests/nonblk.cpp delete mode 100644 tests/server.conf delete mode 100644 tests/testConfig.cpp delete mode 100644 tests/testItoa.cpp delete mode 100644 tests/testParser.cpp delete mode 100644 tests/testRequest.cpp delete mode 100644 tests/testResponse.hpp delete mode 100644 tests/testServer.cpp delete mode 100644 tests/test_default.conf diff --git a/.gdb_history b/.gdb_history deleted file mode 100644 index 6a55cd6..0000000 --- a/.gdb_history +++ /dev/null @@ -1,18 +0,0 @@ -b main -r -n -s -n -info locals -quit -n -r -n -r -b main -n -r -n -n -n -quit diff --git a/.gitignore b/.gitignore index da673f1..aafba88 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ bin/ build/ webserv + diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index d25d3e1..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/webserv", - "args": [], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - }, - { - "description": "Set Disassembly Flavor to Intel", - "text": "-gdb-set disassembly-flavor intel", - "ignoreFailures": true - }, - { - "description": "Set follow-fork-mode to child", - "text": "set follow-fork-mode child", - "ignoreFailures": false - }, - { - "description": "Set detach-on-fork to off", - "text": "set detach-on-fork off", - "ignoreFailures": false - } - ] - } - - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index c32643f..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "files.associations": { - "*.hpp": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "map": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "random": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "new": "cpp", - "numbers": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "typeinfo": "cpp", - "chrono": "cpp", - "ctime": "cpp", - "optional": "cpp", - "ratio": "cpp", - "iomanip": "cpp", - "ranges": "cpp", - "stop_token": "cpp", - "thread": "cpp", - "any": "cpp", - "strstream": "cpp", - "bitset": "cpp", - "codecvt": "cpp", - "complex": "cpp", - "condition_variable": "cpp", - "list": "cpp", - "set": "cpp", - "mutex": "cpp", - "semaphore": "cpp", - "cfenv": "cpp", - "cinttypes": "cpp", - "typeindex": "cpp", - "variant": "cpp" - } -} diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 6e6077b..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(MyWebServer VERSION 1.0) - -# Set the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) - -include_directories(include) - -# Find the Google Test package -find_package(GTest REQUIRED) -include_directories(${GTEST_INCLUDE_DIRS}) - -# Add the main application executable -add_executable(my_web_server src/main.cpp src/Client.cpp src/Config.cpp src/ConfigUtils.cpp src/InitServer.cpp src/Request.cpp src/Response.cpp src/Server.cpp src/ServerUtils.cpp src/utils.cpp) - -# Specify any dependencies for the main application here -# target_link_libraries(my_web_server dependency_name) - -# Define the test executable -add_executable(run_tests tests/main.cpp tests/testConfig.cpp tests/testItoa.cpp tests/testRequest.cpp tests/testServer.cpp) - -# Link the test executable against Google Test -target_link_libraries(run_tests ${GTEST_LIBRARIES} pthread) - -target_include_directories(run_tests PRIVATE include ${GTEST_INCLUDE_DIRS}) # This ensures 'include' and GTest directories are included specifically for run_tests - -# Optionally, enable CMake's built-in test discovery -enable_testing() -add_test(NAME MyWebServerTests COMMAND run_tests) diff --git a/Makefile b/Makefile index 94a486f..14f2d08 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SRC_DIR := src BUILD_DIR := build TESTS_DIR := tests -SRCS := $(wildcard $(SRC_DIR)/*.cpp) +SRCS := $(shell find $(SRC_DIR) -name "*.cpp") OBJS := $(patsubst $(SRC_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(SRCS)) NAME := webserv @@ -23,6 +23,7 @@ $(NAME): $(OBJS) $(CXX) $(CXXFLAGS) -o $@ $^ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR) + @mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) -c -o $@ $< $(BUILD_DIR): diff --git a/arquivo.conf b/arquivo.conf deleted file mode 100644 index 3665f1b..0000000 --- a/arquivo.conf +++ /dev/null @@ -1,60 +0,0 @@ -server { - server_name server.com; - listen 127.0.0.1:8042; - error_page 403 web/403.html; - error_page 404 web/404.html; - error_page 405 web/405.html; - error_page 413 web/413.html; - error_page 500 web/500.html; - client_max_body_size 10000; - - location / { - autoindex on; - allow_methods GET POST DELETE; - root web_root; - upload_dir web_root/uploads; - index index.html index.php; - cgi .py web/test.py; - } - - location /potato/ { - autoindex on; - root web_root; - allow_methods GET POST DELETE; - } - - location /redirect/ { - return 301 https://google.com; - } - -} -server { - server_name server2.com; - listen 127.0.0.1:8041; - error_page 403 error_pages/403.html; - error_page 404 error_pages/404.html; - error_page 405 error_pages/405.html; - error_page 413 error_pages/413.html; - error_page 500 error_pages/500.html; - client_max_body_size 100; - - location / { - autoindex off; - allow_methods GET POST; - root web_root; - upload_dir web_root/uploads; - index index.html index.php; - cgi .py cgi-bin/py-cgi; - } - - location /potato2/ { - autoindex on; - root web_root; - allow_methods GET; - } - - location /redirect/ { - return 301 https://google.com; - } - -} diff --git a/config/default.conf b/config/default.conf new file mode 100644 index 0000000..43dd740 --- /dev/null +++ b/config/default.conf @@ -0,0 +1,49 @@ +# First server block +server { + host 127.0.0.1; + port 8080; + server_names example.com www.example.com; + client_max_size 10M; + + error_pages { + 404 /errors/404.html; + 500 /errors/500.html; + 503 /errors/503.html; + } + + location /static { + methods GET POST DELETE; + root /var/www/static; + directory_list on; + index index.html; + } + + location /upload { + methods POST; + upload_path /var/www/uploads; + client_max_size 20M; # Override global setting + } + + location /api { + methods GET POST; + cgi on; + cgi_extension .php; + cgi_path /usr/bin/php-cgi; + root /var/www/api; + } +} + +# Second server block (different port) +server { + host 127.0.0.1; + port 8081; + server_names api.example.com; + client_max_size 5M; + + location / { + methods GET; + root /var/www/html; + directory_list off; + index index.html; + } +} diff --git a/empty.conf b/config/empty.conf similarity index 100% rename from empty.conf rename to config/empty.conf diff --git a/default.conf b/default.conf deleted file mode 100644 index 5cdd7c9..0000000 --- a/default.conf +++ /dev/null @@ -1,24 +0,0 @@ -server { - listen 127.0.0.1:8042; - server_name localhost; - - location / { - root /usr/share/nginx/html; - index index.html; - cgi .py cgi-bin; - cgi .go cgi-bin; - cgi .php cgi-bin; - } -} - -server { - listen 127.0.0.1:8041; - server_name localhost; - - location / { - root /web; - index index.html; - cgi .py cgi-bin; - } - -} diff --git a/include/Client.hpp b/include/Client.hpp deleted file mode 100644 index 2a587a6..0000000 --- a/include/Client.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Client.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/06/27 14:40:02 by bmoretti #+# #+# */ -/* Updated: 2024/09/14 16:57:29 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#ifndef CLIENT_HPP -#define CLIENT_HPP - -#include "common.hpp" - -class Client -{ -public: - Client(int serverSocket); - ~Client(); - int _getClientSocket() const; - std::string & _getBuffer(); - void _addToBuffer(const std::string &str); - void clearBuff(); - -private: - int _clientSocket; - struct sockaddr_in _address; - std::string _buffer; -}; - -#endif diff --git a/include/Config.hpp b/include/Config.hpp deleted file mode 100644 index abad2a7..0000000 --- a/include/Config.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef CONFIG_HPP -#define CONFIG_HPP - -#include "common.hpp" -#define DEFAULT_CONFIG_FILE "default.conf" -#include - -typedef struct cgi_config -{ - std::string extension; - std::string path; -} t_cgi_config; - -struct LocationConfig -{ - std::string path; - bool autoindex; - std::vector allow_methods; - std::string root; - std::string upload_dir; - std::vector index; - std::vector cgi; - std::string redirect; -}; - -typedef struct ServerConfig -{ - std::string server_name; - std::string address; - int port; - std::map error_pages; - size_t client_max_body_size; - std::vector locations; -} t_ServerConfig; - -class Config -{ -public: - Config(const std::string &filePath); - const std::vector &getServers() const; - void printServers() const; - -private: - std::string filePath; - std::vector servers; - - void checkFile() const; - void parseConfigFile(); - void parseServerBlock(const std::vector &lines, size_t &index); - void parseLocationBlock(const std::vector &lines, size_t &index, ServerConfig &server); - bool checkBraces(const std::vector &lines); -}; - -#endif diff --git a/include/Events.hpp b/include/Events.hpp deleted file mode 100644 index ac2365f..0000000 --- a/include/Events.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Events.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: nivicius +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/08/18 16:05:36 by bmoretti #+# #+# */ -/* Updated: 2024/09/10 21:28:09 by nivicius ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#ifndef EVENTS_HPP -#define EVENTS_HPP - -#include "common.hpp" -#include "Config.hpp" -#include "Server.hpp" - -class Events -{ -public: - Events(const std::vector &servers); - ~Events(); - void run(); - -private: - std::vector _servers; - int _epoll_fd; - epoll_event *_event; -}; - -#endif diff --git a/include/Request.hpp b/include/Request.hpp deleted file mode 100644 index 46a5624..0000000 --- a/include/Request.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Request.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/07/11 18:24:18 by bmoretti #+# #+# */ -/* Updated: 2024/07/11 18:58:26 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#ifndef REQUEST_HPP -#define REQUEST_HPP - -#include "common.hpp" - -enum RequestMethod -{ - GET, - POST, - DELETE, - OTHER -}; - -typedef struct s_request -{ - RequestMethod method; - std::string HTTPVersion; - std::string uri; - std::map headers; -} t_request; - -class Request -{ -public: - Request(std::string & str); - ~Request(); - - t_request getRequest() const; - void printRequest() const; - -private: - std::string & _str; - t_request _request; - - std::string _trim(const std::string &str); - void _getMethod(const std::string &str); - void _getHTTPVersion(const std::string &str); - void _parseHTTPRequest(); -}; - -#endif diff --git a/include/Response.hpp b/include/Response.hpp deleted file mode 100644 index 7965d4e..0000000 --- a/include/Response.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Response.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/07/13 13:06:55 by bmoretti #+# #+# */ -/* Updated: 2024/09/22 17:24:55 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#ifndef RESPONSE_HPP -#define RESPONSE_HPP - -#define PY_PATH "/usr/bin/python3" -#define GO_PATH "/usr/local/go/bin" -#define PHP_PATH "/usr/bin/php" - -#include "Config.hpp" -#include "Request.hpp" -#include "common.hpp" - -namespace HttpStatus { -enum Code { - ZERO, - CONTINUE = 100, - OK = 200, - CREATED = 201, - NO_CONTENT = 204, - MOVED_PERMANENTLY = 301, - BAD_REQUEST = 400, - FORBIDDEN = 403, - NOT_FOUND = 404, - NOT_ALLOWED = 405, - TIMEOUT = 408, - CONFLICT = 409, - PAYLOAD_TOO_LARGE = 413, - SERVER_ERR = 500, - NOT_IMPLEMENTED = 501, - SERVICE_UNAVAILABLE = 503, -}; -}; - -typedef struct s_response { - std::string statusLine; - bool isCGI; - std::map headers; - std::string fullURI; - std::string body; -} t_response; - -class Response { -public: - Response(Request &request, const ServerConfig &config); - ~Response(); - - std::string getResponse() const; - -private: - Request &_request; - const ServerConfig &_config; - t_response _response; - LocationConfig *_locationConfig; - std::map statusMap; - - HttpStatus::Code _status; - - void _fillStatusMap(); - void _determineLocation(); - void _generateFullURI(); - void _generateStatusLine(); - void _generateHeaders(); - void _generateBody(std::string &path); - std::string _generateResponse() const; - void _identifyCGI(); - void _executeCgi(); - std::string _location; - - bool _checkErrors(); - bool _checkError400(); - bool _checkError404(); - bool _error405(); -}; - -// utils -bool endsWith(const std::string &str, const std::string &suffix); -bool isInterpreterInstalled(const char *command); - -#endif diff --git a/include/Server.hpp b/include/Server.hpp deleted file mode 100644 index e655880..0000000 --- a/include/Server.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Server.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/06/27 10:40:41 by bmoretti #+# #+# */ -/* Updated: 2024/09/01 16:26:31 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#ifndef SERVER_HPP -#define SERVER_HPP - -#include "common.hpp" -#include "Request.hpp" -#include "Response.hpp" -#include "Config.hpp" -#include "Client.hpp" - -class Server -{ -public: - Server(const ServerConfig &config, int event_fd, epoll_event *event); - ~Server(); - int _getServerFd() const; - bool _acceptClient(); - void _handleConnection(int client_fd); - bool _isClientConnected(int fd); - void run(); - -private: - /* Server initialization */ - void _initServer(); - void _fillBuffer(int fd, const char *str); - bool _checkEndMessage(int fd); - void _printOnClient(int fd, std::string const &str); - ssize_t _readFromClient(int fd, char *buff); - bool _handleAcceptError(int error_code); - void _initServerAddress(sockaddr_in &server_add); - void _setSocketNonBlocking(int fd); - - std::string _address; - int _port; - int _server_fd; - int _epoll_fd; - epoll_event *_event; - HttpStatus::Code _status; - std::map _buffer_request; - struct epoll_event _events[MAX_EVENTS]; - const ServerConfig &_config; - std::map _clients; -}; - -#endif diff --git a/include/common.hpp b/include/common.hpp index 525e23d..409173c 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -1,53 +1,14 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* common.hpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/06/27 11:24:48 by bmoretti #+# #+# */ -/* Updated: 2024/09/21 12:22:35 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - #ifndef COMMON_HPP #define COMMON_HPP +// Server consts #define PORT 8042 #define BUFFER_SIZE 1024 #define MAX_CONNECTIONS 5 #define MAX_EVENTS 10 +#define DEFAULT_CONFIG_FILE "../config/default.config" -// C libs -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// C++ LIBS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// FORMATTING +// Colors #define BOLD(text) "\033[1m" << text << "\033[0m" #define UNDERLINE(text) "\033[4m" << text << "\033[0m" @@ -74,9 +35,4 @@ #define BG_WHITE(text) "\033[47m" << text << "\033[0m" #define BG_BLACK(text) "\033[40m" << text << "\033[0m" -// functions -std::string itoa(int value); -std::string trim(const std::string &str); -std::vector split(const std::string &str, char delimiter); - #endif diff --git a/server.conf b/server.conf deleted file mode 100644 index 2af8aaf..0000000 --- a/server.conf +++ /dev/null @@ -1,5 +0,0 @@ -port 8080 -port 8081 -host 127.0.0.1 -route / /index.html index.html - diff --git a/src/Client.cpp b/src/Client.cpp deleted file mode 100644 index f56f7fc..0000000 --- a/src/Client.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Client.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/06/27 14:46:10 by bmoretti #+# #+# */ -/* Updated: 2024/09/14 15:00:33 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "../include/Client.hpp" - -Client::Client(int serverSocket) -{ - memset(&this->_address, 0, sizeof(this->_address)); - - socklen_t client_addr_len = sizeof(this->_address); - this->_clientSocket = accept(serverSocket, (sockaddr *)&this->_address, &client_addr_len); - if (this->_clientSocket == -1) - throw std::runtime_error("Failed to accept client"); - int flags = 1; - if (ioctl(this->_clientSocket, FIONBIO, &flags) < 0) - throw std::runtime_error("Failed to set socket non-blocking"); -} - -Client::~Client() -{ - close(this->_clientSocket); -} - -int Client::_getClientSocket() const -{ - return this->_clientSocket; -} - -std::string & Client::_getBuffer() -{ - return this->_buffer; -} -void Client::_addToBuffer(const std::string &str) -{ - this->_buffer += str; -} - -void Client::clearBuff() -{ - this->_buffer.clear(); -} diff --git a/src/Config.cpp b/src/Config.cpp deleted file mode 100644 index 30b362d..0000000 --- a/src/Config.cpp +++ /dev/null @@ -1,223 +0,0 @@ -#include "../include/Config.hpp" -#include - -Config::Config(const std::string &filePath) : filePath(filePath) -{ - this->checkFile(); - parseConfigFile(); -} - -std::vector const &Config::getServers() const -{ - return this->servers; -} - -static void checkLinesContent(const std::vector &vec) -{ - std::vector::const_iterator it; - - for (it = vec.begin(); it != vec.end(); ++it) - if (it->find("server {") != std::string::npos) - return; - throw std::runtime_error("Server Not Found"); -} - -void Config::parseConfigFile() -{ - std::ifstream configFile(filePath.c_str()); - if (!configFile.is_open()) - { - std::cerr << "Error opening config file: " << filePath << std::endl; - return; - } - std::string line; - std::vector lines; - while (std::getline(configFile, line)) - lines.push_back(line); - if (!lines.size()) - throw std::runtime_error("File is empty \U0001F919"); - checkLinesContent(lines); - try - { - size_t index = 0; - checkBraces(lines); - while (index < lines.size()) - { - std::string trimmedLine = trim(lines[index]); - if (trimmedLine == "server {") - parseServerBlock(lines, index); - ++index; - } - } - catch (std::exception &e) - { - std::cerr << "Error parsing config file: " << e.what() << std::endl; - } -} - -void Config::parseServerBlock(const std::vector &lines, size_t &index) -{ - ServerConfig server; - - while (++index < lines.size()) - { - std::string trimmedLine = trim(lines[index]); - if (trimmedLine == "}") - break; - if (!trimmedLine.empty() && - trimmedLine[trimmedLine.size() - 1] != ';' && - trimmedLine.find("location") == std::string::npos) - { - throw std::runtime_error("Invalid line in server block"); - } - else if (trimmedLine.find("server_name") == 0) - server.server_name = trimmedLine.substr(12).erase(trimmedLine.size() - 13); - else if (trimmedLine.find("listen") == 0) - { - std::string str; - std::istringstream iss(trimmedLine.substr(7).erase(trimmedLine.size() - 8)); - iss >> str; - server.address = str.substr(0, str.find(":")); - server.port = atoi(str.substr(str.find(":") + 1).c_str()); - } - else if (trimmedLine.find("client_max_body_size") == 0) - { - std::istringstream iss(trimmedLine.substr(21).erase(trimmedLine.size() - 22)); - iss >> server.client_max_body_size; - } - else if (trimmedLine.find("error_page") == 0) - { - size_t pos = trimmedLine.find(' ', 11); - int errorCode; - std::istringstream iss(trimmedLine.substr(11, pos - 11)); - iss >> errorCode; - std::string errorPage = trimmedLine.substr(pos + 1).erase(trimmedLine.size() - pos - 2); - server.error_pages[errorCode] = errorPage; - } - else if (trimmedLine.find("location") == 0) - { - try - { - parseLocationBlock(lines, index, server); - } - catch (std::exception &e) - { - throw std::runtime_error(e.what()); - } - } - } - servers.push_back(server); -} - -void Config::parseLocationBlock(const std::vector &lines, size_t &index, ServerConfig &server) -{ - LocationConfig location; - - std::string trimmedLine = trim(lines[index]); - size_t pos = trimmedLine.find(' '); - location.path = trim(trimmedLine.substr(pos + 1, trimmedLine.size() - pos - 2)); - - while (++index < lines.size()) - { - std::string trimmedLine = trim(lines[index]); - if (trimmedLine == "}") - break; - if (!trimmedLine.empty() && - trimmedLine[trimmedLine.size() - 1] != ';') - { - throw std::runtime_error("Invalid line in server block"); - } - else if (trimmedLine.find("autoindex") == 0) - location.autoindex = (trimmedLine.substr(10) == "on"); - else if (trimmedLine.find("root") == 0) - location.root = trimmedLine.substr(5).erase(trimmedLine.size() - 6); - else if (trimmedLine.find("upload_dir") == 0) - location.upload_dir = trimmedLine.substr(11).erase(trimmedLine.size() - 12); - else if (trimmedLine.find("index") == 0) - { - std::istringstream iss(trimmedLine.substr(6).erase(trimmedLine.size() - 7)); - std::string idx; - while (iss >> idx) - location.index.push_back(idx); - } - else if (trimmedLine.find("allow_methods") == 0) - { - std::istringstream iss(trimmedLine.substr(14).erase(trimmedLine.size() - 15)); - std::string method; - while (iss >> method) - location.allow_methods.push_back(method); - } - else if (trimmedLine.find("cgi ") == 0) - { - std::vector tokens = split(trimmedLine, ' '); - if (tokens.size() != 3) - throw std::runtime_error("Invalid cgi line"); - location.cgi.push_back(t_cgi_config()); - location.cgi.back().extension = tokens[1]; - location.cgi.back().path = tokens[2]; - } - else if (trimmedLine.find("redirect") == 0) - location.redirect = trimmedLine.substr(9).erase(trimmedLine.size() - 10); - } - server.locations.push_back(location); -} - -bool Config::checkBraces(const std::vector &lines) -{ - int openBraces = 0; - - for (size_t i = 0; i < lines.size(); ++i) - { - const std::string &line = lines[i]; - for (size_t j = 0; j < line.size(); ++j) - { - char c = line[j]; - if (c == '{') - openBraces++; - else if (c == '}') - { - if (openBraces == 0) - throw std::runtime_error("Unmatched closing brace '}' found."); - openBraces--; - } - } - } - if (openBraces != 0) - throw std::runtime_error("Unmatched opening brace '{' found."); - return true; -} - -void Config::printServers() const -{ - std::cout << "Number of servers: " << servers.size() << "\n\n"; - for (size_t i = 0; i < servers.size(); ++i) - { - const ServerConfig &server = servers[i]; - std::cout << "Server Name: " << server.server_name << "\n"; - std::cout << "Address: " << server.address << "\n"; - std::cout << "Port: " << server.port << "\n"; - std::cout << "Client Max Body Size: " << server.client_max_body_size << "\n"; - - for (std::map::const_iterator it = server.error_pages.begin(); it != server.error_pages.end(); ++it) - std::cout << "Error Page " << it->first << ": " << it->second << "\n"; - - for (size_t j = 0; j < server.locations.size(); ++j) - { - const LocationConfig &location = server.locations[j]; - std::cout << "Location: " << location.path << "\n"; - std::cout << " Autoindex: " << (location.autoindex ? "on" : "off") << "\n"; - std::cout << " Root: " << location.root << "\n"; - std::cout << " Upload Dir: " << location.upload_dir << "\n"; - std::cout << " Index: "; - for (size_t k = 0; k < location.index.size(); ++k) - std::cout << location.index[k] << " "; - std::cout << "\n"; - std::cout << " Allow Methods: "; - for (size_t k = 0; k < location.allow_methods.size(); ++k) - std::cout << location.allow_methods[k] << " "; - std::cout << "\n"; - std::cout << " Redirect: " << location.redirect << "\n"; - } - std::cout << "\n"; - } -} diff --git a/src/ConfigUtils.cpp b/src/ConfigUtils.cpp deleted file mode 100644 index c2b0e5e..0000000 --- a/src/ConfigUtils.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "../include/Config.hpp" -#include - -void Config::checkFile() const -{ - struct stat buffer; - - stat(this->filePath.c_str(), &buffer); - if (buffer.st_mode & S_IFREG && !access(this->filePath.c_str(), R_OK)) - return; - else - throw std::runtime_error("Invalid or not accessible file \U0001F972"); -} diff --git a/src/Events.cpp b/src/Events.cpp deleted file mode 100644 index 5432934..0000000 --- a/src/Events.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Events.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/08/18 16:09:46 by bmoretti #+# #+# */ -/* Updated: 2024/09/14 14:50:05 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "Events.hpp" - -Events::Events(const std::vector &servers) -{ - this->_epoll_fd = epoll_create(MAX_CONNECTIONS); - this->_event = new epoll_event[MAX_CONNECTIONS]; - memset(this->_event, 0, sizeof(epoll_event) * MAX_CONNECTIONS); - this->_event->events = EPOLLIN | EPOLLET; - if (this->_epoll_fd == -1) - throw std::runtime_error("Failed to create epoll file descriptor"); - for (std::vector::const_iterator it = servers.begin(); - it != servers.end(); ++it) - { - Server *server = new Server(*it, this->_epoll_fd, this->_event); - this->_servers.push_back(server); - } -} - -Events::~Events() -{ - for (std::vector::iterator it = this->_servers.begin(); - it != this->_servers.end(); ++it) - delete *it; - if (this->_epoll_fd != -1) - close(this->_epoll_fd); - if (this->_event) - delete[] this->_event; -} - -void Events::run() -{ - while (true) - { - int event_count = epoll_wait(this->_epoll_fd, this->_event, MAX_EVENTS, -1); - if (event_count == -1) - throw std::runtime_error("Failed to wait on epoll"); - for (int i = 0; i < event_count; i++) - { - bool found = false; - for(int j = 0, size = this->_servers.size(); j < size; j++) - { - int server_fd = this->_servers[j]->_getServerFd(); - if (_event[i].data.fd == server_fd && this->_servers[j]->_acceptClient()) - { - found = true; - break; - } - else if (this->_servers[j]->_isClientConnected(_event[i].data.fd)) - { - this->_servers[j]->_handleConnection(_event[i].data.fd); - found = true; - break; - } - } - if (found) - break; - } - } -} diff --git a/src/InitServer.cpp b/src/InitServer.cpp deleted file mode 100644 index f33eba6..0000000 --- a/src/InitServer.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "Server.hpp" - -void Server::_initServerAddress(sockaddr_in &server_add) -{ - memset(&server_add, 0, sizeof(server_add)); - server_add.sin_family = AF_INET; - server_add.sin_addr.s_addr = inet_addr(_address.c_str()); - server_add.sin_port = htons(_port); - if (bind(_server_fd, (sockaddr *)&server_add, sizeof(server_add)) == -1) - throw std::runtime_error("Failed to bind socket"); - if (listen(_server_fd, MAX_CONNECTIONS) == -1) - throw std::runtime_error("Failed to listen socket"); -} - -void Server::_initServer() -{ - this->_server_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - OUTNL("SERVER FD: " << this->_server_fd); - if (this->_server_fd == -1) - throw std::runtime_error("Failed to create socket"); - int opt = 1; - if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) - throw std::runtime_error("Failed to set socket options"); - sockaddr_in server_addr; - this->_initServerAddress(server_addr); - (*_event).data.fd = this->_server_fd; - if (epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _server_fd, _event) == -1) - throw std::runtime_error("Failed to add server socket to epoll"); -} diff --git a/src/Request.cpp b/src/Request.cpp deleted file mode 100644 index d5aea67..0000000 --- a/src/Request.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Request.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/07/11 18:29:18 by bmoretti #+# #+# */ -/* Updated: 2024/09/15 15:27:06 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "../include/Request.hpp" - -Request::Request(std::string &str) : _str(str) { this->_parseHTTPRequest(); } - -Request::~Request() {} - -t_request Request::getRequest() const { return this->_request; } - -std::string Request::_trim(const std::string &str) { - std::string::size_type first = str.find_first_not_of(' '); - std::string::size_type last = str.find_last_not_of(' '); - - if (first == std::string::npos || last == std::string::npos) { - return ""; - } - return str.substr(first, last - first + 1); -} - -void Request::_getMethod(const std::string &str) { - if (!str.compare("GET")) { - this->_request.method = GET; - } else if (!str.compare("POST")) { - this->_request.method = POST; - } else if (!str.compare("DELETE")) { - this->_request.method = DELETE; - } else { - this->_request.method = OTHER; - } -} - -void Request::_getHTTPVersion(const std::string &str) { - std::string::size_type pos = str.find("HTTP/"); - if (pos != std::string::npos) - this->_request.HTTPVersion = str.substr(pos + 5); - else - this->_request.HTTPVersion = ""; - OUTNL(this->_request.HTTPVersion + "aaa"); -} - -void Request::_parseHTTPRequest() { - std::istringstream requestStream(this->_str); - std::string line; - std::string requestMethod; - - std::getline(requestStream, line); - std::istringstream requestLineStream(line); - requestLineStream >> requestMethod; - this->_getMethod(requestMethod); - requestLineStream >> this->_request.uri; - - while (std::getline(requestStream, line) && line != "\r") { - std::string::size_type pos = line.find(':'); - if (pos != std::string::npos) { - std::string key = this->_trim(line.substr(0, pos)); - std::string value = this->_trim(line.substr(pos + 1)); - this->_request.headers[key] = value; - } - } -} - -void Request::printRequest() const { - std::cout << "Method: " << this->_request.method << std::endl; - std::cout << "URI: " << this->_request.uri << std::endl; - std::cout << "Headers:" << std::endl; - for (std::map::const_iterator it = - this->_request.headers.begin(); - it != this->_request.headers.end(); ++it) { - std::cout << it->first << ": " << it->second << std::endl; - } -} diff --git a/src/Response.cpp b/src/Response.cpp deleted file mode 100644 index bda709e..0000000 --- a/src/Response.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Response.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/09/21 10:26:03 by bmoretti #+# #+# */ -/* Updated: 2024/09/22 17:32:22 by bmoretti ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "../include/Response.hpp" - -Response::Response(Request &request, const ServerConfig &config) - : _request(request), _config(config) { - this->_fillStatusMap(); - this->_status = HttpStatus::ZERO; - this->_determineLocation(); - if (this->_checkErrors()) - return; - this->_identifyCGI(); - if (this->_response.isCGI) - this->_executeCgi(); - else - this->_generateBody(this->_response.fullURI); - this->_generateStatusLine(); - this->_generateHeaders(); -} - -void Response::_fillStatusMap() { - - this->statusMap[HttpStatus::ZERO] = "UNKNOW STATUS"; - this->statusMap[HttpStatus::CONTINUE] = "100 Continue"; - this->statusMap[HttpStatus::OK] = "200 OK"; - this->statusMap[HttpStatus::CREATED] = "201 Created"; - this->statusMap[HttpStatus::NO_CONTENT] = "204 No Content"; - this->statusMap[HttpStatus::MOVED_PERMANENTLY] = "301 Moved Permanently"; - this->statusMap[HttpStatus::BAD_REQUEST] = "400 Bad Request"; - this->statusMap[HttpStatus::FORBIDDEN] = "403 Forbidden"; - this->statusMap[HttpStatus::NOT_FOUND] = "404 Not Found"; - this->statusMap[HttpStatus::NOT_ALLOWED] = "405 Method Not Allowed"; - this->statusMap[HttpStatus::TIMEOUT] = "408 Request Timeout"; - this->statusMap[HttpStatus::CONFLICT] = "409 Conflict"; - this->statusMap[HttpStatus::PAYLOAD_TOO_LARGE] = "413 Payload Too Large"; - this->statusMap[HttpStatus::SERVER_ERR] = "500 Internal Server Error"; - this->statusMap[HttpStatus::NOT_IMPLEMENTED] = "501 Not Implemented"; - this->statusMap[HttpStatus::SERVICE_UNAVAILABLE] = "503 Service Unavailable"; -} - -void Response::_determineLocation() { - t_request request = this->_request.getRequest(); - ServerConfig server = this->_config; - for (size_t j = 0; j < server.locations.size(); j++) { - if (request.uri.find(server.locations[j].path) != std::string::npos) { - this->_locationConfig = &server.locations[j]; - this->_response.fullURI = "." + server.locations[j].root + request.uri; - return; - } - } - this->_locationConfig = NULL; -} - -Response::~Response() {} - -std::string Response::getResponse() const { return this->_generateResponse(); } - -void Response::_generateStatusLine() { - this->_response.statusLine = "HTTP/1.1 "; - this->_response.statusLine += this->statusMap[this->_status]; -} - -void Response::_generateHeaders() { - // TODO: mocking the headers - this->_response.headers["Content-Type"] = "text/html"; -} - -void Response::_generateBody(std::string &path) { - std::ifstream file(path.c_str()); - - if (file.is_open()) { - std::stringstream buffer; - std::string bufferStr; - buffer << file.rdbuf(); - bufferStr = buffer.str(); - OUTNL(bufferStr); - this->_response.body = bufferStr; - this->_response.headers["Content-Length"] = itoa(bufferStr.size()); - this->_response.headers["Content-Type"] = "text/html"; - file.close(); - } else { - // TODO: mensagem de arquivo não encontrado - } -} - -std::string Response::_generateResponse() const { - std::string response = this->_response.statusLine + "\r\n"; - for (std::map::const_iterator it = - this->_response.headers.begin(); - it != this->_response.headers.end(); ++it) { - response += it->first + ": " + it->second + "\r\n"; - } - response += "\r\n" + this->_response.body; - return response; -} - -// TODO: implement other errors -bool Response::_checkErrors() { - if (this->_request.getRequest().HTTPVersion == "") - this->_response.statusLine = "HTTP/1.1 400 Bad Request"; - if (this->_request.getRequest().method == OTHER) - this->_error405(); - else - return false; - return true; -} - -bool Response::_checkError400() { - t_request request = this->_request.getRequest(); - - if (request.HTTPVersion == "") - return true; - if (request.headers["Host"] == "") - return true; - int content_length = 0; - int body_size = 0; - if (request.headers.find("Content-Length") != request.headers.end()) - content_length = atoi(request.headers["Content-Length"].c_str()); - if (request.headers.find("Body") != request.headers.end()) - body_size = request.headers["Body"].size(); - if (content_length != body_size) - return true; - if (request.method == POST && content_length == 0) - return true; - if (request.method == POST && request.headers["Content-Type"] == "") - return true; - return false; -} - -bool Response::_checkError404() { - struct stat buffer; - if (stat(this->_response.fullURI.c_str(), &buffer) != 0) { - this->_status = HttpStatus::NOT_FOUND; - return true; - } - return false; -} - -// TODO: fix this function, verify where need to return true or false -bool Response::_error405() { - const ServerConfig &server = this->_config; - t_request request = this->_request.getRequest(); - - this->_response.statusLine = "HTTP/1.1 405 Method Not Allowed"; - if (server.server_name == trim(request.headers["Host"])) { - if (server.error_pages.find(405) != server.error_pages.end()) - this->_generateBody((std::string &)server.error_pages.at(405)); - else { - std::string path("/web/405.html"); - this->_generateBody(path); - } - return true; // verify if here is true or false - } - return false; // verify if it's true or false too -} - -void Response::_identifyCGI() { - t_request request = this->_request.getRequest(); - ServerConfig server = this->_config; - for (size_t j = 0; j < server.locations.size(); j++) { - if (request.uri.find(server.locations[j].path) != std::string::npos) { - for (size_t k = 0; k < server.locations[j].cgi.size(); k++) { - if (request.uri.find(server.locations[j].cgi[k].extension) != - std::string::npos) { - this->_location = server.locations[j].root; - this->_response.isCGI = true; - return; - } - } - } - } - this->_response.isCGI = false; -} - -void Response::_executeCgi() { - std::string script_path = this->_request.getRequest().uri; - pid_t pid = fork(); - script_path = this->_location.substr(1) + script_path; - int fd; - - if (pid < 0) { - perror("Fork failed"); - return; - } - - if (pid == 0) { - std::string executablePath; - if (endsWith(script_path, ".py")) { - if (isInterpreterInstalled("python3")) - executablePath = PY_PATH; - } else if (endsWith(script_path, ".go")) { - if (isInterpreterInstalled("go")) - executablePath = GO_PATH; - } else if (endsWith(script_path, ".php")) { - if (isInterpreterInstalled("php")) - executablePath = PHP_PATH; - } else { - OUTNL("Not a valid CGI"); - } - - // Redirect stdout to the client socket - fd = open("temp", O_WRONLY | O_CREAT | O_TRUNC, 0644); - dup2(fd, STDOUT_FILENO); - - // Execute the CGI script - char *args[] = {const_cast(executablePath.c_str()), - const_cast(script_path.c_str()), NULL}; - std::cerr << "Chegou aqui\n"; - execve(args[0], args, NULL); - - // If execve fails - perror("execve failed"); - close(fd); - exit(1); - } else { - // Parent process - // Wait for the child process to finish - waitpid(pid, NULL, 0); - std::string path("temp"); - this->_generateBody(path); - std::remove("temp"); - } -} diff --git a/src/ResponseUtils.cpp b/src/ResponseUtils.cpp deleted file mode 100644 index d620621..0000000 --- a/src/ResponseUtils.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "../include/Response.hpp" - -bool endsWith(const std::string &str, const std::string &suffix) { - if (suffix.size() > str.size()) - return false; - return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; -} - -bool isInterpreterInstalled(const char *command) { - // User system() to check if the interpreter is installed - std::string cmd = command; - - cmd = std::string("which ") + command + " > /dev/null 2>&1"; - int success = system(cmd.c_str()); - return (success == 0); -} diff --git a/src/Server.cpp b/src/Server.cpp deleted file mode 100644 index e8f7398..0000000 --- a/src/Server.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* Server.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/06/27 10:40:35 by bmoretti #+# #+# */ -/* Updated: 2024/08/17 16:21:49 bbbnivicius ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "../include/Server.hpp" - -Server::Server(const ServerConfig &config, int epoll_fd, epoll_event *event) : _config(config) -{ - this->_status = HttpStatus::ZERO; - this->_address = config.address; - this->_port = config.port; - this->_server_fd = -1; - this->_epoll_fd = epoll_fd; - this->_event = event; - this->_initServer(); - OUTNL(MAGENTA("Ready to connect in: " << _address + ":" << _port)); -} - -Server::~Server() -{ - if (_server_fd != -1) - close(_server_fd); - for (std::map::iterator it = _clients.begin(); it != _clients.end(); ++it) - { - delete it->second; - _clients.erase(it); - break; - } -} - -bool Server::_acceptClient() -{ - Client *client = new Client(this->_server_fd); - - int client_fd = client->_getClientSocket(); - - (*_event).events = EPOLLIN | EPOLLET; - (*_event).data.fd = client_fd; - if (epoll_ctl(this->_epoll_fd, EPOLL_CTL_ADD, client_fd, _event) == -1) - { - perror("epoll_ctl failed"); - close(client_fd); - } - this->_clients[client_fd] = client; - return true; -} - -bool Server::_handleAcceptError(int error_code) -{ - if (error_code == EAGAIN || error_code == EWOULDBLOCK) - return false; - else - { - std::cerr << "Failed to accept client connection" << std::endl; - return false; - } - return true; -} - -bool endsWithCRLF(const std::string &str) -{ - const std::string crlf = "\r\n\r\n"; - if (str.length() >= crlf.length()) - return str.substr(str.length() - crlf.length()) == crlf; - return false; -} - -void Server::_handleConnection(int client_fd) -{ - char buffer[BUFFER_SIZE + 1]; - - ssize_t bytes_read = _readFromClient(client_fd, buffer); - if (bytes_read > 0) - { - buffer[bytes_read] = '\0'; - this->_clients[client_fd]->_addToBuffer(buffer); - } - if (endsWithCRLF(this->_clients[client_fd]->_getBuffer())) - { - Request req(this->_clients[client_fd]->_getBuffer()); - Response resp(req, this->_config); - int flags = MSG_NOSIGNAL | MSG_DONTWAIT | MSG_MORE; - size_t size = resp.getResponse().size(); - send(client_fd, resp.getResponse().c_str(), size, flags); - this->_clients[client_fd]->clearBuff(); - } -} - -void Server::_setSocketNonBlocking(int fd) -{ - int flags = 1; - if (ioctl(fd, FIONBIO, &flags) < 0) - throw std::runtime_error("Failed to set socket non-blocking"); -} - -bool Server::_isClientConnected(int fd) -{ - return this->_clients.find(fd) != this->_clients.end(); -} - -int Server::_getServerFd() const -{ - return this->_server_fd; -} diff --git a/src/ServerUtils.cpp b/src/ServerUtils.cpp deleted file mode 100644 index f1933e2..0000000 --- a/src/ServerUtils.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "../include/Server.hpp" - -void Server::_fillBuffer(int fd, const char *str) -{ - std::string buff(str); - if (this->_buffer_request.find(fd) != this->_buffer_request.end()) - this->_buffer_request[fd] += buff; - else - { - if (buff.find("HTTP/1.1") == std::string::npos) - { - this->_status = HttpStatus::BAD_REQUEST; - return; - } - this->_buffer_request[fd] = buff; - } -} - -bool Server::_checkEndMessage(int fd) -{ - std::string &str = this->_buffer_request[fd]; - return (str.find("\r\n\r\n") != (std::string::npos)); -} - -void Server::_printOnClient(int fd, std::string const &str) -{ - ssize_t bytes_written = write(fd, str.c_str(), str.length()); - if (bytes_written == -1) - std::cerr << "Write error" << std::endl; - this->_buffer_request.erase(fd); - this->_status = HttpStatus::ZERO; -} - -ssize_t Server::_readFromClient(int fd, char *buff) -{ - ssize_t bytes_read = read(fd, buff, BUFFER_SIZE - 1); - if (bytes_read == 0) - close(fd); - return (bytes_read); -} diff --git a/src/main.cpp b/src/main.cpp index dffcaf7..f70df72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,21 +1,22 @@ -#include "../include/Server.hpp" -#include "../include/Config.hpp" -#include "../include/Events.hpp" +// +// Created by vinicius on 11/2/24. +// -int main(int ac, char **av) + +#include +#include "common.hpp" +#include "parser_config_file/check_file.h" + +int main(int argc, char* argv[]) { - std::string file; + std::string configuration_file; + + if(argc < 2) + configuration_file = DEFAULT_CONFIG_FILE; + else + configuration_file = argv[1]; + + check_file(configuration_file); - ac == 2 ? file = av[1] : file = DEFAULT_CONFIG_FILE; - try - { - Config config(file); - Events events(config.getServers()); - events.run(); - } - catch (std::exception &e) - { - std::cerr << RED("Error: ") << e.what() << std::endl; - } - return 0; + return EXIT_SUCCESS; } diff --git a/src/parser_config_file/check_file.cpp b/src/parser_config_file/check_file.cpp new file mode 100644 index 0000000..ebe53fa --- /dev/null +++ b/src/parser_config_file/check_file.cpp @@ -0,0 +1,26 @@ +// +// Created by vinicius on 11/2/24. +// + +#include "check_file.h" + +#include +#include +#include + +void check_file(std::string fileName) +{ + if (!fopen(fileName.c_str(), "r")) + { + std::cerr << "Configuration file does not exist." << std::endl; + exit(0); + } + + std::ifstream file(fileName.c_str()); + file.seekg(0, std::ios::end); + if (file.tellg() == 0) + { + std::cerr << "Configuration file is empty." << std::endl; + exit(0); + } +} \ No newline at end of file diff --git a/src/parser_config_file/check_file.h b/src/parser_config_file/check_file.h new file mode 100644 index 0000000..fb5c734 --- /dev/null +++ b/src/parser_config_file/check_file.h @@ -0,0 +1,11 @@ +// +// Created by vinicius on 11/2/24. +// + +#ifndef CHECK_FILE_H +#define CHECK_FILE_H + +#include +void check_file(std::string fileName); + +#endif //CHECK_FILE_H diff --git a/src/utils.cpp b/src/utils.cpp deleted file mode 100644 index fb0ce2f..0000000 --- a/src/utils.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "common.hpp" - -std::string itoa(int value) -{ - std::string str; - std::stringstream ss; - ss << value; - ss >> str; - return str; -} - -std::string trim(const std::string &str) -{ - size_t first = 0; - size_t last = str.size() - 1; - - while (first <= last && std::isspace(str[first])) - ++first; - while (last >= first && std::isspace(str[last])) - --last; - if (first > last) - return ""; - return str.substr(first, last - first + 1); -} - -std::vector split(const std::string &str, char delimiter) -{ - std::vector tokens; - std::string token; - std::istringstream tokenStream(str); - - while (std::getline(tokenStream, token, delimiter)) - { - tokens.push_back(token); - } - - return tokens; -} diff --git a/tests/alternativeConfParser.cpp b/tests/alternativeConfParser.cpp deleted file mode 100644 index 06f7a9d..0000000 --- a/tests/alternativeConfParser.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include -#include - -struct Location -{ - std::string path; - std::map directives; -}; - -struct Server -{ - std::string server_name; - std::string listen; - std::map directives; - std::vector locations; -}; - -struct NginxConfig -{ - std::vector servers; -}; - -class NginxParser -{ -public: - NginxConfig parseConfig(const std::string &filename) - { - std::ifstream file(filename.c_str()); - NginxConfig config; - std::string line; - Server currentServer; - Location currentLocation; - bool inServerBlock = false; - bool inLocationBlock = false; - - while (std::getline(file, line)) - { - line = trim(line); - - if (line.empty() || line[0] == '#') - continue; // Skip comments - if (line == "server {") - { - inServerBlock = true; - currentServer = Server(); - } - else if (line == "}") - { - if (inLocationBlock) - { - currentServer.locations.push_back(currentLocation); - inLocationBlock = false; - } - else if (inServerBlock) - { - config.servers.push_back(currentServer); - inServerBlock = false; - } - } - else if (line.find("location") == 0) - { - inLocationBlock = true; - currentLocation = Location(); - currentLocation.path = line.substr(9, line.find("{") - 9); - currentLocation.path = trim(currentLocation.path); - } - else if (inLocationBlock) - { - size_t pos = line.find(' '); - std::string directive = line.substr(0, pos); - std::string value = trim(line.substr(pos + 1)); - currentLocation.directives[directive] = value; - } - else if (inServerBlock) - { - size_t pos = line.find(' '); - std::string directive = line.substr(0, pos); - std::string value = trim(line.substr(pos + 1)); - if (directive == "server_name") - currentServer.server_name = value; - else if (directive == "listen") - currentServer.listen = value; - else - currentServer.directives[directive] = value; - } - } - return config; - } - -private: - std::string trim(const std::string &s) - { - size_t start = s.find_first_not_of(" \t"); - size_t end = s.find_last_not_of(" \t"); - return (start == std::string::npos) ? "" : s.substr(start, end - start + 1); - } -}; - -int main() -{ - NginxParser parser; - NginxConfig config = parser.parseConfig("empty.conf"); - - for (size_t i = 0; i < config.servers.size(); ++i) - { - const Server &server = config.servers[i]; - std::cout << "Server " << i + 1 << ":\n"; - std::cout << " server_name: " << server.server_name << "\n"; - std::cout << " listen: " << server.listen << "\n"; - for (std::map::const_iterator it = server.directives.begin(); it != server.directives.end(); ++it) - std::cout << " " << it->first << ": " << it->second << "\n"; - for (size_t j = 0; j < server.locations.size(); ++j) - { - const Location &location = server.locations[j]; - std::cout << " Location " << j + 1 << ": " << location.path << "\n"; - for (std::map::const_iterator it = location.directives.begin(); it != location.directives.end(); ++it) - std::cout << " " << it->first << ": " << it->second << "\n"; - } - } - return 0; -} diff --git a/tests/main.cpp b/tests/main.cpp deleted file mode 100644 index 486fa8b..0000000 --- a/tests/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -TEST(SampleTest, AssertionTrue) { ASSERT_TRUE(true); } - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/monolito.cpp b/tests/monolito.cpp deleted file mode 100644 index ec2a0e1..0000000 --- a/tests/monolito.cpp +++ /dev/null @@ -1,321 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Configuration Class -class Configuration { -public: - Configuration(); - bool loadFromFile(const std::string& filename); - - std::vector getPorts() const; - std::string getHost() const; - std::map getRoutes() const; - -private: - std::vector ports; - std::string host; - std::map routes; - - void parseLine(const std::string& line); - void addRoute(const std::string& path, const std::string& file); -}; - -Configuration::Configuration() : host("127.0.0.1") { - // Default values (host can be modified) -} - -bool Configuration::loadFromFile(const std::string& filename) { - std::ifstream file(filename); - if (!file.is_open()) { - std::cerr << "Could not open configuration file: " << filename << std::endl; - return false; - } - - std::string line; - while (std::getline(file, line)) { - parseLine(line); - } - - file.close(); - return true; -} - -void Configuration::parseLine(const std::string& line) { - std::istringstream iss(line); - std::string key, value; - - if (!(iss >> key >> value)) { - return; // Skip empty or malformed lines - } - - if (key == "port") { - ports.push_back(std::stoi(value)); - } else if (key == "host") { - host = value; - } else if (key == "route") { - std::string path, file; - iss >> path >> file; - addRoute(path, file); - } -} - -void Configuration::addRoute(const std::string& path, const std::string& file) { - routes[path] = file; -} - -std::vector Configuration::getPorts() const { - return ports; -} - -std::string Configuration::getHost() const { - return host; -} - -std::map Configuration::getRoutes() const { - return routes; -} - -// Server Class -class Server { -public: - Server(const Configuration& config); - void setup(); - void run(); - -private: - void createSockets(); - void bindSockets(); - void setupEventLoop(); - void handleIncomingConnections(int server_fd); - void handleRequest(int client_fd); - void sendResponse(int client_fd, const std::string& response); - void serveStaticContent(int client_fd, const std::string& file_path); - void throwError(int client_fd, int error_code, const std::string& message); - std::string readFile(const std::string& file_path); - - std::vector server_fds; // Vector of server sockets - int epoll_fd; - std::vector ports; // List of ports - std::string host; - std::map routes; - std::vector events; -}; - -Server::Server(const Configuration& config) : events(10) { - ports = config.getPorts(); // Retrieve multiple ports from configuration - host = config.getHost(); - routes = config.getRoutes(); -} - -void Server::setup() { - createSockets(); - bindSockets(); - setupEventLoop(); -} - -void Server::createSockets() { - for (int port : ports) { - int server_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - if (server_fd < 0) { - throw std::runtime_error("Socket creation failed for port " + std::to_string(port)); - } - server_fds.push_back(server_fd); - } -} - -void Server::bindSockets() { - for (size_t i = 0; i < server_fds.size(); ++i) { - int server_fd = server_fds[i]; - int port = ports[i]; - - sockaddr_in address; - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(port); - - if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { - throw std::runtime_error("Bind failed for port " + std::to_string(port)); - } - - if (listen(server_fd, 10) < 0) { - throw std::runtime_error("Listen failed for port " + std::to_string(port)); - } - - std::cout << "Server listening on " << host << ":" << port << std::endl; - } -} - -void Server::setupEventLoop() { - epoll_fd = epoll_create1(0); - if (epoll_fd < 0) { - throw std::runtime_error("Epoll creation failed"); - } - - for (int server_fd : server_fds) { - struct epoll_event event; - event.events = EPOLLIN; - event.data.fd = server_fd; - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0) { - throw std::runtime_error("Epoll control failed for server socket"); - } - } -} - -void Server::run() { - while (true) { - int event_count = epoll_wait(epoll_fd, events.data(), events.size(), -1); - if (event_count < 0) { - throw std::runtime_error("Epoll wait failed"); - } - - for (int i = 0; i < event_count; ++i) { - int event_fd = events[i].data.fd; - - bool is_server_fd = false; - for (int server_fd : server_fds) { - if (event_fd == server_fd) { - is_server_fd = true; - break; - } - } - - if (is_server_fd) { - handleIncomingConnections(event_fd); - } else { - handleRequest(event_fd); - } - } - } -} - -void Server::handleIncomingConnections(int server_fd) { - sockaddr_in client_address; - socklen_t client_len = sizeof(client_address); - int client_fd = accept(server_fd, (struct sockaddr *)&client_address, &client_len); - - if (client_fd < 0) { - std::cerr << "Failed to accept client connection" << std::endl; - return; - } - - fcntl(client_fd, F_SETFL, O_NONBLOCK); - - struct epoll_event event; - event.events = EPOLLIN | EPOLLET; - event.data.fd = client_fd; - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) < 0) { - close(client_fd); - throw std::runtime_error("Failed to add client to epoll"); - } - - std::cout << "New client connected on port: " << server_fd << std::endl; -} - -void Server::handleRequest(int client_fd) { - char buffer[1024]; - int bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); - - if (bytes_read <= 0) { - epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr); - close(client_fd); - std::cout << "Client disconnected: " << client_fd << std::endl; - return; - } - - buffer[bytes_read] = '\0'; - std::string request(buffer); - std::cout << "Request received:\n" << request << std::endl; - - // Parse HTTP request and determine action - if (request.find("GET") == 0) { - std::string request_path = request.substr(4, request.find(" ", 4) - 4); - std::cout << "this is the request path " << request_path << std::endl; - - if (routes.find(request_path) != routes.end()) { - serveStaticContent(client_fd, routes[request_path]); - } else { - throwError(client_fd, 404, "File Not Found"); - } - } else { - throwError(client_fd, 501, "Not Implemented"); - } -} - -void Server::serveStaticContent(int client_fd, const std::string& file_path) { - std::string content = readFile(file_path); - std::cout << "this is the path " << file_path << std::endl; - - if (content.empty()) { - throwError(client_fd, 404, "File Not Found"); - return; - } - - std::string response = "HTTP/1.1 200 OK\r\n"; - response += "Content-Length: " + std::to_string(content.size()) + "\r\n"; - response += "Content-Type: text/html\r\n"; - response += "\r\n"; - response += content; - - sendResponse(client_fd, response); -} - -void Server::sendResponse(int client_fd, const std::string& response) { - send(client_fd, response.c_str(), response.size(), 0); -} - -void Server::throwError(int client_fd, int error_code, const std::string& message) { - std::string response = "HTTP/1.1 " + std::to_string(error_code) + " " + message + "\r\n"; - response += "Content-Length: " + std::to_string(message.size()) + "\r\n"; - response += "Content-Type: text/plain\r\n"; - response += "\r\n"; - response += message; - - sendResponse(client_fd, response); - epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr); - close(client_fd); -} - -std::string Server::readFile(const std::string& file_path) { - std::ifstream file(file_path, std::ios::in | std::ios::binary); - if (!file) { - return ""; - } - - std::ostringstream content; - content << file.rdbuf(); - file.close(); - return content.str(); -} - -// Main function -int main() { - Configuration config; - if (!config.loadFromFile("server.conf")) { - std::cerr << "Failed to load configuration" << std::endl; - return 1; - } - - try { - Server server(config); - server.setup(); - server.run(); - } catch (const std::exception& e) { - std::cerr << "Server error: " << e.what() << std::endl; - return 1; - } - - return 0; -} diff --git a/tests/nonblk.cpp b/tests/nonblk.cpp deleted file mode 100644 index 152edf5..0000000 --- a/tests/nonblk.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Function to create and configure the server socket -int create_server_socket(int port) -{ - int server_fd; - struct sockaddr_in address; - - // Creating socket file descriptor - if ((server_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) == 0) - { - perror("socket failed"); - exit(EXIT_FAILURE); - } - - // Forcefully attaching socket to the port - int opt = 1; - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) - { - perror("setsockopt failed"); - exit(EXIT_FAILURE); - } - - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(port); - - // Bind the socket to the network address and port - if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) - { - perror("bind failed"); - exit(EXIT_FAILURE); - } - - // Start listening on the socket - if (listen(server_fd, 10) < 0) - { - perror("listen failed"); - exit(EXIT_FAILURE); - } - - return server_fd; -} - -// Function to set a file descriptor to non-blocking mode using ioctl -void set_socket_non_blocking(int fd) -{ - int flags = 1; - if (ioctl(fd, FIONBIO, &flags) < 0) - { - perror("ioctl failed"); - exit(EXIT_FAILURE); - } -} - -// Function to handle incoming connections -void handle_connections(int server_fd) -{ - int epoll_fd = epoll_create1(0); - if (epoll_fd == -1) - { - perror("epoll_create1 failed"); - exit(EXIT_FAILURE); - } - - struct epoll_event event; - event.events = EPOLLIN; - event.data.fd = server_fd; - - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) - { - perror("epoll_ctl failed"); - exit(EXIT_FAILURE); - } - - struct epoll_event events[10]; - while (true) - { - int n = epoll_wait(epoll_fd, events, 10, -1); - for (int i = 0; i < n; i++) - { - if (events[i].data.fd == server_fd) - { - std::cout << "Incoming connection" << std::endl; - struct sockaddr_in client_address; - socklen_t client_len = sizeof(client_address); - int client_fd = accept(server_fd, (struct sockaddr *)&client_address, &client_len); - if (client_fd < 0) - { - perror("accept failed"); - continue; - } - - // Set the client socket to non-blocking - // fcntl(client_fd, F_SETFL, O_NONBLOCK); - set_socket_non_blocking(client_fd); - - event.events = EPOLLIN | EPOLLET; - event.data.fd = client_fd; - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) == -1) - { - perror("epoll_ctl failed"); - close(client_fd); - } - } - else - { - std::cout << "Incoming data" << std::endl; - char buffer[1024] = {0}; - int client_fd = events[i].data.fd; - int bytes_read = read(client_fd, buffer, sizeof(buffer)); - - if (bytes_read > 0) - { - std::cout << "Received request:\n" - << buffer << std::endl; - - // Check if it's a GET request - if (strncmp(buffer, "GET", 3) == 0) - { - const char *response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello, World!"; - send(client_fd, response, strlen(response), 0); - } - } - - close(client_fd); - } - } - } - close(epoll_fd); -} - -// Main function to run the server -int main() -{ - int server_fd = create_server_socket(8042); // Use the desired port - std::cout << "Server is listening on port 8042" << std::endl; - handle_connections(server_fd); - - close(server_fd); - return 0; -} diff --git a/tests/server.conf b/tests/server.conf deleted file mode 100644 index 79fa08d..0000000 --- a/tests/server.conf +++ /dev/null @@ -1,5 +0,0 @@ -port 8080 -port 8081 -host 127.0.0.1 -route ../web/index.html - diff --git a/tests/testConfig.cpp b/tests/testConfig.cpp deleted file mode 100644 index da27577..0000000 --- a/tests/testConfig.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "../include/Config.hpp" - -TEST(ConfigTest, ConstructorSetsFilePath) -{ - Config config("test_default.conf"); - EXPECT_EQ(config.getServerAddress(), "127.0.0.1"); // Example expectation based on your config file -} - -TEST(ConfigTest, ParseConfigFilePopulatesServers) -{ - Config config("test_default.conf"); - EXPECT_GT(config.getServers().size(), 0); // Expect at least one server configuration -} diff --git a/tests/testItoa.cpp b/tests/testItoa.cpp deleted file mode 100644 index fa856f5..0000000 --- a/tests/testItoa.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "../include/common.hpp" -#include - -TEST(ItoaTest, ZeroValue) { - EXPECT_EQ(itoa(0), "0"); -} - -TEST(ItoaTest, PositiveValues) { - EXPECT_EQ(itoa(123), "123"); - EXPECT_EQ(itoa(4567), "4567"); - EXPECT_EQ(itoa(98765), "98765"); -} - -TEST(ItoaTest, NegativeValues) { - EXPECT_EQ(itoa(-123), "-123"); - EXPECT_EQ(itoa(-4567), "-4567"); - EXPECT_EQ(itoa(-98765), "-98765"); -} - -TEST(ItoaTest, LargeValues) { - EXPECT_EQ(itoa(2147483647), "2147483647"); // Maximum positive int - EXPECT_EQ(itoa(-2147483648), "-2147483648"); // Minimum negative int (implementation-dependent) -} diff --git a/tests/testParser.cpp b/tests/testParser.cpp deleted file mode 100644 index 86285a9..0000000 --- a/tests/testParser.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// #include "../include/Parser.hpp" -// #include -// #include -// #include -// #include -// #include - - -// class testParser : public ::testing::Test -// { -// protected: -// Parser* parser; -// std::thread parserThread; - -// virtual void SetUp() {} - -// virtual void TearDown() {} -// }; - -// TEST(ParserTest, EmptyInput) -// { -// Parser parser(""); -// t_request request = parser.getRequest(); -// EXPECT_EQ(request.method, ""); -// EXPECT_EQ(request.uri, ""); -// EXPECT_EQ(request.headers.size(), 0); -// } - -// TEST(ParserTest, SingleLineRequest) -// { -// Parser parser("GET /index.html"); -// t_request request = parser.getRequest(); -// EXPECT_EQ(request.method, "GET"); -// EXPECT_EQ(request.uri, "/index.html"); -// EXPECT_EQ(request.headers.size(), 0); -// } - -// TEST(ParserTest, RequestWithHeaders) -// { -// const char* requestStr = "GET /about HTTP/1.1\r\n" -// "Host: example.com\r\n" -// "Connection: keep-alive\r\n\r\n"; -// Parser parser(requestStr); -// t_request request = parser.getRequest(); -// EXPECT_EQ(request.method, "GET"); -// EXPECT_EQ(request.uri, "/about"); -// EXPECT_EQ(request.headers.size(), 2); -// EXPECT_EQ(request.headers["Host"], "example.com"); -// EXPECT_EQ(request.headers["Connection"], "keep-alive"); -// } - -// TEST(ParserTest, EmptyLineAfterHeaders) -// { -// const char* requestStr = "GET /contact\r\n" -// "Content-Length: 100\r\n" -// "\r\n"; -// Parser parser(requestStr); -// t_request request = parser.getRequest(); -// EXPECT_EQ(request.method, "GET"); -// EXPECT_EQ(request.uri, "/contact"); -// EXPECT_EQ(request.headers.size(), 1); -// EXPECT_EQ(request.headers["Content-Length"], "100"); -// } diff --git a/tests/testRequest.cpp b/tests/testRequest.cpp deleted file mode 100644 index 6684e99..0000000 --- a/tests/testRequest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "Request.hpp" - -TEST(RequestTest, ParseSimpleGetRequest) { - const char * requestStr = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; - Request request(requestStr); - t_request parsedRequest = request.getRequest(); - - EXPECT_EQ(parsedRequest.method, "GET"); - EXPECT_EQ(parsedRequest.uri, "/index.html"); - ASSERT_EQ(parsedRequest.headers.size(), 1); - EXPECT_EQ(parsedRequest.headers["Host"], "example.com"); -} - -TEST(RequestTest, ParseRequestWithMultipleHeaders) { - const char * requestStr = "POST /submit HTTP/1.1\r\nHost: example.com\r\nContent-Length: 27\r\n\r\n"; - Request request(requestStr); - t_request parsedRequest = request.getRequest(); - - EXPECT_EQ(parsedRequest.method, "POST"); - EXPECT_EQ(parsedRequest.uri, "/submit"); - ASSERT_EQ(parsedRequest.headers.size(), 2); - EXPECT_EQ(parsedRequest.headers["Host"], "example.com"); - EXPECT_EQ(parsedRequest.headers["Content-Length"], "27"); -} diff --git a/tests/testResponse.hpp b/tests/testResponse.hpp deleted file mode 100644 index d3a97ec..0000000 --- a/tests/testResponse.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include "../include/Response.hpp" -#include "../include/Request.hpp" - -class ResponseTest : public ::testing::Test { -protected: - void SetUp() override { - const char * requestStr = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; - request = new Request(requestStr); - response = new Response(*request); - } - - void TearDown() override { - delete response; - delete request; - } - - Request *request; - Response *response; -}; - -TEST_F(ResponseTest, GenerateResponse) { - std::string responseStr = response->getResponse(); - EXPECT_NE(responseStr.find("HTTP/1.1 200 OK"), std::string::npos); - EXPECT_NE(responseStr.find("Content-Type: text/html"), std::string::npos); - EXPECT_NE(responseStr.find("Content-Length"), std::string::npos); - EXPECT_NE(responseStr.find(""), std::string::npos); // Assuming your index.html has tag -} diff --git a/tests/testServer.cpp b/tests/testServer.cpp deleted file mode 100644 index 77a8c99..0000000 --- a/tests/testServer.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#include "../include/Server.hpp" -#include -#include -#include -#include -#include -#include -#include - -class ServerTest : public ::testing::Test { -protected: - Server* server; - std::thread serverThread; - - virtual void SetUp() { - server = new Server("127.0.0.1", PORT); - serverThread = std::thread([this]() { - server->run(); - }); - // Give the server a moment to start up - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - virtual void TearDown() { - // Stop the server thread - if (serverThread.joinable()) { - serverThread.detach(); - } - delete server; - } -}; - -TEST_F(ServerTest, ServerStartsSuccessfully) { - // Test if the server starts and listens successfully - int sock = socket(AF_INET, SOCK_STREAM, 0); - ASSERT_NE(sock, -1); - - sockaddr_in server_addr; - memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - server_addr.sin_port = htons(PORT); - - int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); - ASSERT_NE(result, -1); - - close(sock); -} - -// TEST_F(ServerTest, ServerHandlesClientConnection) { -// // Test if the server can handle a client connection -// int sock = socket(AF_INET, SOCK_STREAM, 0); -// ASSERT_NE(sock, -1); - -// sockaddr_in server_addr; -// memset(&server_addr, 0, sizeof(server_addr)); -// server_addr.sin_family = AF_INET; -// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -// server_addr.sin_port = htons(PORT); - -// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); -// ASSERT_NE(result, -1); - -// const char* message = "Hello Server"; -// send(sock, message, strlen(message), 0); - -// char buffer[BUFFER_SIZE]; -// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); -// ASSERT_GT(bytes_received, 0); - -// buffer[bytes_received] = '\0'; -// std::string response(buffer); -// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); - -// close(sock); -// } - -// TEST_F(ServerTest, HandlesMultipleClientConnections) { -// const int num_clients = 5; -// int client_socks[num_clients]; - -// for (int i = 0; i < num_clients; ++i) { -// client_socks[i] = socket(AF_INET, SOCK_STREAM, 0); -// ASSERT_NE(client_socks[i], -1); - -// sockaddr_in server_addr; -// memset(&server_addr, 0, sizeof(server_addr)); -// server_addr.sin_family = AF_INET; -// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -// server_addr.sin_port = htons(PORT); - -// int result = connect(client_socks[i], (struct sockaddr*)&server_addr, sizeof(server_addr)); -// ASSERT_NE(result, -1); -// } - -// for (int i = 0; i < num_clients; ++i) { -// const char* message = "Hello Server"; -// send(client_socks[i], message, strlen(message), 0); - -// char buffer[BUFFER_SIZE]; -// int bytes_received = recv(client_socks[i], buffer, sizeof(buffer) - 1, 0); -// ASSERT_GT(bytes_received, 0); - -// buffer[bytes_received] = '\0'; -// std::string response(buffer); -// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); - -// close(client_socks[i]); -// } -// } - -// TEST_F(ServerTest, HandlesInvalidClientConnections) { -// int sock = socket(AF_INET, SOCK_STREAM, 0); -// ASSERT_NE(sock, -1); - -// sockaddr_in server_addr; -// memset(&server_addr, 0, sizeof(server_addr)); -// server_addr.sin_family = AF_INET; -// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -// server_addr.sin_port = htons(PORT); - -// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); -// ASSERT_NE(result, -1); - -// const char* message = ""; -// send(sock, message, strlen(message), 0); - -// char buffer[BUFFER_SIZE]; -// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); -// ASSERT_EQ(bytes_received, 0); - -// close(sock); -// } - -// TEST_F(ServerTest, HandlesServerShutdown) { -// serverThread.detach(); // Detach the thread to simulate shutdown -// delete server; // Delete the server instance to simulate shutdown - -// // Attempt to connect after shutdown -// int sock = socket(AF_INET, SOCK_STREAM, 0); -// ASSERT_NE(sock, -1); - -// sockaddr_in server_addr; -// memset(&server_addr, 0, sizeof(server_addr)); -// server_addr.sin_family = AF_INET; -// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -// server_addr.sin_port = htons(PORT); - -// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); -// ASSERT_EQ(result, -1); // Connection should fail - -// close(sock); -// } - -// TEST_F(ServerTest, NonBlockingBehavior) { -// int sock = socket(AF_INET, SOCK_STREAM, 0); -// ASSERT_NE(sock, -1); - -// sockaddr_in server_addr; -// memset(&server_addr, 0, sizeof(server_addr)); -// server_addr.sin_family = AF_INET; -// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -// server_addr.sin_port = htons(PORT); - -// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); -// ASSERT_NE(result, -1); - -// const char* message = "Hello Server"; -// send(sock, message, strlen(message), 0); - -// char buffer[1024]; -// int flags = fcntl(sock, F_GETFL, 0); -// ASSERT_NE(flags, -1); -// fcntl(sock, F_SETFL, flags | O_NONBLOCK); - -// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); -// if (bytes_received == -1) { -// ASSERT_EQ(errno, EAGAIN); -// } else { -// ASSERT_GT(bytes_received, 0); -// } -// close(sock); -// } - -// // tests/test_Server.cpp (continuation) -// TEST_F(ServerTest, HandlesLargePayload) { -// int sock = socket(AF_INET, SOCK_STREAM, 0); -// ASSERT_NE(sock, -1); - -// sockaddr_in server_addr; -// memset(&server_addr, 0, sizeof(server_addr)); -// server_addr.sin_family = AF_INET; -// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -// server_addr.sin_port = htons(8080); - -// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); -// ASSERT_NE(result, -1); - -// std::string large_message(10000, 'A'); -// send(sock, large_message.c_str(), large_message.size(), 0); - -// char buffer[1024]; -// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); -// ASSERT_GT(bytes_received, 0); - -// buffer[bytes_received] = '\0'; -// std::string response(buffer); -// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); - -// close(sock); -// } - -// TEST_F(ServerTest, EdgeTriggeredEvents) { -// int sock = socket(AF_INET, SOCK_STREAM, 0); -// ASSERT_NE(sock, -1); - -// sockaddr_in server_addr; -// memset(&server_addr, 0, sizeof(server_addr)); -// server_addr.sin_family = AF_INET; -// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); -// server_addr.sin_port = htons(8080); - -// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); -// ASSERT_NE(result, -1); - -// const char* message = "Hello Server"; -// send(sock, message, strlen(message), 0); - -// char buffer[1024]; -// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); -// ASSERT_GT(bytes_received, 0); - -// buffer[bytes_received] = '\0'; -// std::string response(buffer); -// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); - -// send(sock, message, strlen(message), 0); -// bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); -// ASSERT_GT(bytes_received, 0); - -// buffer[bytes_received] = '\0'; -// response = std::string(buffer); -// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); - -// close(sock); -// } diff --git a/tests/test_default.conf b/tests/test_default.conf deleted file mode 100644 index f40f229..0000000 --- a/tests/test_default.conf +++ /dev/null @@ -1,14 +0,0 @@ -server { - server_name localhost; - listen 127.0.0.1:8042; - client_max_body_size 10M; - error_page 404 /404.html; - location / { - autoindex on; - root /var/www/html; - index index.html index.htm; - allow_methods GET POST; - cgi .php /usr/bin/php-cgi; - redirect /new-path; - } -} From 3a440198a0be1577675429725c88c548d6809f70 Mon Sep 17 00:00:00 2001 From: vinicius Date: Sat, 2 Nov 2024 18:36:00 -0300 Subject: [PATCH 09/16] chore: add parse and check for configuration file. --- .gitignore | 1 + config/default.conf | 63 ++-- src/main.cpp | 24 +- .../{check_file.cpp => CheckFile.cpp} | 4 +- src/parser_config_file/CheckFile.hpp | 11 + src/parser_config_file/ConfigParser.cpp | 322 ++++++++++++++++++ src/parser_config_file/ConfigParser.hpp | 45 +++ src/parser_config_file/ConfigTypes.hpp | 80 +++++ src/parser_config_file/check_file.h | 11 - 9 files changed, 507 insertions(+), 54 deletions(-) rename src/parser_config_file/{check_file.cpp => CheckFile.cpp} (86%) create mode 100644 src/parser_config_file/CheckFile.hpp create mode 100644 src/parser_config_file/ConfigParser.cpp create mode 100644 src/parser_config_file/ConfigParser.hpp create mode 100644 src/parser_config_file/ConfigTypes.hpp delete mode 100644 src/parser_config_file/check_file.h diff --git a/.gitignore b/.gitignore index aafba88..5c6cf2d 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,6 @@ bin/ build/ webserv +.idea diff --git a/config/default.conf b/config/default.conf index 43dd740..670c2de 100644 --- a/config/default.conf +++ b/config/default.conf @@ -1,49 +1,36 @@ -# First server block server { - host 127.0.0.1; - port 8080; - server_names example.com www.example.com; + host 127.0.0.1; + port 8080; + server_names example.com www.example.com; client_max_size 10M; error_pages { 404 /errors/404.html; 500 /errors/500.html; - 503 /errors/503.html; } - location /static { - methods GET POST DELETE; - root /var/www/static; - directory_list on; - index index.html; - } - - location /upload { - methods POST; - upload_path /var/www/uploads; - client_max_size 20M; # Override global setting - } - - location /api { - methods GET POST; - cgi on; - cgi_extension .php; - cgi_path /usr/bin/php-cgi; - root /var/www/api; + location / { + methods GET POST DELETE; + root /var/www/html; + directory_list on; + index index.html; + client_max_size 20M; + + cgi { + extension .php; + path /usr/bin/php-cgi; + } + + upload { + path /var/www/uploads; + max_size 5M; + } } -} - -# Second server block (different port) -server { - host 127.0.0.1; - port 8081; - server_names api.example.com; - client_max_size 5M; - location / { - methods GET; - root /var/www/html; - directory_list off; - index index.html; + location /redirect { + redirect { + code 301; + url /new-location; + } } -} +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f70df72..e4d0c46 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,19 +4,37 @@ #include +#include +#include + #include "common.hpp" -#include "parser_config_file/check_file.h" +#include "parser_config_file/CheckFile.hpp" +#include "parser_config_file/ConfigParser.hpp" int main(int argc, char* argv[]) { std::string configuration_file; - if(argc < 2) + if (argc < 2) configuration_file = DEFAULT_CONFIG_FILE; else configuration_file = argv[1]; - check_file(configuration_file); + CheckFile(configuration_file); + + try + { + ConfigParser parser; + std::vector servers = parser.parse(configuration_file); + + for (std::vector::const_iterator it = servers.begin(); it != servers.end(); ++it) + std::cout << "Server on port: " << it->port << std::endl; + } + catch (const ConfigParseError& e) + { + std::cerr << "Error on line " << e.getLine() << ": " << e.what() << std::endl; + return EXIT_FAILURE; + } return EXIT_SUCCESS; } diff --git a/src/parser_config_file/check_file.cpp b/src/parser_config_file/CheckFile.cpp similarity index 86% rename from src/parser_config_file/check_file.cpp rename to src/parser_config_file/CheckFile.cpp index ebe53fa..40a7689 100644 --- a/src/parser_config_file/check_file.cpp +++ b/src/parser_config_file/CheckFile.cpp @@ -2,13 +2,13 @@ // Created by vinicius on 11/2/24. // -#include "check_file.h" +#include "CheckFile.hpp" #include #include #include -void check_file(std::string fileName) +void CheckFile(const std::string& fileName) { if (!fopen(fileName.c_str(), "r")) { diff --git a/src/parser_config_file/CheckFile.hpp b/src/parser_config_file/CheckFile.hpp new file mode 100644 index 0000000..83ab24a --- /dev/null +++ b/src/parser_config_file/CheckFile.hpp @@ -0,0 +1,11 @@ +// +// Created by vinicius on 11/2/24. +// + +#ifndef CHECKFILE_HPP +#define CHECKFILE_HPP + +#include +void CheckFile(const std::string &fileName); + +#endif //CHECKFILE_HPP diff --git a/src/parser_config_file/ConfigParser.cpp b/src/parser_config_file/ConfigParser.cpp new file mode 100644 index 0000000..69361d0 --- /dev/null +++ b/src/parser_config_file/ConfigParser.cpp @@ -0,0 +1,322 @@ +// +// Created by vinicius on 11/2/24. +// + +#include "ConfigParser.hpp" +#include +#include +#include +#include + +std::string ConfigParser::nextToken() +{ + skipWhitespace(); + + if (_file.eof()) + return ""; + + std::string token; + char c; + + _file.get(c); + if (c == '{' || c == '}' || c == ';') + { + token = c; + return token; + } + + _file.unget(); + while (_file.get(c) && !std::isspace(c) && c != '{' && c != '}' && c != ';') + token += c; + + if (!std::isspace(c)) + _file.unget(); + + return token; +} + +void ConfigParser::skipWhitespace() { + char c; + + while (_file.get(c)) + { + if (c == '#') + while (_file.get(c) && c != '\n') {} + if (c == '\n') + _line_number++; + if (!std::isspace(c)) + { + _file.unget(); + break; + } + } +} + +void ConfigParser::expectToken(const std::string& expected) +{ + const std::string token = nextToken(); + + if (token != expected) + { + const std::string error = "Expected '" + expected + "', got '" + token + "'"; + throw ConfigParseError(error, _line_number); + } +} + +std::string ConfigParser::parseString() { return nextToken(); } + +int ConfigParser::parseNumber() +{ + const std::string token = nextToken(); + std::istringstream iss(token); + int number; + if (!(iss >> number)) + throw ConfigParseError("Invalid number", _line_number); + return number; +} + +size_t ConfigParser::parseSize(const std::string& size_str) const +{ + const size_t len = size_str.length(); + if (len < 2) + throw ConfigParseError("Invalid size format", _line_number); + + const char unit = std::toupper(size_str[len - 1]); + const std::string number_str = size_str.substr(0, len - 1); + const size_t base = std::atol(number_str.c_str()); + + switch (unit) + { + case 'K': return base * 1024; + case 'M': return base * 1024 * 1024; + case 'G': return base * 1024 * 1024 * 1024; + default: + throw ConfigParseError("Invalid size unit (use K, M, or G)", _line_number); + } +} + +ConfigParser::ConfigParser() : _line_number() {} + +ConfigParser::~ConfigParser() {} + +std::vector ConfigParser::parseMethods() +{ + std::vector methods; + std::string method; + + while ((method = nextToken()) != ";") + { + if (!isValidMethod(method)) + throw ConfigParseError("Invalid HTTP method: " + method, _line_number); + methods.push_back(method); + } + _file.unget(); // Push back the semicolon + return methods; +} + +void ConfigParser::parseErrorPages(Server& server) +{ + expectToken("{"); + std::string token; + + while ((token = nextToken()) != "}") + { + if (isdigit(token[0])) + { + int code = std::atoi(token.c_str()); + const std::string path = parseString(); + server.error_pages[code] = path; + expectToken(";"); + } + else + throw ConfigParseError("Expected error code", _line_number); + } +} + +bool ConfigParser::isValidMethod(const std::string& method) +{ + return method == "GET" || + method == "POST" || + method == "DELETE"; +} + +void ConfigParser::parseCGI(Location& loc) { + expectToken("{"); + std::string token; + + while ((token = nextToken()) != "}") + { + if (token == "extension") + { + loc.cgi.extension = parseString(); + expectToken(";"); + } + else if (token == "path") + { + loc.cgi.path = parseString(); + expectToken(";"); + } + } + loc.cgi.enabled = true; +} + +void ConfigParser::parseUpload(Location& loc) { + expectToken("{"); + std::string token; + + while ((token = nextToken()) != "}") + { + if (token == "path") + { + loc.upload.path = parseString(); + expectToken(";"); + } + else if (token == "max_size") + { + std::string size_str = parseString(); + loc.upload.max_size = parseSize(size_str); + expectToken(";"); + } + } + loc.upload.enabled = true; +} + +void ConfigParser::parseRedirect(Location& loc) +{ + expectToken("{"); + std::string token; + + while ((token = nextToken()) != "}") + { + if (token == "code") + { + loc.redirect.code = parseNumber(); + expectToken(";"); + } + else if (token == "url") + { + loc.redirect.url = parseString(); + expectToken(";"); + } + } + loc.redirect.enabled = true; +} + +void ConfigParser::parseServer() +{ + Server server; + expectToken("{"); + + std::string token; + while ((token = nextToken()) != "}") + { + if (token == "host") + { + server.host = parseString(); + expectToken(";"); + } + else if (token == "port") + { + server.port = parseNumber(); + expectToken(";"); + } + else if (token == "location") + server.locations.push_back(parseLocation()); + else if (token == "error_pages") + parseErrorPages(server); + else if (token == "server_names") + { + std::string name; + while ((name = parseString()) != ";") + server.server_names.push_back(name); + } + else if (token == "client_max_size") + { + std::string size_str = parseString(); + server.client_max_size = parseSize(size_str); + expectToken(";"); + } + } + + _servers.push_back(server); +} +std::vector ConfigParser::parse(const std::string& filename) +{ + _file.open(filename.c_str()); + if (!_file.is_open()) + throw ConfigParseError("Cannot open config file", 0); + while (_file.good()) + { + std::string token = nextToken(); + if (token.empty()) + break; + if (token == "server") + parseServer(); + else + throw ConfigParseError("Expected 'server' block", _line_number); + } + validate(); + return _servers; +} + +void ConfigParser::validate() const { + if (_servers.empty()) + throw ConfigParseError("No server blocks found", 0); + + for (std::vector::const_iterator it = _servers.begin(); it != _servers.end(); ++it) + { + if (it->host.empty()) + throw ConfigParseError("Server host not specified", 0); + if (it->port <= 0 || it->port > 65535) + throw ConfigParseError("Invalid port number", 0); + if (it->locations.empty()) + throw ConfigParseError("No locations defined for server", 0); + } +} + +Location ConfigParser::parseLocation() +{ + Location loc; + loc.path = parseString(); + expectToken("{"); + + std::string token; + while ((token = nextToken()) != "}") + { + if (token == "methods") + { + loc.methods = parseMethods(); + expectToken(";"); + } + else if (token == "root") + { + loc.root = parseString(); + expectToken(";"); + } + else if (token == "directory_list") + { + std::string value = parseString(); + loc.directory_listing = (value == "on"); + expectToken(";"); + } + else if (token == "index") + { + loc.index_file = parseString(); + expectToken(";"); + } + else if (token == "cgi") + parseCGI(loc); + else if (token == "upload") + parseUpload(loc); + else if (token == "redirect") + parseRedirect(loc); + else if (token == "client_max_size") + { + std::string size_str = parseString(); + loc.client_max_size = parseSize(size_str); + expectToken(";"); + } + } + + return loc; +} diff --git a/src/parser_config_file/ConfigParser.hpp b/src/parser_config_file/ConfigParser.hpp new file mode 100644 index 0000000..87c6c98 --- /dev/null +++ b/src/parser_config_file/ConfigParser.hpp @@ -0,0 +1,45 @@ +// +// Created by vinicius on 11/2/24. +// + +// config_parser.hpp +#ifndef CONFIGPARSER_HPP +#define CONFIGPARSER_HPP + +#include +#include "ConfigTypes.hpp" + +class ConfigParser { +private: + std::vector _servers; + std::string _current_token; + size_t _line_number; + std::ifstream _file; + + // private methods + void parseServer(); + Location parseLocation(); + void parseErrorPages(Server& server); + std::string parseString(); + int parseNumber(); + std::vector parseMethods(); + + // utils methods + void expectToken(const std::string& expected); + std::string nextToken(); + void skipWhitespace(); + static bool isValidMethod(const std::string& method); + void parseCGI(Location& loc); + void parseUpload(Location& loc); + void parseRedirect(Location& loc); + size_t parseSize(const std::string& size_str) const; + +public: + ConfigParser(); + ~ConfigParser(); + + std::vector parse(const std::string& filename); + void validate() const; +}; + +#endif diff --git a/src/parser_config_file/ConfigTypes.hpp b/src/parser_config_file/ConfigTypes.hpp new file mode 100644 index 0000000..ddef137 --- /dev/null +++ b/src/parser_config_file/ConfigTypes.hpp @@ -0,0 +1,80 @@ +// +// Created by vinicius on 11/2/24. +// + +#ifndef CONFIGTYPES_HPP +#define CONFIGTYPES_HPP + +#include +#include +#include +#include + +class ConfigParseError : public std::exception { +private: + std::string _message; + size_t _line; + +public: + ConfigParseError(const std::string& msg, size_t line_number) + : _message(msg), _line(line_number) {} + + virtual ~ConfigParseError() throw() {} + + virtual const char* what() const throw() { + return _message.c_str(); + } + + size_t getLine() const { return _line; } +}; + +struct CGI { + bool enabled; + std::string extension; + std::string path; + + CGI() : enabled(false) {} +}; + +struct Upload { + bool enabled; + std::string path; + size_t max_size; + + Upload() : enabled(false), max_size(0) {} +}; + +struct Redirect { + bool enabled; + int code; + std::string url; + + Redirect() : enabled(false), code(301) {} +}; + +struct Location { + std::string path; + std::vector methods; + std::string root; + bool directory_listing; + std::string index_file; + CGI cgi; + Upload upload; + Redirect redirect; + size_t client_max_size; + + Location() : directory_listing(false), client_max_size(0) {} +}; + +struct Server { + std::string host; + int port; + std::vector server_names; + size_t client_max_size; + std::map error_pages; + std::vector locations; + + Server() : port(0), client_max_size(0) {} +}; + +#endif \ No newline at end of file diff --git a/src/parser_config_file/check_file.h b/src/parser_config_file/check_file.h deleted file mode 100644 index fb5c734..0000000 --- a/src/parser_config_file/check_file.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Created by vinicius on 11/2/24. -// - -#ifndef CHECK_FILE_H -#define CHECK_FILE_H - -#include -void check_file(std::string fileName); - -#endif //CHECK_FILE_H From 41080adf8c16dd0c30afcf872b60083cba3e05f9 Mon Sep 17 00:00:00 2001 From: vinicius Date: Sat, 2 Nov 2024 19:14:48 -0300 Subject: [PATCH 10/16] chore: added overload on `os` to structs of server --- .gitignore | 1 - src/main.cpp | 4 +- src/parser_config_file/ConfigTypes.hpp | 125 ++++++++++++++++++++++--- 3 files changed, 113 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 5c6cf2d..aafba88 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,5 @@ bin/ build/ webserv -.idea diff --git a/src/main.cpp b/src/main.cpp index e4d0c46..f0d7972 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "common.hpp" @@ -28,7 +29,8 @@ int main(int argc, char* argv[]) std::vector servers = parser.parse(configuration_file); for (std::vector::const_iterator it = servers.begin(); it != servers.end(); ++it) - std::cout << "Server on port: " << it->port << std::endl; + std::cout << *it << std::endl; + } catch (const ConfigParseError& e) { diff --git a/src/parser_config_file/ConfigTypes.hpp b/src/parser_config_file/ConfigTypes.hpp index ddef137..179de31 100644 --- a/src/parser_config_file/ConfigTypes.hpp +++ b/src/parser_config_file/ConfigTypes.hpp @@ -10,49 +10,89 @@ #include #include -class ConfigParseError : public std::exception { +class ConfigParseError : public std::exception +{ private: std::string _message; size_t _line; public: ConfigParseError(const std::string& msg, size_t line_number) - : _message(msg), _line(line_number) {} + : _message(msg), _line(line_number) + { + } - virtual ~ConfigParseError() throw() {} + virtual ~ConfigParseError() throw() + { + } - virtual const char* what() const throw() { + virtual const char* what() const throw() + { return _message.c_str(); } size_t getLine() const { return _line; } }; -struct CGI { +struct CGI +{ bool enabled; std::string extension; std::string path; - CGI() : enabled(false) {} + CGI() : enabled(false) + { + } + + friend std::ostream& operator<<(std::ostream& os, const CGI& cgi) + { + os << "CGI { enabled: " << (cgi.enabled ? "true" : "false") + << ", extension: " << cgi.extension + << ", path: " << cgi.path << " }"; + return os; + } }; -struct Upload { +struct Upload +{ bool enabled; std::string path; size_t max_size; - Upload() : enabled(false), max_size(0) {} + Upload() : enabled(false), max_size(0) + { + } + + friend std::ostream& operator<<(std::ostream& os, const Upload& upload) + { + os << "Upload { enabled: " << (upload.enabled ? "true" : "false") + << ", path: " << upload.path + << ", max_size: " << upload.max_size << " }"; + return os; + } }; -struct Redirect { +struct Redirect +{ bool enabled; int code; std::string url; - Redirect() : enabled(false), code(301) {} + Redirect() : enabled(false), code(301) + { + } + + friend std::ostream& operator<<(std::ostream& os, const Redirect& redirect) + { + os << "Redirect { enabled: " << (redirect.enabled ? "true" : "false") + << ", code: " << redirect.code + << ", url: " << redirect.url << " }"; + return os; + } }; -struct Location { +struct Location +{ std::string path; std::vector methods; std::string root; @@ -63,10 +103,35 @@ struct Location { Redirect redirect; size_t client_max_size; - Location() : directory_listing(false), client_max_size(0) {} + Location() : directory_listing(false), client_max_size(0) + { + } + + friend std::ostream& operator<<(std::ostream& os, const Location& location) + { + os << "Location {\n" + << " path: " << location.path << "\n" + << " methods: ["; + for (size_t i = 0; i < location.methods.size(); ++i) + { + os << location.methods[i]; + if (i < location.methods.size() - 1) os << ", "; + } + os << "]\n" + << " root: " << location.root << "\n" + << " directory_listing: " << (location.directory_listing ? "true" : "false") << "\n" + << " index_file: " << location.index_file << "\n" + << " cgi: " << location.cgi << "\n" + << " upload: " << location.upload << "\n" + << " redirect: " << location.redirect << "\n" + << " client_max_size: " << location.client_max_size << "\n" + << "}"; + return os; + } }; -struct Server { +struct Server +{ std::string host; int port; std::vector server_names; @@ -74,7 +139,37 @@ struct Server { std::map error_pages; std::vector locations; - Server() : port(0), client_max_size(0) {} + Server() : port(0), client_max_size(0) + { + } + + friend std::ostream& operator<<(std::ostream& os, const Server& server) + { + os << "Server {\n" + << " host: " << server.host << "\n" + << " port: " << server.port << "\n" + << " server_names: ["; + for (size_t i = 0; i < server.server_names.size(); ++i) + { + os << server.server_names[i]; + if (i < server.server_names.size() - 1) os << ", "; + } + os << "]\n" + << " client_max_size: " << server.client_max_size << "\n" + << " error_pages: {"; + for (std::map::const_iterator it = server.error_pages.begin(); it != server.error_pages.end(); ++it) + os << " " << page.first << ": " << page.second << ","; + os << " }\n" + << " locations: ["; + for (size_t i = 0; i < server.locations.size(); ++i) + { + os << server.locations[i]; + if (i < server.locations.size() - 1) os << ", "; + } + os << "]\n" + << "}"; + return os; + } }; -#endif \ No newline at end of file +#endif From 8f2bacce200e440996551dea8832b81f85fe182f Mon Sep 17 00:00:00 2001 From: vinicius Date: Sat, 2 Nov 2024 19:23:53 -0300 Subject: [PATCH 11/16] chore: added .idea in gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index aafba88..5c6cf2d 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,6 @@ bin/ build/ webserv +.idea From 07cb640563c86e61d25a45ec80b8c7c7d35371b4 Mon Sep 17 00:00:00 2001 From: vinicius Date: Fri, 15 Nov 2024 18:24:06 -0300 Subject: [PATCH 12/16] fix: change variable name to iterator's name --- src/parser_config_file/ConfigTypes.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser_config_file/ConfigTypes.hpp b/src/parser_config_file/ConfigTypes.hpp index 179de31..f7e6cad 100644 --- a/src/parser_config_file/ConfigTypes.hpp +++ b/src/parser_config_file/ConfigTypes.hpp @@ -158,7 +158,7 @@ struct Server << " client_max_size: " << server.client_max_size << "\n" << " error_pages: {"; for (std::map::const_iterator it = server.error_pages.begin(); it != server.error_pages.end(); ++it) - os << " " << page.first << ": " << page.second << ","; + os << " " << it->first << ": " << it->second << ","; os << " }\n" << " locations: ["; for (size_t i = 0; i < server.locations.size(); ++i) From b19dcaf1683f9dced8a2e82e390d9426ee9a5bb7 Mon Sep 17 00:00:00 2001 From: vinicius Date: Fri, 15 Nov 2024 18:56:01 -0300 Subject: [PATCH 13/16] fix: path to configuration file --- include/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/common.hpp b/include/common.hpp index 409173c..f0e045f 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -6,7 +6,7 @@ #define BUFFER_SIZE 1024 #define MAX_CONNECTIONS 5 #define MAX_EVENTS 10 -#define DEFAULT_CONFIG_FILE "../config/default.config" +#define DEFAULT_CONFIG_FILE "../config/default.conf" // Colors #define BOLD(text) "\033[1m" << text << "\033[0m" From e53622ab02433658129328fe0bf22496fa1ddf08 Mon Sep 17 00:00:00 2001 From: vinicius Date: Fri, 15 Nov 2024 18:57:03 -0300 Subject: [PATCH 14/16] feat: add ostream lib --- src/parser_config_file/ConfigTypes.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parser_config_file/ConfigTypes.hpp b/src/parser_config_file/ConfigTypes.hpp index f7e6cad..0f6bc77 100644 --- a/src/parser_config_file/ConfigTypes.hpp +++ b/src/parser_config_file/ConfigTypes.hpp @@ -9,6 +9,7 @@ #include #include #include +#include class ConfigParseError : public std::exception { From c55bb603b58114d1246800e029fb2ff22704d2ec Mon Sep 17 00:00:00 2001 From: vinicius Date: Fri, 15 Nov 2024 18:58:08 -0300 Subject: [PATCH 15/16] chore: add network and server setup. Fix makefile rules --- Makefile | 5 +- src/network/NetworkSetup.cpp | 99 ++++++++++++++++++++++++++++++++++++ src/network/NetworkSetup.hpp | 30 +++++++++++ src/server/Server.cpp | 62 ++++++++++++++++++++++ src/server/Server.hpp | 38 ++++++++++++++ 5 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 src/network/NetworkSetup.cpp create mode 100644 src/network/NetworkSetup.hpp create mode 100644 src/server/Server.cpp create mode 100644 src/server/Server.hpp diff --git a/Makefile b/Makefile index 14f2d08..22ca13f 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,4 @@ re: fclean all @echo "Rebuilding..." run: all - @./$(NAME) default.conf - -run2: all - @./$(NAME) arquivo.conf + @./$(NAME) config/default.conf \ No newline at end of file diff --git a/src/network/NetworkSetup.cpp b/src/network/NetworkSetup.cpp new file mode 100644 index 0000000..9a8489c --- /dev/null +++ b/src/network/NetworkSetup.cpp @@ -0,0 +1,99 @@ +// +// Created by vinicius on 11/3/24. +// + +#include "NetworkSetup.hpp" +#include +#include +#include +#include +#include +#include // for close() + +NetworkSetup::NetworkSetup() +{ +} + +NetworkSetup::~NetworkSetup() +{ + for (std::vector::iterator it = server_sockets.begin(); it != server_sockets.end(); ++it) + if (*it >= 0) + close(*it); +} + +bool NetworkSetup::setupServer(const std::string& host, int port) +{ + int server_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (server_fd < 0) + return false; + + // Allow reuse of address + const int opt = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) + { + close(server_fd); + return false; + } + + struct sockaddr_in address; + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; // Allow connections on any interface + + // If specific host is provided, use it + if (host != "0.0.0.0" && !host.empty()) + { + if (inet_pton(AF_INET, host.c_str(), &address.sin_addr) <= 0) + { + close(server_fd); + return false; + } + } + + // Bind socket to address and port + if (bind(server_fd, reinterpret_cast(&address), + sizeof(address)) < 0) + { + close(server_fd); + return false; + } + + // Start listening + if (listen(server_fd, SOMAXCONN) < 0) + { + close(server_fd); + return false; + } + + server_sockets.push_back(server_fd); + return true; +} + +int NetworkSetup::acceptConnection(int server_fd) +{ + struct sockaddr_in client_addr; + socklen_t addr_len = sizeof(client_addr); + + int client_fd = accept(server_fd, + reinterpret_cast(&client_addr), + &addr_len); + + // TODO: verify correct return if client_fd is equal to `-1` + if (client_fd < 0) + return -1; + + // Make client socket non-blocking + int flags = 1; + if (ioctl(client_fd, FIONBIO, &flags) < 0) + { + close(client_fd); + return -1; + } + + return client_fd; +} + +const std::vector& NetworkSetup::getServerSockets() const +{ + return server_sockets; +} \ No newline at end of file diff --git a/src/network/NetworkSetup.hpp b/src/network/NetworkSetup.hpp new file mode 100644 index 0000000..f44d2cd --- /dev/null +++ b/src/network/NetworkSetup.hpp @@ -0,0 +1,30 @@ +// +// Created by vinicius on 11/3/24. +// + +#ifndef NETWORKSETUP_HPP +#define NETWORKSETUP_HPP + +#include +#include + +class NetworkSetup +{ +private: + std::vector server_sockets; + +public: + NetworkSetup(); + ~NetworkSetup(); + + bool setupServer(const std::string& host, int port); + static int acceptConnection(int server_fd); + const std::vector& getServerSockets() const; + +private: + // Prevent copying + NetworkSetup(const NetworkSetup& other); + NetworkSetup& operator=(const NetworkSetup& other); +}; + +#endif // NETWORKSETUP_HPP \ No newline at end of file diff --git a/src/server/Server.cpp b/src/server/Server.cpp new file mode 100644 index 0000000..716aa9f --- /dev/null +++ b/src/server/Server.cpp @@ -0,0 +1,62 @@ +// +// Created by vinicius on 11/3/24. +// + +#include "Server.hpp" +#include + +Server_class::Server_class() : _is_running(false), port(0), client_max_size(0) {} + +Server_class::~Server_class() { + if (_is_running) { + stop(); + } +} + +bool Server_class::start() { + if (_is_running) { + return false; + } + + // Validate server configuration + if (host.empty() || port <= 0 || port > 65535) { + std::cerr << "Invalid server configuration" << std::endl; + return false; + } + + // Initialize network setup + if (!_network.setupServer(host, port)) { + std::cerr << "Failed to setup server on " << host << ":" << port << std::endl; + return false; + } + + _is_running = true; + return true; +} + +void Server_class::stop() { + _is_running = false; +} + +bool Server_class::isRunning() const { + return _is_running; +} + +int Server_class::acceptClient() { + if (!_is_running) { + return -1; + } + + const std::vector& sockets = _network.getServerSockets(); + if (sockets.empty()) { + return -1; + } + + // For now, we'll just use the first socket + // You might want to implement a more sophisticated approach for multiple sockets + return _network.acceptConnection(sockets[0]); +} + +const std::vector& Server_class::getServerSockets() const { + return _network.getServerSockets(); +} \ No newline at end of file diff --git a/src/server/Server.hpp b/src/server/Server.hpp new file mode 100644 index 0000000..b04ab3e --- /dev/null +++ b/src/server/Server.hpp @@ -0,0 +1,38 @@ +#ifndef SERVER_HPP +#define SERVER_HPP + +#include +#include +#include +#include +#include "../network/NetworkSetup.hpp" +#include "../parser_config_file/ConfigTypes.hpp" + +class Server_class +{ +private: + NetworkSetup _network; + bool _is_running; + Server_class(const Server_class& other); + Server_class& operator=(const Server_class& other); + +public: + std::string host; + int port; + std::vector server_names; + size_t client_max_size; + std::map error_pages; + std::vector locations; + + Server_class(); + ~Server_class(); + + bool start(); + void stop(); + bool isRunning() const; + int acceptClient(); + const std::vector& getServerSockets() const; + +}; + +#endif // SERVER_HPP \ No newline at end of file From feeb154d410455f673dd901786e63c52325346dd Mon Sep 17 00:00:00 2001 From: vinicius Date: Fri, 15 Nov 2024 19:21:15 -0300 Subject: [PATCH 16/16] chore: removed empty to size function --- src/server/Server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/Server.cpp b/src/server/Server.cpp index 716aa9f..4c15b5e 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -48,7 +48,7 @@ int Server_class::acceptClient() { } const std::vector& sockets = _network.getServerSockets(); - if (sockets.empty()) { + if (!sockets.size()) { return -1; }