Webserv
Loading...
Searching...
No Matches
Client.cpp
Go to the documentation of this file.
1
8#include "webserv.hpp"
9
10inline string get_extension(string str) {
11 size_t pos = str.rfind('.');
12 if (pos != string::npos)
13 return str.substr(pos);
14 else
15 return "";
16}
17
18Client::Client(int fd, ip_port_t ip_port, Master *parent) : _fd(fd), _ip_port(ip_port), _parent(parent) {
19 init();
20 cout << "New connection, socket fd is " << fd << ", ip is : " << _ip_port.ip << ", port : " << _ip_port.port << "\n";
21}
22
24 close(_fd);
25 cout << "Host disconnected, ip " << this->_ip_port.ip << ", port " << this->_ip_port.port << "\n";
26}
27
28void Client::init(void) {
29 this->_server = NULL;
30 this->_route = NULL;
31 this->_method = this->_uri = this->_host = this->_header = this->_body = "";
32 this->_len = 0;
33 this->_last_chunk = false;
34 this->_request.clear();
35}
36
37bool Client::getRequest(Env *env, string paquet) {
38 if (paquet.length() < 1)
39 send_error(403);
40 //if (DEBUG)
41 debug_block("Paquet: ", paquet);
42 if (header_pick("Method:", 0) != "")
43 return getBody(paquet);
44 vec_string lines = split(paquet, "\r\n");
45 for (vec_string::iterator it = lines.begin(); it < lines.end(); it++) {
46 size_t pos = paquet.find("\r\n");
47 if (pos != string::npos)
48 paquet.erase(0, pos + 2);
49 else
50 paquet.clear();
51 _header += *it + (it + 1 != lines.end() ? "\r\n" : "");
52 if (_header.find("\r\n\r\n") != string::npos)
53 return !this->parseHeader(env) ? false : (_len != 0 ? getBody(paquet) : true);
54 }
55 return false;
56}
57
58bool Client::getBody(string paquet) {
59 vec_string lines = split(paquet, "\r\n");
60 vec_string::iterator it;
61
62 for (it = lines.begin(); it < lines.end(); it++) {
63 if (DEBUG)
64 cout << "Remaining length: " << _len << "\n";
65 if ((*it).length() && _len <= 0 && header_pick("Transfer-Encoding:", 0) == "chunked") {
66 _len = std::strtol((*it).c_str(), 0, 16) + 2;
67 _last_chunk = _len == 2 ? true : false;
68 } else if (_len > 0 || it != lines.begin()) {
69 _body += *it + "\r\n";
70 _len -= ((*it).length() + 2);
71 }
72 }
73 // if (_body.size())
74 _body.resize(_body.length() - 2);
75 _len += 2;
76 return (_last_chunk && _len == 0) ? true : false;
77}
78
80 vec_string lines, method, line;
81
82 if (DEBUG)
83 cout << "Parsing header...\n";
84 lines = split(_header, "\r\n");
85 method = split(lines.at(0), " ");
86 _request["Method:"] = method;
87 if (lines.size() > 0) {
88 for (vec_string::iterator it = lines.begin() + 1; it < lines.end(); it++) {
89 line = split(*it, " ");
90 _request[line.at(0)] = vec_string(line.begin() + 1, line.end());
91 }
92 }
93 _method = header_pick("Method:", 0);
94 if ((_method == "POST" || _method == "PUT") && header_pick("Content-Length:", 0) == "" &&
95 header_pick("Transfer-Encoding:", 0) != "chunked")
96 return (send_error(400), false);
97 vec_string uri_split = split(header_pick("Method:", 1), "?");
98 _uri = uri_split.at(0);
99 if (uri_split.size() > 1)
100 _query = uri_split.at(1);
101 _host = header_pick("Host:", 0);
102 _env = env;
105 if (DEBUG)
106 debug_header();
107 string len = header_pick("Content-Length:", 0).c_str();
108 if (len != "") {
109 _len = std::atoi(len.c_str());
110 _last_chunk = true;
113 : INT_MAX;
114 if (_len > max_len)
115 return (send_error(413), false);
116 } else
117 _len = 0;
118 return true;
119}
120
121string Client::header_pick(string key, size_t id) { return _request[key].size() <= id ? "" : _request[key].at(id); }
122
124 vec_string allowed;
125 if ((_route && (allowed = _route->_allowed_methods).size() > 0) ||
126 (_server && (allowed = _server->_allowed_methods).size() > 0) || ((allowed = _env->_allowed_methods).size() > 0))
127 return std::find(allowed.begin(), allowed.end(), _method) < allowed.end() ? true : false;
128 else if (_method == "GET" || _method == "POST" || _method == "DELETE" || _method == "PUT")
129 return (true);
130 return (false);
131}
132
134 if (DEBUG) {
135 debug_block("Header: ", _header);
136 debug_block("Body: ", _body);
137 }
138 string ret;
139 string req_path = _route->getRoot() + _uri;
140 std::cout << "||-> Request for " << req_path << " received <-||\n";
141 string cgi_path = _route->_cgi.size() ? _route->_cgi[get_extension(req_path)]
142 : _server->_cgi.size() ? _server->_cgi[get_extension(req_path)]
143 : "";
144 if (DEBUG)
145 cout << "Path: " << req_path << "\n";
146 if (!check_method())
147 send_error(405);
148 else {
149 if ((ret = _route->getIndex(_uri, req_path)) == "")
150 ret = read_file(req_path);
151 if (ret == "404") {
152 if (_method == "POST" || _method == "PUT")
153 create_file(req_path);
154 else
155 send_error(404);
156 } else if (ret == "403")
157 send_error(403);
158 else if (_method == "DELETE")
159 std::remove(req_path.c_str());
160 else if (cgi_path != "")
161 cgi(cgi_path, req_path);
162 else
163 send_answer("HTTP/1.1 200 OK\r\n" + ret);
164 }
165}
166
167void Client::create_file(string path) {
168 std::ofstream file(path.c_str());
169 if (!file.good())
170 send_error(403);
171 else {
172 file << _body;
173 file.close();
174 send_answer("HTTP/1.1 201 Accepted\r\nContent-Length: 0\r\n\r\n");
175 }
176}
177
178void Client::cgi(string cgi_path, string path) {
179 int status;
180 int fd[2];
181 std::stringstream ss;
182 string ret;
183
184 if (!std::ifstream(cgi_path.c_str()).good())
185 return send_error(404);
186 pipe(fd);
187 if (fork() == 0) {
188 const char **args = new const char *[cgi_path.length() + path.length() + 2];
189 args[0] = cgi_path.c_str();
190 args[1] = path.c_str();
191 args[2] = NULL;
192 string path_info = "PATH_INFO=" + _route->getRoot();
193 string query = "QUERY_STRING=" + _query;
194 const char **env = new const char *[path_info.length() + query.length() + 2];
195 env[0] = path_info.c_str();
196 env[1] = query.c_str();
197 env[2] = NULL;
198 dup2(fd[1], STDOUT_FILENO);
199 close(fd[1]);
200 close(fd[0]);
201 execve(cgi_path.c_str(), (char **)args, (char **)env);
202 }
203 close(fd[1]);
204 waitpid(-1, &status, 0);
205 char buffer[10000];
206 buffer[read(fd[0], buffer, 10000)] = 0;
207 ret = string(buffer);
208 ss << "HTTP/1.1 200 OK\r\nContent-Length: " << ret.length() - ret.find("\r\n\r\n") - 4 << "\r\n\r\n" << ret;
209 send_answer(ss.str());
210}
211
212void Client::send_redir(int redir_code, string opt) {
213 switch (redir_code) {
214 case 301:
215 return send_answer("HTTTP/1.1 301 Moved Permanently\r\nLocation: " + opt + "\r\n\r\n");
216 }
217}
218
219void Client::send_error(int error_code) {
220 switch (error_code) {
221 case 400:
222 return send_answer("HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n");
223 case 403:
224 return send_answer("HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\n");
225 case 404:
226 return send_answer("HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
227 case 405:
228 return send_answer("HTTP/1.1 405 Method Not Allowed\r\nConnection: "
229 "close\r\nContent-Length: 0\r\n\r\n");
230 case 413:
231 return send_answer("HTTP/1.1 413 Payload Too "
232 "Large\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
233 }
234}
235
236void Client::send_answer(string msg) {
237 if (DEBUG)
238 debug_block("ANSWER: ", msg);
239#ifdef __linux__
240 send(this->_fd, msg.c_str(), msg.length(), MSG_NOSIGNAL | MSG_DONTWAIT);
241#elif __APPLE__
242 send(this->_fd, msg.c_str(), msg.length(), 0);
243#endif
244 init();
245}
string get_extension(string str)
Definition: Client.cpp:10
void create_file(string path)
Definition: Client.cpp:167
Client(int fd, ip_port_t ip_port, Master *parent)
Definition: Client.cpp:18
void send_redir(int redir_code, string opt)
Definition: Client.cpp:212
void debug_header(void)
Definition: debug.cpp:11
string _body
Definition: Client.hpp:11
string _host
Definition: Client.hpp:11
int _len
Definition: Client.hpp:12
bool parseHeader(Env *env)
Definition: Client.cpp:79
Env * _env
Definition: Client.hpp:9
void send_answer(string msg)
Definition: Client.cpp:236
Server * _server
Definition: Client.hpp:8
std::map< string, vec_string > _request
Definition: Client.hpp:14
void init(void)
Definition: Client.cpp:28
string _method
Definition: Client.hpp:11
Route * _route
Definition: Client.hpp:10
Master * _parent
Definition: Client.hpp:7
~Client(void)
Definition: Client.cpp:23
bool check_method(void)
Definition: Client.cpp:123
int _fd
Definition: Client.hpp:5
string _query
Definition: Client.hpp:11
string _uri
Definition: Client.hpp:11
ip_port_t _ip_port
Definition: Client.hpp:6
bool getBody(string paquet)
Definition: Client.cpp:58
void cgi(string cgi_path, string path)
Definition: Client.cpp:178
void handleRequest(void)
Definition: Client.cpp:133
string header_pick(string key, size_t id)
Definition: Client.cpp:121
string _header
Definition: Client.hpp:11
void send_error(int error_code)
Definition: Client.cpp:219
bool getRequest(Env *env, string paquet)
Definition: Client.cpp:37
bool _last_chunk
Definition: Client.hpp:13
Definition: Env.hpp:4
vec_string _allowed_methods
Definition: Env.hpp:8
Definition: Master.hpp:4
Server * choose_server(Env *env, string host)
Definition: Master.cpp:113
std::map< string, string > _cgi
Definition: Route.hpp:12
vec_string _allowed_methods
Definition: Route.hpp:11
int _client_max_body_size
Definition: Route.hpp:13
string getIndex(string uri, string path)
Search for an index while generating autoindex.
Definition: Route.cpp:66
string getRoot(void)
Definition: Route.cpp:55
Route * choose_route(string uri)
Choose the route an uri asked to the server.
Definition: Server.cpp:102
void debug_block(string name, string content)
Definition: debug.cpp:3
int port
Definition: webserv.hpp:38
string ip
Definition: webserv.hpp:37
string read_file(string path)
Definition: tools.cpp:58
vec_string split(string str, string delim)
Definition: tools.cpp:20
std::vector< string > vec_string
Definition: webserv.hpp:50
#define DEBUG
Definition: webserv.hpp:2