diff --git a/Makefile b/Makefile index 6116405..dceb576 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # By: adjoly +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2024/10/25 16:09:27 by adjoly #+# #+# # -# Updated: 2025/01/21 13:13:53 by mmoussou ### ########.fr # +# Updated: 2025/02/03 16:43:32 by mmoussou ### ########.fr # # # # **************************************************************************** # @@ -18,6 +18,8 @@ CC = c++ OBJSDIR = obj/ +INCLUDES = ./includes + SRCS = $(shell find . -name '*.cpp') OBJS = $(addprefix $(OBJSDIR), $(SRCS:.cpp=.o)) @@ -38,12 +40,12 @@ endif all: $(NAME) $(NAME): $(OBJS) - @$(CC) $(FLAGS) -I . $(OBJS) -o $(NAME) + @$(CC) $(FLAGS) -I$(INCLUDES) $(OBJS) -o $(NAME) @printf "$(YELLOW)「✨」 feat($(NAME)): program compiled\n" $(OBJSDIR)%.o: %.cpp @mkdir -p $(@D) - @$(CC) $(FLAGS) -I . -c $< -o $@ + @$(CC) $(FLAGS) -I$(INCLUDES) -c $< -o $@ @printf "$(DELETE)$(GREEN)「🔨」 build($<): object compiled\n" clean: diff --git a/NORM.md b/NORM.md index 1692f68..931e93c 100644 --- a/NORM.md +++ b/NORM.md @@ -2,14 +2,14 @@ ## File Structure -- Header Files (.h): +- Header Files (.hpp/.h): - Include declarations of classes, functions, constants, and macros. - Use include guards or #pragma once to prevent multiple inclusions. - Source Files (.cpp): - Contain the implementation of functions and classes. ## Naming Conventions -- Variables: camelCase (e.g., int studentAge;) +- Variables: snake_case (e.g., int student_age;) - Functions: camelCase (e.g., void calculateSum();) - Classes: PascalCase (e.g., class UserAccount {};) - Constants: ALL_CAPS_SNAKE_CASE (e.g., const int MAX_SIZE = 100;) diff --git a/README.md b/README.md index 91961c5..af68a50 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # webserv -Webserv go brrrrr \ -This is the webserver you will see in all your life star this IMMIDIATELY otherwise we will come to your house +webserv go brrrrr \ +this is the webserver you will see in all your life, star this IMMEDIATELY otherwise we will come to your house ## license diff --git a/includes/requests/HttpIMessage.hpp b/includes/requests/HttpIMessage.hpp new file mode 100644 index 0000000..e72e361 --- /dev/null +++ b/includes/requests/HttpIMessage.hpp @@ -0,0 +1,45 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* HttpIMessage.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou +#include + +namespace webserv { +namespace http { + +class IMessage { +public: + virtual std::multimap getHeaders(void) const; + virtual std::string getBody(void) const; + + virtual void setHeaders(std::multimap const headers); + virtual void setBody(std::string const body); + + virtual void addHeader(std::string const key, std::string const value); + virtual void rmHeader(std::string const key); + + virtual std::string str(void) const = 0; + +protected: + std::multimap _headers; + std::string _body; + +}; + +} // -namespace http +} // -namespace webserv + +#endif // __WEBSERV_REQUESTS_HTTP_IMESSAGE_HPP__ diff --git a/includes/requests/HttpRequest.hpp b/includes/requests/HttpRequest.hpp new file mode 100644 index 0000000..830bfaa --- /dev/null +++ b/includes/requests/HttpRequest.hpp @@ -0,0 +1,85 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* HttpRequest.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou +#include +#include + +#include +#include + +namespace webserv { +namespace http { + +class IRequest: public http::IMessage { +public: + virtual void parse(std::string const &data) = 0; + virtual http::Response execute(void) = 0; + + std::string str(void) const; + + std::string getMethod(void) const; + std::string getTarget(void) const; + std::string getProtocol(void) const; + + void setMethod(std::string const method); + void setTarget(std::string const target); + void setProtocol(std::string const protocol); + +protected: + std::string _method; + std::string _target; + std::string _protocol; + +}; + +class Get: public http::IRequest { +public: + Get(void); + Get(std::string &data); + + void parse(std::string const &data); + + http::Response execute(void); + +}; + +class Post: public http::IRequest { +public: + Post(void); + Post(std::string &data); + + void parse(std::string const &data); + + http::Response execute(void); + +}; + +class Delete: public http::IRequest { +public: + Delete(void); + Delete(std::string &data); + + void parse(std::string const &data); + + http::Response execute(void); + +}; + +} // -namespace http +} // -namespace webserv + +#endif // __WEBSERV_REQUESTS_HTTP_REQUEST_HPP__ diff --git a/includes/requests/HttpResponse.hpp b/includes/requests/HttpResponse.hpp new file mode 100644 index 0000000..c9c7304 --- /dev/null +++ b/includes/requests/HttpResponse.hpp @@ -0,0 +1,48 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* HttpResponse.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou + +#include + +namespace webserv { +namespace http { + +class Response: public http::IMessage { +public: + Response(void); + + std::string getProtocol(void) const; + size_t getStatusCode(void) const; + std::string getStatusText(void) const; + + void setProtocol(std::string const protocol); + void setStatusCode(size_t const status_code); + void setStatusText(std::string const status_text); + + std::string str(void) const; + +private: + std::string _protocol; + size_t _status_code; + std::string _status_text; + +}; + +} // -namespace http +} // -namespace webserv + +#endif // __WEBSERV_REQUESTS_HTTP_RESPONSE_HPP__ diff --git a/src/webserv.cpp b/includes/requests/default.hpp similarity index 56% rename from src/webserv.cpp rename to includes/requests/default.hpp index b60c590..3c8763d 100644 --- a/src/webserv.cpp +++ b/includes/requests/default.hpp @@ -1,20 +1,22 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* webserv.cpp :+: :+: :+: */ +/* default.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: adjoly +#+ +:+ +#+ */ +/* By: mmoussou +#pragma once +#ifndef __WEBSERV_REQUESTS_DEFAULT_HPP__ +# define __WEBSERV_REQUESTS_DEFAULT_HPP__ -int main(int ac, char **av, char **env) { - (void)ac; - (void)av; - (void)env; - std::cout << "test" << std::endl; -} +#include +#include + +using namespace webserv; + +#endif // __WEBSERV_REQUESTS_DEFAULT_HPP__ diff --git a/includes/server/default.hpp b/includes/server/default.hpp new file mode 100644 index 0000000..1f956c6 --- /dev/null +++ b/includes/server/default.hpp @@ -0,0 +1,25 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* default.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou +#include +#include +#include +#include +#include +#include +#include +#include + +namespace webserv { + +} //-namespace webserv + +#endif // __WEBSERV_WEBSERV_HPP__ diff --git a/index.html b/index.html new file mode 100644 index 0000000..89abca8 --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + +

