From ea84bd16e1d8a1fe7187de5d181824459e4f9b62 Mon Sep 17 00:00:00 2001 From: agaley Date: Tue, 25 Jun 2024 01:56:42 +0200 Subject: [PATCH] [Cache] Add caching mecanism --- Makefile | 7 +++- default.conf | 1 + src/CacheHandler.cpp | 87 +++++++++++++++++++++++++++++++++++++++ src/CacheHandler.hpp | 40 ++++++++++++++++++ src/ConnectionHandler.cpp | 26 ++++++++++-- src/ConnectionHandler.hpp | 9 ++-- src/HTTPMethods.cpp | 4 +- src/Server.cpp | 2 + src/main.cpp | 3 +- 9 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 src/CacheHandler.cpp create mode 100644 src/CacheHandler.hpp diff --git a/Makefile b/Makefile index 6e808c8..b53d3f4 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # By: agaley +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2023/12/15 15:51:13 by agaley #+# #+# # -# Updated: 2024/06/24 22:57:11 by agaley ### ########lyon.fr # +# Updated: 2024/06/25 00:40:40 by agaley ### ########lyon.fr # # # # **************************************************************************** # @@ -32,7 +32,7 @@ export NGINX_PORT_2 ?= 8001 SRC = $(SRC_DIR)/Server.cpp \ $(SRC_DIR)/Config.cpp $(SRC_DIR)/ConfigManager.cpp $(SRC_DIR)/ConfigParser.cpp \ $(SRC_DIR)/FileManager.cpp \ - $(SRC_DIR)/ConnectionHandler.cpp \ + $(SRC_DIR)/ConnectionHandler.cpp $(SRC_DIR)/CacheHandler.cpp \ $(SRC_DIR)/Worker.cpp \ $(SRC_DIR)/HTTPRequest.cpp $(SRC_DIR)/HTTPResponse.cpp $(SRC_DIR)/URI.cpp \ $(SRC_DIR)/CGIHandler.cpp $(SRC_DIR)/FileHandler.cpp \ @@ -67,6 +67,9 @@ $(DEBUG_OBJ_DIR)/%.o: %.cpp run: daemon $(MAKE) wait-for-healthy + docker compose exec -it webserv make + docker compose exec -it webserv bash -c "kill 1" + sleep 1 @make logs daemon: diff --git a/default.conf b/default.conf index 7aa0752..23499ab 100644 --- a/default.conf +++ b/default.conf @@ -27,6 +27,7 @@ server { } location /cgi/ { + autoindex on; cgi on; limit_except GET POST { deny all; } } diff --git a/src/CacheHandler.cpp b/src/CacheHandler.cpp new file mode 100644 index 0000000..5829346 --- /dev/null +++ b/src/CacheHandler.cpp @@ -0,0 +1,87 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* CacheHandler.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agaley +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/24 23:54:38 by agaley #+# #+# */ +/* Updated: 2024/06/25 01:48:57 by agaley ### ########lyon.fr */ +/* */ +/* ************************************************************************** */ + +#include "CacheHandler.hpp" + +CacheHandler* CacheHandler::_instance = NULL; + +CacheHandler& CacheHandler::getInstance() { + if (_instance == NULL) { + _instance = new CacheHandler(); + } + return *_instance; +} + +void CacheHandler::deleteInstance() { + if (_instance != NULL) { + delete _instance; + _instance = NULL; + } +} + +CacheHandler::CacheHandler() { + pthread_mutex_init(&_mutex, NULL); +} + +CacheHandler::~CacheHandler() { + for (std::map::iterator it = _cache.begin(); + it != _cache.end(); ++it) { + delete it->second; + } + _cache.clear(); + pthread_mutex_destroy(&_mutex); +} + +HTTPResponse* CacheHandler::getResponse(const HTTPRequest& request) { + std::string key = _generateKey(request); + + pthread_mutex_lock(&_mutex); + std::map::const_iterator it = _cache.find(key); + if (it != _cache.end()) { + HTTPResponse* response = new HTTPResponse(*(it->second)); + pthread_mutex_unlock(&_mutex); + return response; + } else { + pthread_mutex_unlock(&_mutex); + return NULL; + } +} + +void CacheHandler::storeResponse(const HTTPRequest& request, + const HTTPResponse& response) { + std::string key = _generateKey(request); + pthread_mutex_lock(&_mutex); + if (_cache.find(key) == _cache.end()) + _cache[key] = new HTTPResponse(response); + pthread_mutex_unlock(&_mutex); +} + +std::string CacheHandler::_generateKey(const HTTPRequest& request) const { + std::ostringstream oss; + oss << _hash(request.getRawRequest()); + return oss.str(); +} + +unsigned long CacheHandler::_hash(const std::string& str) const { + // FNV-1a Hash Algorithm + const unsigned long FNV_prime = 16777619; + const unsigned long offset_basis = 2166136261U; + unsigned long hash = offset_basis; + const char* cstr = str.c_str(); + + while (*cstr) { + hash ^= static_cast(*cstr++); + hash *= FNV_prime; + } + + return hash; +} diff --git a/src/CacheHandler.hpp b/src/CacheHandler.hpp new file mode 100644 index 0000000..1c33f60 --- /dev/null +++ b/src/CacheHandler.hpp @@ -0,0 +1,40 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* CacheHandler.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agaley +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/06/24 23:54:58 by agaley #+# #+# */ +/* Updated: 2024/06/25 01:48:34 by agaley ### ########lyon.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef CACHEHANDLER_HPP +#define CACHEHANDLER_HPP + +#include +#include "HTTPRequest.hpp" +#include "HTTPResponse.hpp" + +class CacheHandler { + public: + static CacheHandler& getInstance(); + static void deleteInstance(); + + void storeResponse(const HTTPRequest& request, const HTTPResponse& response); + HTTPResponse* getResponse(const HTTPRequest& request); + + private: + CacheHandler(); + ~CacheHandler(); + + static CacheHandler* _instance; + std::map _cache; + + std::string _generateKey(const HTTPRequest& request) const; + unsigned long _hash(const std::string& str) const; + mutable pthread_mutex_t _mutex; +}; + +#endif diff --git a/src/ConnectionHandler.cpp b/src/ConnectionHandler.cpp index 1401096..da7ccdf 100644 --- a/src/ConnectionHandler.cpp +++ b/src/ConnectionHandler.cpp @@ -6,16 +6,18 @@ /* By: agaley +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/30 16:11:21 by agaley #+# #+# */ -/* Updated: 2024/06/24 21:59:35 by agaley ### ########lyon.fr */ +/* Updated: 2024/06/25 01:51:28 by agaley ### ########lyon.fr */ /* */ /* ************************************************************************** */ -#include "ConnectionHandler.hpp" #include #include #include #include + +#include "CacheHandler.hpp" #include "Common.hpp" +#include "ConnectionHandler.hpp" #include "Utils.hpp" ConnectionHandler::ConnectionHandler( @@ -28,7 +30,8 @@ ConnectionHandler::ConnectionHandler( _epollSocket(epollSocket), _buffer(new char[BUFFER_SIZE]), _readn(0), - _vservPool(virtualServers) { + _vservPool(virtualServers), + _cacheHandler(CacheHandler::getInstance()) { memset(_buffer, 0, BUFFER_SIZE); } @@ -179,6 +182,16 @@ void ConnectionHandler::_processRequest() { _request->setSessionId(sessionId); } + if (_request->getHeader("Cache-Control") != "no-cache") { + HTTPResponse* cachedResponse = _cacheHandler.getResponse(*_request); + if (cachedResponse) { + _log.info("CONNECTION_HANDLER: Cache hit"); + _response = cachedResponse; + _connectionStatus = SENDING; + return; + } + } + VirtualServer* vserv = _selectVirtualServer(_request->getHost()); if (vserv == NULL) { _log.error("CONNECTION_HANDLER: No virtual server selected"); @@ -195,7 +208,12 @@ void ConnectionHandler::_processRequest() { } _response = vserv->handleRequest(*_request); - _response->setCookie("sessionid", sessionId); + _cacheHandler.storeResponse(*_request, *_response); + + if (_request->getHeader("Set-Cookie").empty()) { + _response->setCookie("sessionid", sessionId); + } + _connectionStatus = SENDING; } diff --git a/src/ConnectionHandler.hpp b/src/ConnectionHandler.hpp index acad391..9244a88 100644 --- a/src/ConnectionHandler.hpp +++ b/src/ConnectionHandler.hpp @@ -3,25 +3,27 @@ /* ::: :::::::: */ /* ConnectionHandler.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: mchenava +#+ +:+ +#+ */ +/* By: agaley +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/30 16:11:25 by agaley #+# #+# */ -/* Updated: 2024/06/24 10:37:08 by mchenava ### ########.fr */ +/* Updated: 2024/06/25 01:51:47 by agaley ### ########lyon.fr */ /* */ /* ************************************************************************** */ #ifndef CONNECTION_HANDLER_H #define CONNECTION_HANDLER_H +#include #include #include #include + +#include "CacheHandler.hpp" #include "Config.hpp" #include "HTTPRequest.hpp" #include "HTTPResponse.hpp" #include "Logger.hpp" #include "VirtualServer.hpp" -#include #define BUFFER_SIZE 16384 @@ -71,6 +73,7 @@ class ConnectionHandler { std::vector _vservPool; HTTPRequest* _request; HTTPResponse* _response; + CacheHandler& _cacheHandler; // pthread_mutex_t _mutex; void _receiveRequest(); diff --git a/src/HTTPMethods.cpp b/src/HTTPMethods.cpp index a487f7d..dadf89d 100644 --- a/src/HTTPMethods.cpp +++ b/src/HTTPMethods.cpp @@ -68,8 +68,8 @@ std::string HTTPMethods::_generateDirectoryListing(const std::string& path) { } HTTPResponse* HTTPMethods::_autoindex(const std::string& path, - LocationConfig& location) { - std::string indexPath = path + "/" + location.index; + LocationConfig& location) { + std::string indexPath = path + location.index; if (FileManager::doesFileExists(indexPath)) { HTTPResponse* response = new HTTPResponse(HTTPResponse::OK); response->addHeader("Content-Type", "text/html"); diff --git a/src/Server.cpp b/src/Server.cpp index 3395652..b0459cd 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -44,6 +44,8 @@ Server::~Server() { _workers.clear(); pthread_mutex_destroy(&_mutex); pthread_mutex_destroy(&_eventsMutex); + CacheHandler::deleteInstance(); + ConfigManager::deleteInstance(); Server::_instance = NULL; } diff --git a/src/main.cpp b/src/main.cpp index 6d7afdc..da2f102 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,7 @@ /* By: agaley +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/28 15:02:12 by agaley #+# #+# */ -/* Updated: 2024/06/24 23:05:06 by agaley ### ########lyon.fr */ +/* Updated: 2024/06/25 01:13:41 by agaley ### ########lyon.fr */ /* */ /* ************************************************************************** */ @@ -47,7 +47,6 @@ int main(int argc, char* argv[]) { server.start(); Logger::getInstance().info("Shutdown WebServ"); usleep(SHUTDOWN_DELAY); // Wait for Logger to finish output logs - ConfigManager::deleteInstance(); Logger::deleteInstance(); return EXIT_SUCCESS; }