#include "webserv.hpp" Socket::Socket(listen_t listen) : _listen(listen) {} Socket::Socket(int fd, Socket *parent) : _fd(fd), _parent(parent) {} Socket::~Socket(void) { close(_fd); cout << "Socket destroyed!\n"; } int Socket::launch(void) { int opt = 1; string ip = _listen.ip; int port = _listen.port; _fd = socket(AF_INET, SOCK_STREAM, 0); if (_fd == 0) { cout << "Socket creation: " << strerror(errno) << "\n"; return (EXIT_FAILURE); } int opt_ret = setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); if (opt_ret < 0) { cout << "Sockopt: " << strerror(errno) << "\n"; return (EXIT_FAILURE); } _address.sin_family = AF_INET; _address.sin_addr.s_addr = inet_addr(ip.c_str()); _address.sin_port = htons(port); if (bind(_fd, (struct sockaddr *)&_address, sizeof(_address)) < 0) { cout << "Bind: " << strerror(errno) << "\n"; return (EXIT_FAILURE); } cout << "Listener " << ip << " on port " << port << "\n"; if (listen(_fd, 3) < 0) { cout << "Listen: " << strerror(errno) << "\n"; return (EXIT_FAILURE); } cout << "Master: " << _fd << "\n"; if (_fd < _min_fd) _min_fd = _fd; _amount++; return (EXIT_SUCCESS); } void Socket::set_fds(void) { int child_fd; FD_SET(_fd, &_readfds); for (std::vector::iterator it = _childs.begin(); it < _childs.end(); it++) { child_fd = (*it)->_fd; FD_SET(child_fd, &_readfds); if (child_fd > _max_fd) _max_fd = child_fd; } } void Socket::refresh(Env *env) { int valread; int addrlen = sizeof(_address); char buffer[10000]; if (FD_ISSET(_fd, &_readfds)) { int new_socket = accept(_fd, (struct sockaddr *)&_address, (socklen_t *)&addrlen); if (new_socket < 0) { cout << "Accept: " << strerror(errno) << "\n"; exit(EXIT_FAILURE); } #ifdef __APPLE__ // fcntl(new_socket, F_GETNOSIGPIPE); fcntl(new_socket, F_SETFL, O_NONBLOCK); #endif cout << "New connection, socket fd is " << new_socket << ", ip is : " << inet_ntoa(_address.sin_addr) << ", port : " << ntohs(_address.sin_port) << "\n"; _childs.push_back(new Socket(new_socket, this)); } int child_fd; for (std::vector::iterator it = _childs.begin(); it < _childs.end(); it++) { child_fd = (*it)->_fd; if (FD_ISSET(child_fd, &_readfds)) { valread = read(child_fd, buffer, 10000); if (valread == 0) { getpeername(child_fd, (struct sockaddr *)&_address, (socklen_t *)&addrlen); cout << "Host disconnected, ip " << inet_ntoa(_address.sin_addr) << ", port " << ntohs(_address.sin_port) << "\n"; delete (*it); _childs.erase(it); } else { buffer[valread] = '\0'; if ((*it)->getRequest(buffer)) (*it)->answer(env); } } } } bool Socket::parseHeader() { std::vector lines = split(_header, '\n'); std::vector line; if (lines.size() > 0) { for (std::vector::iterator it = lines.begin() + 1; it < lines.end(); it++) { line = split(*it, ' '); cout << line.at(0) << "scraped from header\n"; _request[line.at(0)] = std::vector(line.begin() + 1, line.end()); } } std::vector method = split(lines.at(0), ' '); if (method.at(0) == "POST" && _request.find("Content-Length:") == _request.end() && _request.find("Transfer-Encoding:") ==_request.end()) return false; _request["Method:"] = method; return true; } bool Socket::getRequest(string paquet) { cout << "|===|paquet|===>" << paquet << "|===||\n"; if (paquet.length() < 1) //HTTPS? return false; std::vector lines = split(paquet, '\n'); long chunk_len = (_content.length() > 0 && _request["Transfer-Encoding:"].size() && _request["Transfer-Encoding:"].at(0) == "chunked") ? std::strtol(lines.at(0).substr(1).c_str(), 0, 16) : -1; cout << "Chunk length: " << chunk_len << "\n"; for (std::vector::iterator it = lines.begin(); it < lines.end(); it++) { if (*it == "\r" && _content.length() == 0) this->parseHeader(); if (*it != "\r" && _content.length() == 0) _header += *it + "\n"; else if (chunk_len == -1 || it != lines.begin()) _content += *it + "\n"; } cout << "Header: \n-|" << _header << "|-\n"; cout << "Content: \n-|" << _content << "|-\n"; if (_content.length() > 0) { _content.resize(_content.length() - 1); if ( _request["Method:"].at(0) == "GET" || (chunk_len == 0 || std::strtoul(_request["Content-Length:"].at(0).c_str(), 0, 10) <= _content.length() ) ) { cout << "Request received\n"; return true; } } else _header.resize(_header.length() - 1); return false; } int Socket::answer(Env *env) { cout << "Method: " << _request["Method:"].at(0) << "\n"; cout << "URI: " << _request["Method:"].at(1) << "\n"; cout << "Host: " << _request["Host:"].at(0) << "\n"; string ret; std::stringstream answer; answer << "HTTP/1.1"; Server *server = env->choose_server(_parent, _request["Host:"].at(0)); Route *route = server->get_route(_request["Method:"].at(1)); string method = _request["Method:"].at(0); std::vector allowed; if (method != "GET" && method != "POST" && method != "DELETE") send_answer( "HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); else if ((allowed = route->getHeadersLst()).size() > 0) { if (std::find(allowed.begin(), allowed.end(), method) == allowed.end()) send_answer("HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); } else if ((allowed = server->getHeadersLst()).size() > 0) { if (std::find(allowed.begin(), allowed.end(), method) == allowed.end()) send_answer("HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); } string path = route->correctUri(_request["Method:"].at(1)); cout << "Path: " << path << "\n"; ret = route->getIndex(_request["Method:"].at(1), path); if (ret == "") { cout << "No index: lf file\n"; ret = read_file(path); } answer << (ret == "" ? " 404 Not Found\r\nContent-length: 0\r\n\r\n" : " 200 OK\r\n") << ret; cout << "|===|Answer|===|\n" << answer.str() << "|===|End of answer|===|\n"; send_answer(answer.str()); _content = ""; _header = ""; return EXIT_SUCCESS; } void Socket::send_answer(string msg) { #ifdef __linux__ send(_fd, msg.c_str(), msg.length(), MSG_NOSIGNAL); #elif __APPLE__ send(_fd, msg.c_str(), msg.length(), 0); #endif }