#include "Webserv.hpp" void Webserv::_response(Client *client) { _send_response(client); if (g_last_signal) _handle_last_signal(); } void Webserv::_send_response(Client *client) { ssize_t ret; std::cerr << "send()\n"; _append_base_headers(client); if (!client->status) _construct_response(client); _insert_status_line(client); if (client->status >= 400) _error_html_response(client); std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG 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 ; } std::cerr << "ret send() = " << ret << "\n"; // DEBUG if (client->get_headers("Connection") == "close") _close_client(client->fd); else { _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD); client->clear(); } } void Webserv::_append_base_headers(Client *client) { client->response.append("Server: Webserv/0.1" CRLF); if (client->get_headers("Connection") == "close") client->response.append("Connection: close" CRLF); else client->response.append("Connection: keep-alive" CRLF); } void Webserv::_construct_response(Client *client) { // TODO : Move this in read(), stop read if content too large if (client->get_body().size() > client->assigned_server->client_body_limit) { client->status = 413; return; } _process_method(client); } void Webserv::_process_method(Client *client) { std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug std::cerr << "allow_methods = " << client->assigned_location->allow_methods << "\n"; // debug if (client->get_method() == UNKNOWN) { client->status = 501; } else if (client->assigned_location->allow_methods & client->get_method()) { switch (client->get_method()) { case (GET): _get(client); break; case (POST): _post(client); break; case (DELETE): _delete(client); break; default: break; } } else { client->status = 405; client->response.append("Allow: "); client->response.append(::http_methods_to_str(client->assigned_location->allow_methods)); client->response.append(CRLF); } } void Webserv::_insert_status_line(Client *client) { std::string status_line; status_line.append("HTTP/1.1 "); status_line.append(_http_status[client->status]); status_line.append(CRLF); client->response.insert(0, status_line); } void Webserv::_error_html_response(Client *client) { if (client->assigned_server->error_pages[client->status].empty()) { std::string html_page = HTML_ERROR; ::replace_all_substr(html_page, STATUS_PLACEHOLDER, _http_status[client->status]); _append_body(client, html_page, "html"); } else _get_file(client, client->assigned_server->error_pages[client->status]); } void Webserv::_append_body(Client *client, const std::string &body, const std::string &file_extension) { const std::string &mime_type = _mime_types[file_extension]; client->response.append("Content-Type: "); if (mime_type.empty()) client->response.append(MIME_TYPE_DEFAULT); else { client->response.append(mime_type); if (mime_type.find("text/") != std::string::npos) client->response.append("; charset=UTF-8"); } client->response.append(CRLF); client->response.append("Content-Length: "); std::string tmp = ::itos(body.size()); client->response.append(tmp); client->response.append(CRLF); client->response.append(CRLF); client->response.append(body); } ServerConfig *Webserv::_determine_process_server(Client *client) { /* http://nginx.org/en/docs/http/request_processing.html _determine_process_server() should be complete. TODO : test it */ std::string &server_name = client->get_headers("Host"); std::vector::iterator it = _servers.begin(); std::vector::iterator default_server = _servers.end(); while (it != _servers.end()) { if (it->host == client->lsocket->host && it->port == client->lsocket->port) { if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() ) break; else if (default_server == _servers.end()) default_server = it; } ++it; } if (it != _servers.end()) return (&(*it)); else return (&(*default_server)); } const LocationConfig *Webserv::_determine_location(const ServerConfig &server, const std::string &path) const { // std::cout << "determin location path sent: " << path << '\n'; std::vector::const_iterator it = server.locations.begin(); while (it != server.locations.end()) { // std::cout << it->path << " -- "; // if (it->path.compare(0, path.size(), path) == 0) if (it->path.compare(0, it->path.size(), path) == 0) break; // kinda gross i know but... have to deal with when there's a / at the end if (it->path[it->path.size() - 1] == '/' \ && it->path.compare(0, it->path.size() - 1, path) == 0) break; ++it; } if (it != server.locations.end()) return (&(*it)); else return (&(server.locations.back())); } std::string Webserv::_determine_file_extension(const std::string &path) const { size_t dot_pos = path.rfind("."); if (dot_pos != std::string::npos && dot_pos + 1 < path.size()) return ( path.substr(dot_pos + 1) ); return (std::string("")); }