├── .github └── workflows │ └── main.yml ├── .gitignore ├── Makefile ├── README.md ├── bin ├── auth.php ├── counetr.php ├── infinite.php ├── php-cgi ├── script.php ├── time.pl └── upload.html ├── conf └── file.conf ├── explanation ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── delete.jpg ├── fds.jpg ├── get.jpg └── post.jpg ├── includes ├── Client.hpp ├── Config.hpp ├── Handler.hpp ├── Server.hpp └── Shared.hpp ├── main.cpp ├── samples ├── 404_page │ ├── 404.html │ ├── css │ │ └── 404.css │ └── js │ │ └── 404.js ├── directoryListPage.html ├── errorPageSample.html ├── tst1 │ ├── LICENSE │ ├── README.md │ ├── hero.png │ └── index.html └── tst2 │ ├── LICENSE │ ├── README.md │ ├── bookmarks.js │ ├── favicon.png │ ├── index.html │ └── styles.css └── srcs ├── Cgi.cpp ├── Config.cpp ├── Handler.cpp ├── Server.cpp └── Shared.cpp /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: C++ Code Scan 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v2 16 | 17 | - name: Set up GCC 18 | uses: actions/setup-buildtools@v1 19 | with: 20 | tool: gcc 21 | version: 'latest' 22 | 23 | - name: Build 24 | run: | 25 | cd your_project_directory 26 | cmake. 27 | make 28 | 29 | - name: Initialize CodeQL 30 | uses: actions/setup-codeql@v1 31 | with: 32 | languages: "cpp" 33 | 34 | - name: Perform CodeQL Analysis 35 | uses: github/codeql-action/analyze@v1 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Subject.pdf 2 | ./Server 3 | Server 4 | *.o 5 | *.mp4 6 | */*.o 7 | .vscode 8 | *.dSYM 9 | .idea 10 | .DS_Store 11 | conf/ 12 | logs 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NAME = Webserv 2 | CC = c++ 3 | CFLAGS = -std=c++98 -Wall -Wextra -Werror 4 | MKFL = Makefile 5 | 6 | FILES = main.cpp \ 7 | srcs/Server.cpp \ 8 | srcs/Handler.cpp \ 9 | srcs/Shared.cpp \ 10 | srcs/Config.cpp \ 11 | srcs/Cgi.cpp \ 12 | 13 | HEADERS = includes/Server.hpp \ 14 | includes/Client.hpp \ 15 | includes/Shared.hpp \ 16 | includes/Config.hpp \ 17 | includes/Handler.hpp \ 18 | 19 | 20 | all : $(NAME) 21 | 22 | $(NAME): $(FILES) $(HEADERS) $(MKFL) 23 | $(CC) $(CFLAGS) $(FILES) -o $(NAME) 24 | 25 | clean: 26 | rm -f $(NAME) 27 | rm -rf Server.dSYM 28 | 29 | fclean: clean 30 | rm -f $(NAME) 31 | 32 | re: fclean all 33 | 34 | .PHONY : clean all fclean re 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Webserv 2 | Building a web server from scratch using C++, employing server analogy and implementing multiplexing using select() for better handling of simultaneous connections 3 | 4 | ## How web server works: 5 | Explaining how a web server works using a call center analogy 6 | 7 | * Imagine the server as a call center where clients can call in and request information or resources 8 | 9 |

10 | 11 | 12 | * Setting up for example a phone line for the call center. The server creates a socket to listen for incoming connections from clients. 13 | 14 |

15 | 16 | 17 | * Assigning a phone number to the call center's phone line. The server binds the socket to a specific IP address and port number so that clients can connect to it 18 | 19 |

20 | 21 | 22 | * Start listening for incoming connections it's like having the phone line open and available for incoming calls so the server listens for incoming connections from clients on the server socket, Now we do have multiple phone lines available for incoming calls the server creates an array of sockets ```fd_set``` to manage incoming connections from clients 23 | 24 |

25 | 26 | 27 | 28 | * Using the ```select``` function to monitor sockets this is like having a team of operators at the call center who can monitor incoming calls on multiple phone lines simultaneously.The server uses the select function to monitor the array of sockets ```fd_set``` and check for incoming connections or data from clients 29 | 30 |

31 | 32 | 33 | 34 | * Accepting incoming connections and adding them to an array of connected clients () so when a client connects to the server, the server accepts the connection and adds the client to an array of connected clients so that they are ready for I/O operations. 35 | 36 |

37 | 38 | 39 | * Using ```FD_ISSET``` to check which sockets have incoming data or connections waiting this is like having the operators at the call center use a caller ID system to see which callers are waiting on hold or have requested a callback, he server divides the handling of incoming data into two teams one for reading data from clients (incoming requests) and one for writing data to clients (sending responses). 40 | 41 |

42 | 43 | 44 | 45 | ********* 46 | 47 | 48 | Here are the macros used in combination with the select function to monitor one or more file descriptors for I/O 49 | 50 |

51 | 52 | 53 | 54 | ## DELETE Method Implementation : 55 | 56 | Implemented and explained by [TouFa7](https://github.com/toufa7) 57 | 58 | 59 |

60 | 61 | 62 | 63 | int stat (const char *filename, struct stat *buf); 64 | 65 | struct stat { 66 | st_mode; // S_ISREG, S_ISDIR 67 | { 68 | // File Permissions 69 | // { 70 | // S_IRUSR : Read 71 | // S_IWUSR : Write 72 | // S_IXUSR : Execute 73 | // } 74 | 75 | } 76 | st_size; // File size in bytes 77 | } 78 | 79 | https://www.mkssoftware.com/docs/man5/struct_stat.5.asp 80 | 81 | 82 | struct dirent *readdir(DIR *); 83 | struct dirent { 84 | d_type; // Type of file (DT_REG, DT_DIR) 85 | d_name[256]; // Filename 86 | } 87 | 88 | https://stackoverflow.com/questions/12991334/members-of-dirent-structure 89 | 90 | https://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html 91 | 92 | 93 | ## GET Method Implementation : 94 | 95 | Implemented and explained by [Ibranad](https://github.com/ibranad) 96 | 97 |

98 | 99 | 100 | 101 | ## POST Method Implementation : 102 | 103 | Implemented and explained by [Abouchfa](https://github.com/Abdeljalil-Bouchfar) 104 | 105 |

106 | 107 | 108 | 109 | # Resources 110 | 111 | https://www.gta.ufrj.br/ensino/eel878/sockets/index.html 112 | 113 | https://ipwithease.com/what-is-a-websocket/ 114 | 115 | https://stackoverflow.com/questions/6729366/what-is-the-difference-between-af-inet-and-pf-inet-in-socket-programming 116 | 117 | https://stackoverflow.com/questions/76412255/how-to-fix-error-141-when-using-select-and-send-in-c-web-server-for-multip/76413445 118 | 119 | https://stackoverflow.com/questions/5815675/what-is-sock-dgram-and-sock-stream 120 | 121 | 122 | 123 | ## TIPS: 124 | 125 | if you want to look for a manual of any function use this website mkssoftware/qnx (eg: mkssoftware select) 126 | -------------------------------------------------------------------------------- /bin/auth.php: -------------------------------------------------------------------------------- 1 | 50 | 51 |

52 | 53 |

54 |

Hello, !


55 |
avatar


56 |
57 |


58 |
Logout
59 |

60 | 61 |
62 | 63 | 64 | 65 | 66 |
67 | 68 |
-------------------------------------------------------------------------------- /bin/counetr.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | Increment Counter Example 17 | 18 | 19 |

Counter:

20 |
21 | 22 |
23 | 24 | -------------------------------------------------------------------------------- /bin/infinite.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bin/php-cgi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/bin/php-cgi -------------------------------------------------------------------------------- /bin/script.php: -------------------------------------------------------------------------------- 1 | $tmp_name ){ 8 | $file_name = $uploadedFiles['name'][$key]; 9 | $file_size = $uploadedFiles['size'][$key]; 10 | $file_tmp = $uploadedFiles['tmp_name'][$key]; 11 | $file_type= $uploadedFiles['type'][$key]; 12 | if($file_size > 2097152){ 13 | $errors[]='File size must be less than 2 MB'; 14 | } 15 | $uploadPath = $uploadDirectory . basename($file_name); 16 | if(empty($errors)==true){ 17 | if(move_uploaded_file($file_tmp,$uploadPath)){ 18 | echo "Successfully uploaded"; 19 | }else{ 20 | echo "Error uploading file"; 21 | } 22 | }else{ 23 | print_r($errors); 24 | } 25 | } 26 | } 27 | ?> 28 | -------------------------------------------------------------------------------- /bin/time.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use CGI; 5 | my $q = new CGI; 6 | my $timestamp = localtime; 7 | print $q->header( "text/html" ), 8 | $q->start_html( -title => "The Time", -bgcolor => "#ffffff" ), 9 | $q->h2( "Current Time" ), 10 | $q->hr, 11 | $q->p( "The current time according to this system is: ", $q->b( $timestamp ) ), 12 | $q->end_html; -------------------------------------------------------------------------------- /bin/upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PHP Form Example 5 | 6 | 7 |
8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /conf/file.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 10.11.3.1:8080; 3 | server_names ABOUCHFA; 4 | error_page 404 samples/404_page/404.html; 5 | client_body_size 1000000000; 6 | 7 | location / { 8 | root /Users/ibnada/goinfre; 9 | allow_methods GET POST DELETE; 10 | autoindex on; 11 | upload on; 12 | cgi .php bin/php-cgi; 13 | cgi .pl /usr/bin/perl; 14 | } 15 | 16 | location /delete { 17 | root /Users/ibnada/goinfre; 18 | allow_methods DELETE GET; 19 | autoindex on; 20 | cgi .php bin/php-cgi; 21 | cgi .pl /usr/bin/perl; 22 | upload off; 23 | } 24 | 25 | location /get { 26 | root /Users/ibnada/goinfre; 27 | allow_methods GET POST; 28 | autoindex on; 29 | cgi .php bin/php-cgi; 30 | cgi .pl /usr/bin/perl; 31 | upload off; 32 | } 33 | 34 | location /post { 35 | root /Users/ibnada/goinfre; 36 | allow_methods POST GET; 37 | autoindex on; 38 | cgi .php bin/php-cgi; 39 | cgi .pl /usr/bin/perl; 40 | upload on; 41 | } 42 | } -------------------------------------------------------------------------------- /explanation/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/1.jpg -------------------------------------------------------------------------------- /explanation/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/2.jpg -------------------------------------------------------------------------------- /explanation/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/3.jpg -------------------------------------------------------------------------------- /explanation/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/4.jpg -------------------------------------------------------------------------------- /explanation/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/5.jpg -------------------------------------------------------------------------------- /explanation/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/6.jpg -------------------------------------------------------------------------------- /explanation/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/7.jpg -------------------------------------------------------------------------------- /explanation/delete.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/delete.jpg -------------------------------------------------------------------------------- /explanation/fds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/fds.jpg -------------------------------------------------------------------------------- /explanation/get.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/get.jpg -------------------------------------------------------------------------------- /explanation/post.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/explanation/post.jpg -------------------------------------------------------------------------------- /includes/Client.hpp: -------------------------------------------------------------------------------- 1 | #include "Handler.hpp" 2 | #include "Config.hpp" 3 | #include "Shared.hpp" 4 | 5 | class Client 6 | { 7 | private: 8 | int _socket; 9 | public: 10 | Client() {}; 11 | ServerConfig _cltconfig; 12 | Handler _client_handler; 13 | Client(int socket) 14 | { 15 | _socket = socket; 16 | _client_handler.client_socket = socket; 17 | _client_handler.setData(); 18 | } 19 | int GetCltSocket() 20 | { 21 | return (this->_socket); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /includes/Config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "Shared.hpp" 11 | 12 | struct cgi 13 | { 14 | std::string type; 15 | std::string path; 16 | }; 17 | 18 | struct error_page 19 | { 20 | std::string code; 21 | std::string path; 22 | }; 23 | 24 | struct redirection 25 | { 26 | bool RedirectionFlag; 27 | std::string RedirectionCode; 28 | std::string RedirectionPath; 29 | }; 30 | 31 | class ServerLocation 32 | { 33 | protected: 34 | int _AutoIndex; 35 | int _Upload; 36 | cgi _CgiInfoPhp; 37 | cgi _CgiInfoPerl; 38 | redirection _RedirectionInfo; 39 | std::string _LocationPath; 40 | std::string _Root; 41 | // std::string _Upload; 42 | std::vector _AllowedMethodsVec; 43 | std::vector _IndexesVec; 44 | public: 45 | 46 | ServerLocation(); 47 | ~ServerLocation(); 48 | ServerLocation(const ServerLocation & ServerObj); 49 | ServerLocation & operator = (const ServerLocation & ServerObj); 50 | bool operator < (const ServerLocation & ServerObj); 51 | bool operator > (const ServerLocation & ServerObj); 52 | int GetAutoIndex(void); 53 | int GetUpload(void); 54 | cgi& GetCgiInfoPhp(void); 55 | cgi& GetCgiInfoPerl(void); 56 | redirection& GetRedirectionInfo(void); 57 | std::string GetLocationPath(void); 58 | std::string GetRoot(void); 59 | //std::string GetUpload(void); 60 | std::vector GetAllowedMethodsVec(void); 61 | std::vector GetIndexesVec(void); 62 | }; 63 | 64 | class ServerConfig : public ServerLocation 65 | { 66 | public: 67 | // int ; 68 | int _ServerSocket; 69 | unsigned int _Port; 70 | std::string _Host; 71 | std::string _ServerNames; 72 | std::string _ClientBodySize; 73 | std::vector _LocationsVec; 74 | std::map _ErrorPageMap; 75 | ServerConfig(); 76 | ~ServerConfig(); 77 | ServerConfig(const ServerConfig & ServerObj); 78 | ServerConfig & operator = (const ServerConfig & ServerObj); 79 | int GetServerSocket(void); 80 | unsigned int GetPort(void); 81 | std::string GetHost(void); 82 | std::string GetClientBodySize(void); 83 | std::string GetServerNames(void); 84 | void SetServerSocket(int socket); 85 | void ParseServerLocation(std::string location); 86 | void PrintServerLocation(unsigned int index); 87 | void setClientSocket(int n); 88 | std::vector& GetLocationsVec(void); 89 | std::map& GetErrorPageMap(void); 90 | void ParseErrorPage(std::string error_directive); 91 | }; 92 | 93 | class GlobalConfig 94 | { 95 | protected: 96 | unsigned int _ServerCount; 97 | std::vector _ServersConfigVec; 98 | public: 99 | GlobalConfig(); 100 | GlobalConfig(const GlobalConfig & ServerObj); 101 | GlobalConfig & operator = (const GlobalConfig & ServerObj); 102 | ~GlobalConfig(); 103 | void ParseConfigFile(char *av); 104 | void ParseServerConfig(std::string server); 105 | void PrintServerConfig(unsigned int index); 106 | void PrintServers(void); 107 | unsigned int GetServerCount(void); 108 | std::vector& GetServersVector(void); 109 | }; 110 | 111 | void InvalidConfigFile(std::string err_message); 112 | 113 | #endif -------------------------------------------------------------------------------- /includes/Handler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HANDLER_HPP 2 | #define HANDLER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "Shared.hpp" 16 | #include "Config.hpp" 17 | 18 | #define CHUNK_SIZE 1024 19 | 20 | class Handler 21 | { 22 | public: 23 | void setData(); 24 | std::string GetRootLocation(std::string uri, std::string locationPath, std::string root); 25 | int Driver(char *requested_data, int bytesreceived); 26 | void setConfig(ServerConfig &config); 27 | 28 | int _cgiTmpFilefd; 29 | int client_socket; 30 | int requested_file; 31 | std::string _cgiTmpFileName; 32 | std::map _req_header; 33 | 34 | private: 35 | Shared _shared; 36 | ServerConfig _config; 37 | ServerLocation _workingLocation; 38 | /* 39 | * Member Variables 40 | */ 41 | std::string _method; 42 | std::string _uri; // The Request-URI (Uniform Resource Identifier) 43 | std::string _path; 44 | std::string _postFilePath; 45 | std::string _querystring; 46 | std::string _chunkHex; 47 | int _chunkHexState; 48 | char buffer[CHUNK_SIZE]; 49 | int bytesread; 50 | int bytessent; 51 | int _postRecv; 52 | int _chunkSize; 53 | int _postFileFd; 54 | int _headerflag; 55 | int _cgiPid; 56 | 57 | 58 | /* 59 | * Member Functions 60 | */ 61 | int parseRequestHeader(char *req, int bytesreceived); 62 | int HandleGet(); 63 | int HandleDelete(); 64 | int HandlePost(char *body, int bytesreceived); 65 | int chunkedPost(char *body, int bytesreceived); 66 | int HandleCgi(std::string path, std::string method, cgi &cgitype); 67 | char **CgiSetEnv(std::string method); 68 | bool ValidateRequest(); 69 | bool MatchLocation(); 70 | bool ValidateURI(const std::string &uri); 71 | void SendResponseHeader(std::string statusCode, std::string fileExt, std::string location, int contentLength); 72 | void sendCodeResponse(std::string statusCode); 73 | void DeleteFile(const char *path); 74 | int DeleteDirectory(const char *path); 75 | std::string generateListDir(std::string statusCode, std::string ls); 76 | }; 77 | 78 | #endif -------------------------------------------------------------------------------- /includes/Server.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_H 2 | #define SERVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "Handler.hpp" 21 | #include "Config.hpp" 22 | #include "Client.hpp" 23 | 24 | #define CHUNK_SIZE 1024 25 | 26 | // Setuping and startig the server : Creating socket -> binding -> listening (Handling multiple clients) 27 | 28 | 29 | class Server 30 | { 31 | private: 32 | ServerConfig _config; 33 | std::list _clients; 34 | std::list::iterator itb; 35 | 36 | public: 37 | Server(){}; 38 | Server(ServerConfig &config); 39 | 40 | /* 41 | * Member Variables 42 | */ 43 | 44 | int server_socket; // The server listen on this socket 45 | int client_socket; // The server serve the client on this socket 46 | struct addrinfo server_infos; 47 | struct addrinfo *sinfo_ptr; 48 | struct sockaddr_storage storage_sock; 49 | socklen_t clt_addr; 50 | char requested_data[CHUNK_SIZE]; 51 | char buffer[CHUNK_SIZE]; 52 | int bytesread, bytessent, bytesreceived; 53 | fd_set readfds, writefds, tmpfdsread, tmpfdswrite; 54 | int maxfds, activity, active_clt; 55 | bool readyforwrite; 56 | struct timeval timeout_keep_alive; 57 | struct timeval timeout; 58 | 59 | /* 60 | * Member Functions 61 | */ 62 | void Init(); 63 | void Start(); 64 | void DropClient(); 65 | void CreateServer(); 66 | void SelectSetsInit(); 67 | int AcceptAddClientToSet(); 68 | }; 69 | 70 | #endif 71 | 72 | -------------------------------------------------------------------------------- /includes/Shared.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_HPP 2 | #define SHARED_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class Shared 12 | { 13 | public: 14 | Shared(); 15 | 16 | 17 | std::string generateFileName(const std::string& path, const std::string& fileExtension); 18 | 19 | std::map mime_types; 20 | std::map file_extensions; 21 | std::map status_codes; 22 | std::string fileExtention(std::string fileName); 23 | }; 24 | 25 | class Exceptions : public std::exception 26 | { 27 | std::string _error_message; 28 | public: 29 | Exceptions(std::string error_message); 30 | const char *what() const throw(); 31 | ~Exceptions() throw(); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "includes/Server.hpp" 2 | #include "includes/Handler.hpp" 3 | #include "includes/Config.hpp" 4 | 5 | int main(int ac, char **av) 6 | { 7 | // Seed the random number generator 8 | std::srand(time(NULL)); 9 | 10 | std::vector ports; 11 | std::vector::iterator it; 12 | 13 | GlobalConfig configuration; 14 | std::vector servers; 15 | char conf[17] = "conf/config.conf"; 16 | 17 | if (ac == 2) 18 | configuration.ParseConfigFile(av[1]); 19 | else 20 | configuration.ParseConfigFile(conf); 21 | for (size_t i = 0; i < configuration.GetServersVector().size(); i++) 22 | { 23 | Server WebServer(configuration.GetServersVector()[i]); 24 | WebServer.CreateServer(); 25 | WebServer.SelectSetsInit(); 26 | servers.push_back(WebServer); 27 | it = std::find(ports.begin(), ports.end(), configuration.GetServersVector()[i].GetPort()); 28 | if (it != ports.end()) 29 | { 30 | std::cout << "Already Used\n"; 31 | exit(0); 32 | } 33 | ports.push_back(configuration.GetServersVector()[i].GetPort()); 34 | } 35 | while (TRUE) 36 | { 37 | for (size_t i = 0; i < servers.size(); i++) 38 | { 39 | servers[i].Start(); 40 | } 41 | } 42 | return (0); 43 | } 44 | -------------------------------------------------------------------------------- /samples/404_page/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 Not Found 6 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

