#include "Webserv.hpp" void Webserv::_response(Client *client) { ServerConfig &server = _determine_process_server(client); _send_response(client, server); if (g_last_signal) _handle_last_signal(); } void Webserv::_send_response(Client *client, ServerConfig &server) { ssize_t ret; std::cerr << "send()\n"; // std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n"; // DEBUG _construct_response(client, server); ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0); if (ret == -1) { std::perror("err send()"); std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG _close_client(client->fd); return ; } if (client->raw_request.find("Connection: close") != std::string::npos) _close_client(client->fd); else { _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD); client->raw_request.clear(); client->response.clear(); } } void Webserv::_construct_response(Client *client, ServerConfig &server) { LocationConfig &location = _determine_location(server, client->get_path()); client->status = 200; // default value client->response.append("Server: Webserv/0.1\r\n"); if (client->get_headers("Connection") == "close") client->response.append("Connection: close\r\n"); else client->response.append("Connection: keep-alive\r\n"); unsigned int allow_methods = ALL_METHODS; // TEMP VARIABLE // after update in ConfigParser, use the "allow_methods" of location. // TODO in ConfigParser : by default if no field in config file, "allow_methods" must be set to ALL_METHODS if (client->get_method() == UNKNOWN) { client->status = 400; } else if (allow_methods & client->get_method()) { if (client->get_method() & GET) _get_ressource(client, server, location); else if (client->get_method() & POST) _post(client, server, location); else if (client->get_method() & DELETE) _delete(client, server, location); } else { client->status = 405; client->response.append("Allow: "); client->response.append(::http_methods_to_str(allow_methods)); client->response.append("\r\n"); } _insert_status_line(client, server); } // https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml #define HTML_ERROR(STATUS) "\r\n
Le Webserv/0.1
" #define S200 "200 OK" #define S400 "400 Bad Request" #define S404 "404 Not Found" #define S500 "500 Internal Server Error" void Webserv::_insert_status_line(Client *client, ServerConfig &server) { std::string status_line; status_line.append("HTTP/1.1 "); // WIP, maybe make a map for status response switch (client->status) { case (200): status_line.append(S200); break; case (400): status_line.append(S400); client->response.append(HTML_ERROR(S400)); break; case (404): status_line.append(S404); client->response.append(HTML_ERROR(S404)); break; case (500): status_line.append(S500); client->response.append(HTML_ERROR(S500)); break; } status_line.append("\r\n"); client->response.insert(0, status_line); } #define ROOT "www" #define INDEX "index.html" #define MAX_FILESIZE 1000000 // (1Mo) void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfig &location) { std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ? char buf[MAX_FILESIZE+1]; std::string tmp; std::string path = client->get_path(); if (path == "/") // TODO ; With server config path.append(INDEX); path.insert(0, ROOT); std::cerr << "path = " << path << "\n"; // TMP HUGO // if (_is_cgi(client)) { _exec_cgi(client); return; } // // END TMP HUGO if (access(path.c_str(), R_OK) == -1) { std::perror("err access()"); client->status = 404; return ; } ifd.open(path.c_str(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?) if (!ifd) { std::cerr << path << ": open fail" << '\n'; client->status = 500; } else { // WIP : Chunk or not chunk (if filesize too big) std::streampos size = ifd.tellg(); if (size > MAX_FILESIZE) { // Then chunk client->status = 500; // WIP temp std::cerr << "File too large for non chunk body\n"; ifd.close(); return ; } ifd.seekg(0, std::ios::beg); ifd.read(buf, size); buf[ifd.gcount()] = '\0'; client->response.append("Content-Type: text/html; charset=UTF-8\r\n"); // TODO : determine Content-Type client->response.append("Content-Length: "); tmp = ::itos(ifd.gcount()); client->response.append(tmp); client->response.append("\r\n"); // Body client->response.append("\r\n"); client->response.append(buf); ifd.close(); } } void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location) { /* TODO */ (void)0; } void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location) { /* TODO */ (void)0; } ServerConfig &Webserv::_determine_process_server(Client *client) { /* TODO : determine virtual server based on ip_address::port and server_name Ior now its just based on server_name. (maybe with a map< string, std::vector