├── .vscode ├── launch.json └── tasks.json ├── Makefile ├── README.md ├── client ├── client.cpp ├── configs ├── default.config └── test.config ├── flowchart ├── CGI.drawio ├── CGI.png ├── DELETE.drawio ├── DELETE.png ├── GET.drawio ├── GET.png ├── POST.drawio ├── POST.png ├── REDIRECTION.drawio └── REDIRECTION.png ├── incs ├── Client.hpp ├── Config.hpp ├── FdBase.hpp ├── Libft.hpp ├── Location.hpp ├── Request.hpp ├── Resource.hpp ├── Response.hpp ├── Server.hpp └── Webserv.hpp ├── srcs ├── Client.cpp ├── Config.cpp ├── FdBase.cpp ├── Libft.cpp ├── Location.cpp ├── Request.cpp ├── Resource.cpp ├── Response.cpp ├── Server.cpp ├── Webserv.cpp ├── addResponse.cpp ├── cgiResponse.cpp └── main.cpp └── tests ├── test1 ├── asb ├── directory │ ├── Yeah │ │ └── not_happy.bad_extension │ ├── index.html │ ├── other.pouic │ ├── youpi.bad_extension │ └── youpi.php ├── error404.html ├── floder │ └── file1.html ├── index.html ├── index33.html └── youpi.php └── tester_bin ├── cgi_tester ├── first.pl ├── php-cgi └── tester /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "name": "(lldb) 시작", 10 | "type": "lldb", 11 | "request": "launch", 12 | "program": "${workspaceFolder}/webserv", 13 | "args": [], 14 | "stopAtEntry": false, 15 | "cwd": "${workspaceFolder}", 16 | "environment": [], 17 | "externalConsole": false, 18 | "MIMode": "lldb" 19 | }, 20 | { 21 | "name": "gcc build and debug active file", 22 | "type": "cppdbg", 23 | "request": "launch", 24 | "program": "${fileDirname}/a.out", 25 | "args": [], 26 | "stopAtEntry": false, 27 | "cwd": "${workspaceFolder}", 28 | "environment": [], 29 | "externalConsole": false, 30 | "MIMode": "lldb", 31 | "preLaunchTask": "gcc build active file" 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "runner": "terminal", 4 | "type": "shell", 5 | "echoCommand": true, 6 | "presentation" : { "reveal": "always" }, 7 | "tasks": [ 8 | { 9 | "label": "save and compile for C++", 10 | "command": "g++", 11 | "args": [ 12 | "${file}", 13 | "-g", 14 | "-o", 15 | "${fileDirname}/${fileBasenameNoExtension}" 16 | ], 17 | "group": "build", 18 | "problemMatcher": { 19 | "fileLocation": [ 20 | "relative", 21 | "${workspaceRoot}" 22 | ], 23 | "pattern": { 24 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning error):\\s+(.*)$", 25 | "file": 1, 26 | "line": 2, 27 | "column": 3, 28 | "severity": 4, 29 | "message": 5 30 | } 31 | } 32 | }, 33 | { 34 | "label": "save and compile for C", 35 | "command": "gcc", 36 | "args": [ 37 | "${file}", 38 | "-g", 39 | "-o", 40 | "${fileDirname}/a.out" 41 | ], 42 | "group": "build", 43 | "problemMatcher": { 44 | "fileLocation": [ 45 | "relative", 46 | "${workspaceRoot}" 47 | ], 48 | "pattern": { 49 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning error):\\s+(.*)$", 50 | "file": 1, 51 | "line": 2, 52 | "column": 3, 53 | "severity": 4, 54 | "message": 5 55 | } 56 | } 57 | }, 58 | { 59 | "label": "execute", 60 | "command": "cmd", 61 | "group": "test", 62 | "args": [ 63 | "/C", 64 | "${fileDirname}\\${fileBasenameNoExtension}" 65 | ] 66 | }, 67 | { 68 | "type": "shell", 69 | "label": "clang build active file", 70 | "command": "/usr/bin/clang", 71 | "args": [ 72 | "-g", 73 | "${file}", 74 | "-o", 75 | "${fileDirname}/${fileBasenameNoExtension}" 76 | ], 77 | "options": { 78 | "cwd": "/usr/bin" 79 | }, 80 | "problemMatcher": [ 81 | "$gcc" 82 | ], 83 | "group": "build" 84 | } 85 | ] 86 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GREEN = \033[0;32m 2 | RED = \033[0;31m 3 | LIGHT_SKYBLUE_COLOR=\033[36m\033[01m 4 | CLEAR = \033[0m 5 | 6 | NAME = webserv 7 | CC = clang++ -std=c++98 8 | # FLAGS = -Wall -Wextra -Werror -g3 -fsanitize=address 9 | FLAGS = -Wall -Wextra -Werror -g 10 | 11 | DIR_HEADER = ./incs/ 12 | DIR_SRC = ./srcs/ 13 | 14 | SRC = Request.cpp Response.cpp cgiResponse.cpp addResponse.cpp Resource.cpp Client.cpp main.cpp Config.cpp Libft.cpp FdBase.cpp Server.cpp Location.cpp Webserv.cpp 15 | 16 | SRCS = $(addprefix $(DIR_SRC), $(SRC)) 17 | OBJS = $(SRCS:%.cpp=%.o) 18 | 19 | all: $(NAME) 20 | 21 | $(NAME): $(OBJS) 22 | @$(CC) $(FLAGS) -I $(DIR_HEADER) $(OBJS) -o $(NAME) 23 | @echo "$(LIGHT_SKYBLUE_COLOR)MAKEFILE DONE$(CLEAR)" 24 | 25 | %.o: %.cpp 26 | @$(CC) $(FLAGS) -I $(DIR_HEADER) -c $< -o $@ 27 | @echo "$(GREEN)Compiled "$<" successfully!$(CLEAR)" 28 | 29 | clean: 30 | @echo "$(RED)rm $(OBJS)$(CLEAR)" 31 | @rm -f $(OBJS) 32 | @echo "$(GREEN)clean successfully!$(CLEAR)" 33 | 34 | fclean: clean 35 | @echo "$(RED)rm $(NAME)$(CLEAR)" 36 | @rm -f $(NAME) 37 | @echo "$(GREEN)fclean successfully!$(CLEAR)" 38 | 39 | re: fclean all 40 | 41 | .PHONY: all clean fclean re 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | redirection 2 | 3 | # webserv 4 | 5 | webserv is a I/O Multiplexing HTTP/1.1 server. 6 | 7 | ## Authors 8 | 9 | * [selim](https://github.com/seohl16) 10 | * [jiholee](https://github.com/zittoooo) 11 | 12 | 👉 노션 페이지 13 | 14 | 15 | 16 | ## 1. Build & Usage 17 | 18 | ```shell 19 | # Compile the sources 20 | make 21 | ``` 22 | ```shell 23 | # Run the server (if no 24 | ./webserv [config_file] 25 | ``` 26 | 27 | 28 | ## 2. Features 29 | - Nginx-like configuration file 30 | - HTTP Protocol (ex. status line, request line...) 31 | - HTTP 1.1 Header 32 | - I/O multiplexing (kqueue) 33 | - GET, POST, DELETE HTTP methods 34 | - HTTP redirections 35 | - HTTP response status codes (ex. 200, 301...) 36 | - CGI implementation (ex. bla, php...) 37 | - Auto Index on/off 38 | 39 | 40 | ## 3. Configuration File Example 41 | 42 | ``` 43 | server 44 | { 45 | server_name default 46 | listen 8180 127.0.0.1 47 | 48 | location / 49 | { 50 | error_page 404 ./tests/test1/error404.html 51 | allow_methods GET POST DELETE 52 | root ./tests/test1/ 53 | index index.html index2.html 54 | auto_index on 55 | cgi_info .php ./tests/tester_bin/php-cgi 56 | cgi_info .bla ./tests/tester_bin/cgi_tester 57 | } 58 | 59 | location /auth/ 60 | { 61 | allow_methods GET POST DELETE 62 | request_max_body_size 42 63 | root ./tests/test1/ 64 | index index.html index2.html 65 | auto_index on 66 | cgi_info .php ./tests/tester_bin/php-cgi 67 | auth_key selim:1234 68 | } 69 | } 70 | 71 | ``` 72 | - `server` : server block 73 | - `listen` : port and ip 74 | - `location` : set for specific route 75 | - `error_page` : path for custom error page 76 | - `allow_method` : allowed methods for HTTP requests 77 | - `index` : default file for the requested URI 78 | - `cgi_info` : cgi execute for specific file extension 79 | - `request_max_body_size` : max limit for request body size 80 | - `auth_key` : authorization needed 81 | 82 | ## 4. Test 83 | - curl 84 | ``` 85 | curl -X POST -H “Content-Type: plain/text” –data “BODY is here and write something longer or shorter than limit” 86 | ``` 87 | - Postman 88 | 89 | ``` 90 | [POST] localhost:8179/index.html 91 | ``` 92 | post 93 | 94 | ``` 95 | [GET/DELETE] localhost:8179/index 96 | ``` 97 | get,delete 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | - Browser 106 | ``` 107 | localhost:8182 108 | ``` 109 | redirection 110 | 111 | 112 | 113 | ``` 114 | localhost:8180/youpi.php 115 | ``` 116 | cgi 117 | 118 | 119 | - Siege 120 | ```shell 121 | # 소켓 제한을 풀어주는 명령어 122 | sudo sysctl -w net.inet.tcp.msl=100 123 | 124 | # seige 명령어 125 | siege -b -R <(echo connection = keep-alive) -c100 127.0.0.1:8180 126 | ``` 127 | seige 128 | 129 | 130 | 131 | ## 5. HTTP Method function explained with flowchart 132 | 133 | ### 5.1. GET 134 | 135 |
136 | 137 | 138 | ### 5.2. POST 139 | 140 |
141 | 142 | 143 | ### 5.3. DELETE 144 | 145 |
146 | 147 | ### 5.4. REDIRECTION 148 | 149 |
150 | 151 | 152 | ### 5.5. CGI 153 | 154 |
155 | 156 | -------------------------------------------------------------------------------- /client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/client -------------------------------------------------------------------------------- /client.cpp: -------------------------------------------------------------------------------- 1 | /* echo_client.c 2 | **데이터를 보낼 서버에 연결 요청을 보내고 수락되는 일반적인 클라이언트의 과정을 거치게 되고, 3 | **연결이 완료되면 서버로 데이터를 전송하고 에코(echo)되어 돌아오는 데이터를 수신하는 과정을 거치게 된다. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #define BUFSIZE 1024 14 | 15 | void error_handling(char *message); 16 | 17 | int main(int argc, char **argv) 18 | { 19 | int sock; 20 | struct sockaddr_in serv_addr; 21 | char message[BUFSIZE]; 22 | int str_len; 23 | if (argc != 3) 24 | { 25 | printf("Usage : %s \n", argv[0]); 26 | exit(1); 27 | } 28 | sock = socket(PF_INET, SOCK_STREAM, 0); /* 서버 접속을 위한 소켓 생성 */ 29 | if (sock == -1) 30 | error_handling("socket() error"); 31 | memset(&serv_addr, 0, sizeof(serv_addr)); 32 | serv_addr.sin_family = AF_INET; 33 | serv_addr.sin_addr.s_addr = inet_addr(argv[1]); 34 | serv_addr.sin_port = htons(atoi(argv[2])); 35 | if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) 36 | error_handling("connect() error"); 37 | while (1) 38 | { 39 | /* 메시지 입력 전송*/ 40 | fputs("전송할 메시지를 입력하세요(q to quit) : ", stdout); 41 | fgets(message, BUFSIZE, stdin); 42 | if (!strcmp(message, "q\n")) 43 | break; 44 | send(sock, message, strlen(message), 0); 45 | /* 메시지 수신 출력 */ 46 | // str_len = recv(sock, message, BUFSIZE - 1, 0); 47 | // message[str_len] = 0; 48 | // printf("서버로부터 전송된 메시지 : %s \n", message); 49 | } 50 | close(sock); 51 | return 0; 52 | } 53 | 54 | void error_handling(char *message) 55 | { 56 | fputs(message, stderr); 57 | fputc('\n', stderr); 58 | exit(1); 59 | } -------------------------------------------------------------------------------- /configs/default.config: -------------------------------------------------------------------------------- 1 | #주석가능하긴한데 예약어로 쓰인 것들은 적으면 안됩니다. 예약어 기준으로 파싱합니다. 2 | #얌체같이 파싱했습니다. 3 | #로케이션 중에 루트 로케이션 ( / ) 는 사용하지 않더라도반드시 필요합니다. 제발 써주세요. 4 | 5 | server 6 | { 7 | server_name default 8 | listen 8180 127.0.0.1 # 7번라인 8번라인 반드시 연달아와야합니다. 만약 서버네임을 입력하고 싶지 않다면, 7번라인 값에 NONE 을 입력합니다. (그래도 8번라인은 필요합니다.) 9 | 10 | location / # / 로케이션은 반드시 존재해야합니다. (디폴트서버) 11 | { 12 | error_page 404 ./tests/test1/error404.html 13 | error_page 405 ./tests/test1/error405.html 14 | allow_methods GET POST DELETE 15 | root ./tests/test1/ 16 | index index.html index2.html 17 | auto_index on 18 | cgi_info .php ./tests/tester_bin/php-cgi 19 | cgi_info .bla ./tests/tester_bin/cgi_tester 20 | } 21 | 22 | location /virtual/ 23 | { 24 | allow_methods GET POST DELETE 25 | request_max_body_size 42 26 | root ./tests/test1/ 27 | index index.html index2.html 28 | auto_index on 29 | cgi_info .php ./tests/tester_bin/php-cgi 30 | auth_key selim:1234 31 | } 32 | } 33 | 34 | server 35 | { 36 | server_name second 37 | listen 8181 127.0.0.1 38 | 39 | location / 40 | { 41 | allow_methods GET 42 | root ./tests/test1/ 43 | index second.html 44 | } 45 | } 46 | 47 | server 48 | { 49 | server_name google.com 50 | listen 8182 127.0.0.1 51 | 52 | location / 53 | { 54 | allow_methods GET 55 | return 301 http://google.com 56 | } 57 | } -------------------------------------------------------------------------------- /configs/test.config: -------------------------------------------------------------------------------- 1 | #주석가능하긴한데 예약어로 쓰인 것들은 적으면 안됩니다. 예약어 기준으로 파싱합니다. 2 | #얌체같이 파싱했습니다. 3 | #로케이션 중에 루트 로케이션 ( / ) 는 사용하지 않더라도반드시 필요합니다. 제발 써주세요. 4 | 5 | server 6 | { 7 | server_name default 8 | listen 8176 127.0.0.1 # 7번라인 8번라인 반드시 연달아와야합니다. 만약 서버네임을 입력하고 싶지 않다면, 7번라인 값에 NONE 을 입력합니다. (그래도 8번라인은 필요합니다.) 9 | 10 | location / # / 로케이션은 반드시 존재해야합니다. (디폴트서버) 11 | { 12 | error_page 404 ./tests/test1/error404.html 13 | error_page 405 ./tests/test1/error405.html 14 | allow_methods GET DELETE 15 | root ./tests/test1/ 16 | index index.html index2.html 17 | auto_index off 18 | cgi_info .bla ./tests/tester_bin/cgi_tester 19 | cgi_info .php ./tests/tester_bin/php-cgi 20 | } 21 | 22 | location /directory/ # / 로케이션은 반드시 존재해야합니다. (디폴트서버) 23 | { 24 | error_page 404 ./tests/test1/error404.html 25 | error_page 405 ./tests/test1/error405.html 26 | allow_methods GET DELETE 27 | root ./tests/test1/directory/ 28 | index index.html index2.html 29 | auto_index off 30 | cgi_info .bla ./tests/tester_bin/cgi_tester 31 | cgi_info .php ./tests/tester_bin/php-cgi 32 | } 33 | 34 | location /directory/nop/ # / 로케이션은 반드시 존재해야합니다. (디폴트서버) 35 | { 36 | error_page 404 ./tests/test1/error404.html 37 | error_page 405 ./tests/test1/error405.html 38 | allow_methods GET DELETE 39 | root ./tests/test1/directory/ 40 | index index.html index2.html 41 | auto_index on 42 | cgi_info .bla ./tests/tester_bin/cgi_tester 43 | cgi_info .php ./tests/tester_bin/php-cgi 44 | } 45 | 46 | location /virtual/ 47 | { 48 | allow_methods GET POST DELETE 49 | request_max_body_size 42 50 | root ./tests/test1/ 51 | cgi_info .php ./tests/tester_bin/php-cgi 52 | auth_key selim:1234 53 | } 54 | } 55 | 56 | server 57 | { 58 | server_name second 59 | listen 8178 127.0.0.1 60 | 61 | location /test 62 | { 63 | allow_methods GET 64 | root ./tests/test1/ 65 | index second.html 66 | } 67 | } 68 | 69 | server 70 | { 71 | server_name google.com 72 | listen 8177 127.0.0.1 73 | 74 | location / 75 | { 76 | allow_methods GET 77 | return 301 http://google.com 78 | } 79 | } -------------------------------------------------------------------------------- /flowchart/CGI.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /flowchart/CGI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/flowchart/CGI.png -------------------------------------------------------------------------------- /flowchart/DELETE.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /flowchart/DELETE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/flowchart/DELETE.png -------------------------------------------------------------------------------- /flowchart/GET.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /flowchart/GET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/flowchart/GET.png -------------------------------------------------------------------------------- /flowchart/POST.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /flowchart/POST.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/flowchart/POST.png -------------------------------------------------------------------------------- /flowchart/REDIRECTION.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /flowchart/REDIRECTION.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/flowchart/REDIRECTION.png -------------------------------------------------------------------------------- /incs/Client.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLIENT_HPP 2 | # define CLIENT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "FdBase.hpp" 10 | #include "Response.hpp" 11 | #include "Request.hpp" 12 | #include "Server.hpp" 13 | 14 | class Server; 15 | 16 | typedef enum t_c_status 17 | { 18 | REQUEST_RECEIVING, 19 | MAKE_RESPONSE, 20 | FILE_READING, 21 | FILE_READ_DONE, 22 | FILE_WRITING, 23 | FILE_WRITE_DONE, 24 | MAKE_RESPONSE_DONE 25 | } e_c_status; 26 | 27 | 28 | class Client : public FdBase 29 | { 30 | private: 31 | Request m_request; 32 | Response m_response; 33 | e_c_status m_c_status; 34 | unsigned long m_last_time; 35 | 36 | Server *m_server; 37 | 38 | public: 39 | Client(); 40 | Client(Server *server, int c_fd); 41 | virtual ~Client(); 42 | Client(const Client &other); 43 | Client &operator=(const Client &other); 44 | 45 | Request &getRequest(void); 46 | Response &getResponse(void); 47 | e_c_status &getCStatus(void); 48 | unsigned long &getLastTime(void); 49 | Server* getServer(void); 50 | 51 | void setLastTime(unsigned long last_time); 52 | void setCStatus(e_c_status c_status); 53 | 54 | void appendOrigin(std::string newstr); 55 | bool parseRequest(); 56 | void makeResponse(); 57 | void initRequestandResponse(); 58 | }; 59 | 60 | #endif -------------------------------------------------------------------------------- /incs/Config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_HPP 2 | # define CONFIG_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "Server.hpp" 13 | #include "Location.hpp" 14 | #include "Libft.hpp" 15 | #include "Webserv.hpp" 16 | 17 | class Server; 18 | class Webserv; 19 | 20 | class Config 21 | { 22 | private: 23 | Config(const Config &other); 24 | 25 | 26 | Webserv *m_webserv; 27 | static Config *m_config; 28 | std::map m_server_map; 29 | std::map m_mime_typeMap; 30 | std::map m_status_codeMap; 31 | 32 | public: 33 | Config(); 34 | virtual ~Config(); 35 | Config &operator=(const Config &other); 36 | 37 | static Config* getConfig(); 38 | void parsingConfig(std::string path); 39 | 40 | static const int decodeMimeBase64[256]; 41 | //get 42 | Webserv* getWebserv(); 43 | std::map &getServerMap(); 44 | std::map &getMimeTypeMap(); 45 | std::map &getStatusCodeMap(); 46 | Server* getLastServer(); 47 | 48 | //set 49 | void setWebserv(Webserv* webserv); 50 | 51 | //is 52 | bool isKeyword(std::string keyword); 53 | 54 | //add 55 | // void addServerMap(std::string ipPort, Server Server); 56 | }; 57 | 58 | #endif -------------------------------------------------------------------------------- /incs/FdBase.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FD_BASE_HPP 2 | # define FD_BASE_HPP 3 | 4 | typedef enum t_fd_type 5 | { 6 | FD_SERVER, 7 | FD_CLIENT, 8 | FD_RESOURCE 9 | } e_fd_type; 10 | 11 | class FdBase 12 | { 13 | protected: 14 | int m_fd; 15 | e_fd_type m_fd_type; 16 | 17 | public: 18 | FdBase(); 19 | FdBase(const FdBase &other); 20 | virtual ~FdBase(); 21 | FdBase &operator=(const FdBase &other); 22 | 23 | int getFd(void) const; 24 | e_fd_type getFdType(void) const; 25 | 26 | void setFd(int fd); 27 | void setFdType(e_fd_type fd_type); 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /incs/Libft.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIBFT_HPP 2 | # define LIBFT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void ft_split(const std::string &target, const std::string &sep, std::vector &infos); 9 | void *ft_memset(void *s, int c, size_t n); 10 | #endif -------------------------------------------------------------------------------- /incs/Location.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LOCATION_HPP 2 | # define LOCATION_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Location { 10 | private: 11 | int m_max_body_size; 12 | int m_return_num; 13 | bool m_auto_index; 14 | std::string m_root; 15 | std::string m_upload_path; // where are you from 16 | std::string m_uri; 17 | std::string m_auth_key; 18 | std::string m_return_url; 19 | std::vector m_allow_methods; 20 | std::vector m_indexs; 21 | std::map m_error_pages; 22 | std::map m_cgi; 23 | 24 | public: 25 | Location(); 26 | virtual ~Location(); 27 | Location(const Location &src); 28 | Location& operator=(const Location &src); 29 | 30 | //get 31 | int &getMaxBodySize(); 32 | bool &getAutoIndex(); 33 | std::string &getUploadPath(); 34 | std::string &getUri(); 35 | std::string &getAuthKey(); 36 | std::string &getRoot(); 37 | int &getReturnNum(); 38 | std::string &getReturnUrl(); 39 | std::vector &getAllowMethods(); 40 | std::vector &getIndexs(); 41 | std::map &getErrorPages(); 42 | std::map &getCgi(); 43 | 44 | //set 45 | void setMaxBodySize(int size); 46 | void setReturnNum(int return_num); 47 | void setAutoIndex(bool auto_index); 48 | void setRoot(std::string root); 49 | void setUploadPath(std::string path); 50 | void setUri(std::string uri); 51 | void setAuthKey(std::string auth_key); 52 | void setReturnUrl(std::string return_url); 53 | }; 54 | 55 | #endif -------------------------------------------------------------------------------- /incs/Request.hpp: -------------------------------------------------------------------------------- 1 | #ifndef REQUEST_HPP 2 | # define REQUEST_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Libft.hpp" 11 | 12 | class Client; 13 | class Location; 14 | 15 | typedef enum t_req_status 16 | { 17 | HEADER_PARSING, 18 | BODY_PARSING, 19 | CHUNKED, 20 | CHUNKED_BODY, 21 | CONTENT_BODY 22 | } e_req_status; 23 | 24 | class Request 25 | { 26 | private: 27 | std::string m_origin; 28 | std::string m_body; 29 | 30 | std::string m_method; 31 | std::string m_reqlocation; 32 | std::string m_httpver; 33 | std::map m_headersMap; 34 | 35 | e_req_status m_request_status; 36 | 37 | Client *m_client; 38 | size_t m_remain_body_value; 39 | int base64_decode(const char * text, char * dst, int numBytes); 40 | 41 | public: 42 | Request(); 43 | virtual ~Request(); 44 | Request(const Request &other); 45 | Request &operator=(const Request &other); 46 | 47 | //get 48 | std::string& getOrigin(); 49 | std::string& getBody(); 50 | std::string& getMethod(); 51 | std::string& getReqLocation(); 52 | std::string& getHttpVer(); 53 | std::map& getHeadersMap(); 54 | e_req_status& getRequestStatus(); 55 | Client* getClient(); 56 | size_t getRemainBodyValue(); 57 | 58 | //set 59 | void setOrigin(std::string); 60 | void setBody(std::string); 61 | void setMethod(std::string); 62 | void setReqLocation(std::string); 63 | void setHttpver(std::string); 64 | // void setHeadersMap(); 65 | void setRequestStatus(e_req_status); 66 | void setClient(Client* client); 67 | void setRemainBodyValue(size_t len); 68 | 69 | bool makeHeader(void); 70 | bool makeBody(void); 71 | bool checkValidRequest(std::string fin); 72 | bool isValidAuthHeader(Location &loc); 73 | bool isValidMethod(Location &loc); 74 | bool isValidRequestMaxBodySize(Location &loc); 75 | 76 | void initRequest(); 77 | }; 78 | 79 | #endif -------------------------------------------------------------------------------- /incs/Resource.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RESOURCE_HPP 2 | # define RESOURCE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include "FdBase.hpp" 8 | 9 | class Client; 10 | 11 | typedef enum t_resource_types 12 | { 13 | READ_RESOURCE, // FD_TO_RAW_DATA 14 | WRITE_RESOURCE // RAWDATA_TO_FD 15 | } e_resource_type; 16 | 17 | typedef enum t_nextcall 18 | { 19 | MAKING_ERROR_RESPONSE, 20 | MAKING_RESPONSE 21 | } e_nextcall; 22 | 23 | typedef enum t_rsc_status 24 | { 25 | READY, 26 | NOT_YET, 27 | CGI_CRASH 28 | } e_rsc_status; 29 | 30 | class Resource : public FdBase 31 | { 32 | private: 33 | std::string &m_raw_data; // response의 m_body 34 | std::string m_unlink_path; 35 | Client *m_client; 36 | e_resource_type m_type; 37 | e_nextcall m_next; 38 | int m_response_error_num; 39 | size_t m_write_index; 40 | 41 | int m_pid; 42 | bool m_is_seeked; 43 | 44 | public: 45 | // Resource(); // 기본 생성자를 쓸 일이 없음 일단 주석~ 46 | Resource(int fd, std::string& response_message, Client* clnt, e_resource_type type, e_nextcall nxt, int err); 47 | virtual ~Resource(); 48 | Resource(Resource & rsc); 49 | Resource& operator=(Resource& rsc); 50 | 51 | // get 52 | std::string& getRawData(); 53 | std::string getUnlinkPath(); 54 | Client* getClient(); 55 | e_resource_type getResourceType(); 56 | e_nextcall getNextCall(); 57 | int getResponseErrorNum(); 58 | size_t getWriteIndex(); 59 | int getPid(); 60 | bool getIsSeeked(); 61 | 62 | //set 63 | void setUnlinkPath(std::string path); 64 | void setClient(Client * clnt); 65 | void setResourceType(e_resource_type type); 66 | void setNext(e_nextcall next); 67 | void setResponseErrorNum(int err_num); 68 | void setWriteIndex(size_t idx); 69 | void setPid(int pid); 70 | void setIsSeeked(bool seeked); 71 | 72 | e_rsc_status isReady(void); 73 | void doNext(void); 74 | }; 75 | 76 | 77 | #endif -------------------------------------------------------------------------------- /incs/Response.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RESPONSE_HPP 2 | # define RESPONSE_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 | 16 | // #include "Client.hpp" 17 | #include "Config.hpp" 18 | #include "Location.hpp" 19 | #include "Resource.hpp" 20 | 21 | 22 | class Location; 23 | class Client; 24 | 25 | 26 | class Response 27 | { 28 | private: 29 | bool m_return; 30 | bool m_disconnect; 31 | Client *m_client; 32 | 33 | std::string m_message; 34 | std::string m_resource_path; 35 | Location *m_location; 36 | 37 | std::string m_cgi_extension; 38 | size_t m_write_idx; 39 | std::list m_resourceList; 40 | 41 | int m_fd_read; 42 | int m_fd_write; 43 | 44 | public: 45 | Response(); 46 | virtual ~Response(); 47 | Response(const Response &other); 48 | Response &operator=(const Response &other); 49 | 50 | //get 51 | bool getReturn(); 52 | bool getDisconnect(); 53 | Client* getClient(); 54 | std::string& getMessage(); 55 | std::string getResourcePath(); 56 | Location* getLocation(); 57 | std::string getCgiExtension(); 58 | size_t getWriteIdx(); 59 | int getFdRead(); 60 | int getFdWrite(); 61 | std::list& getResourceList(); 62 | 63 | //set 64 | void setReturn(bool); 65 | void setDisconnect(bool); 66 | void setClient(Client* client); 67 | void setMessage(std::string message); 68 | void setResourcePath(std::string path); 69 | void setLocation(Location *location); 70 | void setCgi(std::string cgi); 71 | void setWriteIdx(size_t idx); 72 | void setFdRead(int fd); 73 | void setFdWrite(int fd); 74 | void setResource(int res_fd, e_resource_type type, e_nextcall ctype, int errornum = -1); 75 | 76 | void makeCgiResponse(void); 77 | void makeGetResponse(void); 78 | void makePostResponse(void); 79 | void makeRedirection(void); 80 | void makeDeleteResponse(void); 81 | void makeErrorResponse(int err); // 헤더 넣고 바디에 addErrorBody(errorcode) or setResource 82 | void makeAutoIndexPage(void); 83 | void makeFileList(std::string &body); 84 | 85 | char **makeCgiEnv(void); 86 | 87 | void addStatusLine(int err); 88 | void addDate(); 89 | void addContentLanguage(); 90 | void addContentType(std::string type); 91 | void addContentLength(int size); 92 | void addAllowMethod(); 93 | void addEmptyLine(); 94 | void addErrorBody(int errorcode); // 다양한 errorcode가 들어간 body 만들어서 return 95 | void addDefaultErrorBody(std::string& message, int errorcode); // 실제 errorcode body 만드는 함수 96 | void addServer(); 97 | void addLocation(std::string &url); 98 | void addWWWAuthenticate(); 99 | 100 | bool isDirectory(std::string path); 101 | bool isExist(std::string path); 102 | 103 | void initResponse(); 104 | 105 | }; 106 | 107 | #endif -------------------------------------------------------------------------------- /incs/Server.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_HPP 2 | # define SERVER_HPP 3 | 4 | #include "FdBase.hpp" 5 | #include "Location.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class Server : public FdBase 12 | { 13 | private: 14 | std::string m_server_name; 15 | std::string m_ip; 16 | std::string m_port; 17 | std::map m_locationMap; 18 | 19 | public: 20 | Server(); 21 | Server(const Server &other); 22 | virtual ~Server(); 23 | Server &operator=(const Server &other); 24 | 25 | void setServerName(std::string server_name); 26 | void setIp(std::string ip); 27 | void setPort(std::string port); 28 | 29 | const std::string &getServerName(void) const; 30 | const std::string &getIp(void) const; 31 | const std::string &getPort(void) const; 32 | std::map &getLocations(); 33 | 34 | Location& getLastLocation(void); 35 | Location& getPerfectLocation(std::string &uri); 36 | 37 | 38 | 39 | }; 40 | 41 | std::ostream &operator<<(std::ostream &o, Server &server); 42 | 43 | #endif -------------------------------------------------------------------------------- /incs/Webserv.hpp: -------------------------------------------------------------------------------- 1 | #ifndef WEBSERV_HPP 2 | # define WEBSERV_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 16 | #include 17 | #include 18 | #include "../incs/Config.hpp" 19 | #include "../incs/Server.hpp" 20 | #include "../incs/Location.hpp" 21 | #include "../incs/FdBase.hpp" 22 | #include "../incs/Client.hpp" 23 | #include "../incs/Resource.hpp" 24 | 25 | # define MAX_FD_SIZE 1024 26 | # define BUFSIZE 1025 27 | 28 | class Server; 29 | class Location; 30 | class Config; 31 | 32 | class Webserv 33 | { 34 | private: 35 | int m_kq; 36 | struct kevent m_return_events[1024]; 37 | std::vector m_change_list; 38 | std::vector m_fd_pool; 39 | unsigned long m_timeout; 40 | 41 | public: 42 | Webserv(); 43 | Webserv(const Webserv &other); 44 | virtual ~Webserv(); 45 | Webserv &operator=(const Webserv &other); 46 | 47 | void startServer(); 48 | void testServer(); 49 | void change_events(std::vector &change_list, uintptr_t ident, int16_t filter, 50 | uint16_t flags, uint32_t fflags, intptr_t data, void *udata); 51 | 52 | std::vector& getChangeList(); 53 | void addFdPool(FdBase* res); 54 | void deleteFdPool(FdBase *res); 55 | void signalExit(); 56 | unsigned long call_time(void); 57 | }; 58 | 59 | #endif -------------------------------------------------------------------------------- /srcs/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Client.hpp" 2 | 3 | Client::Client() 4 | { 5 | this->m_server = 0; 6 | this->m_c_status = REQUEST_RECEIVING; 7 | this->m_fd_type = FD_CLIENT; 8 | this->m_fd = -1; 9 | this->m_request.setClient(this); 10 | this->m_response.setClient(this); 11 | struct timeval tv; 12 | gettimeofday(&tv, NULL); 13 | this->m_last_time = (tv.tv_sec * 1000 + tv.tv_usec / 1000); 14 | } 15 | 16 | Client::Client(Server *server, int c_fd) 17 | { 18 | this->m_server = server; 19 | this->m_c_status = REQUEST_RECEIVING; 20 | this->m_fd_type = FD_CLIENT; 21 | this->m_fd = c_fd; 22 | this->m_request.setClient(this); 23 | this->m_response.setClient(this); 24 | struct timeval tv; 25 | gettimeofday(&tv, NULL); 26 | this->m_last_time = (tv.tv_sec * 1000 + tv.tv_usec / 1000); 27 | } 28 | Client::~Client() 29 | { 30 | 31 | } 32 | 33 | Client::Client(const Client &other) 34 | { 35 | *this = other; 36 | } 37 | 38 | Client &Client::operator=(const Client &other) 39 | { 40 | this->m_server = other.m_server; 41 | this->m_c_status = other.m_c_status; 42 | this->m_fd_type = other.m_fd_type; 43 | this->m_fd = other.m_fd; 44 | return (*this); 45 | } 46 | 47 | Request &Client::getRequest(void) 48 | { 49 | return (this->m_request); 50 | } 51 | 52 | Response &Client::getResponse(void) 53 | { 54 | return (this->m_response); 55 | } 56 | 57 | e_c_status &Client::getCStatus(void) 58 | { 59 | return (this->m_c_status); 60 | } 61 | 62 | unsigned long &Client::getLastTime(void) 63 | { 64 | return (this->m_last_time); 65 | } 66 | 67 | Server* Client::getServer(void) 68 | { 69 | return (this->m_server); 70 | } 71 | 72 | void Client::setLastTime(unsigned long last_time) 73 | { 74 | this->m_last_time = last_time; 75 | } 76 | 77 | void Client::setCStatus(e_c_status c_status) 78 | { 79 | this->m_c_status = c_status; 80 | } 81 | 82 | void Client::appendOrigin(std::string newstr) 83 | { 84 | this->getRequest().getOrigin() += newstr; 85 | } 86 | 87 | bool Client::parseRequest() 88 | { 89 | // m_request.setClient(this); // 90 | if (m_request.getRequestStatus() == HEADER_PARSING) 91 | { 92 | std::size_t idx = m_request.getOrigin().find("\r\n\r\n"); 93 | if (idx == std::string::npos) 94 | return false; 95 | // m_request.makeStartLine(); 96 | m_request.makeHeader(); // startline, header 97 | m_request.setRequestStatus(BODY_PARSING); 98 | } 99 | if (m_request.getRequestStatus() == BODY_PARSING) 100 | { 101 | if ((m_request.getHeadersMap().count("Transfer-Encoding") == 1) && \ 102 | (m_request.getHeadersMap()["Transfer-Encoding"] == "chunked")) 103 | { 104 | m_request.setRequestStatus(CHUNKED); 105 | return (m_request.makeBody()); 106 | } 107 | else if (m_request.getHeadersMap().count("Content-Length")) 108 | { 109 | m_request.setRemainBodyValue(atoi(m_request.getHeadersMap()["Content-Length"].c_str())); 110 | if (m_request.getRemainBodyValue() == 0) 111 | { 112 | return (m_request.checkValidRequest("FINISHED")); 113 | } 114 | m_request.setRequestStatus(CONTENT_BODY); 115 | return (m_request.makeBody()); 116 | } 117 | else 118 | return (m_request.checkValidRequest("FINISHED")); 119 | } 120 | 121 | return (m_request.makeBody()); 122 | } 123 | 124 | void Client::makeResponse() 125 | { 126 | if(m_response.getCgiExtension() != "") 127 | return (m_response.makeCgiResponse()); 128 | if (m_response.getReturn()) 129 | return (m_response.makeRedirection()); 130 | 131 | if(m_request.getMethod() == "GET") 132 | { 133 | if (getCStatus() == MAKE_RESPONSE) 134 | m_response.makeGetResponse(); 135 | else if (getCStatus() == FILE_READ_DONE) 136 | this->setCStatus(MAKE_RESPONSE_DONE); 137 | return ; 138 | } 139 | if (m_request.getMethod() == "POST") 140 | { 141 | if (getCStatus() == MAKE_RESPONSE) 142 | m_response.makePostResponse(); 143 | else if (getCStatus() == FILE_WRITE_DONE) 144 | this->setCStatus(MAKE_RESPONSE_DONE); 145 | } 146 | if(m_request.getMethod() == "DELETE") 147 | { 148 | if (getCStatus() == MAKE_RESPONSE) 149 | m_response.makeDeleteResponse(); 150 | else if (getCStatus() == FILE_READ_DONE) 151 | this->setCStatus(MAKE_RESPONSE_DONE); 152 | return ; 153 | } 154 | 155 | } 156 | 157 | void Client::initRequestandResponse() 158 | { 159 | m_request.initRequest(); 160 | m_response.initResponse(); 161 | } -------------------------------------------------------------------------------- /srcs/Config.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Config.hpp" 2 | 3 | Config* Config::m_config = 0; // static 멤버 변수 초기화 4 | 5 | int const Config::decodeMimeBase64[256] = { 6 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ 7 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ 8 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ 9 | 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ 10 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ 11 | 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ 12 | -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ 13 | 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ 14 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ 15 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ 16 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ 17 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ 18 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ 19 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ 20 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ 21 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ 22 | }; 23 | 24 | Config::Config() 25 | { 26 | m_status_codeMap["100"] = "Continue"; 27 | m_status_codeMap["101"] = "Switching Protocols"; 28 | m_status_codeMap["200"] = "OK"; 29 | m_status_codeMap["201"] = "Created"; 30 | m_status_codeMap["202"] = "Accepted"; 31 | m_status_codeMap["203"] = "Non-authoritative Information"; 32 | m_status_codeMap["204"] = "No Content"; 33 | m_status_codeMap["205"] = "Reset Content"; 34 | m_status_codeMap["206"] = "Partial Content"; 35 | m_status_codeMap["300"] = "Multiple Choices"; 36 | m_status_codeMap["301"] = "Moved Permanently"; 37 | m_status_codeMap["302"] = "Found"; 38 | m_status_codeMap["303"] = "See Other"; 39 | m_status_codeMap["304"] = "Not Modified"; 40 | m_status_codeMap["305"] = "Use Proxy"; 41 | m_status_codeMap["307"] = "Temporary Redirect"; 42 | m_status_codeMap["400"] = "Bad Request"; 43 | m_status_codeMap["401"] = "Unauthorized"; 44 | m_status_codeMap["402"] = "Payment Required"; 45 | m_status_codeMap["403"] = "Forbidden"; 46 | m_status_codeMap["404"] = "Not found"; 47 | m_status_codeMap["405"] = "Method Not Allowed"; 48 | m_status_codeMap["406"] = "Not Acceptable"; 49 | m_status_codeMap["407"] = "Proxy Authentication Required"; 50 | m_status_codeMap["408"] = "Required Timeout"; 51 | m_status_codeMap["409"] = "Conflict"; 52 | m_status_codeMap["410"] = "Gone"; 53 | m_status_codeMap["411"] = "Length Required"; 54 | m_status_codeMap["412"] = "Precondition Failed"; 55 | m_status_codeMap["413"] = "Request Entity Too Large"; 56 | m_status_codeMap["414"] = "Request URI Too Long"; 57 | m_status_codeMap["415"] = "Unsupported Media Type"; 58 | m_status_codeMap["416"] = "Requested Range Not Satisfiable"; 59 | m_status_codeMap["417"] = "Expectation Failed"; 60 | m_status_codeMap["418"] = "IM_A_TEAPOT"; 61 | m_status_codeMap["500"] = "Internal Server Error"; 62 | m_status_codeMap["501"] = "Not Implemented"; 63 | m_status_codeMap["502"] = "Bad Gateway"; 64 | m_status_codeMap["503"] = "Service Unavailable"; 65 | m_status_codeMap["504"] = "Gateway Timeout"; 66 | m_status_codeMap["505"] = "HTTP Version Not Supported"; 67 | m_mime_typeMap[".aac"] = "audio/aac"; 68 | m_mime_typeMap[".abw"] = "application/x-abiword"; 69 | m_mime_typeMap[".arc"] = "application/octet-stream"; 70 | m_mime_typeMap[".avi"] = "video/x-msvideo"; 71 | m_mime_typeMap[".azw"] = "application/vnd.amazon.ebook"; 72 | m_mime_typeMap[".bin"] = "application/octet-stream"; 73 | m_mime_typeMap[".bz"] = "application/x-bzip"; 74 | m_mime_typeMap[".bz2"] = "application/x-bzip2"; 75 | m_mime_typeMap[".csh"] = "application/x-csh"; 76 | m_mime_typeMap[".css"] = "text/css"; 77 | m_mime_typeMap[".csv"] = "text/csv"; 78 | m_mime_typeMap[".doc"] = "application/msword"; 79 | m_mime_typeMap[".epub"] = "application/epub+zip"; 80 | m_mime_typeMap[".gif"] = "image/gif"; 81 | m_mime_typeMap[".htm"] = "text/html"; 82 | m_mime_typeMap[".html"] = "text/html"; 83 | m_mime_typeMap[".ico"] = "image/x-icon"; 84 | m_mime_typeMap[".ics"] = "text/calendar"; 85 | m_mime_typeMap[".jar"] = "application/java-archive"; 86 | m_mime_typeMap[".jpeg"] = "image/jpeg"; 87 | m_mime_typeMap[".jpg"] = "image/jpeg"; 88 | m_mime_typeMap[".js"] = "application/js"; 89 | m_mime_typeMap[".json"] = "application/json"; 90 | m_mime_typeMap[".mid"] = "audio/midi"; 91 | m_mime_typeMap[".midi"] = "audio/midi"; 92 | m_mime_typeMap[".mpeg"] = "video/mpeg"; 93 | m_mime_typeMap[".mpkg"] = "application/vnd.apple.installer+xml"; 94 | m_mime_typeMap[".odp"] = "application/vnd.oasis.opendocument.presentation"; 95 | m_mime_typeMap[".ods"] = "application/vnd.oasis.opendocument.spreadsheet"; 96 | m_mime_typeMap[".odt"] = "application/vnd.oasis.opendocument.text"; 97 | m_mime_typeMap[".oga"] = "audio/ogg"; 98 | m_mime_typeMap[".ogv"] = "video/ogg"; 99 | m_mime_typeMap[".ogx"] = "application/ogg"; 100 | m_mime_typeMap[".pdf"] = "application/pdf"; 101 | m_mime_typeMap[".ppt"] = "application/vnd.ms-powerpoint"; 102 | m_mime_typeMap[".rar"] = "application/x-rar-compressed"; 103 | m_mime_typeMap[".rtf"] = "application/rtf"; 104 | m_mime_typeMap[".sh"] = "application/x-sh"; 105 | m_mime_typeMap[".svg"] = "image/svg+xml"; 106 | m_mime_typeMap[".swf"] = "application/x-shockwave-flash"; 107 | m_mime_typeMap[".tar"] = "application/x-tar"; 108 | m_mime_typeMap[".tif"] = "image/tiff"; 109 | m_mime_typeMap[".tiff"] = "image/tiff"; 110 | m_mime_typeMap[".ttf"] = "application/x-font-ttf"; 111 | m_mime_typeMap[".vsd"] = "application/vnd.visio"; 112 | m_mime_typeMap[".wav"] = "audio/x-wav"; 113 | m_mime_typeMap[".weba"] = "audio/webm"; 114 | m_mime_typeMap[".webm"] = "video/webm"; 115 | m_mime_typeMap[".webp"] = "image/webp"; 116 | m_mime_typeMap[".woff"] = "application/x-font-woff"; 117 | m_mime_typeMap[".xhtml"] = "application/xhtml+xml"; 118 | m_mime_typeMap[".xls"] = "application/vnd.ms-excel"; 119 | m_mime_typeMap[".xml"] = "application/xml"; 120 | m_mime_typeMap[".xul"] = "application/vnd.mozilla.xul+xml"; 121 | m_mime_typeMap[".zip"] = "application/zip"; 122 | m_mime_typeMap[".3gp"] = "video/3gpp audio/3gpp"; 123 | m_mime_typeMap[".3g2"] = "video/3gpp2 audio/3gpp2"; 124 | m_mime_typeMap[".7z"] = "application/x-7z-compressed"; 125 | } 126 | 127 | Config::~Config() 128 | { 129 | delete this->m_config; 130 | } 131 | 132 | Config::Config(const Config &other) 133 | { 134 | *this = other; 135 | } 136 | 137 | Config& Config::operator=(const Config & other) 138 | { 139 | this->m_webserv = other.m_webserv; 140 | this->m_server_map = other.m_server_map; 141 | this->m_mime_typeMap = other.m_mime_typeMap; 142 | this->m_status_codeMap = other.m_status_codeMap; 143 | return *this; 144 | } 145 | 146 | Config* Config::getConfig(void) 147 | { 148 | if (m_config == NULL) 149 | { 150 | m_config = new Config(); 151 | } 152 | return m_config; 153 | } 154 | 155 | Webserv* Config::getWebserv() 156 | { 157 | return this->m_webserv; 158 | } 159 | 160 | std::map &Config::getServerMap() 161 | { 162 | return this->m_server_map; 163 | } 164 | 165 | std::map &Config::getMimeTypeMap() 166 | { 167 | return this->m_mime_typeMap; 168 | } 169 | 170 | std::map &Config::getStatusCodeMap() 171 | { 172 | return this->m_status_codeMap; 173 | } 174 | 175 | Server* Config::getLastServer(void) 176 | { 177 | std::map::iterator it = m_server_map.end(); 178 | it--; 179 | return &(it->second); 180 | } 181 | 182 | 183 | void Config::setWebserv(Webserv* webserv) 184 | { 185 | this->m_webserv = webserv; 186 | } 187 | 188 | bool Config::isKeyword(std::string keyword) 189 | { 190 | if (keyword == "server" || 191 | keyword == "listen" || 192 | keyword == "server_name" || 193 | keyword == "location" || 194 | keyword == "error_page" || 195 | keyword == "allow_methods" || 196 | keyword == "root" || 197 | keyword == "index" || 198 | keyword == "upload_path" || 199 | keyword == "auto_index" || 200 | keyword == "request_max_body_size" || 201 | keyword == "auth_key" || 202 | keyword == "cgi_info" || 203 | keyword == "return" || 204 | keyword == "}" || 205 | keyword == "{" ) 206 | return (true); 207 | return (false); 208 | } 209 | 210 | void Config::parsingConfig(std::string path) 211 | { 212 | std::ifstream output; 213 | std::string lines; 214 | std::string temp; 215 | std::vector vinfos; 216 | Server *server; 217 | Location *location; 218 | 219 | output.open(path, std::ofstream::in); 220 | if (output.fail()) 221 | { 222 | std::cerr << "ERROR" << std::endl; 223 | exit(1); 224 | } 225 | while (getline(output, temp)) 226 | { 227 | lines += temp; 228 | } 229 | ft_split(lines, " \t}{", vinfos); 230 | for (std::vector::const_iterator it = vinfos.begin(); it != vinfos.end(); it++) 231 | { 232 | if (*it == "server_name") 233 | { 234 | it++; 235 | std::string server_name = *it; 236 | it++; 237 | it++; 238 | std::string port = *it; 239 | it++; 240 | std::string ip = *it; 241 | std::string key = ip +":"+ port; 242 | if (getServerMap().find(key) != getServerMap().end()) 243 | { 244 | throw "Duplicated Server Ip:Port"; 245 | } 246 | getServerMap()[key].setServerName(server_name); 247 | getServerMap()[key].setIp(ip); 248 | getServerMap()[key].setPort(port); 249 | } 250 | if (*it == "location") 251 | { 252 | server = getLastServer(); 253 | it++; 254 | std::string uri = *it; 255 | if (server->getLocations().find(uri) != server->getLocations().end()) 256 | { 257 | throw "Duplicated Location Uri"; 258 | } 259 | server->getLocations()[uri].setUri(uri); 260 | location = &(server->getLocations()[uri]); 261 | } 262 | if (*it == "error_page") 263 | { 264 | it++; 265 | int ernum = std::atoi((*it).c_str()); 266 | it++; 267 | location->getErrorPages()[ernum] = *it; 268 | } 269 | if (*it == "allow_methods") 270 | { 271 | it++; 272 | std::vector gpd; 273 | gpd.push_back("GET"); 274 | gpd.push_back("POST"); 275 | gpd.push_back("DELETE"); 276 | while (std::find(gpd.begin(), gpd.end(), *it) != gpd.end()) 277 | { 278 | location->getAllowMethods().push_back(*it); 279 | it++; 280 | } 281 | it--; 282 | } 283 | if (*it == "root") 284 | { 285 | it++; 286 | location->setRoot(*it); 287 | } 288 | if (*it == "index") 289 | { 290 | it++; 291 | while(!isKeyword(*it)) 292 | { 293 | location->getIndexs().push_back(*it); 294 | it++; 295 | } 296 | it--; 297 | } 298 | if (*it == "auto_index") 299 | { 300 | it++; 301 | if (*it == "on") 302 | location->setAutoIndex(true); 303 | else 304 | location->setAutoIndex(false); 305 | } 306 | if (*it == "cgi_info") 307 | { 308 | it++; 309 | std::string cgikey = *it; 310 | it++; 311 | location->getCgi()[cgikey] = *it; 312 | 313 | } 314 | if (*it == "auth_key") 315 | { 316 | it++; 317 | location->setAuthKey(*it); 318 | } 319 | if (*it == "return") 320 | { 321 | it++; 322 | location->setReturnNum(std::atoi((*it).c_str())); 323 | it++; 324 | location->setReturnUrl(*it); 325 | } 326 | if (*it == "request_max_body_size") 327 | { 328 | it++; 329 | location->setMaxBodySize(std::atoi((*it).c_str())); 330 | } 331 | 332 | 333 | } 334 | // for (std::map::iterator k = getServerMap().begin(); k != getServerMap().end(); k++) 335 | // { 336 | // std::cout << k->second; 337 | // } 338 | 339 | output.close(); 340 | } 341 | -------------------------------------------------------------------------------- /srcs/FdBase.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/FdBase.hpp" 2 | 3 | FdBase::FdBase(void) : m_fd(-1) 4 | { 5 | } 6 | 7 | FdBase::FdBase(const FdBase &other) 8 | { 9 | *this = other; 10 | } 11 | 12 | FdBase::~FdBase(void) 13 | { 14 | 15 | } 16 | 17 | FdBase &FdBase::operator=(const FdBase &other) 18 | { 19 | this->m_fd = other.getFd(); 20 | this->m_fd_type = other.getFdType(); 21 | return (*this); 22 | } 23 | 24 | int FdBase::getFd(void) const 25 | { 26 | return (this->m_fd); 27 | } 28 | 29 | e_fd_type FdBase::getFdType(void) const 30 | { 31 | return (this->m_fd_type); 32 | } 33 | 34 | void FdBase::setFd(int fd) 35 | { 36 | this->m_fd = fd; 37 | } 38 | 39 | void FdBase::setFdType(e_fd_type fd_type) 40 | { 41 | this->m_fd_type = fd_type; 42 | } -------------------------------------------------------------------------------- /srcs/Libft.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Libft.hpp" 2 | 3 | void ft_split(const std::string &target, const std::string &sep, std::vector &infos) 4 | { 5 | std::string word; 6 | 7 | for (std::string::const_iterator it = target.begin(); it != target.end(); it++) 8 | { 9 | if (sep.find(*it) == std::string::npos) 10 | { 11 | word += *it; 12 | } 13 | else 14 | { 15 | if (word != "") 16 | { 17 | infos.push_back(word); 18 | word.clear(); 19 | } 20 | } 21 | } 22 | if (word != "") 23 | { 24 | infos.push_back(word); 25 | word.clear(); 26 | } 27 | } -------------------------------------------------------------------------------- /srcs/Location.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Location.hpp" 2 | 3 | Location::Location() 4 | { 5 | this->m_max_body_size = INT_MAX; 6 | this->m_auto_index = false; 7 | this->m_return_num = -1; 8 | } 9 | 10 | Location::~Location() 11 | { 12 | } 13 | 14 | Location::Location(const Location &src) 15 | { 16 | *this = src; 17 | } 18 | 19 | Location& Location::operator=(const Location &src) 20 | { 21 | this->m_max_body_size = src.m_max_body_size; 22 | this->m_return_num = src.m_return_num; 23 | this->m_auto_index = src.m_auto_index; 24 | this-> m_root = src.m_root; 25 | this->m_upload_path = src.m_upload_path; 26 | this->m_uri = src.m_uri; 27 | this->m_auth_key = src.m_auth_key; 28 | this->m_return_url = src.m_return_url; 29 | this->m_allow_methods = src.m_allow_methods; 30 | this->m_error_pages = src.m_error_pages; 31 | this->m_cgi = src.m_cgi; 32 | return *this; 33 | } 34 | 35 | int &Location::getMaxBodySize() 36 | { 37 | return m_max_body_size; 38 | } 39 | 40 | bool &Location::getAutoIndex() 41 | { 42 | return m_auto_index; 43 | } 44 | 45 | std::string &Location::getUploadPath() 46 | { 47 | return m_upload_path; 48 | } 49 | 50 | std::string &Location::getUri() 51 | { 52 | return m_uri; 53 | } 54 | 55 | std::string &Location::getAuthKey() 56 | { 57 | return m_auth_key; 58 | } 59 | 60 | std::string &Location::getRoot() 61 | { 62 | return m_root; 63 | } 64 | 65 | int &Location::getReturnNum() 66 | { 67 | return m_return_num; 68 | } 69 | 70 | std::string &Location::getReturnUrl() 71 | { 72 | return m_return_url; 73 | } 74 | 75 | std::vector &Location::getAllowMethods() 76 | { 77 | return m_allow_methods; 78 | } 79 | 80 | std::vector &Location::getIndexs() 81 | { 82 | return m_indexs; 83 | } 84 | 85 | std::map &Location::getErrorPages() 86 | { 87 | return m_error_pages; 88 | } 89 | 90 | std::map &Location::getCgi() 91 | { 92 | return m_cgi; 93 | } 94 | 95 | void Location::setMaxBodySize(int size) 96 | { 97 | m_max_body_size = size; 98 | } 99 | 100 | void Location::setReturnNum(int return_num) 101 | { 102 | m_return_num = return_num; 103 | } 104 | 105 | void Location::setAutoIndex(bool auto_index) 106 | { 107 | m_auto_index = auto_index; 108 | } 109 | 110 | void Location::setRoot(std::string root) 111 | { 112 | m_root = root; 113 | } 114 | 115 | void Location::setUploadPath(std::string path) 116 | { 117 | m_upload_path = path; 118 | } 119 | 120 | void Location::setUri(std::string uri) 121 | { 122 | m_uri = uri; 123 | } 124 | 125 | void Location::setAuthKey(std::string auth_key) 126 | { 127 | m_auth_key = auth_key; 128 | } 129 | 130 | void Location::setReturnUrl(std::string return_url) 131 | { 132 | m_return_url = return_url; 133 | } 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /srcs/Request.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Request.hpp" 2 | #include "../incs/Config.hpp" 3 | 4 | Request::Request() 5 | { 6 | this->m_request_status = HEADER_PARSING; 7 | } 8 | 9 | Request::~Request() 10 | { 11 | 12 | } 13 | 14 | Request::Request(const Request& other) 15 | { 16 | *this = other; 17 | } 18 | 19 | Request& Request::operator=(const Request& other) 20 | { 21 | m_origin = other.m_origin; 22 | m_body = other.m_body; 23 | m_method = other.m_method; 24 | m_reqlocation = other.m_reqlocation; 25 | m_httpver = other.m_httpver; 26 | for (std::map::const_iterator it = other.m_headersMap.begin(); it != other.m_headersMap.end(); it++) 27 | { 28 | m_headersMap[it->first] = it->second; 29 | } 30 | return *this; 31 | } 32 | 33 | std::string& Request::getOrigin() 34 | { 35 | return m_origin; 36 | } 37 | 38 | std::string& Request::getBody() 39 | { 40 | return m_body; 41 | } 42 | 43 | std::string& Request::getMethod() 44 | { 45 | return m_method; 46 | } 47 | 48 | std::string& Request::getReqLocation() 49 | { 50 | return m_reqlocation; 51 | } 52 | 53 | std::string& Request::getHttpVer() 54 | { 55 | return m_httpver; 56 | } 57 | 58 | std::map & Request::getHeadersMap() 59 | { 60 | return m_headersMap; 61 | } 62 | 63 | e_req_status& Request::getRequestStatus() 64 | { 65 | return m_request_status; 66 | } 67 | 68 | Client* Request::getClient() 69 | { 70 | return m_client; 71 | } 72 | 73 | size_t Request::getRemainBodyValue() 74 | { 75 | return m_remain_body_value; 76 | } 77 | 78 | 79 | void Request::setOrigin(std::string origin) 80 | { 81 | m_origin = origin; 82 | } 83 | 84 | void Request::setBody(std::string body) 85 | { 86 | m_body = body; 87 | } 88 | 89 | void Request::setMethod(std::string method) 90 | { 91 | m_method = method; 92 | } 93 | 94 | void Request::setReqLocation(std::string location) 95 | { 96 | m_reqlocation = location; 97 | } 98 | 99 | void Request::setHttpver(std::string httpver) 100 | { 101 | m_httpver = httpver; 102 | } 103 | 104 | void Request::setRequestStatus(e_req_status status) 105 | { 106 | m_request_status = status; 107 | } 108 | 109 | void Request::setClient(Client* client) 110 | { 111 | m_client = client; 112 | } 113 | 114 | void Request::setRemainBodyValue(size_t len) 115 | { 116 | m_remain_body_value = len; 117 | } 118 | 119 | std::string trim(std::string& str) 120 | { 121 | std::size_t first = str.find_first_not_of(' '); 122 | if (std::string::npos == first) 123 | { 124 | return str; 125 | } 126 | std::size_t last = str.find_last_not_of(' '); 127 | return str.substr(first, (last - first + 1)); 128 | } 129 | 130 | int Request::base64_decode(const char * text, char * dst, int numBytes) 131 | { 132 | const char* cp; 133 | int space_idx = 0, phase; 134 | int d, prev_d = 0; 135 | char c; 136 | space_idx = 0; 137 | phase = 0; 138 | for (cp = text; *cp != '\0'; ++cp) { 139 | d = Config::decodeMimeBase64[(int)*cp]; 140 | if (d != -1) { 141 | switch (phase) { 142 | case 0: 143 | ++phase; 144 | break; 145 | case 1: 146 | c = ((prev_d << 2) | ((d & 0x30) >> 4)); 147 | if (space_idx < numBytes) 148 | dst[space_idx++] = c; 149 | ++phase; 150 | break; 151 | case 2: 152 | c = (((prev_d & 0xf) << 4) | ((d & 0x3c) >> 2)); 153 | if (space_idx < numBytes) 154 | dst[space_idx++] = c; 155 | ++phase; 156 | break; 157 | case 3: 158 | c = (((prev_d & 0x03) << 6) | d); 159 | if (space_idx < numBytes) 160 | dst[space_idx++] = c; 161 | phase = 0; 162 | break; 163 | } 164 | prev_d = d; 165 | } 166 | } 167 | return space_idx; 168 | } 169 | 170 | bool Request::makeHeader(void) 171 | { 172 | std::size_t found = this->m_origin.find("\r\n"); 173 | std::vector vFirsts; 174 | std::string firstline = this->m_origin.substr(0, found); 175 | ft_split(firstline, " ", vFirsts); 176 | this->setMethod(vFirsts[0]); 177 | this->setReqLocation(vFirsts[1]); 178 | this->setHttpver(vFirsts[2]); 179 | if (this->m_origin.length() >= found+2) 180 | this->setOrigin(this->m_origin.substr(found+2)); 181 | else 182 | this->setOrigin(""); 183 | 184 | found = m_origin.find("\r\n\r\n"); 185 | std::string tempheader = m_origin.substr(0, found); 186 | std::vector tempVHeaders; 187 | ft_split(tempheader, "\r\n", tempVHeaders); 188 | for (std::vector::iterator it = tempVHeaders.begin(); it != tempVHeaders.end(); it++) 189 | { 190 | std::string line = *it; 191 | std::size_t idx = line.find(':'); 192 | std::string key = line.substr(0, idx); 193 | std::string value = ""; 194 | if (line.length() != (found+1)) 195 | value = line.substr(idx+1); 196 | m_headersMap[trim(key)] = trim(value); 197 | } 198 | if (this->m_origin.length() >= found+4) 199 | this->setOrigin(this->m_origin.substr(found+4)); 200 | else 201 | this->setOrigin(""); 202 | return true; 203 | } 204 | bool Request::makeBody(void) 205 | { 206 | if (m_request_status == CONTENT_BODY) 207 | { 208 | if (m_remain_body_value <= m_origin.length()) 209 | { 210 | m_body.append(m_origin.substr(0, m_remain_body_value)); 211 | m_origin.erase(0, m_remain_body_value); 212 | m_remain_body_value = 0; 213 | return (checkValidRequest("FINISHED")); 214 | } 215 | return (false); 216 | } 217 | else if (m_request_status == CHUNKED) 218 | { 219 | size_t tmp; 220 | std::stringstream ss; 221 | std::size_t found = m_origin.find("\r\n"); 222 | if (found == std::string::npos) 223 | return false; 224 | else 225 | { 226 | ss << std::hex << m_origin.substr(0, found); 227 | ss >> tmp; 228 | m_remain_body_value = tmp + 2; 229 | m_origin = m_origin.substr(found+2); 230 | m_request_status = CHUNKED_BODY; 231 | return (makeBody()); 232 | } 233 | } 234 | else if (CHUNKED_BODY) 235 | { 236 | if (m_remain_body_value <= m_origin.size()) 237 | { 238 | size_t oldbodysize = m_body.size(); 239 | m_body.append(m_origin.substr(0, m_remain_body_value -2)); 240 | m_origin.erase(0, m_remain_body_value); 241 | 242 | m_remain_body_value = 0; 243 | if (m_body.size() == oldbodysize) 244 | { 245 | return (checkValidRequest("FINISHED")); 246 | } 247 | m_request_status = CHUNKED; 248 | return (makeBody()); 249 | } 250 | } 251 | return (checkValidRequest("FINISHED")); 252 | } 253 | 254 | bool Request::checkValidRequest(std::string fin) 255 | { 256 | if (fin != "FINISHED") 257 | { 258 | std::cout << "checkValidRequest return false" << std::endl; 259 | return false; 260 | } 261 | // 파싱이 끝났으면 올바른지 확인하는 코드가 밑에 있다 262 | Location &loc = m_client->getServer()->getPerfectLocation(m_reqlocation); 263 | m_client->getResponse().setLocation(&loc); 264 | 265 | if (isValidAuthHeader(loc) == false) 266 | { 267 | m_client->setCStatus(MAKE_RESPONSE); 268 | m_client->getResponse().makeErrorResponse(401); 269 | return (false); 270 | } 271 | if (isValidMethod(loc) == false) 272 | { 273 | m_client->setCStatus(MAKE_RESPONSE); 274 | m_client->getResponse().makeErrorResponse(405); 275 | return (false); 276 | } 277 | if (isValidRequestMaxBodySize(loc) == false) 278 | { 279 | m_client->setCStatus(MAKE_RESPONSE); 280 | m_client->getResponse().makeErrorResponse(413); 281 | return (false); 282 | } 283 | 284 | //GET /index.html http1.1 285 | std::string resource_path = loc.getRoot() + this->m_reqlocation.substr(loc.getUri().size()); 286 | m_client->getResponse().setResourcePath(resource_path); 287 | 288 | for (std::map::iterator iter = loc.getCgi().begin(); iter != loc.getCgi().end(); iter++) 289 | { 290 | if (resource_path.find(iter->first) != std::string::npos) // cgi_extention 표현을 찾았다면 291 | { 292 | this->m_client->getResponse().setCgi(iter->first); 293 | break; 294 | } 295 | } 296 | if (loc.getReturnNum() != -1) 297 | this->m_client->getResponse().setReturn(true); 298 | 299 | setRequestStatus(HEADER_PARSING); 300 | return true; 301 | } 302 | 303 | bool Request::isValidAuthHeader(Location &loc) 304 | { 305 | if (loc.getAuthKey() != "") 306 | { 307 | char result[200]; 308 | memset(result, 0, 200); 309 | 310 | if (this->m_headersMap.find("Authorization") == this->m_headersMap.end()) // auth key 헤더가 아예 안들어왔다. 311 | { 312 | return (false); 313 | } 314 | else 315 | { 316 | size_t idx = this->m_headersMap["Authorization"].find_first_of(' '); 317 | std::string secret = this->m_headersMap["Authorization"].substr(idx + 1); 318 | base64_decode(secret.c_str(), result, secret.size()); 319 | if (std::string(result) != loc.getAuthKey()) // 키가 맞지 않는다. 320 | return (false); 321 | } 322 | } 323 | return (true); 324 | } 325 | 326 | bool Request::isValidMethod(Location &loc) 327 | { 328 | bool isAllowCheckOkay = false; 329 | for (std::vector::iterator iter = loc.getAllowMethods().begin(); iter != loc.getAllowMethods().end(); iter++) 330 | { 331 | if (this->m_method == *iter) 332 | { 333 | isAllowCheckOkay = true; 334 | break ; 335 | } 336 | } 337 | if (isAllowCheckOkay != true) // allow method check 가 안되었다. -> 405 338 | return (false); 339 | return (true); 340 | } 341 | 342 | bool Request::isValidRequestMaxBodySize(Location &loc) 343 | { 344 | if (this->m_body.size() > (size_t)(loc.getMaxBodySize())) 345 | return (false); 346 | return (true); 347 | } 348 | 349 | void Request::initRequest() 350 | { 351 | m_origin.clear(); 352 | m_body.clear(); 353 | m_method.clear(); 354 | m_reqlocation.clear(); 355 | m_httpver.clear(); 356 | m_headersMap.clear(); 357 | m_request_status = HEADER_PARSING; 358 | m_remain_body_value = 0; 359 | } -------------------------------------------------------------------------------- /srcs/Resource.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Resource.hpp" 2 | 3 | // Resource::Resource() 4 | // { 5 | 6 | // } 7 | 8 | Resource::Resource(int fd, std::string& response_message, Client* clnt, e_resource_type type, e_nextcall nxt, int err) : m_raw_data(response_message), m_client(clnt), m_type(type), m_next(nxt), m_response_error_num(err) 9 | { 10 | m_fd = fd; 11 | m_fd_type = FD_RESOURCE; 12 | m_pid = -1; 13 | m_is_seeked = false; 14 | m_write_index = 0; 15 | m_unlink_path.clear(); 16 | m_next = nxt; 17 | } 18 | 19 | 20 | Resource::~Resource() 21 | { 22 | 23 | } 24 | 25 | // 멤버변수 getRawData가 참조라서 26 | Resource::Resource(Resource & rsc) : m_raw_data(rsc.m_raw_data) 27 | { 28 | *this = rsc; 29 | } 30 | 31 | Resource& Resource::operator=(Resource& rsc) 32 | { 33 | m_fd = rsc.m_fd; 34 | m_fd_type = rsc.m_fd_type; 35 | m_pid = rsc.m_pid; 36 | m_is_seeked = rsc.m_is_seeked; 37 | m_next = rsc.m_next; 38 | m_raw_data = rsc.m_raw_data; 39 | m_response_error_num = rsc.m_response_error_num; 40 | m_type = rsc.m_type; 41 | m_unlink_path = rsc.m_unlink_path; 42 | m_write_index = rsc.m_write_index; 43 | return *this; 44 | } 45 | 46 | std::string& Resource::getRawData() 47 | { 48 | return m_raw_data; 49 | } 50 | 51 | std::string Resource::getUnlinkPath() 52 | { 53 | return m_unlink_path; 54 | } 55 | 56 | Client* Resource::getClient() 57 | { 58 | return m_client; 59 | } 60 | 61 | e_resource_type Resource::getResourceType() 62 | { 63 | return m_type; 64 | } 65 | 66 | e_nextcall Resource::getNextCall() 67 | { 68 | return m_next; 69 | } 70 | 71 | int Resource::getResponseErrorNum() 72 | { 73 | return m_response_error_num; 74 | } 75 | 76 | size_t Resource::getWriteIndex() 77 | { 78 | return m_write_index; 79 | } 80 | 81 | int Resource::getPid() 82 | { 83 | return m_pid; 84 | } 85 | 86 | bool Resource::getIsSeeked() 87 | { 88 | return m_is_seeked; 89 | } 90 | 91 | void Resource::setUnlinkPath(std::string path) 92 | { 93 | m_unlink_path = path; 94 | } 95 | void Resource::setClient(Client * clnt) 96 | { 97 | m_client = clnt; 98 | } 99 | void Resource::setResourceType(e_resource_type type) 100 | { 101 | m_type = type; 102 | } 103 | void Resource::setNext(e_nextcall next) 104 | { 105 | m_next = next; 106 | } 107 | void Resource::setResponseErrorNum(int err_num) 108 | { 109 | m_response_error_num = err_num; 110 | } 111 | 112 | void Resource::setWriteIndex(size_t idx) 113 | { 114 | m_write_index = idx; 115 | } 116 | void Resource::setPid(int pid) 117 | { 118 | m_pid = pid; 119 | } 120 | 121 | void Resource::setIsSeeked(bool seeked) 122 | { 123 | m_is_seeked = seeked; 124 | } 125 | 126 | e_rsc_status Resource::isReady(void) 127 | { 128 | int status; 129 | 130 | if (m_pid == -1) 131 | return (READY); 132 | else 133 | { 134 | if (waitpid(m_pid, &status, WNOHANG) == 0) 135 | { 136 | return (NOT_YET); 137 | } 138 | else 139 | { 140 | if (WIFEXITED(status) == 0) 141 | return (CGI_CRASH); 142 | else 143 | { 144 | if (m_is_seeked == false) 145 | { 146 | lseek(m_fd, 0, SEEK_SET); 147 | m_is_seeked = true; 148 | } 149 | return (READY); 150 | } 151 | } 152 | } 153 | 154 | } -------------------------------------------------------------------------------- /srcs/Response.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Client.hpp" 2 | #include "../incs/Response.hpp" 3 | 4 | Response::Response() 5 | { 6 | this->m_return = false; 7 | this->m_disconnect = false; 8 | this->m_message.clear(); 9 | this->m_resource_path.clear(); 10 | this->m_location = NULL; 11 | this->m_cgi_extension.clear(); 12 | this->m_write_idx = 0; 13 | this->m_resourceList.clear(); 14 | this->m_fd_read = -1; 15 | this->m_fd_write = -1; 16 | } 17 | 18 | Response::~Response() 19 | { 20 | if (this->m_fd_read != -1) 21 | close(this->m_fd_read); 22 | if (this->m_fd_write != -1) 23 | close(this->m_fd_write); 24 | // for문 필요 25 | } 26 | 27 | Response::Response(const Response &other) 28 | { 29 | *this = other; 30 | } 31 | 32 | Response& Response::operator=(const Response &other) 33 | { 34 | m_return = other.m_return; 35 | m_disconnect = other.m_disconnect; 36 | m_client = other.m_client; 37 | m_message = other.m_message; 38 | m_resource_path = other.m_resource_path; 39 | m_location = other.m_location; 40 | 41 | m_cgi_extension = other.m_cgi_extension; 42 | m_write_idx = other.m_write_idx; 43 | 44 | m_fd_read = other.m_fd_read; 45 | m_fd_write = other.m_fd_write; 46 | return (*this); 47 | } 48 | 49 | bool Response::getReturn() 50 | { 51 | return m_return; 52 | } 53 | 54 | bool Response::getDisconnect() 55 | { 56 | return m_disconnect; 57 | } 58 | 59 | Client* Response::getClient() 60 | { 61 | return m_client; 62 | } 63 | 64 | std::string& Response::getMessage() 65 | { 66 | return m_message; 67 | } 68 | 69 | std::string Response::getResourcePath() 70 | { 71 | return m_resource_path; 72 | } 73 | 74 | Location* Response::getLocation() 75 | { 76 | return m_location; 77 | } 78 | 79 | std::string Response::getCgiExtension() 80 | { 81 | return m_cgi_extension; 82 | } 83 | 84 | size_t Response::getWriteIdx() 85 | { 86 | return m_write_idx; 87 | } 88 | 89 | int Response::getFdRead() 90 | { 91 | return m_fd_read; 92 | } 93 | 94 | int Response::getFdWrite() 95 | { 96 | return m_fd_write; 97 | } 98 | 99 | std::list& Response::getResourceList() 100 | { 101 | return m_resourceList; 102 | } 103 | 104 | 105 | void Response::setReturn(bool ret) 106 | { 107 | m_return = ret; 108 | } 109 | 110 | void Response::setDisconnect(bool disconnect) 111 | { 112 | m_disconnect = disconnect; 113 | } 114 | 115 | void Response::setClient(Client* client) 116 | { 117 | m_client = client; 118 | } 119 | 120 | void Response::setMessage(std::string message) 121 | { 122 | m_message = message; 123 | } 124 | 125 | void Response::setResourcePath(std::string path) 126 | { 127 | m_resource_path = path; 128 | } 129 | 130 | void Response::setLocation(Location *location) 131 | { 132 | m_location = location; 133 | } 134 | 135 | void Response::setCgi(std::string cgi) 136 | { 137 | m_cgi_extension = cgi; 138 | } 139 | 140 | void Response::setWriteIdx(size_t idx) 141 | { 142 | m_write_idx = idx; 143 | } 144 | 145 | void Response::setFdRead(int fd) 146 | { 147 | m_fd_read = fd; 148 | } 149 | 150 | void Response::setFdWrite(int fd) 151 | { 152 | m_fd_write = fd; 153 | } 154 | 155 | void Response::makeGetResponse() 156 | { 157 | int fd; 158 | struct stat sb; 159 | size_t idx; 160 | 161 | if (isDirectory(m_resource_path)) 162 | { 163 | if (*(--m_resource_path.end()) != '/') 164 | { 165 | m_resource_path += '/'; 166 | } 167 | bool is_exist = false; 168 | std::string pathwithfile; 169 | for (std::vector::iterator it = m_location->getIndexs().begin(); 170 | it != m_location->getIndexs().end(); it++) 171 | { 172 | pathwithfile = m_resource_path + (*it); 173 | is_exist = isExist(pathwithfile); 174 | if (is_exist == true) 175 | break; 176 | } 177 | if (is_exist == false && m_location->getAutoIndex() == true) 178 | return (makeAutoIndexPage()); 179 | m_resource_path = pathwithfile; 180 | } 181 | if (!isExist(m_resource_path)) // not found 182 | return (makeErrorResponse(404)); 183 | if ((fd = open(m_resource_path.c_str(), O_RDONLY)) < 0) 184 | return (makeErrorResponse(403)); 185 | if (fstat(fd, &sb) < 0) 186 | return (makeErrorResponse(500)); 187 | 188 | // 문제가 없을 경우 헤더 만들기 시작 189 | addStatusLine(200); 190 | addDate(); 191 | m_message += "Content-Language: ko-kr\r\n"; 192 | m_message += "Connection: Keep-Alive\r\n"; 193 | m_message += "Keep-Alive: timeout=5, max=1000\r\n"; 194 | 195 | idx = m_resource_path.find_first_of('/'); 196 | idx = m_resource_path.find_first_of('.', idx); 197 | if (idx == std::string::npos) 198 | addContentType(".arc"); 199 | else 200 | addContentType(m_resource_path.substr(idx)); 201 | m_message += "Content-Length: " + std::to_string((int)sb.st_size) + "\r\n"; 202 | m_message += "\r\n"; 203 | setResource(fd, READ_RESOURCE, MAKING_RESPONSE); 204 | } 205 | 206 | void Response::makePostResponse(void) 207 | { 208 | if (m_client->getRequest().getBody().size() == 0) 209 | return (makeErrorResponse(411)); 210 | if (isDirectory(m_resource_path)) 211 | { 212 | makeErrorResponse(400); 213 | std::cout << "directory error" << std::endl; 214 | return; 215 | } 216 | 217 | int fd; 218 | if (isExist(m_resource_path)) 219 | { 220 | if ((fd = open(m_resource_path.c_str(), O_WRONLY | O_APPEND, 0777)) < 0) 221 | { 222 | makeErrorResponse(403); 223 | std::cout << "file create error" << std::endl; 224 | return; 225 | } 226 | addStatusLine(204); 227 | } 228 | else 229 | { 230 | if ((fd = open(m_resource_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0) 231 | { 232 | makeErrorResponse(500); 233 | std::cout << "file open error" << std::endl; 234 | return; 235 | } 236 | addStatusLine(201); 237 | } 238 | addDate(); 239 | struct stat sb; 240 | if (fstat(fd, &sb) < 0) 241 | return (makeErrorResponse(500)); 242 | addContentLength(0); 243 | addEmptyLine(); 244 | setResource(fd, WRITE_RESOURCE, MAKING_RESPONSE); 245 | m_client->setCStatus(FILE_WRITING); 246 | } 247 | 248 | void Response::makeRedirection(void) 249 | { 250 | m_message.clear(); 251 | addStatusLine(m_location->getReturnNum()); 252 | addDate(); 253 | addServer(); 254 | addLocation(m_location->getReturnUrl()); 255 | addEmptyLine(); 256 | 257 | m_client->setCStatus(MAKE_RESPONSE_DONE); 258 | setDisconnect(true); 259 | return ; 260 | } 261 | 262 | void Response::makeDeleteResponse(void) 263 | { 264 | m_message.clear(); 265 | if (!isExist(m_resource_path)) 266 | makeErrorResponse(404); 267 | else 268 | { 269 | if (isDirectory(m_resource_path)) 270 | makeErrorResponse(403); 271 | else 272 | { 273 | // int fd; 274 | // if ((fd = open(m_resource_path.c_str(), O_RDONLY)) < 0) 275 | // return (makeErrorResponse(403)); 276 | // close(fd); 277 | int del = unlink(m_resource_path.c_str()); // unlink전에 fd close 해야 합니다! 278 | if (del < 0) 279 | makeErrorResponse(403); 280 | else 281 | { 282 | addStatusLine(204); 283 | addDate(); 284 | addServer(); 285 | addContentLength(0); 286 | addEmptyLine(); 287 | m_client->setCStatus(MAKE_RESPONSE_DONE); 288 | } 289 | } 290 | } 291 | } 292 | 293 | void Response::makeErrorResponse(int errorcode) 294 | { 295 | m_message.clear(); 296 | addStatusLine(errorcode); 297 | addDate(); 298 | addContentLanguage(); 299 | addServer(); 300 | addContentType(".html"); 301 | if (errorcode == 401) 302 | addWWWAuthenticate(); 303 | if (errorcode == 405) 304 | addAllowMethod(); 305 | if (errorcode == 408) 306 | m_message += "Connection: close\r\n"; 307 | if (m_location->getErrorPages().count(errorcode) == 0) // default 에러 페이지 없으면 308 | return(addErrorBody(errorcode)); 309 | 310 | std::string resource_path = getLocation()->getErrorPages()[errorcode]; 311 | struct stat sb; 312 | int fd; 313 | if ((fd = open(resource_path.c_str(), O_RDONLY)) < 0) 314 | return (addErrorBody(errorcode)); 315 | else 316 | { 317 | if (fstat(fd, &sb) < 0) 318 | return (addErrorBody(errorcode)); 319 | else 320 | { 321 | addContentLength(int(sb.st_size)); 322 | addEmptyLine(); 323 | setResource(fd, READ_RESOURCE, MAKING_RESPONSE); 324 | } 325 | } 326 | } 327 | 328 | void Response::makeAutoIndexPage(void) 329 | { 330 | m_message.clear(); 331 | 332 | addStatusLine(200); 333 | addContentLanguage(); 334 | addContentType(".html"); 335 | addDate(); 336 | 337 | std::string body = ""; 338 | body += "\n"; 339 | body += "\n"; 340 | body += "\n"; 341 | body += "\n"; 342 | body += ""; 343 | body += "autoindex page\n\n"; 344 | body += "

"; 345 | makeFileList(body); 346 | body += "\n"; 347 | body += "\n"; 348 | addContentLength(body.size()); 349 | addEmptyLine(); 350 | m_message += body; 351 | m_client->setCStatus(MAKE_RESPONSE_DONE); 352 | 353 | } 354 | 355 | void Response::makeFileList(std::string &body) 356 | { 357 | std::string http_host_port = "http://" + m_client->getRequest().getHeadersMap()["Host"] + m_client->getRequest().getReqLocation() ; // : 358 | if (http_host_port[http_host_port.length()-1] != '/') 359 | http_host_port += "/"; 360 | DIR *dir = NULL; 361 | struct dirent *directory = NULL; 362 | 363 | if ((dir = opendir(m_resource_path.c_str())) == NULL) 364 | return (makeErrorResponse(500)); 365 | while ((directory = readdir(dir))) 366 | { 367 | std::string file_name(directory->d_name); 368 | if (file_name != "." && file_name != "..") 369 | { 370 | body += "" + file_name + "
"; 371 | // std::cout << "" + file_name + "
" << std::endl; 372 | } 373 | } 374 | closedir(dir); 375 | } 376 | 377 | void Response::setResource(int res_fd, e_resource_type type, e_nextcall ctype, int errornum) 378 | { 379 | Resource* res; 380 | 381 | Webserv* webserv = Config::getConfig()->getWebserv(); 382 | 383 | if (type == WRITE_RESOURCE) 384 | { 385 | res = new Resource(res_fd, m_client->getRequest().getBody(), m_client, WRITE_RESOURCE, ctype, errornum); 386 | m_resourceList.push_back(res); 387 | webserv->addFdPool(dynamic_cast(res)); 388 | webserv->change_events(webserv->getChangeList(), res_fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL); 389 | } 390 | else if (type == READ_RESOURCE) 391 | { 392 | res = new Resource(res_fd, m_message, m_client, READ_RESOURCE, ctype, errornum); 393 | m_resourceList.push_back(res); 394 | webserv->addFdPool(dynamic_cast(res)); 395 | webserv->change_events(webserv->getChangeList(), res_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 396 | } 397 | } 398 | 399 | void Response::initResponse() 400 | { 401 | m_return = false; 402 | m_disconnect = false; 403 | m_message.clear(); 404 | m_resource_path.clear(); 405 | m_location = NULL; 406 | m_cgi_extension.clear(); 407 | m_write_idx = 0; 408 | m_resourceList.clear(); 409 | m_fd_read = -1; 410 | m_fd_write = -1; 411 | } 412 | 413 | -------------------------------------------------------------------------------- /srcs/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Server.hpp" 2 | 3 | Server::Server() 4 | { 5 | this->m_fd_type = FD_SERVER; 6 | this->m_port = -1; 7 | } 8 | 9 | Server::Server(const Server &other) 10 | { 11 | this->m_fd = other.m_fd; 12 | this->m_fd_type = other.m_fd_type; 13 | this->m_ip = other.m_ip; 14 | this->m_port = other.m_port; 15 | this->m_server_name = other.m_server_name; 16 | this->m_locationMap.insert(other.m_locationMap.begin(), other.m_locationMap.end()); 17 | 18 | } 19 | Server::~Server() 20 | { 21 | 22 | } 23 | 24 | Server &Server::operator=(const Server &other) 25 | { 26 | this->m_fd = other.m_fd; 27 | this->m_fd_type = other.m_fd_type; 28 | this->m_ip = other.m_ip; 29 | this->m_port = other.m_port; 30 | this->m_server_name = other.m_server_name; 31 | if (!this->m_locationMap.empty()) 32 | { 33 | this->m_locationMap.clear(); 34 | } 35 | this->m_locationMap.insert(other.m_locationMap.begin(), other.m_locationMap.end()); 36 | return (*this); 37 | } 38 | 39 | void Server::setServerName(std::string server_name) 40 | { 41 | this->m_server_name = server_name; 42 | } 43 | 44 | void Server::setIp(std::string ip) 45 | { 46 | this->m_ip = ip; 47 | } 48 | 49 | void Server::setPort(std::string port) 50 | { 51 | this->m_port = port; 52 | } 53 | 54 | const std::string &Server::getServerName(void) const 55 | { 56 | return (this->m_server_name); 57 | } 58 | 59 | const std::string &Server::getIp(void) const 60 | { 61 | return (this->m_ip); 62 | } 63 | 64 | const std::string &Server::getPort(void) const 65 | { 66 | return (this->m_port); 67 | } 68 | 69 | std::map &Server::getLocations() 70 | { 71 | return (this->m_locationMap); 72 | } 73 | 74 | Location& Server::getLastLocation(void) 75 | { 76 | std::map::iterator it = m_locationMap.end(); 77 | it--; 78 | return (it->second); 79 | } 80 | 81 | std::ostream &operator<<(std::ostream &o, Server &server) 82 | { 83 | o << "==========Server==========" << std::endl; 84 | o << "IP: " << server.getIp() << std::endl; 85 | o << "Port: " << server.getPort() << std::endl; 86 | o << "Server_name: " << server.getServerName() << std::endl; 87 | 88 | o << "----------Location----------" << std::endl; 89 | for (std::map::iterator iter = server.getLocations().begin(); iter != server.getLocations().end(); iter++) 90 | { 91 | 92 | o << "maxbody: " << iter->second.getMaxBodySize() << std::endl; 93 | o << "returnNum: " << iter->second.getReturnNum() << std::endl; 94 | o << "autoindex: " << iter->second.getAutoIndex() << std::endl; 95 | o << "root: " << iter->second.getRoot() << std::endl; 96 | o << "Uri: " << iter->second.getUri() << std::endl; 97 | o << "authkey: " << iter->second.getAuthKey() << std::endl; 98 | o << "returnUrl: " << iter->second.getReturnUrl() << std::endl; 99 | 100 | 101 | o << "AllowMethods: "; 102 | for (std::vector::iterator i = iter->second.getAllowMethods().begin(); i != iter->second.getAllowMethods().end(); i++) 103 | { 104 | o << *i << " "; 105 | } 106 | o << std::endl << "Indexs: "; 107 | for (std::vector::iterator i = iter->second.getIndexs().begin(); i != iter->second.getIndexs().end(); i++) 108 | { 109 | o << *i << " "; 110 | } 111 | o << std::endl << "ErrorPages : "; 112 | for (std::map::iterator i = iter->second.getErrorPages().begin(); i != iter->second.getErrorPages().end(); i++) 113 | { 114 | o << (i->first) << " "<< (i->second) << " "; 115 | } 116 | 117 | o << std::endl << "Cgis : "; 118 | for (std::map::iterator i = iter->second.getCgi().begin(); i != iter->second.getCgi().end(); i++) 119 | { 120 | o << (i->first) << " "<< (i->second) << " "; 121 | } 122 | o << std::endl; 123 | } 124 | o << std::endl; 125 | 126 | return o; 127 | } 128 | 129 | Location &Server::getPerfectLocation(std::string &uri) 130 | { 131 | Location *ret = &(this->m_locationMap["/"]); 132 | std::string key = ""; 133 | for (std::string::const_iterator iter = uri.begin(); iter != uri.end(); iter++) 134 | { 135 | key += *iter; 136 | if (*iter == '/') 137 | { 138 | if (this->m_locationMap.find(key) == this->m_locationMap.end()) 139 | return (*ret); 140 | else 141 | ret = &(this->m_locationMap[key]); 142 | } 143 | } 144 | if ( *(--key.end()) != '/') // '/'로 끝나지 않았고 145 | { 146 | key += '/'; 147 | if (this->m_locationMap.find(key) != this->m_locationMap.end()) 148 | { 149 | uri = key; 150 | return (this->m_locationMap[key]); 151 | } 152 | } 153 | return (*ret); 154 | } -------------------------------------------------------------------------------- /srcs/Webserv.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Webserv.hpp" 2 | 3 | Webserv::Webserv() 4 | { 5 | this->m_fd_pool.resize(MAX_FD_SIZE, NULL); 6 | this->m_timeout = 700000; 7 | std::cout << "Webserv constructor called" << std::endl; 8 | } 9 | 10 | Webserv::Webserv(const Webserv &other) 11 | { 12 | *this = other; 13 | } 14 | 15 | Webserv::~Webserv() 16 | { 17 | std::cout << "Webserv destructor called" << std::endl; 18 | // clean_everything(); 19 | } 20 | 21 | Webserv &Webserv::operator=(const Webserv &other) 22 | { 23 | this->m_kq = other.m_kq; 24 | this->m_fd_pool = other.m_fd_pool; 25 | for (int i = 0; i < MAX_FD_SIZE; i++) 26 | { 27 | this->m_return_events[i] = other.m_return_events[i]; 28 | } 29 | return (*this); 30 | } 31 | 32 | static void error_handling(const char *message) 33 | { 34 | fputs(message, stderr); 35 | fputc('\n', stderr); 36 | exit(1); 37 | } 38 | 39 | void Webserv::change_events(std::vector &change_list, uintptr_t ident, int16_t filter, 40 | uint16_t flags, uint32_t fflags, intptr_t data, void *udata) 41 | { 42 | struct kevent temp_event; 43 | 44 | EV_SET(&temp_event, ident, filter, flags, fflags, data, udata); 45 | change_list.push_back(temp_event); 46 | } 47 | 48 | void Webserv::startServer() 49 | { 50 | Config* config = Config::getConfig(); 51 | // std::cout << config->getServerMap().begin()->second; 52 | if((m_kq = kqueue()) == -1) 53 | { 54 | error_handling("kqueue() error"); 55 | } 56 | 57 | for (std::map::iterator it = config->getServerMap().begin(); it != config->getServerMap().end(); it++) 58 | { 59 | int serv_sock; 60 | struct sockaddr_in serv_addr; 61 | 62 | serv_sock = socket(PF_INET, SOCK_STREAM, 0); /* 서버 소켓 생성 */ 63 | it->second.setFd(serv_sock); 64 | if (serv_sock == -1) 65 | error_handling("socket() error"); 66 | int opt = 1; 67 | setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 68 | memset(&serv_addr, 0, sizeof(serv_addr)); 69 | serv_addr.sin_family = AF_INET; 70 | serv_addr.sin_addr.s_addr = inet_addr(it->second.getIp().c_str()); 71 | serv_addr.sin_port = htons(std::atoi(it->second.getPort().c_str())); 72 | 73 | /* 소켓에 주소 할당 */ 74 | if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) 75 | error_handling("bind() error"); 76 | if (listen(serv_sock, 100000) == -1) /* 연결 요청 대기 상태로 진입 */ 77 | error_handling("listen() error"); 78 | std::cout << it->second.getIp() << ":" << it->second.getPort() << " server on"<< "\n"; 79 | fcntl(serv_sock, F_SETFL, O_NONBLOCK); 80 | change_events(m_change_list, serv_sock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 81 | m_fd_pool[serv_sock] = &(it->second); 82 | } 83 | 84 | testServer(); 85 | } 86 | 87 | void Webserv::testServer(void) 88 | { 89 | int new_events; 90 | struct kevent* curr_event; 91 | while (1) 92 | { 93 | new_events = kevent(m_kq, &m_change_list[0], m_change_list.size(), m_return_events, 1024, NULL); 94 | if (new_events == -1) 95 | { 96 | error_handling("kevent() error\n"); 97 | } 98 | 99 | m_change_list.clear(); 100 | for (int i = 0; i < new_events; i++) 101 | { 102 | curr_event = &m_return_events[i]; 103 | if (curr_event->flags & EV_ERROR) 104 | { 105 | std::cout << "error socket deleted" << std::endl; 106 | deleteFdPool(m_fd_pool[curr_event->ident]); 107 | } 108 | else if (curr_event->filter == EVFILT_READ) 109 | { 110 | if (m_fd_pool[curr_event->ident]->getFdType() == FD_SERVER) 111 | { 112 | int serv_fd = m_fd_pool[curr_event->ident]->getFd(); 113 | int clnt_sock; 114 | 115 | if ((clnt_sock = accept(serv_fd, NULL, NULL)) == -1) 116 | { 117 | std::cerr << "accept() error " << std::endl; 118 | continue ; 119 | } 120 | fcntl(clnt_sock, F_SETFL, O_NONBLOCK); 121 | struct timeval tv; 122 | tv.tv_sec = 60; 123 | tv.tv_usec = 0; 124 | if (setsockopt(clnt_sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval*)&tv, sizeof(struct timeval)) < 0) 125 | { 126 | std::cerr << "setsockop() recv_timeout error" << std::endl; 127 | continue ; 128 | } 129 | if (setsockopt(clnt_sock, SOL_SOCKET, SO_SNDTIMEO, (struct timeval*)&tv, sizeof(struct timeval)) < 0) 130 | { 131 | std::cerr << "setsockop() send_timeout error" << std::endl; 132 | continue ; 133 | } 134 | change_events(m_change_list, clnt_sock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 135 | change_events(m_change_list, clnt_sock, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL); 136 | 137 | Client *clnt = new Client((dynamic_cast(m_fd_pool[serv_fd])), clnt_sock); 138 | m_fd_pool[clnt_sock] = clnt; 139 | 140 | } 141 | else if (m_fd_pool[curr_event->ident]->getFdType() == FD_CLIENT) 142 | { 143 | Client *clnt = dynamic_cast(m_fd_pool[curr_event->ident]); 144 | clnt->setLastTime(call_time()); 145 | char buf[BUFSIZE]; 146 | int n = 1; 147 | memset(buf, 0, BUFSIZE); 148 | if ((n = recv(curr_event->ident, buf, BUFSIZE-1, 0)) == -1) 149 | { 150 | deleteFdPool(m_fd_pool[curr_event->ident]); 151 | continue ; 152 | } 153 | if (n == 0) 154 | { 155 | deleteFdPool(m_fd_pool[curr_event->ident]); 156 | } 157 | else if (n > 0) 158 | { 159 | buf[n] = '\0'; 160 | clnt->appendOrigin(buf); 161 | if(clnt->getCStatus() == REQUEST_RECEIVING && clnt->parseRequest()) 162 | { 163 | clnt->setCStatus(MAKE_RESPONSE); 164 | clnt->makeResponse(); 165 | } 166 | } 167 | } 168 | else if (m_fd_pool[curr_event->ident]->getFdType() == FD_RESOURCE) 169 | { 170 | Resource *rsc = dynamic_cast(m_fd_pool[curr_event->ident]); 171 | e_rsc_status ret = rsc->isReady(); 172 | if (ret == READY) 173 | { 174 | char buff[BUFSIZE]; 175 | unsigned long n = 0; 176 | memset(buff, 0, BUFSIZE); 177 | if ((n = read(curr_event->ident, buff, BUFSIZE-1)) < 0) 178 | { 179 | std::cerr << ("read() error in Resources") << std::endl; 180 | continue ; 181 | } 182 | buff[n] = '\0'; 183 | rsc->getRawData() += buff; 184 | if (n < BUFSIZE-1) 185 | { 186 | rsc->getClient()->setCStatus(FILE_READ_DONE); 187 | rsc->getClient()->makeResponse(); 188 | deleteFdPool(m_fd_pool[curr_event->ident]); 189 | } 190 | } 191 | else if (ret == CGI_CRASH) 192 | { 193 | rsc->getClient()->getResponse().makeErrorResponse(500); 194 | deleteFdPool(rsc); 195 | } 196 | } 197 | } 198 | else if (curr_event->filter == EVFILT_WRITE) 199 | { 200 | if (m_fd_pool[curr_event->ident]->getFdType() == FD_CLIENT) 201 | { 202 | Client* clnt = dynamic_cast(m_fd_pool[curr_event->ident]); 203 | if (call_time() - clnt->getLastTime() > m_timeout) 204 | { 205 | if (clnt->getCStatus() == REQUEST_RECEIVING) 206 | { 207 | deleteFdPool(clnt); 208 | break; 209 | } 210 | else 211 | { 212 | clnt->getResponse().makeErrorResponse(408); 213 | clnt->getResponse().setDisconnect(true); 214 | } 215 | } 216 | if (clnt->getCStatus() == MAKE_RESPONSE_DONE) 217 | { 218 | size_t n; 219 | 220 | Response &rsp = clnt->getResponse(); 221 | n = write(curr_event->ident, rsp.getMessage().c_str(), rsp.getMessage().length()); 222 | if (n < 0) 223 | { 224 | std::cerr << "client write() error" << std::endl; 225 | continue ; 226 | } 227 | if (n < rsp.getMessage().length()) 228 | { 229 | rsp.getMessage().erase(0, n); 230 | } 231 | else 232 | { 233 | if (rsp.getDisconnect()) 234 | deleteFdPool(clnt); 235 | else 236 | { 237 | clnt->setCStatus(REQUEST_RECEIVING); 238 | clnt->initRequestandResponse(); 239 | } 240 | } 241 | } 242 | } 243 | else if (m_fd_pool[curr_event->ident]->getFdType() == FD_RESOURCE) 244 | { 245 | Resource* res = dynamic_cast(m_fd_pool[curr_event->ident]); 246 | size_t n = 0; 247 | 248 | n = write(curr_event->ident, res->getRawData().c_str(), (res->getRawData().length())); 249 | if (n < 0) 250 | { 251 | std::cerr << "resource write error" << std::endl; 252 | continue ; 253 | } 254 | if (n < res->getRawData().length()) 255 | { 256 | res->getRawData().erase(0,n); 257 | } 258 | else 259 | { 260 | res->getClient()->setCStatus(FILE_WRITE_DONE); 261 | res->getClient()->makeResponse(); 262 | deleteFdPool(res); 263 | } 264 | } 265 | } 266 | } 267 | usleep(5); 268 | } 269 | } 270 | 271 | 272 | std::vector& Webserv::getChangeList() 273 | { 274 | return m_change_list; 275 | } 276 | 277 | void Webserv::addFdPool(FdBase* res) 278 | { 279 | if (m_fd_pool[res->getFd()] != NULL) 280 | { 281 | std::cout << "duplicated fd" << std::endl; 282 | } 283 | m_fd_pool[res->getFd()] = res; 284 | } 285 | 286 | // fd close, delete resourceList, m_fd_pool[instance] = NULL, delete instance 287 | void Webserv::deleteFdPool(FdBase* instance) 288 | { 289 | if (instance == NULL) 290 | return ; 291 | 292 | close(instance->getFd()); 293 | if (instance->getFdType() == FD_CLIENT) 294 | { 295 | Client *clnt = dynamic_cast(instance); 296 | std::list &rspList = clnt->getResponse().getResourceList(); 297 | if (clnt->getResponse().getResourceList().size() > 1) 298 | { 299 | for (std::list::iterator it = rspList.begin(); it != rspList.end(); it++) 300 | { 301 | if (*it) 302 | deleteFdPool(dynamic_cast(*it)); 303 | } 304 | } 305 | // std::cout << "Client >> close fd : " <getFd() << std::endl; 306 | } 307 | else if (instance->getFdType() == FD_RESOURCE) 308 | { 309 | Resource * res = dynamic_cast(instance); 310 | Client *clnt = res->getClient(); 311 | if (clnt) 312 | { 313 | std::list &rspList = clnt->getResponse().getResourceList(); 314 | if (!rspList.empty()) 315 | { 316 | std::list::iterator it = std::find(rspList.begin(), rspList.end(), res); 317 | if (it != rspList.end()) 318 | { 319 | rspList.erase(it); 320 | } 321 | } 322 | } 323 | // std::cout << "Resource >> close fd : " <getFd() << std::endl; 324 | } 325 | // if (instance->getFdType() == FD_SERVER) 326 | // std::cout << "Server >> close fd : " << instance->getFd() << std::endl; 327 | m_fd_pool[instance->getFd()] = NULL; 328 | if (instance->getFdType() != FD_SERVER) 329 | delete instance; 330 | } 331 | 332 | void Webserv::signalExit() 333 | { 334 | for (std::vector::iterator it = m_fd_pool.begin(); it != m_fd_pool.end(); it++) 335 | { 336 | if (*it != NULL) 337 | deleteFdPool(*it); 338 | } 339 | } 340 | 341 | unsigned long Webserv::call_time(void) 342 | { 343 | struct timeval tv; 344 | 345 | gettimeofday(&tv, NULL); 346 | return (tv.tv_sec * 1000 + tv.tv_usec / 1000); 347 | } -------------------------------------------------------------------------------- /srcs/addResponse.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Client.hpp" 2 | #include "../incs/Response.hpp" 3 | #include "../incs/Config.hpp" 4 | 5 | bool Response::isDirectory(std::string path) 6 | { 7 | struct stat info; 8 | 9 | if (stat(path.c_str(), &info) != 0) 10 | return false; 11 | else if (info.st_mode & S_IFDIR) 12 | return true; 13 | else 14 | return false; 15 | } 16 | 17 | bool Response::isExist(std::string path) 18 | { 19 | struct stat info; 20 | return (stat(path.c_str(), &info) == 0); 21 | } 22 | 23 | 24 | void Response::addStatusLine(int status) 25 | { 26 | std::string statuscode; 27 | std::string codemsg; 28 | 29 | statuscode = std::to_string(status); 30 | codemsg = Config::getConfig()->getStatusCodeMap()[statuscode]; 31 | m_message += "HTTP/1.1 "+statuscode + " " + codemsg + "\r\n"; 32 | return ; 33 | } 34 | 35 | void Response::addDate(void) 36 | { 37 | time_t rawtime; 38 | struct tm *timeinfo; 39 | char buff[80]; 40 | 41 | time(&rawtime); 42 | timeinfo = localtime(&rawtime); 43 | 44 | strftime(buff, 80, "%a, %d %b %Y %H:%M:%S GMT", timeinfo); 45 | m_message += "Date: " + std::string(buff) + "\r\n"; 46 | 47 | return ; 48 | } 49 | 50 | void Response::addContentLanguage() 51 | { 52 | m_message += "Content-Language: ko-kr\r\n"; 53 | return ; 54 | } 55 | 56 | void Response::addContentType(std::string type) 57 | { 58 | std::string contenttype = ""; 59 | if (Config::getConfig()->getMimeTypeMap().count(type) == 0) 60 | contenttype = "application/octet-stream"; 61 | else 62 | contenttype = Config::getConfig()->getMimeTypeMap()[type]; 63 | m_message += "Content-Type: " + contenttype + "\r\n"; 64 | } 65 | 66 | void Response::addContentLength(int size) 67 | { 68 | m_message += "Content-Length: " + std::to_string(size) + "\r\n"; 69 | } 70 | 71 | void Response::addEmptyLine(void) 72 | { 73 | m_message += "\r\n"; 74 | } 75 | 76 | void Response::addErrorBody(int error) 77 | { 78 | std::string body = ""; 79 | body += "\n"; 80 | body += "\n"; 81 | body += "\n"; 82 | body += "\n"; 83 | body += ""; 84 | body += std::to_string(error); 85 | body += "\n"; 86 | body += "\n"; 87 | addContentLength(body.size()); 88 | addEmptyLine(); 89 | m_message += body; 90 | m_client->setCStatus(MAKE_RESPONSE_DONE); 91 | } 92 | 93 | void Response::addServer(void) 94 | { 95 | std::string server_name = m_client->getServer()->getServerName(); 96 | m_message += "Server: " + server_name + "\r\n"; 97 | } 98 | 99 | void Response::addLocation(std::string &url) 100 | { 101 | m_message += "Location: " + url + "\r\n"; 102 | 103 | } 104 | 105 | void Response::addAllowMethod() 106 | { 107 | std::string method = ""; 108 | for (std::vector::iterator it = m_location->getAllowMethods().begin(); it != m_location->getAllowMethods().end(); it++) 109 | { 110 | method += *it; 111 | method += ' '; 112 | } 113 | m_message += "Allow: " + method + "\r\n"; 114 | } 115 | 116 | void Response::addWWWAuthenticate() 117 | { 118 | // this->m_disconnect = true; 119 | m_message += "WWW-Authenticate: Basic realm=\"ID:PASS\""; 120 | m_message += "\r\n"; 121 | } 122 | 123 | -------------------------------------------------------------------------------- /srcs/cgiResponse.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Client.hpp" 2 | #include "../incs/Response.hpp" 3 | 4 | char **Response::makeCgiEnv(void) 5 | { 6 | char **ret; 7 | 8 | std::map cgi_map; 9 | size_t idx; 10 | std::map &headersMap = m_client->getRequest().getHeadersMap(); 11 | 12 | std::string &reqlocation = getClient()->getRequest().getReqLocation(); //"/" 13 | std::string path_info = reqlocation.substr(reqlocation.find(m_cgi_extension) + m_cgi_extension.size()); // "/abc.cgi" ""? 14 | std::string path_translated = m_resource_path.substr(0, m_resource_path.find(m_cgi_extension) + m_cgi_extension.size()); 15 | std::string query_string; //?~ 16 | 17 | idx = path_info.find('?'); 18 | if (idx != std::string::npos) 19 | { 20 | query_string = path_info.substr(idx+1); 21 | path_info = path_info.substr(0, idx); // ?없앰 22 | } 23 | if (path_info == "") 24 | path_info += '/'; 25 | 26 | if (headersMap.count("Authorization") == 1) 27 | { 28 | idx = headersMap["Authorization"].find(' '); 29 | cgi_map["AUTH_TYPE"] = headersMap["Authorization"].substr(0, idx); 30 | cgi_map["REMOTE_USER"] = headersMap["Authorization"].substr(idx+1); 31 | cgi_map["REMOTE_IDENT"] = headersMap["Authorization"].substr(idx+1); 32 | } 33 | cgi_map["CONTENT_LENGTH"] = std::to_string(getClient()->getRequest().getBody().size()); 34 | if (headersMap.count("Content-Type") == 1) 35 | { 36 | cgi_map["CONTENT_TYPE"] = headersMap["Content-Type"]; 37 | } 38 | cgi_map["GATEWAY_INTERFACE"] = "CGI/1.1"; 39 | cgi_map["PATH_INFO"] = path_info; 40 | cgi_map["PATH_TRANSLATED"] = path_translated; 41 | cgi_map["QUERY_STRING"] = query_string; 42 | cgi_map["REMOTE_ADDR"] = m_client->getServer()->getIp(); 43 | cgi_map["REQUEST_METHOD"] = m_client->getRequest().getMethod(); 44 | if (m_cgi_extension == ".bla") 45 | cgi_map["REQUEST_URI"] = path_info; // query까지 46 | else 47 | cgi_map["REQUEST_URI"] = m_client->getRequest().getReqLocation(); 48 | cgi_map["SCRIPT_EXEC"] = m_location->getCgi()[m_cgi_extension]; 49 | cgi_map["SERVER_NAME"] = m_client->getServer()->getServerName(); 50 | cgi_map["SERVER_PORT"] = m_client->getServer()->getPort(); 51 | cgi_map["SERVER_PROTOCOL"] = "HTTP/1.1"; 52 | cgi_map["SERVER_SOFTWARE"] = "nginx"; 53 | cgi_map["SCRIPT_FILENAME"] = path_translated; 54 | 55 | cgi_map["REDIRECT_STATUS"]="200"; 56 | cgi_map["SCRIPT_NAME"] = m_location->getCgi()[m_cgi_extension]; 57 | 58 | for (std::map::iterator it = headersMap.begin(); it != headersMap.end(); it++) 59 | cgi_map["HTTP_" + it->first] = it->second; 60 | if (!(ret = (char **)malloc(sizeof(char *) * (cgi_map.size() + 1)))) 61 | return (NULL); 62 | int i = 0; 63 | for (std::map::iterator it = cgi_map.begin(); it != cgi_map.end(); it++) 64 | { 65 | ret[i] = strdup((it->first + "=" + it->second).c_str()); 66 | i++; 67 | } 68 | ret[i] = NULL; 69 | return (ret); 70 | } 71 | 72 | void Response::makeCgiResponse(void) 73 | { 74 | if (m_client->getCStatus() == MAKE_RESPONSE) 75 | { 76 | int read_fds[2]; 77 | int write_fds[2]; 78 | 79 | if ((pipe(read_fds)) == -1) 80 | return (makeErrorResponse(500)); 81 | if ((pipe(write_fds)) == -1) 82 | return (makeErrorResponse(500)); 83 | 84 | int pid = fork(); 85 | if (pid == 0) // 자식이면 86 | { 87 | char *args[3]; 88 | std::string uriuntilparam = m_resource_path.substr(0, m_resource_path.find(m_cgi_extension) + m_cgi_extension.size()); 89 | args[0] = strdup(m_location->getCgi()[m_cgi_extension].c_str()); 90 | args[1] = strdup(uriuntilparam.c_str()); 91 | args[2] = 0; 92 | char **cgi_env = makeCgiEnv(); 93 | 94 | dup2(write_fds[0], STDIN_FILENO); 95 | dup2(read_fds[1], STDOUT_FILENO); 96 | close(write_fds[0]); 97 | close(write_fds[1]); 98 | close(read_fds[0]); 99 | close(read_fds[1]); 100 | 101 | int ret; 102 | ret = execve(args[0], args, cgi_env); 103 | exit(ret); 104 | } 105 | else if (pid < 0) 106 | return (makeErrorResponse(500)); 107 | else 108 | { 109 | close(write_fds[0]); 110 | close(read_fds[1]); 111 | 112 | m_fd_read = read_fds[0]; 113 | m_fd_write = write_fds[1]; 114 | 115 | fcntl(write_fds[1], F_SETFL, O_NONBLOCK); 116 | setResource(write_fds[1], WRITE_RESOURCE, MAKING_RESPONSE, -1); 117 | 118 | Resource *res = new Resource(m_fd_read, m_message, m_client, READ_RESOURCE, MAKING_RESPONSE, -1); 119 | res->setPid(pid); 120 | m_resourceList.push_back(res); 121 | Config::getConfig()->getWebserv()->addFdPool(res); 122 | Config::getConfig()->getWebserv()->change_events(Config::getConfig()->getWebserv()->getChangeList(), \ 123 | m_fd_read, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); 124 | m_client->setCStatus(FILE_WRITING); 125 | 126 | } 127 | } 128 | else if (m_client->getCStatus() == FILE_READ_DONE) 129 | { 130 | close(m_fd_read); 131 | std::string read_result = m_message.substr(); 132 | 133 | m_message.clear(); 134 | size_t status_idx1 = read_result.find("Status: ") + 8; 135 | size_t status_idx2 = read_result.find("\r\n", status_idx1); 136 | m_message += "HTTP/1.1 " + read_result.substr(status_idx1, status_idx2 - status_idx1) + "\r\n"; 137 | addDate(); 138 | addContentLanguage(); 139 | size_t body_size = read_result.substr(read_result.find("\r\n\r\n") + 4).size(); 140 | addContentLength(body_size); 141 | m_message += read_result; 142 | m_client->setCStatus(MAKE_RESPONSE_DONE); 143 | } 144 | } -------------------------------------------------------------------------------- /srcs/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../incs/Config.hpp" 2 | #include 3 | 4 | void signalhandler(int sigint) 5 | { 6 | if (sigint == 2) 7 | { 8 | std::cout << "signal 보내 signal 보내!!" << std::endl; 9 | Config::getConfig()->getWebserv()->signalExit(); 10 | } 11 | exit(1); // 숫자 뭐해야함? 12 | } 13 | 14 | int main(int argc, char **argv) 15 | { 16 | Config *config; 17 | 18 | config = Config::getConfig(); 19 | try 20 | { 21 | if (argc < 2) 22 | config->parsingConfig(std::string("./configs/default.config")); 23 | if (argc >= 2) 24 | config->parsingConfig(std::string(argv[1])); 25 | 26 | } 27 | catch(const char* e) 28 | { 29 | std::cerr << e << '\n'; 30 | exit(1); 31 | } 32 | Webserv webserv; 33 | 34 | signal(SIGINT, signalhandler); 35 | config->setWebserv(&webserv); 36 | config->getWebserv()->startServer(); 37 | 38 | } -------------------------------------------------------------------------------- /tests/test1/asb: -------------------------------------------------------------------------------- 1 | 01234567890123456789 -------------------------------------------------------------------------------- /tests/test1/directory/Yeah/not_happy.bad_extension: -------------------------------------------------------------------------------- 1 | asd -------------------------------------------------------------------------------- /tests/test1/directory/index.html: -------------------------------------------------------------------------------- 1 | index..... -------------------------------------------------------------------------------- /tests/test1/directory/other.pouic: -------------------------------------------------------------------------------- 1 | asd -------------------------------------------------------------------------------- /tests/test1/directory/youpi.bad_extension: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test1/directory/youpi.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test1/error404.html: -------------------------------------------------------------------------------- 1 | 404 -------------------------------------------------------------------------------- /tests/test1/floder/file1.html: -------------------------------------------------------------------------------- 1 | sads -------------------------------------------------------------------------------- /tests/test1/index.html: -------------------------------------------------------------------------------- 1 | index..... -------------------------------------------------------------------------------- /tests/test1/index33.html: -------------------------------------------------------------------------------- 1 | 0123401234012340123401234012340123401234012340123401234abcdeeeeeabcdeeeeeabcdeeeeeabcdeeeee 2 | abcdeeeee 3 | abcdeeeee 4 | abcdeeeee 5 | abcdeeeee 6 | abcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeeeabcdeeeee -------------------------------------------------------------------------------- /tests/test1/youpi.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tester_bin/cgi_tester: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/tests/tester_bin/cgi_tester -------------------------------------------------------------------------------- /tests/tester_bin/first.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | print "Content-type: text/html\n\n"; 3 | print "Hello, World."; -------------------------------------------------------------------------------- /tests/tester_bin/php-cgi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/tests/tester_bin/php-cgi -------------------------------------------------------------------------------- /tests/tester_bin/tester: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/42-Workmap/webserv/14751af9e449b17b1a7345a1e8078aabb3adde75/tests/tester_bin/tester --------------------------------------------------------------------------------