404

17 |

This page does not exist.

18 |
19 | 24 | 25 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /samples/404_page/css/404.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Roboto+Mono"); 2 | .text-center { 3 | position: absolute; 4 | width: 30%; 5 | border-radius: 2rem; 6 | height: calc(30%); 7 | top: calc((100% - 30%) / 2); 8 | text-align: center; 9 | left: calc((100% - 30% )/2); 10 | color: white; 11 | } 12 | .text-center h1 { 13 | font-size: 11em; 14 | font-family: "Roboto Mono", sans-serif; 15 | } 16 | .text-center h2 { 17 | font-family: "Roboto Mono", sans-serif; 18 | font-size: 2rem; 19 | margin: 0%; 20 | } 21 | -------------------------------------------------------------------------------- /samples/404_page/js/404.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | await loadPolygonPath(tsParticles); 3 | 4 | await tsParticles.load({ 5 | particles: { 6 | color: { 7 | value: "#FFFF00", 8 | animation: { 9 | enable: true, 10 | speed: 10, 11 | }, 12 | }, 13 | move: { 14 | attract: { 15 | enable: true, 16 | rotate: { 17 | distance: 100, 18 | x: 2000, 19 | y: 2000, 20 | }, 21 | }, 22 | direction: "none", 23 | enable: true, 24 | outModes: { 25 | default: "destroy", 26 | }, 27 | path: { 28 | clamp: true, 29 | enable: true, 30 | delay: { 31 | value: 0, 32 | }, 33 | generator: "polygonPathGenerator", 34 | options: { 35 | sides: 4, 36 | turnSteps: 30, 37 | angle: 0, 38 | }, 39 | }, 40 | random: true, 41 | speed: 15, 42 | straight: true, 43 | trail: { 44 | fillColor: "#000", 45 | length: 10, 46 | enable: true, 47 | }, 48 | }, 49 | number: { 50 | density: { 51 | enable: true, 52 | area: 800, 53 | }, 54 | value: 0, 55 | }, 56 | opacity: { 57 | value: 1, 58 | }, 59 | shape: { 60 | type: "square", 61 | }, 62 | size: { 63 | value: 4, 64 | }, 65 | }, 66 | background: { 67 | color: "#000", 68 | }, 69 | fullScreen: { 70 | zIndex: -1, 71 | }, 72 | emitters: [{ 73 | direction: "none", 74 | rate: { 75 | quantity: 10, 76 | delay: 0.25, 77 | }, 78 | size: { 79 | width: 0, 80 | height: 0, 81 | }, 82 | position: { 83 | x: 0, 84 | y: 0, 85 | }, 86 | },{ 87 | direction: "none", 88 | rate: { 89 | quantity: 10, 90 | delay: 0.25, 91 | }, 92 | size: { 93 | width: 0, 94 | height: 0, 95 | }, 96 | position: { 97 | x: 100, 98 | y: 100, 99 | }, 100 | },{ 101 | direction: "none", 102 | rate: { 103 | quantity: 10, 104 | delay: 0.25, 105 | }, 106 | size: { 107 | width: 0, 108 | height: 0, 109 | }, 110 | position: { 111 | x: 0, 112 | y: 100, 113 | }, 114 | },{ 115 | direction: "none", 116 | rate: { 117 | quantity: 10, 118 | delay: 0.25, 119 | }, 120 | size: { 121 | width: 0, 122 | height: 0, 123 | }, 124 | position: { 125 | x: 100, 126 | y: 0, 127 | }, 128 | },], 129 | }); 130 | })(); 131 | -------------------------------------------------------------------------------- /samples/directoryListPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Directory list 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /samples/errorPageSample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 45 | 51 | 52 | 53 |
54 |

55 | 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /samples/tst1/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tailwind Toolbox 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/tst1/README.md: -------------------------------------------------------------------------------- 1 | # [Tailwind Toolbox](https://www.tailwindtoolbox.com/) - [Landing Page Template](https://www.tailwindtoolbox.com/templates/landing-page) 2 | 3 | [Landing Page](https://www.tailwindtoolbox.com/templates/landing-page) is an open source, generic landing page template for [Tailwind CSS](https://tailwindcss.com/) created by [Tailwind Toolbox](https://www.tailwindtoolbox.com/). 4 | 5 | ![Landing Page](https://www.tailwindtoolbox.com/templates/landing-page.png) 6 | 7 | 8 | ## Getting Started 9 | 10 | Choose one of the following options to get started: 11 | * [Download the latest release](https://github.com/tailwindtoolbox/Landing-Page/archive/master.zip) 12 | * Clone the repo: `git clone https://github.com/tailwindtoolbox/Landing-Page.git` 13 | * Fork the repo 14 | 15 | ## Using the Template 16 | 17 | The template is just a HTML file using a full CDN hosted Tailwind CSS file. 18 | 19 | To get the best out of Tailwind CSS, you need to really start customising it. 20 | Take a look at our [setup guide](https://www.tailwindtoolbox.com/setup) to start tweaking! 21 | 22 | ## Sites created using this template 23 | 24 | * [AnonAddy.com](https://anonaddy.com) 25 | * [MentorCV.com](https://mentorcv.com) 26 | * [Nodewood.com](https://nodewood.com) 27 | * [X-Wing AI](https://xwing.app) 28 | * [Auto-Swiper](https://www.auto-swiper.ch) 29 | * [Hosted Git](https://hosted-git.com) 30 | * [Qiusheji](https://qiusheji.com) 31 | 32 | ## Bugs and Issues 33 | 34 | Have a bug or an issue with this template? [Open a new issue](https://github.com/tailwindtoolbox/Landing-Page/issues/new) here on GitHub. 35 | 36 | ## Creator 37 | 38 | [Tailwind Toolbox](https://www.tailwindtoolbox.com/) was created by and is maintained by **[Amrit Nagi](https://amritnagi.info/)**, Co-owner of [Astrava.Solutions](https://astrava.solutions). 39 | 40 | * https://twitter.com/tailwindtoolbox 41 | * https://twitter.com/amritnagi 42 | * https://github.com/tailwindtoolbox 43 | 44 | Tailwind Toolbox is based on the [Tailwind CSS](https://www.tailwindcss.com/) framework created by [Adam Wathan](https://twitter.com/adamwathan), [Jonathan Reinink](https://twitter.com/reinink), [David Hemphill](https://twitter.com/davidhemphill) and [Steve Schoger](https://twitter.com/steveschoger) 45 | 46 | 47 | ## Image Attribution 48 | 49 | [Hero vector created by freepik.com](https://www.freepik.com/free-vector/isometric-education-illustration_3940819.htm#page=1&query=isometric%20plane&position=1) 50 | 51 | Free for personal and commercial purpose with attribution 52 | 53 | ## Copyright and License 54 | 55 | Copyright 2018-2022 Astrava.Solutions Ltd. Code released under the MIT license. 56 | -------------------------------------------------------------------------------- /samples/tst1/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/samples/tst1/hero.png -------------------------------------------------------------------------------- /samples/tst1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Tailwind Starter Template - Landing Page Template: Tailwind Toolbox 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 70 | 71 |
72 |
73 | 74 |
75 |

What business are you?

76 |

77 | Main Hero Message to sell yourself! 78 |

79 |

80 | Sub-hero message, not too long and not too short. Make it just right! 81 |

82 | 85 |
86 | 87 |
88 | 89 |
90 |
91 |
92 |
93 | 94 | 95 | 96 | 97 | 101 | 102 | 103 | 104 | 107 | 108 | 109 | 110 |
111 |
112 |
113 |

114 | Title 115 |

116 |
117 |
118 |
119 |
120 |
121 |

122 | Lorem ipsum dolor sit amet 123 |

124 |

125 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at ipsum eu nunc commodo posuere et sit amet ligula. 126 |
127 |
128 | 129 | Images from: 130 | 131 | undraw.co 132 |

133 |
134 |
135 | 136 | travel booking 137 | 142 | 143 | 151 | 152 | 153 | 154 | 155 | 156 | 161 | 162 | 163 | 164 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 185 | 186 | 187 | 188 | 193 | 198 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 216 | 221 | 226 | 231 | 236 | 237 | 242 | 247 | 252 | 253 | 254 | 259 | 260 |
261 |
262 |
263 |
264 | 265 | connected world 266 | 271 | 276 | 281 | 282 | 287 | 292 | 297 | 302 | 307 | 312 | 317 | 322 | 327 | 332 | 337 | 342 | 347 | 352 | 357 | 362 | 367 | 372 | 377 | 382 | 387 | 396 | 405 | 406 | 407 | 408 | 409 | 410 | 411 |
412 |
413 |
414 |

415 | Lorem ipsum dolor sit amet 416 |

417 |

418 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam at ipsum eu nunc commodo posuere et sit amet ligula. 419 |
420 |
421 | Images from: 422 | 423 | undraw.co 424 |

425 |
426 |
427 |
428 |
429 |
430 |
431 | 505 |
506 |
507 |
508 |

509 | Pricing 510 |

511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 | Free 519 |
520 |
    521 |
  • Thing
  • 522 |
  • Thing
  • 523 |
  • Thing
  • 524 |
