├── .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, = $_COOKIE['name'] ?>!
55 |
56 |
57 |
58 |
Logout
59 |
60 |
61 |
67 |
68 |
--------------------------------------------------------------------------------
/bin/counetr.php:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 | Increment Counter Example
17 |
18 |
19 | Counter:
20 |
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 |
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 | Go Back
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 | 
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 |
83 | Subscribe
84 |
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 |
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 |
432 |
433 | Title
434 |
435 |
438 |
439 |
452 |
453 |
454 |
455 | Action
456 |
457 |
458 |
459 |
460 |
461 |
474 |
475 |
476 |
477 | Action
478 |
479 |
480 |
481 |
482 |
483 |
496 |
497 |
498 |
499 | Action
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 | Pricing
510 |
511 |
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 |
533 | Sign Up
534 |
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 |
556 | Sign Up
557 |
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 |
579 | Sign Up
580 |
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 |
616 |
617 | Main Hero Message to sell yourself!
618 |
619 |
620 | Action!
621 |
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 | 
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 |
14 |
20 |
21 |
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("<") + 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 ");
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 ");
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 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 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 => ");
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 ");
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 => ");
616 | bytessent = send(this->client_socket, buffer, bytesread, 0);
617 | if (bytessent < 1 || bytesread < CHUNK_SIZE)
618 | {
619 | indexfileflag = 0;
620 | perror("Error : Send -> ");
621 | // if (close(requested_file))
622 | // perror("Error : CLOSE ");
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 ");
680 | }
681 | return (0);
682 | }
683 |
684 | void Handler::DeleteFile(const char *path)
685 | {
686 | if (unlink(path) != 0)
687 | perror("Error : UNLINK -> ");
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 -> ");
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 -> ");
63 | if (newconnection == -1)
64 | perror("Error: ACCEPT -> ");
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 -> ");
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 | }
--------------------------------------------------------------------------------