evilge

+ + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c718751 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,106 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou +#include + +#define PORT 8080 +#define BUFFER_SIZE 4096 + +int server_socket; + +void close_socket(int signal) +{ + close(server_socket); + exit(signal); +} + +int main() { + // handle ctrl-C to close server socket + if (signal(SIGINT, close_socket) == SIG_ERR) { + std::cerr << "Error registering signal handler!" << std::endl; + return 1; + } + + // create a socket + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket == -1) { + std::cerr << "Failed to create socket" << std::endl; + return 1; + } + + // prepare the server address + sockaddr_in server_address; + std::memset(&server_address, 0, sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = INADDR_ANY; + server_address.sin_port = htons(PORT); + + // bind the socket to the address + if (bind(server_socket, (sockaddr*)&server_address, sizeof(server_address)) == -1) { + std::cerr << "Failed to bind socket" << std::endl; + return 1; + } + + // listen for incoming connections + if (listen(server_socket, 5) == -1) { + std::cerr << "Failed to listen on socket" << std::endl; + return 1; + } + + std::cout << "Server is listening on port " << PORT << std::endl; + + while (true) { + // accept an incoming connection + sockaddr_in client_address; + socklen_t client_address_len = sizeof(client_address); + int client_socket = accept(server_socket, (sockaddr*)&client_address, &client_address_len); + if (client_socket == -1) { + std::cerr << "Failed to accept connection" << std::endl; + continue; + } + + // receive the HTTP request + char buffer[BUFFER_SIZE]; + std::memset(buffer, 0, BUFFER_SIZE); + ssize_t bytes_received = recv(client_socket, buffer, BUFFER_SIZE - 1, 0); + if (bytes_received == -1) { + std::cerr << "Failed to receive request" << std::endl; + close(client_socket); + continue; + } + + // parse the request + std::string received_data(buffer, bytes_received); + //HttpRequest request = parseRequest(received_data); + http::Get request(received_data); + + std::cout << "Received " << request.getMethod() << " request for " << request.getTarget() << std::endl; + + // handle the request + std::string response; + if (request.getMethod() == "GET") + { + response = request.execute().str(); + } + else + { + response = "HTTP/1.1 501 Not Implemented\r\nContent-Type: text/html\r\n\r\n

501 Not Implemented