525 |
526 |
527 |
528 | £0 529 | for one user 530 |
531 |
532 | 535 |
536 |
537 |
538 |
539 |
540 |
Basic
541 |
542 |
    543 |
  • Thing
  • 544 |
  • Thing
  • 545 |
  • Thing
  • 546 |
  • Thing
  • 547 |
548 |
549 |
550 |
551 | £x.99 552 | / per user 553 |
554 |
555 | 558 |
559 |
560 |
561 |
562 |
563 |
564 | Pro 565 |
566 |
    567 |
  • Thing
  • 568 |
  • Thing
  • 569 |
  • Thing
  • 570 |
571 |
572 |
573 |
574 | £x.99 575 | / per user 576 |
577 |
578 | 581 |
582 |
583 |
584 |
585 |
586 |
587 | 588 | 589 | 590 | 591 | 592 | 595 | 596 | 597 | 598 | 599 | 603 | 604 | 605 | 606 | 607 | 608 | 609 |
610 |

611 | Call to Action 612 |

613 |
614 |
615 |
616 |

617 | Main Hero Message to sell yourself! 618 |

619 | 622 |
623 | 624 | 697 | 700 | 744 | 781 | 782 | 783 | -------------------------------------------------------------------------------- /samples/tst2/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Jared Jones 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/tst2/README.md: -------------------------------------------------------------------------------- 1 | # [Homepage](https://danggoodcode.com/startpage) 2 | 3 | ![homepage](https://i.redd.it/cbnzq36zj3601.gif) 4 | 5 | ## Customization 6 | 7 | ### Customize Bookmarks 8 | 9 | Bookmarks are now held in the `bookmarks.js` file for easy updating. `bookmarks` is an array of objects with a `title` and `links` property. The `title` defines what the header of the "bookmark section" box will be. `link` is an array of link objects each with a name and a url to link to. 10 | 11 | > The way the site is currently styled bookmarks should always have a length of `4` if you want to have more sections you need to change the `width` property of the css class `bookmark-set` 12 | 13 | ### Customize Search Engine 14 | 15 | You can change the search engine used by the search overlay by updating the url value stored in the `searchUrl` var in `index.html` to the correct string for your engine. 16 | 17 | Examples: 18 | 19 | - DuckDuckGo: `https://duckduckgo.com/?q=` 20 | - Bing: `https://www.bing.com/search?q=` 21 | 22 | ### Customize Styling 23 | 24 | Styles are handled through CSS variables. To update the colors you just need to change the variable definitions defined in `:root`. 25 | 26 | | Variable | default | description | 27 | | ------------------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------- | 28 | | `--bg` | `#5f4b8b` | Defines the body background color | 29 | | `--fg` | `#ffffff` | Defines the primary foreground (text) color for clock, weather, and titles | 30 | | `--secondaryFg` | `#b3b3b3` | Defines the foreground (text) color for links | 31 | | `--containerBg` | `#272727` | Defines the background color of the boxes | 32 | | `--searchBg` | `--containerBg` | Defines the background color of the search overlay | 33 | | `--scrollbarColor` | `#3f3f3f` | Defines the color of the custom scrollbars | 34 | | `--fontFamily` | `"Roboto Mono", monospace` | Defines the font used. To change to a custom font you will also have to import that font from whatever source is available | 35 | -------------------------------------------------------------------------------- /samples/tst2/bookmarks.js: -------------------------------------------------------------------------------- 1 | // Note: having length != 4 will mess with layout based on how the site is styled 2 | const bookmarks = [ 3 | { 4 | title: "Daily", 5 | links: [ 6 | { name: "Inbox", url: "https://inbox.google.com" }, 7 | { name: "GitHub", url: "https://github.com" }, 8 | { name: "Drive", url: "https://drive.google.com" }, 9 | ], 10 | }, 11 | { 12 | title: "Media", 13 | links: [ 14 | { name: "Youtube", url: "https://youtube.com" }, 15 | { name: "Netflix", url: "https://netflix.com" }, 16 | { name: "Crunchyroll", url: "https://crunchyroll.com" }, 17 | { 18 | name: "Amazon Prime", 19 | url: "https://www.amazon.com/Amazon-Video", 20 | }, 21 | ], 22 | }, 23 | { 24 | title: "Reddit", 25 | links: [ 26 | { name: "/r/overwatch", url: "https://reddit.com/r/overwatch" }, 27 | { 28 | name: "/r/pcmasterrace", 29 | url: "https://reddit.com/r/pcmasterrace", 30 | }, 31 | { name: "/r/me_irl", url: "https://reddit.com/r/me_irl" }, 32 | { 33 | name: "/r/battlestations", 34 | url: "https://reddit.com/r/battlestations", 35 | }, 36 | { name: "/r/unixporn", url: "https://reddit.com/r/unixporn" }, 37 | { name: "/r/news", url: "https://reddit.com/r/news" }, 38 | ], 39 | }, 40 | { 41 | title: "Social", 42 | links: [ 43 | { name: "Twitter", url: "https://twitter.com" }, 44 | { name: "Facebook", url: "https://facebook.com" }, 45 | ], 46 | }, 47 | ]; -------------------------------------------------------------------------------- /samples/tst2/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toufa7/WebServer/30883826fc81794c9a40de9c9ee09c1a461f18e4/samples/tst2/favicon.png -------------------------------------------------------------------------------- /samples/tst2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Homepage 9 | 10 | 11 | 12 | 13 | 21 |
22 |
23 |
24 |
25 |
26 |
-
27 |
28 |
29 |
30 |
31 |
32 | 33 | 34 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /samples/tst2/styles.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Roboto+Mono'); 2 | 3 | :root { 4 | --bg: #5f4b8b; 5 | --fg: #ffffff; 6 | --secondaryFg: #b3b3b3; 7 | --containerBg: #272727; 8 | --searchBg: var(--containerBg); 9 | --scrollbarColor: #3f3f3f; 10 | --fontFamily: 'Roboto Mono', monospace; 11 | } 12 | 13 | body { 14 | background-color: var(--bg); 15 | margin: 0px; 16 | } 17 | 18 | .container { 19 | width: 100%; 20 | height: 100vh; 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | flex-direction: column; 25 | } 26 | 27 | #clock { 28 | font-family: sans-serif; 29 | font-size: 3.5rem; 30 | font-weight: 600; 31 | font-family: var(--fontFamily); 32 | color: var(--fg); 33 | margin-bottom: 0.25em; 34 | } 35 | 36 | #search { 37 | width: 100%; 38 | height: 100vh; 39 | background-color: var(--searchBg); 40 | display: none; 41 | position: absolute; 42 | box-sizing: border-box; 43 | flex-direction: column; 44 | align-items: center; 45 | justify-content: center; 46 | } 47 | 48 | #search-field { 49 | width: 90%; 50 | padding: 0.75em 1em; 51 | box-sizing: border-box; 52 | background-color: var(--searchBg); 53 | border: solid 0px var(--searchBg); 54 | font-family: var(--fontFamily); 55 | font-size: 4rem; 56 | color: var(--fg); 57 | outline: none; 58 | border-radius: 3px; 59 | margin-bottom: 1em; 60 | text-align: center; 61 | } 62 | 63 | .weather-container { 64 | width: 30%; 65 | background-color: var(--containerBg); 66 | padding: 1em; 67 | border-radius: 3px; 68 | font-family: var(--fontFamily); 69 | color: var(--fg); 70 | text-align: center; 71 | } 72 | .inline { 73 | display: inline-block; 74 | } 75 | 76 | #bookmark-container { 77 | display: flex; 78 | flex-direction: row; 79 | justify-content: center; 80 | width: 50%; 81 | margin: 1em 0em; 82 | } 83 | 84 | @media only screen and (max-width: 960px) { 85 | .container { 86 | height: auto; 87 | } 88 | #clock { 89 | margin-top: 1em; 90 | } 91 | .container > #bookmark-container { 92 | flex-direction: column; 93 | width: 60%; 94 | } 95 | #bookmark-container > .bookmark-set { 96 | width: auto; 97 | margin: 1em 0em; 98 | } 99 | } 100 | 101 | .bookmark-set { 102 | padding: 1em; 103 | background-color: var(--containerBg); 104 | border-radius: 3px; 105 | font-family: var(--fontFamily); 106 | font-size: 0.85rem; 107 | width: 25%; 108 | height: 12em; 109 | margin: 0em 0.5em; 110 | box-sizing: border-box; 111 | } 112 | 113 | .bookmark-inner-container { 114 | overflow-y: scroll; 115 | height: 80%; 116 | vertical-align: top; 117 | padding-right: 6px; 118 | box-sizing: border-box; 119 | 120 | scrollbar-width: thin; 121 | scrollbar-color: var(--scrollbarColor) #ffffff00; 122 | } 123 | 124 | .bookmark-inner-container::-webkit-scrollbar { 125 | width: 6px; 126 | } 127 | .bookmark-inner-container::-webkit-scrollbar-track { 128 | background: #ffffff00; 129 | } 130 | .bookmark-inner-container::-webkit-scrollbar-thumb { 131 | background-color: var(--scrollbarColor); 132 | border-radius: 6px; 133 | border: 3px solid #ffffff00; 134 | } 135 | 136 | .bookmark-title { 137 | font-size: 1.1rem; 138 | font-weight: 600; 139 | color: var(--fg); 140 | margin: 0em 0em 0.35em 0em; 141 | } 142 | .bookmark { 143 | text-decoration: none; 144 | color: var(--secondaryFg); 145 | display: block; 146 | margin: 0.5em 0em; 147 | } 148 | .bookmark:hover { 149 | color: var(--fg); 150 | } 151 | -------------------------------------------------------------------------------- /srcs/Cgi.cpp: -------------------------------------------------------------------------------- 1 | #include "../includes/Handler.hpp" 2 | 3 | std::string CgiHeaderFindStatus(std::string &Header) 4 | { 5 | int StatusPosition; 6 | std::string StatusString, StatusLocation, StatusCode; 7 | 8 | StatusPosition = Header.find("Status: "); 9 | if (StatusPosition < 0) 10 | return ("HTTP/1.1 200 OK\r\n"); 11 | else 12 | { 13 | StatusCode = Header.substr(StatusPosition + 8, 3); 14 | StatusPosition = Header.find("Location: "); 15 | if (StatusPosition >= 0) 16 | StatusLocation = Header.substr(StatusPosition + 10, (Header.find("\r\n", StatusPosition + 11) - (StatusPosition + 10))); 17 | StatusString = "HTTP/1.1 "; 18 | StatusString += StatusCode; 19 | StatusString += " "; 20 | StatusString += StatusLocation; 21 | } 22 | StatusString += "\r\n"; 23 | return (StatusString); 24 | } 25 | 26 | std::string CgiBodySize(int BodySize) 27 | { 28 | //cgi body size 29 | std::string ContentLenght; 30 | // struct stat FileStat; 31 | 32 | ContentLenght = "Content-Length: "; 33 | // int StatReturn = stat(tmpfilename.c_str(), &FileStat); 34 | // if (StatReturn == 0) 35 | ContentLenght += std::to_string((BodySize)); 36 | // else 37 | // ContentLenght += "0"; 38 | ContentLenght += "\r\n"; 39 | 40 | return (ContentLenght); 41 | } 42 | 43 | char **Handler::CgiSetEnv(std::string method) 44 | { 45 | std::string REDIRECT_STATUS = "REDIRECT_STATUS=200", 46 | REQUEST_METHOD = "REQUEST_METHOD=", 47 | SCRIPT_FILENAME = "SCRIPT_FILENAME=", 48 | PATH_INFO = "PATH_INFO=", 49 | CONTENT_TYPE = "CONTENT_TYPE=", 50 | CONTENT_LENGTH = "CONTENT_LENGTH=", 51 | HTTP_COOKIE= "HTTP_COOKIE=", 52 | QUERY_STRING = "QUERY_STRING="; 53 | REQUEST_METHOD += method; 54 | SCRIPT_FILENAME += this->_path.substr(_path.find_last_of('/', 0), _path.length()); 55 | PATH_INFO += this->_path; 56 | if (this->_req_header.find("Content-Length") != this->_req_header.end()) 57 | CONTENT_LENGTH += this->_req_header["Content-Length"]; 58 | if (this->_req_header.find("Content-Type") != this->_req_header.end()) 59 | CONTENT_TYPE += this->_req_header["Content-Type"]; 60 | 61 | if (this->_req_header.find("Cookie") != this->_req_header.end()) 62 | HTTP_COOKIE += this->_req_header["Cookie"]; 63 | 64 | if (!this->_querystring.empty()) 65 | QUERY_STRING += this->_querystring; 66 | 67 | char **newEnv = new char*[9]; 68 | 69 | newEnv[0] = new char[REDIRECT_STATUS.length() + 1]; 70 | newEnv[1] = new char[REQUEST_METHOD.length() + 1]; 71 | newEnv[2] = new char[SCRIPT_FILENAME.length() + 1]; 72 | newEnv[3] = new char[PATH_INFO.length() + 1]; 73 | newEnv[4] = new char[QUERY_STRING.length() + 1]; 74 | newEnv[5] = new char[CONTENT_TYPE.length() + 1]; 75 | newEnv[6] = new char[CONTENT_LENGTH.length() + 1]; 76 | newEnv[7] = new char[HTTP_COOKIE.length() + 1]; 77 | 78 | memcpy(newEnv[0], REDIRECT_STATUS.c_str(), REDIRECT_STATUS.length() + 1); 79 | memcpy(newEnv[1], REQUEST_METHOD.c_str(), REQUEST_METHOD.length() + 1); 80 | memcpy(newEnv[2], SCRIPT_FILENAME.c_str(), SCRIPT_FILENAME.length() + 1); 81 | memcpy(newEnv[3], PATH_INFO.c_str(), PATH_INFO.length() + 1); 82 | memcpy(newEnv[4], QUERY_STRING.c_str(), QUERY_STRING.length() + 1); 83 | memcpy(newEnv[5], CONTENT_TYPE.c_str(), CONTENT_TYPE.length() + 1); 84 | memcpy(newEnv[6], CONTENT_LENGTH.c_str(), CONTENT_LENGTH.length() + 1); 85 | memcpy(newEnv[7], HTTP_COOKIE.c_str(), HTTP_COOKIE.length() + 1); 86 | newEnv[8] = NULL; 87 | 88 | return (newEnv); 89 | } 90 | 91 | 92 | int Handler::HandleCgi(std::string path, std::string method, cgi &cgitype) 93 | { 94 | int outFd; 95 | std::string Buf, Header, Body, tmpfilename; 96 | struct stat s; 97 | 98 | if (stat(path.c_str(), &s) == 0 && (s.st_mode & S_IFREG)) 99 | { 100 | if (this->_cgiPid == -1) 101 | { 102 | char **env = CgiSetEnv(method); 103 | 104 | tmpfilename = this->_shared.generateFileName("/tmp/", ""); 105 | outFd = open(tmpfilename.c_str(), O_CREAT | O_RDWR | O_TRUNC , 0777); 106 | if (outFd < 0) 107 | { 108 | this->sendCodeResponse("500"); 109 | return (0); 110 | } 111 | this->_cgiTmpFileName = tmpfilename; 112 | 113 | //PHP Script child process 114 | char *excearr[] = {const_cast(cgitype.path.c_str()), const_cast(path.c_str()), NULL}; 115 | this->_cgiPid = fork(); 116 | if (this->_cgiPid == 0) 117 | { 118 | if (method == "POST") 119 | { 120 | int fd = open(this->_postFilePath.c_str(), O_RDONLY); 121 | dup2(fd, 0); 122 | close(fd); 123 | } 124 | dup2(outFd, 1); 125 | close(outFd); 126 | execve(excearr[0], excearr, env); 127 | } 128 | // Free env 129 | for (unsigned int i = 0; env[i] != NULL; i++) 130 | delete env[i]; 131 | delete env; 132 | } 133 | 134 | if (this->_cgiPid != -1 && waitpid(this->_cgiPid, NULL, WNOHANG) == this->_cgiPid) 135 | { 136 | //Reading tmp file 137 | std::ifstream TmpOutFile(this->_cgiTmpFileName.c_str()); 138 | if (!TmpOutFile) 139 | { 140 | this->sendCodeResponse("500"); 141 | return (0); 142 | } 143 | std::stringstream ss; 144 | ss << TmpOutFile.rdbuf(); 145 | Buf = ss.str(); 146 | ss.clear(); 147 | TmpOutFile.close(); 148 | // Parse header 149 | Header = Buf.substr(0, Buf.find("\r\n\r\n")); 150 | if (Header.length() + 4 < Buf.length()) 151 | Body = Buf.substr(Header.length() + 4, (Buf.length() - Header.length() - 4)); 152 | Buf.clear(); 153 | Buf.append(CgiHeaderFindStatus(Header)); 154 | Buf.append(Header); 155 | Buf.append(CgiBodySize(Body.length())); 156 | Buf.append("\r\n\r\n"); 157 | Buf.append(Body); 158 | if (send(this->client_socket, Buf.c_str(), Buf.size(), 0) == -1) 159 | perror("Error : Send -> "); 160 | remove(tmpfilename.c_str()); 161 | if (method == "POST") 162 | remove(this->_postFilePath.c_str()); 163 | this->_cgiPid = -1; 164 | 165 | return 0; 166 | } 167 | else if (this->_cgiPid != -1 && waitpid(this->_cgiPid, NULL, WNOHANG) == -1) 168 | { 169 | this->sendCodeResponse("500"); 170 | return (0); 171 | } 172 | } 173 | else 174 | { 175 | this->sendCodeResponse("404"); 176 | return (0); 177 | } 178 | return (1); 179 | } 180 | -------------------------------------------------------------------------------- /srcs/Config.cpp: -------------------------------------------------------------------------------- 1 | #include "../includes/Config.hpp" 2 | 3 | //ServerLocation OCF 4 | ServerLocation::ServerLocation() 5 | { 6 | _RedirectionInfo.RedirectionFlag = false; 7 | _RedirectionInfo.RedirectionCode = "n/a"; 8 | _RedirectionInfo.RedirectionPath = "n/a"; 9 | 10 | _CgiInfoPhp.type = "n/a"; 11 | _CgiInfoPhp.path = "n/a"; 12 | 13 | _CgiInfoPerl.type = "n/a"; 14 | _CgiInfoPerl.path = "n/a"; 15 | 16 | _LocationPath = "n/a"; 17 | _AutoIndex = 0; 18 | _Root = "n/a"; 19 | _Upload = 0; 20 | } 21 | 22 | bool ServerLocation::operator < (const ServerLocation & ServerObj) 23 | { 24 | return this->GetLocationPath() < ServerObj._LocationPath; 25 | } 26 | 27 | bool ServerLocation::operator > (const ServerLocation & ServerObj) 28 | { 29 | return this->GetLocationPath() > ServerObj._LocationPath; 30 | } 31 | 32 | 33 | ServerLocation::ServerLocation(const ServerLocation & ServerObj) 34 | { 35 | *this = ServerObj; 36 | } 37 | 38 | ServerLocation & ServerLocation::operator = (const ServerLocation & ServerObj) 39 | { 40 | this->_AutoIndex = ServerObj._AutoIndex; 41 | this->_CgiInfoPhp.path = ServerObj._CgiInfoPhp.path; 42 | this->_CgiInfoPhp.type = ServerObj._CgiInfoPhp.type; 43 | this->_CgiInfoPerl.path = ServerObj._CgiInfoPerl.path; 44 | this->_CgiInfoPerl.type = ServerObj._CgiInfoPerl.type; 45 | this->_RedirectionInfo.RedirectionFlag = ServerObj._RedirectionInfo.RedirectionFlag; 46 | this->_RedirectionInfo.RedirectionCode = ServerObj._RedirectionInfo.RedirectionCode; 47 | this->_RedirectionInfo.RedirectionPath = ServerObj._RedirectionInfo.RedirectionPath; 48 | this->_LocationPath = ServerObj._LocationPath; 49 | this->_Root = ServerObj._Root; 50 | this->_Upload = ServerObj._Upload; 51 | this->_AllowedMethodsVec = ServerObj._AllowedMethodsVec; 52 | this->_IndexesVec = ServerObj._IndexesVec; 53 | return *this; 54 | } 55 | 56 | ServerLocation::~ServerLocation() 57 | { 58 | 59 | } 60 | //ServerLocation OCF end 61 | 62 | //ServerConfig OCF 63 | ServerConfig::ServerConfig() 64 | { 65 | _Port = 8080; 66 | _Host = "n/a"; 67 | _ClientBodySize = "n/a"; 68 | } 69 | 70 | ServerConfig::ServerConfig(const ServerConfig & ServerObj) 71 | { 72 | *this = ServerObj; 73 | } 74 | 75 | ServerConfig & ServerConfig::operator = (const ServerConfig & ServerObj) 76 | { 77 | // this->_clientSocket = ServerObj._clientSocket; 78 | this->_ServerSocket = ServerObj._ServerSocket; 79 | this->_Port = ServerObj._Port; 80 | this->_Host = ServerObj._Host; 81 | this->_ServerNames = ServerObj._ServerNames; 82 | this->_ClientBodySize = ServerObj._ClientBodySize; 83 | this->_LocationsVec = ServerObj._LocationsVec; 84 | this->_ErrorPageMap = ServerObj._ErrorPageMap; 85 | return *this; 86 | } 87 | 88 | ServerConfig::~ServerConfig() 89 | { 90 | 91 | } 92 | //ServerConfig OCF end 93 | 94 | //GlobalConfig OCF 95 | GlobalConfig::GlobalConfig() 96 | { 97 | _ServerCount = 0; 98 | } 99 | 100 | GlobalConfig::GlobalConfig(const GlobalConfig & ServerObj) 101 | { 102 | *this = ServerObj; 103 | } 104 | 105 | GlobalConfig & GlobalConfig::operator = (const GlobalConfig & ServerObj) 106 | { 107 | this->_ServerCount = ServerObj._ServerCount; 108 | this->_ServersConfigVec = ServerObj._ServersConfigVec; 109 | return *this; 110 | } 111 | 112 | GlobalConfig::~GlobalConfig() 113 | { 114 | 115 | } 116 | //GlobalConfig OCF end 117 | 118 | void InvalidConfigFile(std::string err_message) 119 | { 120 | std::cout << err_message << std::endl; 121 | exit(1); 122 | } 123 | 124 | void GlobalConfig::ParseConfigFile(char *av) 125 | { 126 | int dot_position = 0, oc = 0, soc = 0;//oc: occurrence of some things, soc: "server" substring occurrence in string 127 | std::string buffer, read_data, file_name(av), server; 128 | std::ifstream config_file; 129 | 130 | /*----------------------------------- Reading config file ---------------------------------------*/ 131 | dot_position = file_name.find_last_of('.'); 132 | if (dot_position > 0) 133 | { 134 | if (file_name.substr(dot_position ,file_name.length()) != ".conf") 135 | InvalidConfigFile("Invalid config file: wrong extension."); 136 | } 137 | else 138 | InvalidConfigFile("Invalid config file: wrong extension."); 139 | config_file.open(file_name); 140 | if (!config_file) 141 | InvalidConfigFile("Invalid config file: there was an error when opening config file."); 142 | while (config_file) 143 | { 144 | std::getline(config_file, buffer); 145 | read_data += buffer += '\n'; 146 | } 147 | //For the last '\n' 148 | read_data.pop_back(); 149 | /*------------------------------------- End of reading -----------------------------------------*/ 150 | 151 | 152 | /*----------------------------------- Extracting each "server" ----------------------------------*/ 153 | oc = read_data.find("server "); 154 | if (oc >= 0) 155 | { 156 | while (oc >= 0) 157 | { 158 | soc = read_data.find("server ", oc + 1); 159 | if (soc > oc)//since oc is already bigger than 0,so for soc to be after oc, it should be be bigger 160 | { 161 | server = read_data.substr(oc, soc - oc); 162 | oc = read_data.find("server ", soc + 1); 163 | ParseServerConfig(server); 164 | } 165 | if (soc < oc && soc > 0) 166 | { 167 | server = read_data.substr(soc, oc - soc); 168 | soc = read_data.find("server ", oc + 1); 169 | ParseServerConfig(server); 170 | } 171 | if ( soc < 0 || oc < 0 || oc == 0 ) // if soc < 0 that means there's only one server, (soc < 0 || oc < 0) in case error happened break from the loop 172 | { 173 | if (soc > 0) 174 | server = read_data.substr(soc, read_data.length()); 175 | else if (oc > 0) 176 | server = read_data.substr(oc, read_data.length()); 177 | else if (oc == 0) 178 | server = read_data.substr(oc, read_data.length()); 179 | ParseServerConfig(server);//call to this f() to parse each server individually 180 | break; 181 | } 182 | } 183 | } 184 | else 185 | InvalidConfigFile("Invalid config file : server directive not found"); 186 | /*--------------------------------- End of extracting "server" ----------------------------------*/ 187 | } 188 | 189 | void GlobalConfig::ParseServerConfig(std::string server) 190 | { 191 | int key_pos, colon_pos, value_pos, scolon_pos; 192 | std::string location, tmp_str; 193 | ServerConfig tmp; 194 | 195 | /*------------------------------- Error check for server string end -----------------------------------*/ 196 | for (unsigned int i = server.length() - 1; i > 0; i--) 197 | { 198 | if (server[i] == '}' || server[i] == '\n') 199 | { 200 | if (server[i] == '}') 201 | { 202 | if (server[i - 1] == '\n') 203 | { 204 | if (server[i - 2] == '}') 205 | break; 206 | else 207 | InvalidConfigFile("Invalid config file : invalid server closing, closing brace should be proceeded by last location closing brace"); 208 | } 209 | else 210 | InvalidConfigFile("Invalid config file : invalid server closing, closing brace should be proceeded by last location closing brace"); 211 | } 212 | else 213 | continue; 214 | } 215 | else 216 | InvalidConfigFile("Invalid config file : invalid server closing"); 217 | } 218 | /*---------------------------------------- Error check end --------------------------------------------*/ 219 | 220 | 221 | _ServerCount++; 222 | /*------------------------------- host and port -----------------------------------*/ 223 | key_pos = server.find("listen "); 224 | if (key_pos >= 0) 225 | { 226 | colon_pos = server.find(":", key_pos); 227 | if (colon_pos < 0) 228 | InvalidConfigFile("Invalid config file : There was an error (Find Host Port)."); 229 | tmp._Host = server.substr(key_pos + 7, (colon_pos - (key_pos + 7))); 230 | value_pos = server.find(";", colon_pos); 231 | if (value_pos < 0) 232 | InvalidConfigFile("Invalid config file : There was an error."); 233 | tmp._Port = std::atoi(server.substr(colon_pos + 1, (((value_pos - colon_pos) - 1))).c_str()); 234 | if (tmp._Port < 0 || tmp._Port > 65536) 235 | InvalidConfigFile("Invalid config file : Wrong port number"); 236 | } 237 | else 238 | InvalidConfigFile("Invalid config file : listen directive is not found."); 239 | /*------------------------------- End of host port --------------------------------*/ 240 | 241 | /*---------------------------- server_names -----------------------------------*/ 242 | key_pos = server.find("server_names "); 243 | if (key_pos > 0) 244 | { 245 | scolon_pos = server.find(";", (key_pos + 13)); 246 | if (scolon_pos < 0) 247 | InvalidConfigFile("Invalid config file : There was an error (Find Server Names)."); 248 | tmp._ServerNames = server.substr((key_pos + 13), scolon_pos - (key_pos + 13)); 249 | value_pos = tmp._ServerNames.find(" "); 250 | if (value_pos != -1) 251 | InvalidConfigFile("Invalid config file : Wrong error page directive."); 252 | 253 | //std::cout << "--->" << tmp._ServerNames << "\n"; 254 | /* In case we wanted to split each server names 255 | std::stringstream ss(tmp._ServerNames); 256 | std::istream_iterator begin(ss); 257 | std::istream_iterator end; 258 | std::vector vstrings(begin, end); 259 | std::cout << "--->" << vstrings[1] << "\n"; 260 | */ 261 | } 262 | else 263 | InvalidConfigFile("Invalid config file : server names directive is not found."); 264 | /*---------------------------- End of server_names --------------------------------*/ 265 | 266 | /*--------------------------------- client body size -------------------------------------*/ 267 | key_pos = server.find("client_body_size "); 268 | if (key_pos >= 0) 269 | { 270 | scolon_pos = server.find(";", (key_pos + 17)); 271 | if (scolon_pos < 0) 272 | InvalidConfigFile("Invalid config file : There was an error (Find Client Body Size)."); 273 | tmp._ClientBodySize = server.substr((key_pos + 17), scolon_pos - (key_pos + 17)); 274 | } 275 | else 276 | InvalidConfigFile("Invalid config file : client body size is not found or not valid."); 277 | /*---------------------------- End of client body size -----------------------------------*/ 278 | 279 | /*-------------------------------------- error page ---------------------------------------*/ 280 | key_pos = server.find("error_page "); 281 | if (key_pos > 0) 282 | { 283 | while (1) 284 | { 285 | if (key_pos >= 0) 286 | { 287 | scolon_pos = server.find(";", (key_pos + 11)); 288 | if (scolon_pos < 0) 289 | InvalidConfigFile("Invalid config file : There was an error (Find Error Page)."); 290 | tmp_str = server.substr((key_pos + 11), scolon_pos - (key_pos + 11)); 291 | tmp.ParseErrorPage(tmp_str); 292 | } 293 | else 294 | break; 295 | key_pos = server.find("error_page ", key_pos + 1); 296 | 297 | } 298 | } 299 | /*----------------------------------- end of error page -----------------------------------*/ 300 | 301 | /*------------------------------------- find locations -------------------------------------*/ 302 | 303 | key_pos = server.find("location "); 304 | if (key_pos > 0) 305 | { 306 | while (1) 307 | { 308 | if (key_pos >= 0) 309 | { 310 | value_pos = server.find("}", key_pos); 311 | if (value_pos < 0) 312 | InvalidConfigFile("Invalid config file : There was an error (Find Loactions)."); 313 | location = server.substr(key_pos, (value_pos - key_pos) + 1); 314 | tmp.ParseServerLocation(location); 315 | } 316 | else 317 | break; 318 | key_pos = server.find("location ", key_pos + 1); 319 | } 320 | } 321 | else 322 | InvalidConfigFile("Invalid config file : location directive not found."); 323 | /*----------------------------------- End find locations -----------------------------------*/ 324 | 325 | _ServersConfigVec.push_back(tmp); 326 | } 327 | 328 | void ServerConfig::ParseServerLocation(std::string location) 329 | { 330 | int key_pos, value_pos, npos = 0; 331 | ServerConfig location_tmp; 332 | std::string tmp_str; 333 | 334 | /*------------------------------------- find location path -------------------------------------*/ 335 | key_pos = location.find("location "); 336 | if (key_pos < 0) 337 | InvalidConfigFile("Invalid config file : There was an error (Find Location Path)."); 338 | value_pos = location.find("{", key_pos + 1); 339 | if (value_pos < 0) 340 | InvalidConfigFile("Invalid config file : There was an error (Find Location Path)."); 341 | location_tmp._LocationPath = location.substr((key_pos + 9), value_pos - (key_pos + 10)); 342 | /*----------------------------------- end find location path -----------------------------------*/ 343 | 344 | /*----------------------------------------- allowed methods ----------------------------------------*/ 345 | key_pos = location.find("allow_methods "); 346 | if (key_pos > 0) 347 | { 348 | value_pos = location.find(";", key_pos + 1); 349 | if (value_pos < 0) 350 | InvalidConfigFile("Invalid config file : There was an error (Find allowedmwthodes)."); 351 | tmp_str = location.substr((key_pos + 14), value_pos - (key_pos + 14)); 352 | 353 | npos = tmp_str.find("GET"); 354 | if (npos >= 0) 355 | location_tmp._AllowedMethodsVec.push_back("GET"); 356 | npos = tmp_str.find("POST"); 357 | if (npos >= 0) 358 | location_tmp._AllowedMethodsVec.push_back("POST"); 359 | npos = tmp_str.find("DELETE"); 360 | if (npos >= 0) 361 | location_tmp._AllowedMethodsVec.push_back("DELETE"); 362 | tmp_str.erase(); 363 | } 364 | else 365 | InvalidConfigFile("Invalid config file : allowed methods not found (Find allowed methodes)."); 366 | /*------------------------------------- End of allowed methods -------------------------------------*/ 367 | 368 | /*------------------------------------------ autoindex ----------------------------------------*/ 369 | key_pos = location.find("autoindex "); 370 | if (key_pos > 0) 371 | { 372 | value_pos = location.find(";", key_pos + 1); 373 | if (value_pos < 0) 374 | InvalidConfigFile("Invalid config file : There was an error (Find autoindex)."); 375 | tmp_str = location.substr((key_pos + 10), value_pos - (key_pos + 10)); 376 | if (tmp_str.find("on") != std::string::npos) 377 | location_tmp._AutoIndex = 1; 378 | tmp_str.erase(); 379 | } 380 | else 381 | InvalidConfigFile("Invalid config file : auto index not found (Find autoindex)."); 382 | /*------------------------------------- End of auto index -------------------------------------*/ 383 | 384 | /*------------------------------------------ upload ----------------------------------------*/ 385 | key_pos = location.find("upload "); 386 | if (key_pos > 0) 387 | { 388 | value_pos = location.find(";", key_pos + 1); 389 | if (value_pos < 0) 390 | InvalidConfigFile("Invalid config file : There was an error (Find upload)."); 391 | tmp_str = location.substr((key_pos + 7), value_pos - (key_pos + 7)); 392 | if (tmp_str.find("on") != std::string::npos) 393 | location_tmp._Upload = 1; 394 | tmp_str.erase(); 395 | } 396 | else 397 | InvalidConfigFile("Invalid config file : auto index not found (Find upload)."); 398 | /*------------------------------------- upload index -------------------------------------*/ 399 | 400 | /*------------------------------------- find root -------------------------------------*/ 401 | key_pos = location.find("root "); 402 | if (key_pos >= 0) 403 | { 404 | value_pos = location.find(";", key_pos + 1); 405 | if (value_pos < 0) 406 | InvalidConfigFile("Invalid config file : There was an error (Find Root)."); 407 | location_tmp._Root = location.substr((key_pos + 5), value_pos - (key_pos + 5)); 408 | } 409 | else 410 | InvalidConfigFile("Invalid config file : root directive is not found."); 411 | 412 | /*----------------------------------- end find root -----------------------------------*/ 413 | 414 | /*------------------------------------- find cgi -----------------------------------------*/ 415 | //PHP CGI 416 | struct stat interpreterPhp; 417 | 418 | key_pos = location.find("cgi "); 419 | if (key_pos >= 0) 420 | { 421 | value_pos = location.find(";", key_pos + 1); 422 | if (value_pos < 0) 423 | InvalidConfigFile("Invalid config file : There was an error (Find CGI)."); 424 | tmp_str = location.substr((key_pos + 4), value_pos - (key_pos + 4)); 425 | npos = tmp_str.find(" ", 1); 426 | if (npos < 0) 427 | InvalidConfigFile("Invalid config file : There was an error (Find CGI)."); 428 | location_tmp._CgiInfoPhp.type = tmp_str.substr(0, npos); 429 | npos = tmp_str.find(" "); 430 | if (npos < 0) 431 | InvalidConfigFile("Invalid config file : There was an error (Find CGI)."); 432 | location_tmp._CgiInfoPhp.path = tmp_str.substr(tmp_str.find(" ") + 1, value_pos - (tmp_str.find(" ") + 1)); 433 | 434 | if (stat(location_tmp._CgiInfoPhp.path.c_str(), &interpreterPhp) != 0) 435 | InvalidConfigFile("Invalid config file : Invalid interpreter path (Find PHP CGI)."); 436 | 437 | tmp_str.erase(); 438 | } 439 | 440 | //Perl CGI 441 | struct stat interpreterPerl; 442 | key_pos = location.find("cgi ", key_pos + 1); 443 | if (key_pos >= 0) 444 | { 445 | value_pos = location.find(";", key_pos + 1); 446 | if (value_pos < 0) 447 | InvalidConfigFile("Invalid config file : There was an error (Find CGI)."); 448 | tmp_str = location.substr((key_pos + 4), value_pos - (key_pos + 4)); 449 | npos = tmp_str.find(" ", 1); 450 | if (npos < 0) 451 | InvalidConfigFile("Invalid config file : There was an error (Find CGI)."); 452 | location_tmp._CgiInfoPerl.type = tmp_str.substr(0, npos); 453 | npos = tmp_str.find(" "); 454 | if (npos < 0) 455 | InvalidConfigFile("Invalid config file : There was an error (Find CGI)."); 456 | location_tmp._CgiInfoPerl.path = tmp_str.substr(tmp_str.find(" ") + 1, value_pos - (tmp_str.find(" ") + 1)); 457 | 458 | if (stat(location_tmp._CgiInfoPerl.path.c_str(), &interpreterPerl) != 0) 459 | InvalidConfigFile("Invalid config file : Invalid interpreter path (Find PERL CGI)."); 460 | 461 | tmp_str.erase(); 462 | } 463 | /*----------------------------------- end of find cgi -----------------------------------*/ 464 | 465 | /*------------------------------------- find redirection -----------------------------------------*/ 466 | key_pos = location.find("return "); 467 | if (key_pos >= 0) 468 | { 469 | location_tmp._RedirectionInfo.RedirectionFlag = true; 470 | value_pos = location.find(";", key_pos + 1); 471 | if (value_pos < 0) 472 | InvalidConfigFile("Invalid config file : There was an error (Find Redirection)."); 473 | tmp_str = location.substr((key_pos + 7), value_pos - (key_pos + 7)); 474 | npos = tmp_str.find(" ", 1); 475 | if (npos < 0) 476 | InvalidConfigFile("Invalid config file : There was an error (Find Redirection)."); 477 | location_tmp._RedirectionInfo.RedirectionCode = tmp_str.substr(0, npos); 478 | location_tmp._RedirectionInfo.RedirectionPath = tmp_str.substr(npos + 1, value_pos - (npos + 1)); 479 | tmp_str.erase(); 480 | } 481 | /*----------------------------------- end of find redirection -----------------------------------*/ 482 | 483 | /*----------------------------------------- find indexes ----------------------------------------*/ 484 | key_pos = location.find("indexes "); 485 | if (key_pos > 0) 486 | { 487 | struct stat indexFileStat; 488 | std::string indexFilePath; 489 | 490 | while (1) 491 | { 492 | if (key_pos >= 0) 493 | { 494 | value_pos = location.find("\n", key_pos + 1); 495 | if (value_pos < 0) 496 | InvalidConfigFile("Invalid config file : There was an error (Find Index)."); 497 | indexFilePath = location_tmp._Root += '/'; 498 | indexFilePath += location.substr((key_pos + 8), value_pos - (key_pos + 9)); 499 | if ((stat(indexFilePath.c_str(), &indexFileStat) == 0) && (indexFileStat.st_mode & S_IFREG)) 500 | location_tmp._IndexesVec.push_back(location.substr((key_pos + 8), value_pos - (key_pos + 9))); 501 | } 502 | else 503 | break; 504 | key_pos = location.find("indexes ", key_pos + 1); 505 | } 506 | } 507 | /*-------------------------------------- end of find indexes ------------------------------------*/ 508 | this->_LocationsVec.push_back(location_tmp); 509 | } 510 | 511 | void GlobalConfig::PrintServerConfig(unsigned int index) 512 | { 513 | if (index <= (_ServerCount - 1)) { 514 | std::cout << "Server index : " << index << "\n"; 515 | std::cout << "Server host : " << _ServersConfigVec[index].GetHost() << "\n"; 516 | std::cout << "Server port : " << _ServersConfigVec[index].GetPort() << "\n"; 517 | if (_ServersConfigVec[index].GetServerNames() != "n/a") 518 | std::cout << "Server name : " << _ServersConfigVec[index].GetServerNames() << "\n"; 519 | std::cout << "Server client body size : " << _ServersConfigVec[index].GetClientBodySize() << "\n"; 520 | 521 | if (_ServersConfigVec[index].GetErrorPageMap().empty() == false) 522 | { 523 | std::map::iterator it; 524 | 525 | std::cout << "\nServer error page(s) : " << "\n"; 526 | for (it = _ServersConfigVec[index].GetErrorPageMap().begin(); it != _ServersConfigVec[index].GetErrorPageMap().end(); ++it) 527 | { 528 | std::cout << "Error code : " << it->first << "\n"; 529 | std::cout << "Error page path : " << it->second << "\n"; 530 | } 531 | } 532 | 533 | std::cout << "\nServer location(s)\n\n"; 534 | for (unsigned long i = 0; i < _ServersConfigVec[index].GetLocationsVec().size(); i++) { 535 | _ServersConfigVec[index].PrintServerLocation(i); 536 | std::cout << "\n"; 537 | } 538 | } 539 | } 540 | 541 | void ServerConfig::PrintServerLocation(unsigned int index) 542 | { 543 | if (index <= _LocationsVec.size()) 544 | { 545 | std::cout << "Location index : " << index << "\n"; 546 | std::cout << "Location path : " << _LocationsVec[index].GetLocationPath() << "\n"; 547 | std::cout << "Location root : " << _LocationsVec[index].GetRoot() << "\n"; 548 | std::cout << "Location auto index : " ; 549 | if (_LocationsVec[index].GetAutoIndex() == 0) 550 | std::cout << "OFF"; 551 | else 552 | std::cout << "OFF"; 553 | std::cout << "\n"; 554 | 555 | if (_LocationsVec[index].GetCgiInfoPhp().type != "n/a") 556 | { 557 | std::cout << "Location cgi type : " << _LocationsVec[index].GetCgiInfoPhp().type << "\n"; 558 | std::cout << "Location cgi path : " << _LocationsVec[index].GetCgiInfoPhp().path << "\n"; 559 | } 560 | 561 | // if (_LocationsVec[index].GetUpload() != "n/a") 562 | // std::cout << "server _Upload : " << _LocationsVec[index].GetUpload() << "\n"; 563 | 564 | if (_LocationsVec[index].GetAllowedMethodsVec().size() > 0) 565 | { 566 | std::cout << "Location allowed methods : " ; 567 | for (unsigned int i = 0; i < _LocationsVec[index].GetAllowedMethodsVec().size(); i++) 568 | std::cout << _LocationsVec[index].GetAllowedMethodsVec()[i] << " "; 569 | } 570 | 571 | std::cout << "\n"; 572 | 573 | if (_LocationsVec[index].GetRedirectionInfo().RedirectionFlag == true) 574 | { 575 | std::cout << "Redirection code : " << _LocationsVec[index].GetRedirectionInfo().RedirectionCode << "\n"; 576 | std::cout << "Redirection path : " << _LocationsVec[index].GetRedirectionInfo().RedirectionPath << "\n"; 577 | } 578 | std::cout << "\n"; 579 | } 580 | } 581 | 582 | void GlobalConfig::PrintServers(void) 583 | { 584 | for (unsigned int i = 0; i < _ServersConfigVec.size(); i++) 585 | PrintServerConfig(i); 586 | } 587 | 588 | void ServerConfig::ParseErrorPage(std::string error_directive) 589 | { 590 | 591 | std::stringstream ss(error_directive); 592 | std::istream_iterator begin(ss); 593 | std::istream_iterator end; 594 | std::vector SplitedStringsVec(begin, end); 595 | 596 | if (SplitedStringsVec.empty() != 1) 597 | this->_ErrorPageMap[SplitedStringsVec[0]] = SplitedStringsVec[1]; 598 | else 599 | InvalidConfigFile("Invalid config file : There was an error."); 600 | } 601 | 602 | // --------------------- ACCESSOR ---------------- 603 | 604 | std::vector& GlobalConfig::GetServersVector(void) 605 | { 606 | return (_ServersConfigVec); 607 | } 608 | 609 | unsigned int GlobalConfig::GetServerCount(void) 610 | { 611 | return (_ServerCount); 612 | } 613 | 614 | unsigned int ServerConfig::GetPort(void) 615 | { 616 | return (_Port); 617 | } 618 | 619 | std::string ServerConfig::GetHost(void) 620 | { 621 | return (_Host); 622 | } 623 | 624 | std::string ServerConfig::GetServerNames(void) 625 | { 626 | return (_ServerNames); 627 | } 628 | 629 | std::string ServerConfig::GetClientBodySize(void) 630 | { 631 | return (_ClientBodySize); 632 | } 633 | 634 | std::vector& ServerConfig::GetLocationsVec(void) 635 | { 636 | return (_LocationsVec); 637 | } 638 | 639 | int ServerLocation::GetAutoIndex(void) 640 | { 641 | return (_AutoIndex); 642 | } 643 | 644 | int ServerLocation::GetUpload(void) 645 | { 646 | return (_Upload); 647 | } 648 | 649 | cgi& ServerLocation::GetCgiInfoPhp(void) 650 | { 651 | return (_CgiInfoPhp); 652 | } 653 | 654 | cgi& ServerLocation::GetCgiInfoPerl(void) 655 | { 656 | return (_CgiInfoPerl); 657 | } 658 | 659 | std::string ServerLocation::GetLocationPath(void) 660 | { 661 | return (_LocationPath); 662 | } 663 | 664 | std::string ServerLocation::GetRoot(void) 665 | { 666 | return (_Root); 667 | } 668 | 669 | // std::string ServerLocation::GetUpload(void) 670 | // { 671 | // return (_Upload); 672 | // } 673 | 674 | std::vector ServerLocation::GetAllowedMethodsVec(void) 675 | { 676 | return (_AllowedMethodsVec); 677 | } 678 | 679 | void ServerConfig::SetServerSocket(int socket) 680 | { 681 | //Do not forget to check for errors 682 | _ServerSocket = socket; 683 | } 684 | 685 | int ServerConfig::GetServerSocket(void) 686 | { 687 | return (_ServerSocket); 688 | } 689 | 690 | redirection& ServerLocation::GetRedirectionInfo(void) 691 | { 692 | return (_RedirectionInfo); 693 | } 694 | 695 | std::map& ServerConfig::GetErrorPageMap(void) 696 | { 697 | return (_ErrorPageMap); 698 | } 699 | 700 | std::vector ServerLocation::GetIndexesVec(void) 701 | { 702 | return (_IndexesVec); 703 | } -------------------------------------------------------------------------------- /srcs/Handler.cpp: -------------------------------------------------------------------------------- 1 | #include "../includes/Handler.hpp" 2 | 3 | // ------------- CONSTRUCTOR && DESTRUCTOR -------------------- 4 | 5 | void Handler::setData() 6 | { 7 | this->_postFileFd = -1; 8 | this->_headerflag = 0; 9 | this->_chunkSize = 0; 10 | this->_postRecv = 0; 11 | this->_chunkHexState = 0; 12 | this->_cgiPid = -1; 13 | } 14 | 15 | // ------------- ACCESSOR -------------------- 16 | 17 | void Handler::setConfig(ServerConfig &config) 18 | { 19 | this->_config = config; 20 | } 21 | 22 | // ------------- METHODS ------------- 23 | 24 | int Handler::Driver(char *requested_data, int bytesreceived) 25 | { 26 | int re = 1; 27 | if (this->_headerflag == 0) 28 | re = this->parseRequestHeader(requested_data, bytesreceived); 29 | else 30 | { 31 | if (this->_method == "GET") 32 | re = this->HandleGet(); 33 | else if (this->_method == "POST") 34 | re = this->HandlePost(requested_data, bytesreceived); 35 | else if (this->_method == "DELETE") 36 | re = this->HandleDelete(); 37 | } 38 | this->_headerflag = 1; 39 | return re; 40 | } 41 | 42 | std::string Handler::GetRootLocation(std::string uri, std::string locationPath, std::string root) 43 | { 44 | std::string MatchedUri; 45 | if (uri.find(locationPath) != std::string::npos) 46 | { 47 | root += '/'; 48 | MatchedUri = uri.replace(0, locationPath.length(), root); 49 | } 50 | else 51 | return (uri); 52 | return (MatchedUri); 53 | } 54 | 55 | // Generate a response header from the recieved argements 56 | void Handler::SendResponseHeader(std::string statusCode, std::string fileExt, std::string location, int contentLength) 57 | { 58 | // 59 | std::stringstream header; 60 | 61 | header << "HTTP/1.1 " << statusCode << " " << this->_shared.status_codes[statusCode] << "\r\n"; 62 | header << "Server: " << this->_config.GetServerNames() << "\r\n"; 63 | 64 | if (!location.empty()) 65 | header << "Location: " << location << "\r\n"; 66 | if (!fileExt.empty()) 67 | header << "Content-Type: " << this->_shared.mime_types[fileExt] << "\r\n"; 68 | if (contentLength) 69 | header << "Content-Length: " << contentLength << "\r\n"; 70 | 71 | header << "Connection: close\r\n"; 72 | header << "\r\n"; 73 | 74 | if (send(this->client_socket, header.str().c_str(), header.str().length(), 0) == -1) 75 | { 76 | perror("Error : Send -> "); 77 | } 78 | } 79 | 80 | std::string Handler::generateListDir(std::string statusCode, std::string ls) 81 | { 82 | if (ls.empty() == 1) // if an error happened, check ls wether is empty or not 83 | { 84 | perror("Error : GenerateListDir "); 85 | this->sendCodeResponse("500"); 86 | } 87 | 88 | std::stringstream s(ls); 89 | std::string statusMessage = this->_shared.status_codes[statusCode]; 90 | std::string TmpStr, res = "Directory list

"; 103 | return res; 104 | } 105 | 106 | void Handler::sendCodeResponse(std::string statusCode) 107 | { 108 | std::string htmlContent; 109 | 110 | // Check for this error page in the server config 111 | if (this->_config._ErrorPageMap.find(statusCode) != this->_config._ErrorPageMap.end()) 112 | { 113 | std::ifstream file(this->_config._ErrorPageMap[statusCode].c_str()); 114 | if (file) 115 | { 116 | std::stringstream buffer; 117 | buffer << file.rdbuf(); 118 | htmlContent = buffer.str(); 119 | file.close(); 120 | } 121 | } 122 | if (htmlContent.empty()) 123 | { 124 | std::ifstream file("samples/errorPageSample.html"); 125 | std::string statusMessage = this->_shared.status_codes[statusCode]; 126 | std::string res = "" + statusCode + " " + statusMessage + "" + "

" + 127 | statusCode + " " + statusMessage + "

"; 128 | if (file) 129 | { 130 | std::stringstream buffer; 131 | buffer << file.rdbuf(); 132 | file.close(); 133 | res = buffer.str(); 134 | res.insert(res.find("<") + 7, statusCode + " - " + statusMessage); 135 | res.insert(res.find("<h1><") + 4, statusCode + " - " + statusMessage); 136 | } 137 | htmlContent = res; 138 | } 139 | SendResponseHeader(statusCode, ".html", "", htmlContent.length()); 140 | if (send(this->client_socket, htmlContent.c_str(), htmlContent.length(), 0) == -1) 141 | { 142 | perror("Error : Send <Error Response> "); 143 | } 144 | } 145 | 146 | // -------------------------------- Request parse and validation ------------ 147 | 148 | int Handler::parseRequestHeader(char *req, int bytesreceived) 149 | { 150 | int delimiter_position; 151 | std::string current_line, key, value; 152 | char *body; 153 | 154 | std::string request = req; 155 | size_t header_len = request.find("\r\n\r\n"); // Find the end of the request header 156 | if (header_len == std::string::npos) 157 | { 158 | perror("Error : ParseRequstHeader <Finding end of request> "); 159 | this->sendCodeResponse("500"); 160 | return 0; 161 | } 162 | std::string header = request.substr(0, header_len); // Save the header 163 | body = req + header_len + 4, bytesreceived -= header_len + 4; // Save the body 164 | std::stringstream request_stream(header); 165 | 166 | request_stream >> std::skipws >> std::ws >> this->_method; // Streaming methode into _methode while taking care of white spaces 167 | request_stream >> std::skipws >> std::ws >> this->_uri; // same for path 168 | std::getline(request_stream, current_line); // skip the remaining part of the request line (HTTP/1.1) 169 | 170 | while (getline(request_stream >> std::ws >> std::skipws, current_line, '\n')) 171 | { 172 | current_line.erase(std::remove(current_line.begin(), current_line.end(), '\r'), current_line.end()); // remove every occurence of '/r' in line 173 | delimiter_position = current_line.find(':'); 174 | key = current_line.substr(0, delimiter_position); 175 | value = current_line.substr(delimiter_position + 2, current_line.length()); // [delimiter_position + 2] to remove the extra space before value 176 | // storing key and value in map 177 | this->_req_header[key] = value; 178 | } 179 | 180 | if (!this->ValidateRequest()) 181 | return 0; 182 | 183 | if (this->_method == "GET") 184 | return this->HandleGet(); 185 | else if (this->_method == "POST") 186 | return this->HandlePost(body, bytesreceived); 187 | else if (this->_method == "DELETE") 188 | return this->HandleDelete(); 189 | return 0; 190 | } 191 | 192 | // Check for Possible error in the Request 193 | bool Handler::ValidateRequest() 194 | { 195 | // if Transfer-Encoding exist and not match [chunked] 196 | if (this->_req_header.find("Transfer-Encoding") != this->_req_header.end() && this->_req_header["Transfer-Encoding"] != "chunked") 197 | { 198 | this->sendCodeResponse("501"); 199 | return false; 200 | } 201 | // if both Transfer-Encoding and Content-Length not provided 202 | if (this->_method == "POST" && this->_req_header.find("Transfer-Encoding") == this->_req_header.end() && 203 | this->_req_header.find("Content-Length") == this->_req_header.end()) 204 | { 205 | this->sendCodeResponse("400"); 206 | return false; 207 | } 208 | // URI should start with a leading slash ("/") and not contain any illegal characters 209 | if (!this->ValidateURI(this->_uri)) 210 | { 211 | this->sendCodeResponse("400"); 212 | return false; 213 | } 214 | // URI should not have more than 2048 215 | if (this->_uri.length() > 2048) 216 | { 217 | this->sendCodeResponse("414"); 218 | return false; 219 | } 220 | // Request body size should not be more than [client_body_size] from confing file 221 | if (this->_req_header.find("Content-Length") != this->_req_header.end() && 222 | std::stoll(this->_req_header["Content-Length"]) > std::stoll(this->_config.GetClientBodySize())) 223 | { 224 | this->sendCodeResponse("413"); 225 | return false; 226 | } 227 | return this->MatchLocation(); 228 | } 229 | 230 | bool fn(ServerLocation &x, ServerLocation &y) 231 | { 232 | return x.GetLocationPath().length() > y.GetLocationPath().length(); 233 | } 234 | 235 | // match location from the config file and validate method 236 | bool Handler::MatchLocation() 237 | { 238 | this->_path = this->_uri; 239 | std::vector<ServerLocation> serverLocations = this->_config.GetLocationsVec(); 240 | size_t i = 0; 241 | 242 | // Seperate Path from args if there is any 243 | if (this->_uri.find('?') != std::string::npos) 244 | { 245 | _path = this->_uri.substr(0, this->_uri.find('?')); 246 | _querystring = this->_uri.substr(this->_uri.find('?') + 1, this->_uri.length()); 247 | } 248 | 249 | std::sort(serverLocations.begin(), serverLocations.end(), fn); 250 | 251 | // find the closest location to requested resource (new) 252 | for (i = 0; i < serverLocations.size(); i++) 253 | { 254 | std::string locationslash; 255 | 256 | size_t j = 0; 257 | while (j < _path.size() && j < serverLocations[i].GetLocationPath().size() && 258 | _path[j] == serverLocations[i].GetLocationPath()[j]) 259 | j++; 260 | 261 | if ((j == _path.size() && j == serverLocations[i].GetLocationPath().size()) 262 | || (j == serverLocations[i].GetLocationPath().size() && ((j < _path.size() && _path[j] == '/') || (j > 0 && _path[j - 1] == '/')))) 263 | { 264 | this->_workingLocation = serverLocations[i]; 265 | break; 266 | } 267 | } 268 | if (i == serverLocations.size()) 269 | { 270 | this->sendCodeResponse("404"); 271 | return (0); 272 | } 273 | 274 | 275 | // Check for location redirection 276 | if (this->_workingLocation.GetRedirectionInfo().RedirectionFlag) 277 | { 278 | _path = this->_workingLocation.GetRedirectionInfo().RedirectionPath; 279 | this->SendResponseHeader(this->_workingLocation.GetRedirectionInfo().RedirectionCode, "", _path, 0); 280 | return false; 281 | } 282 | 283 | std::vector<std::string> allowedMethods = this->_workingLocation.GetAllowedMethodsVec(); 284 | if (std::find(allowedMethods.begin(), allowedMethods.end(), this->_method) == allowedMethods.end()) 285 | { 286 | this->sendCodeResponse("405"); 287 | return false; 288 | } 289 | 290 | _path = GetRootLocation(this->_path, this->_workingLocation.GetLocationPath(), this->_workingLocation.GetRoot()); 291 | return true; 292 | } 293 | 294 | // Check for any any illegal characters in the URI 295 | bool Handler::ValidateURI(const std::string &uri) 296 | { 297 | // Check if the URI starts with a leading slash ("/") 298 | if (uri.empty() || uri[0] != '/') 299 | return false; 300 | 301 | // Check for any invalid characters in the URI 302 | const std::string invalidChars = " <>{}|\\^`"; 303 | if (uri.find_first_of(invalidChars) != std::string::npos) 304 | return false; 305 | return true; 306 | } 307 | 308 | // -------------------------------- POST method ---------------------- 309 | 310 | int Handler::chunkedPost(char *body, int bytesreceived) 311 | { 312 | // _chunkHexStates: 313 | // 0: Still in the \r\n before the hex 314 | // 1: in the hex number 315 | // 2: in the \r\n after the hex 316 | 317 | 318 | if (this->_chunkHexState == 2) 319 | { 320 | int i = 0; 321 | while (this->_chunkHexState == 2 && i < bytesreceived && (body[i] == '\r' || body[i] == '\n')) 322 | i++; 323 | this->_chunkHexState = 0; 324 | 325 | if (bytesreceived - i <= 0) 326 | return 1; 327 | 328 | body += i, bytesreceived -= i; 329 | } 330 | if (this->_chunkSize <= 0) 331 | { 332 | int i = 0; 333 | 334 | while (this->_chunkHexState == 0 && i < bytesreceived && (body[i] == '\r' || body[i] == '\n')) 335 | i++; 336 | 337 | if (i == bytesreceived && body[i - 1] == '\n') 338 | this->_chunkHexState = 1; 339 | else 340 | { 341 | for (; i < bytesreceived && body[i] != '\r'; i++) 342 | this->_chunkHex.push_back(body[i]); 343 | this->_chunkHexState = 1; 344 | if (i < bytesreceived && body[i] == '\r') 345 | { 346 | this->_chunkHexState = 2; 347 | while (i < bytesreceived && (body[i] == '\r' || body[i] == '\n')) 348 | i++; 349 | if ((i < bytesreceived && (body[i] != '\r' || body[i] != '\n')) || (i == bytesreceived && body[i - 1] == '\n')) 350 | this->_chunkHexState = 0; 351 | } 352 | } 353 | if (this->_chunkHex == "0") 354 | return 0; 355 | 356 | if (this->_chunkHexState == 1) 357 | return 1; 358 | 359 | std::stringstream ss; 360 | ss << std::hex << this->_chunkHex; 361 | ss >> this->_chunkSize; 362 | 363 | this->_chunkHex.clear(); 364 | if (bytesreceived - i <= 0) 365 | return 1; 366 | 367 | body += i, bytesreceived -= i; 368 | } 369 | 370 | if (this->_chunkSize >= bytesreceived && bytesreceived > 0) 371 | { 372 | write(this->_postFileFd, body, bytesreceived); 373 | this->_chunkSize -= bytesreceived; 374 | return 1; 375 | } 376 | else if (this->_chunkSize > 0 ) 377 | { 378 | if (bytesreceived == 0) 379 | return 1; 380 | write(this->_postFileFd, body, this->_chunkSize); 381 | bytesreceived -= this->_chunkSize; 382 | body += this->_chunkSize; 383 | this->_chunkSize = 0; 384 | chunkedPost(body, bytesreceived); 385 | } 386 | return 1; 387 | } 388 | 389 | int Handler::HandlePost(char *body, int bytesreceived) 390 | { 391 | if (this->_cgiPid != -1) 392 | { 393 | if (this->_workingLocation.GetCgiInfoPhp().type == this->_shared.fileExtention(this->_path)) 394 | return this->HandleCgi(_path, "POST", this->_workingLocation.GetCgiInfoPhp()); 395 | else if (this->_workingLocation.GetCgiInfoPerl().type == this->_shared.fileExtention(this->_path)) 396 | return this->HandleCgi(_path, "POST", this->_workingLocation.GetCgiInfoPerl()); 397 | } 398 | 399 | std::string mimeType = ""; 400 | struct stat s; 401 | int returnVal = 1; 402 | 403 | 404 | // Save MIME type and boundary if it exist 405 | if (this->_req_header.find("Content-Type") != this->_req_header.end()) 406 | { 407 | int semiPos = this->_req_header["Content-Type"].find(';'); 408 | if (semiPos != -1) 409 | mimeType = this->_req_header["Content-Type"].substr(0, semiPos); 410 | else 411 | mimeType = this->_req_header["Content-Type"]; 412 | } 413 | 414 | // Create a file stream for writing 415 | if (this->_headerflag == 0) 416 | { 417 | stat(this->_path.c_str(), &s); 418 | if (S_ISDIR(s.st_mode)) 419 | { 420 | if (this->_workingLocation.GetUpload() == 0) 421 | { 422 | this->sendCodeResponse("403"); 423 | return 0; 424 | } 425 | if (_path.back() != '/') 426 | _path += "/"; 427 | _postFilePath = this->_shared.generateFileName(this->_path, this->_shared.file_extensions[mimeType]); 428 | this->_postFileFd = open(_postFilePath.c_str(), O_CREAT | O_RDWR | O_APPEND, 0777); 429 | } 430 | else 431 | { 432 | std::string fileExt = this->_shared.fileExtention(this->_path); 433 | if ((this->_workingLocation.GetCgiInfoPhp().path != "n/a" && this->_workingLocation.GetCgiInfoPhp().type == fileExt) || 434 | (this->_workingLocation.GetCgiInfoPerl().path != "n/a" && this->_workingLocation.GetCgiInfoPerl().type == fileExt)) 435 | { 436 | _postFilePath = this->_shared.generateFileName("/tmp/", this->_shared.file_extensions[mimeType]); 437 | this->_postFileFd = open(_postFilePath.c_str(), O_CREAT | O_RDWR | O_APPEND, 0777); 438 | } 439 | else 440 | { 441 | this->sendCodeResponse("404"); 442 | return 0; 443 | } 444 | } 445 | if (stat(this->_postFilePath.c_str(), &s) != 0) 446 | { 447 | this->sendCodeResponse("404"); 448 | return 0; 449 | } 450 | if (this->_postFileFd < 0) 451 | { 452 | this->sendCodeResponse("500"); 453 | return 0; 454 | } 455 | } 456 | else if (access(_postFilePath.c_str(), F_OK) == -1 || access(_postFilePath.c_str(), W_OK) == -1 || access(_postFilePath.c_str(), R_OK) == -1) 457 | { 458 | this->sendCodeResponse("500"); 459 | return 0; 460 | } 461 | 462 | 463 | if (this->_req_header.find("Transfer-Encoding") != this->_req_header.end()) 464 | { 465 | returnVal = this->chunkedPost(body, bytesreceived); 466 | } 467 | else 468 | { 469 | long long remmining = std::stoll(this->_req_header["Content-Length"]) - this->_postRecv; 470 | // Write the request body data to the file 471 | if (bytesreceived <= remmining) 472 | write(this->_postFileFd, body, bytesreceived); 473 | else 474 | write(this->_postFileFd, body, remmining); 475 | 476 | this->_postRecv += bytesreceived; 477 | if (this->_postRecv >= std::stoll(this->_req_header["Content-Length"])) 478 | returnVal = 0; 479 | } 480 | 481 | if (!returnVal) 482 | { 483 | stat(this->_path.c_str(), &s); 484 | if (!S_ISDIR(s.st_mode)) 485 | { 486 | std::string fileExt = this->_shared.fileExtention(this->_path); 487 | if (this->_workingLocation.GetCgiInfoPhp().path != "n/a" && this->_workingLocation.GetCgiInfoPhp().type == fileExt) 488 | returnVal = this->HandleCgi(_path, "POST", this->_workingLocation.GetCgiInfoPhp()); 489 | else if (this->_workingLocation.GetCgiInfoPerl().path != "n/a" && this->_workingLocation.GetCgiInfoPerl().type == fileExt) 490 | returnVal = this->HandleCgi(_path, "POST", this->_workingLocation.GetCgiInfoPerl()); 491 | } 492 | else 493 | this->sendCodeResponse("201"); 494 | close(this->_postFileFd); 495 | } 496 | return returnVal; 497 | } 498 | 499 | // -------------------------------- GET method ---------------------- 500 | 501 | int Handler::HandleGet() 502 | { 503 | 504 | if (this->_cgiPid != -1) 505 | { 506 | if ((this->_shared.fileExtention(_path) == this->_workingLocation.GetCgiInfoPhp().type)) 507 | return this->HandleCgi(_path, "GET", this->_workingLocation.GetCgiInfoPhp()); 508 | 509 | if ((this->_shared.fileExtention(_path) == this->_workingLocation.GetCgiInfoPerl().type)) 510 | return this->HandleCgi(_path, "GET", this->_workingLocation.GetCgiInfoPerl()); 511 | } 512 | 513 | // TODO: Function to match the location, takes locationsVec, and uri , and should return the closest match 514 | int indexfileflag = 0; 515 | std::string RealPath, tmp_str, DirStr, UriInit; 516 | struct stat s; 517 | 518 | UriInit = _uri; 519 | if (stat(_path.c_str(), &s) == 0) 520 | { 521 | /*------------------------------------------- DIR Handler ----------------------------------------------------*/ 522 | if (s.st_mode & S_IFDIR) 523 | { 524 | if (_path[_path.size() - 1] != '/') 525 | _path += '/'; 526 | 527 | if ((s.st_mode & S_IRUSR) == 0) 528 | { 529 | this->sendCodeResponse("403"); 530 | return (0); 531 | } 532 | 533 | if (this->_workingLocation.GetIndexesVec().empty() == 0) 534 | { 535 | // case of valid index file so you shuold handle cgi or not 536 | std::string indexfilepath; 537 | 538 | indexfilepath = _path; 539 | indexfilepath += this->_workingLocation.GetIndexesVec()[0]; 540 | this->_path = indexfilepath; 541 | indexfileflag = 1; 542 | } 543 | else 544 | { 545 | // case of no index file and should check autoindex 546 | if (this->_workingLocation.GetAutoIndex() == 1) 547 | { 548 | DIR *DirPtr; 549 | struct dirent *Dir; 550 | DirPtr = opendir(_path.c_str()); 551 | if (DirPtr) 552 | { 553 | std::string IfDir = UriInit; 554 | if (IfDir[IfDir.length() - 1] != '/') 555 | IfDir += '/'; 556 | while ((Dir = readdir(DirPtr)) != NULL) 557 | { 558 | DirStr += IfDir; 559 | DirStr += Dir->d_name; 560 | DirStr += '\n'; 561 | } 562 | closedir(DirPtr); 563 | } 564 | if (DirStr.empty() == 0) 565 | { 566 | std::string lsDir = generateListDir("200", DirStr); 567 | if (this->_headerflag == 0) 568 | SendResponseHeader("200", ".html", "", lsDir.length()); 569 | if (send(this->client_socket, lsDir.c_str(), lsDir.length(), 0) == -1) 570 | { 571 | perror("Error : Send <Index Of> => "); 572 | return (0); 573 | } 574 | return (0); 575 | } 576 | } 577 | else 578 | { 579 | this->sendCodeResponse("403"); // case of no autoindex and no index file 580 | return (0); 581 | } 582 | } 583 | } 584 | /*------------------------------------------- DIR Handler end ------------------------------------------------*/ 585 | 586 | /*--------------------------------------------- File Handler -------------------------------------------------*/ 587 | if ((s.st_mode & S_IFREG) || (indexfileflag == 1)) 588 | { 589 | if (this->_workingLocation.GetCgiInfoPhp().path != "n/a" || this->_workingLocation.GetCgiInfoPerl().path != "n/a") 590 | { 591 | // handle file cgi 592 | if ((this->_shared.fileExtention(_path) == this->_workingLocation.GetCgiInfoPhp().type)) 593 | { 594 | return this->HandleCgi(_path, "GET", this->_workingLocation.GetCgiInfoPhp()); 595 | } 596 | if ((this->_shared.fileExtention(_path) == this->_workingLocation.GetCgiInfoPerl().type)) 597 | { 598 | return this->HandleCgi(_path, "GET", this->_workingLocation.GetCgiInfoPerl()); 599 | } 600 | } 601 | if (this->_workingLocation.GetCgiInfoPhp().path == "n/a" || this->_workingLocation.GetCgiInfoPerl().path == "n/a" || this->_shared.fileExtention(_path) != this->_workingLocation.GetCgiInfoPhp().type || (indexfileflag == 1)) // regular file, non valid cgi extension and index file present with cgi off 602 | { 603 | struct stat file; 604 | if (this->_headerflag == 0) 605 | { 606 | std::string filext = this->_shared.fileExtention(_path); 607 | requested_file = open(this->_path.c_str(), O_RDONLY); 608 | if (requested_file < 0) 609 | perror("Error : Get <Opening file to send it> "); 610 | stat(this->_path.c_str(), &file); 611 | SendResponseHeader("200", filext, "", file.st_size); 612 | } 613 | bytesread = read(requested_file, buffer, sizeof(buffer)); 614 | if (bytesread == -1) 615 | perror("Error : Read <Regular File> => "); 616 | bytessent = send(this->client_socket, buffer, bytesread, 0); 617 | if (bytessent < 1 || bytesread < CHUNK_SIZE) 618 | { 619 | indexfileflag = 0; 620 | perror("Error : Send <Regular File> -> "); 621 | // if (close(requested_file)) 622 | // perror("Error : CLOSE <Regular File>"); 623 | return (0); 624 | } 625 | return (1); 626 | } 627 | } 628 | /*--------------------------------------------- File Handler end -------------------------------------------------*/ 629 | } 630 | else 631 | { 632 | this->sendCodeResponse("404"); 633 | return (0); 634 | } 635 | return (1); 636 | } 637 | 638 | // -------------------------------- Delete method ---------------------- 639 | 640 | int Handler::DeleteDirectory(const char *path) 641 | { 642 | DIR *directory; 643 | struct dirent *entry; 644 | struct stat file; 645 | char subdir[256]; 646 | 647 | if ((directory = opendir(path)) == NULL) 648 | { 649 | std::cerr << "Cannot Open Directory: " << path << std::endl; 650 | sendCodeResponse("403"); 651 | return (1); 652 | } 653 | while ((entry = readdir(directory)) != NULL) 654 | { 655 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 656 | continue; 657 | snprintf(subdir, sizeof(subdir), "%s/%s", path, entry->d_name); 658 | if (stat(subdir, &file) == 0) 659 | { 660 | if (S_ISREG(file.st_mode) && (file.st_mode & S_IWUSR)) 661 | { 662 | DeleteFile(subdir); 663 | } 664 | else if (S_ISDIR(file.st_mode)) 665 | { 666 | DeleteDirectory(subdir); 667 | } 668 | } 669 | else 670 | { 671 | std::cerr << "Error getting file or directory " << subdir << std::endl; 672 | sendCodeResponse("403"); 673 | return 1; 674 | } 675 | } 676 | closedir(directory); 677 | if (rmdir(path) != 0) 678 | { 679 | perror("Error : RMDIR <Deleting Directory> "); 680 | } 681 | return (0); 682 | } 683 | 684 | void Handler::DeleteFile(const char *path) 685 | { 686 | if (unlink(path) != 0) 687 | perror("Error : UNLINK <Delete File> -> "); 688 | } 689 | 690 | int Handler::HandleDelete() 691 | { 692 | struct stat file; 693 | std::string path; 694 | 695 | path = this->_path; 696 | if (stat(path.c_str(), &file) == 0) 697 | { 698 | if (S_ISREG(file.st_mode)) 699 | { 700 | /* 701 | * Allowed Permissions 702 | */ 703 | if (S_ISREG(file.st_mode) && (file.st_mode & S_IWUSR)) 704 | { 705 | DeleteFile(path.c_str()); 706 | SendResponseHeader("204", ".html", "", file.st_size); 707 | return (0); 708 | } 709 | /* 710 | ! No permissions 711 | */ 712 | else 713 | { 714 | sendCodeResponse("403"); 715 | return (0); 716 | } 717 | } 718 | else if (S_ISDIR(file.st_mode)) 719 | { 720 | if (path[path.size() - 1] == '/') 721 | { 722 | /* 723 | * Allowed Permissions 724 | */ 725 | if (S_ISDIR(file.st_mode) && (file.st_mode & S_IWUSR)) 726 | { 727 | if (DeleteDirectory(path.c_str()) == 1) 728 | return (0); 729 | else 730 | SendResponseHeader("204", ".html", "", file.st_size); 731 | } 732 | /* 733 | ! No permissions 734 | */ 735 | else 736 | { 737 | sendCodeResponse("403"); 738 | return (0); 739 | } 740 | } 741 | else 742 | { 743 | sendCodeResponse("409"); 744 | return (0); 745 | } 746 | } 747 | } 748 | /* 749 | ! File or Directory doesn't exist 750 | */ 751 | else 752 | { 753 | sendCodeResponse("404"); 754 | return (0); 755 | } 756 | return (0); 757 | } -------------------------------------------------------------------------------- /srcs/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "../includes/Server.hpp" 2 | 3 | Server::Server(ServerConfig &config) 4 | { 5 | this->_config = config; 6 | } 7 | 8 | void Server::Init() 9 | { 10 | std::cout << this->_config.GetHost().c_str() << ":" << std::to_string(this->_config.GetPort()).c_str() << std::endl; 11 | memset(&server_infos, 0, sizeof(server_infos)); 12 | server_infos.ai_family = AF_INET; 13 | server_infos.ai_socktype = SOCK_STREAM; 14 | server_infos.ai_flags = AI_PASSIVE; 15 | getaddrinfo(this->_config.GetHost().c_str(), std::to_string(this->_config.GetPort()).c_str(), &server_infos, &sinfo_ptr); 16 | } 17 | 18 | void Server::CreateServer() 19 | { 20 | Init(); 21 | if ((server_socket = socket(sinfo_ptr->ai_family, sinfo_ptr->ai_socktype, sinfo_ptr->ai_protocol)) == -1) 22 | { 23 | perror("Error: SOCKET failed -> "); 24 | exit(1); 25 | } 26 | if (fcntl(server_socket, F_SETFL, O_NONBLOCK) == -1) 27 | perror("Error: FCNTL <Server Socket> -> "); 28 | int optval = 1; 29 | if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) == -1) 30 | perror("Error: SETSOCKOPT failed -> "); 31 | if (bind(server_socket, sinfo_ptr->ai_addr, sinfo_ptr->ai_addrlen) == -1) 32 | { 33 | close(server_socket); 34 | perror("Error: BIND failed -> "); 35 | exit(1); 36 | } 37 | if (listen(server_socket, FD_SETSIZE) == -1) 38 | { 39 | close(server_socket); 40 | perror("Error: LISTEN failed -> "); 41 | exit(1); 42 | } 43 | freeaddrinfo(sinfo_ptr); 44 | } 45 | 46 | void Server::DropClient() 47 | { 48 | if (active_clt > 0) 49 | close(active_clt); 50 | if (this->itb->_client_handler.requested_file > 0) 51 | close(this->itb->_client_handler.requested_file); 52 | FD_CLR(active_clt, &readfds); 53 | FD_CLR(active_clt, &writefds); 54 | _clients.erase(itb++); 55 | maxfds -= 1; 56 | } 57 | 58 | int Server::AcceptAddClientToSet() 59 | { 60 | int newconnection = accept(server_socket, (struct sockaddr *)&storage_sock, &clt_addr); 61 | if (fcntl(newconnection, F_SETFL, O_NONBLOCK) == -1) 62 | perror("Error: FCNTL <New Connection> -> "); 63 | if (newconnection == -1) 64 | perror("Error: ACCEPT <New Connection> -> "); 65 | _clients.push_back(Client(newconnection)); 66 | _clients.back()._client_handler.setConfig(this->_config); 67 | readyforwrite = false; 68 | FD_SET(_clients.back().GetCltSocket(), &readfds); 69 | FD_SET(_clients.back().GetCltSocket(), &writefds); 70 | if (_clients.back().GetCltSocket() > maxfds) 71 | maxfds = _clients.back().GetCltSocket(); 72 | return (newconnection); 73 | } 74 | 75 | void Server::SelectSetsInit() 76 | { 77 | timeout.tv_usec = 0; 78 | timeout.tv_sec = 0; 79 | 80 | FD_ZERO(&readfds); 81 | FD_ZERO(&writefds); 82 | FD_SET(server_socket, &readfds); 83 | FD_SET(server_socket, &writefds); 84 | maxfds = server_socket; 85 | } 86 | 87 | 88 | void Server::Start() 89 | { 90 | signal(SIGPIPE, SIG_IGN); 91 | tmpfdsread = readfds; 92 | tmpfdswrite = writefds; 93 | 94 | activity = select(maxfds + 1, &tmpfdsread, &tmpfdswrite, NULL, &timeout); 95 | if (activity == -1) 96 | perror("Error: Select Failed -> "); 97 | 98 | if (FD_ISSET(server_socket, &tmpfdsread)) 99 | { 100 | client_socket = AcceptAddClientToSet(); 101 | } 102 | for (itb = _clients.begin(); itb != _clients.end();) 103 | { 104 | bytesreceived = 0; 105 | active_clt = itb->GetCltSocket(); 106 | 107 | if (FD_ISSET(active_clt, &tmpfdsread)) 108 | { 109 | bytesreceived = recv(active_clt, requested_data, sizeof(requested_data), 0); 110 | if (bytesreceived == 0) 111 | { 112 | std::cerr << "Connection Closed by peer" << std::endl; 113 | DropClient(); 114 | continue; 115 | } 116 | else if (bytesreceived < 0) 117 | { 118 | perror("Error: RECV <An error occured during the receiving> -> "); 119 | DropClient(); 120 | continue; 121 | } 122 | else 123 | { 124 | readyforwrite = true; 125 | } 126 | } 127 | if (FD_ISSET(active_clt, &tmpfdswrite) && readyforwrite == true) 128 | { 129 | if (itb->_client_handler.Driver(requested_data, bytesreceived) == 0) 130 | { 131 | DropClient(); 132 | continue; 133 | } 134 | } 135 | itb++; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /srcs/Shared.cpp: -------------------------------------------------------------------------------- 1 | #include "../includes/Shared.hpp" 2 | 3 | Shared::Shared() 4 | { 5 | this->file_extensions["text/html"]= ".html"; 6 | this->file_extensions["text/css"]= ".css"; 7 | this->file_extensions["application/javascript"]= ".js"; 8 | this->file_extensions["application/json"]= ".json"; 9 | this->file_extensions["application/xml"]= ".xml"; 10 | this->file_extensions["text/plain"]= ".txt"; 11 | this->file_extensions["image/jpeg"]= ".jpg"; 12 | this->file_extensions["image/png"]= ".png"; 13 | this->file_extensions["image/gif"]= ".gif"; 14 | this->file_extensions["image/bmp"]= ".bmp"; 15 | this->file_extensions["image/x-icon"]= ".ico"; 16 | this->file_extensions["application/pdf"]= ".pdf"; 17 | this->file_extensions["application/zip"]= ".zip"; 18 | this->file_extensions["application/x-tar"]= ".tar"; 19 | this->file_extensions["application/gzip"]= ".gz"; 20 | this->file_extensions["application/x-rar-compressed"]= ".rar"; 21 | this->file_extensions["application/x-7z-compressed"]= ".7z"; 22 | this->file_extensions["audio/mpeg"]= ".mp3"; 23 | this->file_extensions["audio/wav"]= ".wav"; 24 | this->file_extensions["video/mp4"]= ".mp4"; 25 | this->file_extensions["video/x-msvideo"] = ".avi"; 26 | this->file_extensions["application/vnd.ms-powerpoint"] = ".ppt"; 27 | this->file_extensions["application/vnd.openxmlformats-officedocument.presentationml.presentation"] = ".pptx"; 28 | this->file_extensions["application/msword"] = ".doc"; 29 | this->file_extensions["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] = ".docx"; 30 | this->file_extensions["application/vnd.ms-excel"] = ".xls"; 31 | this->file_extensions["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = ".xlsx"; 32 | this->file_extensions["text/csv"] = ".csv"; 33 | this->file_extensions["application/x-shockwave-flash"] = ".swf"; 34 | this->file_extensions["image/svg+xml"] = ".svg"; 35 | this->file_extensions["video/mpeg"] = ".mpg"; 36 | this->file_extensions["video/webm"] = ".webm"; 37 | this->file_extensions["audio/ogg"] = ".ogg"; 38 | this->file_extensions["video/ogg"] = ".ogg"; 39 | this->file_extensions["image/webp"] = ".webp"; 40 | this->file_extensions["image/tiff"] = ".tif"; 41 | this->file_extensions["application/font-woff"] = ".woff"; 42 | this->file_extensions["application/font-woff2"] = ".woff2"; 43 | this->file_extensions["application/x-font-ttf"] = ".ttf"; 44 | this->file_extensions["application/x-font-opentype"] = ".otf"; 45 | this->file_extensions["application/vnd.ms-fontobject"] = ".eot"; 46 | this->file_extensions["application/octet-stream"] = ".bin"; 47 | this->file_extensions["application/x-perl"] = ".pl"; 48 | this->file_extensions["application/x-httpd-php"] = ".php"; 49 | this->file_extensions["video/quicktime"] = ".mov"; 50 | 51 | // MIME Types 52 | this->mime_types[".html"] = "text/html"; 53 | this->mime_types[".htm"] = "text/html"; 54 | this->mime_types[".css"] = "text/css"; 55 | this->mime_types[".js"] = "application/javascript"; 56 | this->mime_types[".json"] = "application/json"; 57 | this->mime_types[".xml"] = "application/xml"; 58 | this->mime_types[".txt"] = "text/plain"; 59 | this->mime_types[".jpg"] = "image/jpeg"; 60 | this->mime_types[".jpeg"] = "image/jpeg"; 61 | this->mime_types[".png"] = "image/png"; 62 | this->mime_types[".gif"] = "image/gif"; 63 | this->mime_types[".bmp"] = "image/bmp"; 64 | this->mime_types[".ico"] = "image/x-icon"; 65 | this->mime_types[".pdf"] = "application/pdf"; 66 | this->mime_types[".zip"] = "application/zip"; 67 | this->mime_types[".tar"] = "application/x-tar"; 68 | this->mime_types[".gz"] = "application/gzip"; 69 | this->mime_types[".rar"] = "application/x-rar-compressed"; 70 | this->mime_types[".7z"] = "application/x-7z-compressed"; 71 | this->mime_types[".mp3"] = "audio/mpeg"; 72 | this->mime_types[".wav"] = "audio/wav"; 73 | this->mime_types[".mp4"] = "video/mp4"; 74 | this->mime_types[".avi"] = "video/x-msvideo"; 75 | this->mime_types[".ppt"] = "application/vnd.ms-powerpoint"; 76 | this->mime_types[".pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; 77 | this->mime_types[".doc"] = "application/msword"; 78 | this->mime_types[".docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; 79 | this->mime_types[".xls"] = "application/vnd.ms-excel"; 80 | this->mime_types[".xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; 81 | this->mime_types[".csv"] = "text/csv"; 82 | this->mime_types[".swf"] = "application/x-shockwave-flash"; 83 | this->mime_types[".svg"] = "image/svg+xml"; 84 | this->mime_types[".mpg"] = "video/mpeg"; 85 | this->mime_types[".mpeg"] = "video/mpeg"; 86 | this->mime_types[".webm"] = "video/webm"; 87 | this->mime_types[".ogg"] = "audio/ogg"; 88 | this->mime_types[".ogg"] = "video/ogg"; 89 | this->mime_types[".webp"] = "image/webp"; 90 | this->mime_types[".tif"] = "image/tiff"; 91 | this->mime_types[".tiff"] = "image/tiff"; 92 | this->mime_types[".woff"] = "application/font-woff"; 93 | this->mime_types[".woff2"] = "application/font-woff2"; 94 | this->mime_types[".ttf"] = "application/x-font-ttf"; 95 | this->mime_types[".otf"] = "application/x-font-opentype"; 96 | this->mime_types[".eot"] = "application/vnd.ms-fontobject"; 97 | this->mime_types[".bin"] = "application/octet-stream"; 98 | this->mime_types[".php"] = "application/x-httpd-php"; 99 | this->mime_types[".pl"] = "application/x-perl"; 100 | this->mime_types[".mov"] = "video/quicktime"; 101 | 102 | // Status codes 103 | this->status_codes["100"] = "Continue"; 104 | this->status_codes["101"] = "Switching Protocols"; 105 | this->status_codes["102"] = "Processing"; 106 | this->status_codes["200"] = "OK"; 107 | this->status_codes["201"] = "Created"; 108 | this->status_codes["202"] = "Accepted"; 109 | this->status_codes["203"] = "Non-Authoritative Information"; 110 | this->status_codes["204"] = "No Content"; 111 | this->status_codes["205"] = "Reset Content"; 112 | this->status_codes["206"] = "Partial Content"; 113 | this->status_codes["207"] = "Multi-Status"; 114 | this->status_codes["208"] = "Already Reported"; 115 | this->status_codes["226"] = "IM Used"; 116 | this->status_codes["300"] = "Multiple Choices"; 117 | this->status_codes["301"] = "Moved Permanently"; 118 | this->status_codes["302"] = "Found"; 119 | this->status_codes["303"] = "See Other"; 120 | this->status_codes["304"] = "Not Modified"; 121 | this->status_codes["305"] = "Use Proxy"; 122 | this->status_codes["307"] = "Temporary Redirect"; 123 | this->status_codes["308"] = "Permanent Redirect"; 124 | this->status_codes["400"] = "Bad Request"; 125 | this->status_codes["401"] = "Unauthorized"; 126 | this->status_codes["402"] = "Payment Required"; 127 | this->status_codes["403"] = "Forbidden"; 128 | this->status_codes["404"] = "Not Found"; 129 | this->status_codes["405"] = "Method Not Allowed"; 130 | this->status_codes["406"] = "Not Acceptable"; 131 | this->status_codes["407"] = "Proxy Authentication Required"; 132 | this->status_codes["408"] = "Request Timeout"; 133 | this->status_codes["409"] = "Conflict"; 134 | this->status_codes["410"] = "Gone"; 135 | this->status_codes["411"] = "Length Required"; 136 | this->status_codes["412"] = "Precondition Failed"; 137 | this->status_codes["413"] = "Payload Too Large"; 138 | this->status_codes["414"] = "URI Too Long"; 139 | this->status_codes["415"] = "Unsupported Media Type"; 140 | this->status_codes["416"] = "Range Not Satisfiable"; 141 | this->status_codes["417"] = "Expectation Failed"; 142 | this->status_codes["418"] = "I'm a teapot"; 143 | this->status_codes["421"] = "Misdirected Request"; 144 | this->status_codes["422"] = "Unprocessable Entity"; 145 | this->status_codes["423"] = "Locked"; 146 | this->status_codes["424"] = "Failed Dependency"; 147 | this->status_codes["425"] = "Too Early"; 148 | this->status_codes["426"] = "Upgrade Required"; 149 | this->status_codes["428"] = "Precondition Required"; 150 | this->status_codes["429"] = "Too Many Requests"; 151 | this->status_codes["431"] = "Request Header Fields Too Large"; 152 | this->status_codes["451"] = "Unavailable For Legal Reasons"; 153 | this->status_codes["500"] = "Internal Server Error"; 154 | this->status_codes["501"] = "Not Implemented"; 155 | this->status_codes["502"] = "Bad Gateway"; 156 | this->status_codes["503"] = "Service Unavailable"; 157 | this->status_codes["504"] = "Gateway Timeout"; 158 | this->status_codes["505"] = "HTTP Version Not Supported"; 159 | this->status_codes["506"] = "Variant Also Negotiates"; 160 | this->status_codes["507"] = "Insufficient Storage"; 161 | this->status_codes["508"] = "Loop Detected"; 162 | this->status_codes["510"] = "Not Extended"; 163 | this->status_codes["511"] = "Network Authentication Required"; 164 | } 165 | 166 | 167 | std::string Shared::generateFileName(const std::string& path, const std::string& fileExtension) 168 | { 169 | std::string fileName = path; 170 | const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 171 | 172 | // Generate a random string for the file name 173 | for (int i = 0; i < 10; ++i) 174 | fileName += characters[std::rand() % characters.length()]; 175 | 176 | fileName += fileExtension; 177 | 178 | return fileName; 179 | } 180 | 181 | std::string Shared::fileExtention(std::string fileName) 182 | { 183 | std::string extention; 184 | int dot_position = fileName.find_last_of('.'); 185 | 186 | if (dot_position > 0) 187 | { 188 | extention = fileName.substr(dot_position ,fileName.length()); 189 | return (extention); 190 | } 191 | else 192 | return (""); 193 | } --------------------------------------------------------------------------------