"; + } + + send(client_socket, response.c_str(), response.length(), 0); + close(client_socket); + } + + close(server_socket); + return 0; +} diff --git a/src/requests_handling/HttpIMessage.cpp b/src/requests_handling/HttpIMessage.cpp new file mode 100644 index 0000000..0a1a85d --- /dev/null +++ b/src/requests_handling/HttpIMessage.cpp @@ -0,0 +1,45 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* HttpIMessage.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou + +using namespace webserv; + +std::multimap http::IMessage::getHeaders(void) const +{ + return (this->_headers); +} + +std::string http::IMessage::getBody(void) const +{ + return (this->_body); +} + +void http::IMessage::setHeaders(std::multimap const headers) +{ + this->_headers = headers; +} + +void http::IMessage::setBody(std::string const body) +{ + this->_body = body; +} + +void http::IMessage::addHeader(std::string const key, std::string const value) +{ + this->_headers.insert(std::make_pair(key, value)); +} + +void http::IMessage::rmHeader(std::string const key) +{ + this->_headers.erase(key); +} diff --git a/src/requests_handling/HttpRequests.cpp b/src/requests_handling/HttpRequests.cpp new file mode 100644 index 0000000..37ccdec --- /dev/null +++ b/src/requests_handling/HttpRequests.cpp @@ -0,0 +1,144 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* HttpRequests.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou + +using namespace webserv; + +std::string http::IRequest::str(void) const +{ + std::ostringstream response; + + response << this->_method << " " << this->_target << " " << this->_protocol; + response << "\r\n"; + + for (std::multimap::const_iterator it = this->_headers.begin(); it != this->_headers.end(); ++it) + response << it->first << ": " << it->second << "\r\n"; + + response << "\r\n"; + response << this->_body; + + return (response.str()); +} + +void parse(std::string const &data) { (void) data; } +http::Response execute(void) { return (http::Response()); } + +std::string http::IRequest::getMethod(void) const +{ + return (this->_method); +} + +std::string http::IRequest::getTarget(void) const +{ + return (this->_target); +} + +std::string http::IRequest::getProtocol(void) const +{ + return (this->_protocol); +} + +void http::IRequest::setMethod(std::string const method) +{ + this->_method = method; +} + +void http::IRequest::setTarget(std::string const target) +{ + this->_target = target; +} + +void http::IRequest::setProtocol(std::string const protocol) +{ + this->_protocol = protocol; +} + +// ------------------------------------------------------------------ + +http::Get::Get(void) +{ +} + +http::Get::Get(std::string &data) +{ + this->parse(data); +} + +void http::Get::parse(std::string const &data) +{ + std::istringstream stream(data); + std::string line; + + if (std::getline(stream, line)) + { + std::istringstream line_stream(line); + line_stream >> this->_method >> this->_target >> this->_protocol; + this->_target.insert(this->_target.begin(), '.'); + } + + while (std::getline(stream, line) && line != "\r") + { + size_t delimiter_index = line.find(':'); + if (delimiter_index != std::string::npos) + { + std::string key = line.substr(0, delimiter_index); + std::string value = line.substr(delimiter_index + 2); + this->_headers.insert(std::make_pair(key, value)); + } + } + + std::ostringstream body_stream; + while (std::getline(stream, line)) + body_stream << line << "\n"; + this->_body = body_stream.str(); + + /* + std::cout << "method: " << this->_method << std::endl; + std::cout << "target: " << this->_target << std::endl; + std::cout << "protocol: " << this->_protocol << std::endl; + std::cout << std::endl; + std::cout << "-- headers --" << std::endl; + for (std::map::const_iterator it = this->_headers.begin(); it != this->_headers.end(); ++it) + std::cout << it->first << ": " << it->second << std::endl; + std::cout << std::endl; + std::cout << "-- body --" << std::endl << this->_body << std::endl; + */ +} + +http::Response http::Get::execute(void) +{ + http::Response response; + + try + { + std::ifstream file(this->_target.c_str(), std::ios::binary); + response.setProtocol(this->_protocol); + response.setStatusCode(200); + response.setStatusText("OK"); + response.addHeader("Content-Type", "text/html"); + response.setBody(std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator())); + } + catch (...) + { + // TODO: replace with a predefined array of error pages + response.setProtocol(this->_protocol); + response.setStatusCode(404); + response.setStatusText("Not Found"); + response.addHeader("Content-Type", "text/html"); + response.setBody("nuh uh, get 404'd >:D"); + } + + return (response); +} + +// ------------------------------------------------------------------ diff --git a/src/requests_handling/HttpResponse.cpp b/src/requests_handling/HttpResponse.cpp new file mode 100644 index 0000000..5857f28 --- /dev/null +++ b/src/requests_handling/HttpResponse.cpp @@ -0,0 +1,70 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* HttpResponse.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mmoussou _protocol << " " << this->_status_code << " " << this->_status_text; + response << "\r\n"; + + for (std::multimap::const_iterator it = this->_headers.begin(); it != this->_headers.end(); ++it) + response << it->first << ": " << it->second << "\r\n"; + + response << "\r\n"; + response << this->_body; + + return (response.str()); +} + +std::string http::Response::getProtocol(void) const +{ + return (this->_protocol); +} + +size_t http::Response::getStatusCode(void) const +{ + return (this->_status_code); +} + +std::string http::Response::getStatusText(void) const +{ + return (this->_status_text); +} + +void http::Response::setProtocol(std::string const protocol) +{ + this->_protocol = protocol; +} + +void http::Response::setStatusCode(size_t const status_code) +{ + this->_status_code = status_code; +} + +void http::Response::setStatusText(std::string const status_text) +{ + this->_status_text = status_text; +}