feat: serve static pages
This commit is contained in:
parent
c5f7b82997
commit
bcd33dacd7
@ -62,7 +62,7 @@
|
|||||||
{ include: ["\"webserv/config/ConfigManager.hpp\"", "public", "<webserv/config/ConfigManager.hpp>", "public"] },
|
{ include: ["\"webserv/config/ConfigManager.hpp\"", "public", "<webserv/config/ConfigManager.hpp>", "public"] },
|
||||||
{ include: ["\"webserv/config/ServerConfig.hpp\"", "public", "<webserv/config/ServerConfig.hpp>", "public"] },
|
{ include: ["\"webserv/config/ServerConfig.hpp\"", "public", "<webserv/config/ServerConfig.hpp>", "public"] },
|
||||||
{ include: ["\"webserv/config/LocationConfig.hpp\"", "public", "<webserv/config/LocationConfig.hpp>", "public"] },
|
{ include: ["\"webserv/config/LocationConfig.hpp\"", "public", "<webserv/config/LocationConfig.hpp>", "public"] },
|
||||||
{ include: ["\"webserv/config/utils.hpp\"", "public", "<webserv/config/utils.hpp>", "public"] },
|
{ include: ["\i"webserv/utils/utls.hpp\"", "public", "<webserv/utils/utils.hpp>", "public"] },
|
||||||
|
|
||||||
{ include: ["\"webserv/server/Server.hpp\"", "public", "<webserv/server/Server.hpp>", "public"] },
|
{ include: ["\"webserv/server/Server.hpp\"", "public", "<webserv/server/Server.hpp>", "public"] },
|
||||||
{ include: ["\"webserv/client/Client.hpp\"", "public", "<webserv/client/Client.hpp>", "public"] },
|
{ include: ["\"webserv/client/Client.hpp\"", "public", "<webserv/client/Client.hpp>", "public"] },
|
||||||
|
|||||||
@ -26,7 +26,8 @@ server {
|
|||||||
|
|
||||||
location / {
|
location / {
|
||||||
autoindex off;
|
autoindex off;
|
||||||
index index.html;
|
root ./static_site/;
|
||||||
|
index index2.html index.html;
|
||||||
allowed_methods GET POST DELETE;
|
allowed_methods GET POST DELETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
location /images {
|
location /images {
|
||||||
root /var/www/images;
|
root ./static_site/img;
|
||||||
autoindex off;
|
autoindex off;
|
||||||
index index.jpg;
|
index index.jpg;
|
||||||
allowed_methods GET;
|
allowed_methods GET;
|
||||||
|
|||||||
BIN
static_site/img/nginy.jpg
Normal file
BIN
static_site/img/nginy.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
192
static_site/index.html
Normal file
192
static_site/index.html
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>WebServ - HTTP Server</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
font-size: 3.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
header p {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card {
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-card h3 {
|
||||||
|
color: #5a67d8;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator {
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: #48bb78;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 10px;
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 3rem;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.8rem 1.5rem;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 25px;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<h1>WebServ</h1>
|
||||||
|
<p>High-Performance HTTP Server</p>
|
||||||
|
<div class="nav-links">
|
||||||
|
<a href="/">Home</a>
|
||||||
|
<a href="/about">About</a>
|
||||||
|
<a href="/docs">Documentation</a>
|
||||||
|
<a href="/test">Test Page</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="features">
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3>⚡ Fast & Efficient</h3>
|
||||||
|
<p>Built with performance in mind, handling multiple concurrent connections with minimal resource usage.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3>🛡️ Secure</h3>
|
||||||
|
<p>Implements robust security measures and follows best practices for web server development.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3>🔧 Configurable</h3>
|
||||||
|
<p>Highly customizable with flexible configuration options to suit your specific needs.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feature-card">
|
||||||
|
<h3>📊 HTTP/1.1 Compliant</h3>
|
||||||
|
<p>Full support for HTTP/1.1 protocol with proper request/response handling.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status">
|
||||||
|
<h2>Server Status</h2>
|
||||||
|
<p><span class="status-indicator"></span>Server is running and ready to serve requests</p>
|
||||||
|
<p><strong>Version:</strong> 1.0.0</p>
|
||||||
|
<p><strong>Started:</strong> <span id="timestamp"></span></p>
|
||||||
|
</div>
|
||||||
|
<img src="/images/nginy.jpg" alt="Nginx"
|
||||||
|
style="display: block; margin: 2rem auto; max-width: 100%; border-radius: 15px; box-shadow: 0 8px 32px rgba(0,0,0,0.1);">
|
||||||
|
<footer class="footer">
|
||||||
|
<p>© 2024 WebServ Project. Built with passion for web technologies.</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Display current timestamp
|
||||||
|
document.getElementById('timestamp').textContent = new Date().toLocaleString();
|
||||||
|
|
||||||
|
// Update timestamp every second
|
||||||
|
setInterval(() => {
|
||||||
|
document.getElementById('timestamp').textContent = new Date().toLocaleString();
|
||||||
|
}, 1000);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
</footer>
|
||||||
@ -115,7 +115,7 @@ std::vector<uint8_t> Client::getResponse() const
|
|||||||
|
|
||||||
const Router &router = server_.getRouter();
|
const Router &router = server_.getRouter();
|
||||||
auto response = router.handleRequest(*httpRequest_);
|
auto response = router.handleRequest(*httpRequest_);
|
||||||
return response.toBytes();
|
return response->toBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void Client::setError(int statusCode)
|
// void Client::setError(int statusCode)
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
#include <webserv/config/AConfig.hpp> // for AConfig
|
#include <webserv/config/AConfig.hpp> // for AConfig
|
||||||
|
|
||||||
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
||||||
#include <webserv/config/directive/DirectiveFactory.hpp> // for DirectiveFactory
|
#include <webserv/config/directive/DirectiveFactory.hpp> // for DirectiveFactory
|
||||||
#include <webserv/config/utils.hpp> // for trim
|
|
||||||
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
||||||
|
#include <webserv/utils/utils.hpp> // for trim
|
||||||
|
|
||||||
#include <sstream> // for basic_stringstream, stringstream
|
#include <sstream> // for basic_stringstream, stringstream
|
||||||
#include <utility> // for move, pair
|
#include <utility> // for move, pair
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
||||||
#include <webserv/config/directive/DirectiveValue.hpp>
|
#include <webserv/config/directive/DirectiveValue.hpp>
|
||||||
|
|
||||||
#include <map> // for map
|
|
||||||
#include <memory> // for unique_ptr
|
#include <memory> // for unique_ptr
|
||||||
|
#include <optional>
|
||||||
#include <string> // for string
|
#include <string> // for string
|
||||||
#include <vector> // for vector
|
#include <vector> // for vector
|
||||||
|
|
||||||
@ -21,17 +21,17 @@ class AConfig
|
|||||||
virtual ~AConfig() = default;
|
virtual ~AConfig() = default;
|
||||||
|
|
||||||
void addDirective(const std::string &line);
|
void addDirective(const std::string &line);
|
||||||
[[nodiscard]] const ADirective *getDirective(const std::string &name) const;
|
|
||||||
[[nodiscard]] std::string getErrorPage(int statusCode) const;
|
[[nodiscard]] std::string getErrorPage(int statusCode) const;
|
||||||
|
|
||||||
[[nodiscard]] bool hasDirective(const std::string &name) const;
|
[[nodiscard]] bool hasDirective(const std::string &name) const;
|
||||||
|
|
||||||
template <typename T> T getDirectiveValue(const std::string &name, const T &defaultValue = T{}) const
|
template <typename T>
|
||||||
|
std::optional<T> get(const std::string &name) const
|
||||||
{
|
{
|
||||||
const auto *directive = getDirective(name);
|
const auto *directive = getDirective(name);
|
||||||
if (!directive)
|
if (!directive)
|
||||||
{
|
{
|
||||||
return defaultValue;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto value = directive->getValue();
|
auto value = directive->getValue();
|
||||||
@ -39,10 +39,11 @@ class AConfig
|
|||||||
{
|
{
|
||||||
return value.get<T>();
|
return value.get<T>();
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
[[nodiscard]] const ADirective *getDirective(const std::string &name) const;
|
||||||
virtual void parseBlock(const std::string &block) = 0;
|
virtual void parseBlock(const std::string &block) = 0;
|
||||||
void parseDirectives(const std::string &declarations);
|
void parseDirectives(const std::string &declarations);
|
||||||
std::vector<std::unique_ptr<ADirective>>
|
std::vector<std::unique_ptr<ADirective>>
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
#include <webserv/config/ConfigManager.hpp>
|
#include <webserv/config/ConfigManager.hpp>
|
||||||
|
|
||||||
#include <webserv/config/GlobalConfig.hpp> // for GlobalConfig
|
#include <webserv/config/GlobalConfig.hpp> // for GlobalConfig
|
||||||
#include <webserv/config/utils.hpp> // for removeComments
|
|
||||||
#include <webserv/log/Log.hpp> // for Log
|
#include <webserv/log/Log.hpp> // for Log
|
||||||
|
#include <webserv/utils/utils.hpp> // for removeComments
|
||||||
|
|
||||||
#include <fstream> // for basic_ifstream, basic_filebuf, basic_ostream::operator<<, ifstream, stringstream
|
#include <fstream> // for basic_ifstream, basic_filebuf, basic_ostream::operator<<, ifstream, stringstream
|
||||||
#include <sstream> // for basic_stringstream
|
#include <sstream> // for basic_stringstream
|
||||||
@ -86,8 +85,8 @@ ServerConfig *ConfigManager::getMatchingServerConfig(const std::string &host, in
|
|||||||
std::vector<ServerConfig *> serverConfigs = globalConfig_->getServerConfigs();
|
std::vector<ServerConfig *> serverConfigs = globalConfig_->getServerConfigs();
|
||||||
for (ServerConfig *serverConfig : serverConfigs)
|
for (ServerConfig *serverConfig : serverConfigs)
|
||||||
{
|
{
|
||||||
auto serverName = serverConfig->getDirectiveValue<std::string>("server_name", "");
|
auto serverName = serverConfig->get<std::string>("server_name").value_or("");
|
||||||
auto listenPorts = serverConfig->getDirectiveValue<int>("listen", 80);
|
auto listenPorts = serverConfig->get<int>("listen").value_or(80);
|
||||||
Log::debug("Checking server config: " + serverName + " on port " + std::to_string(listenPorts));
|
Log::debug("Checking server config: " + serverName + " on port " + std::to_string(listenPorts));
|
||||||
if ((serverName == host) && (listenPorts == port))
|
if ((serverName == host) && (listenPorts == port))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#include <webserv/config/GlobalConfig.hpp>
|
#include <webserv/config/GlobalConfig.hpp>
|
||||||
|
|
||||||
#include <webserv/config/utils.hpp> // for findCorrespondingClosingBrace
|
|
||||||
#include <webserv/log/Log.hpp> // for Log
|
#include <webserv/log/Log.hpp> // for Log
|
||||||
|
#include <webserv/utils/utils.hpp> // for findCorrespondingClosingBrace
|
||||||
|
|
||||||
#include <stdexcept> // for runtime_error
|
#include <stdexcept> // for runtime_error
|
||||||
#include <vector> // for vector
|
#include <vector> // for vector
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#include <webserv/config/AConfig.hpp> // for AConfig
|
#include <webserv/config/AConfig.hpp> // for AConfig
|
||||||
#include <webserv/config/LocationConfig.hpp> // for LocationConfig
|
#include <webserv/config/LocationConfig.hpp> // for LocationConfig
|
||||||
#include <webserv/config/ServerConfig.hpp>
|
#include <webserv/config/ServerConfig.hpp>
|
||||||
#include <webserv/config/utils.hpp> // for findCorrespondingClosingBrace, trim
|
|
||||||
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
||||||
|
#include <webserv/utils/utils.hpp> // for findCorrespondingClosingBrace, trim
|
||||||
|
|
||||||
#include <stdexcept> // for runtime_error
|
#include <stdexcept> // for runtime_error
|
||||||
#include <utility> // for pair
|
#include <utility> // for pair
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
#include <webserv/config/directive/BoolDirective.hpp> // for IntDirective
|
|
||||||
|
|
||||||
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
||||||
|
#include <webserv/config/directive/BoolDirective.hpp> // for IntDirective
|
||||||
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
|
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
|
||||||
#include <webserv/config/utils.hpp> // for trim
|
#include <webserv/utils/utils.hpp> // for trim
|
||||||
|
|
||||||
#include <algorithm> // for __transform_fn, transform
|
#include <algorithm> // for __transform_fn, transform
|
||||||
#include <cctype> // for tolower
|
#include <cctype> // for tolower
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
#include <webserv/config/directive/DirectiveFactory.hpp> // for DirectiveFactory
|
|
||||||
|
|
||||||
#include <webserv/config/directive/BoolDirective.hpp> // for BoolDirective
|
#include <webserv/config/directive/BoolDirective.hpp> // for BoolDirective
|
||||||
|
#include <webserv/config/directive/DirectiveFactory.hpp> // for DirectiveFactory
|
||||||
#include <webserv/config/directive/IntDirective.hpp> // for IntDirective
|
#include <webserv/config/directive/IntDirective.hpp> // for IntDirective
|
||||||
#include <webserv/config/directive/IntStringDirective.hpp> // for IntStringDirective
|
#include <webserv/config/directive/IntStringDirective.hpp> // for IntStringDirective
|
||||||
#include <webserv/config/directive/SizeDirective.hpp> // for SizeDirective
|
#include <webserv/config/directive/SizeDirective.hpp> // for SizeDirective
|
||||||
#include <webserv/config/directive/StringDirective.hpp> // for StringDirective
|
#include <webserv/config/directive/StringDirective.hpp> // for StringDirective
|
||||||
#include <webserv/config/directive/VectorDirective.hpp> // for VectorDirective
|
#include <webserv/config/directive/VectorDirective.hpp> // for VectorDirective
|
||||||
#include <webserv/config/utils.hpp> // for trim, trimSemi
|
|
||||||
#include <webserv/log/Log.hpp> // for LOCATION, Log
|
#include <webserv/log/Log.hpp> // for LOCATION, Log
|
||||||
|
#include <webserv/utils/utils.hpp> // for trim, trimSemi
|
||||||
|
|
||||||
#include <sstream> // for basic_stringstream, stringstream
|
#include <sstream> // for basic_stringstream, stringstream
|
||||||
#include <stdexcept> // for invalid_argument
|
#include <stdexcept> // for invalid_argument
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
#include <webserv/config/directive/IntStringDirective.hpp> // for IntDirective
|
|
||||||
|
|
||||||
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
||||||
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
|
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
|
||||||
#include <webserv/config/utils.hpp> // for trim
|
#include <webserv/config/directive/IntStringDirective.hpp> // for IntDirective
|
||||||
|
#include <webserv/utils/utils.hpp> // for trim
|
||||||
|
|
||||||
#include <sstream> // for basic_istringstream, basic_istream::operator>>, istringstream
|
#include <sstream> // for basic_istringstream, basic_istream::operator>>, istringstream
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
#include <webserv/config/directive/SizeDirective.hpp> // for SizeDirective
|
|
||||||
|
|
||||||
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
#include <webserv/config/directive/ADirective.hpp> // for ADirective
|
||||||
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
|
#include <webserv/config/directive/DirectiveValue.hpp> // for DirectiveValueType
|
||||||
#include <webserv/config/utils.hpp> // for trim
|
#include <webserv/config/directive/SizeDirective.hpp> // for SizeDirective
|
||||||
|
#include <webserv/utils/utils.hpp> // for trim
|
||||||
|
|
||||||
#include <algorithm> // for __transform_fn, transform
|
#include <algorithm> // for __transform_fn, transform
|
||||||
#include <cctype> // for tolower
|
#include <cctype> // for tolower
|
||||||
|
|||||||
@ -3,11 +3,12 @@
|
|||||||
#include "webserv/http/HttpResponse.hpp"
|
#include "webserv/http/HttpResponse.hpp"
|
||||||
|
|
||||||
#include <webserv/config/AConfig.hpp>
|
#include <webserv/config/AConfig.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class ErrorHandler
|
class ErrorHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static HttpResponse getErrorResponse(int statusCode, AConfig *config = nullptr);
|
static std::unique_ptr<HttpResponse> getErrorResponse(int statusCode, AConfig *config = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string generateErrorPage(int statusCode, AConfig *config = nullptr);
|
static std::string generateErrorPage(int statusCode, AConfig *config = nullptr);
|
||||||
|
|||||||
@ -8,18 +8,21 @@
|
|||||||
#include <webserv/log/Log.hpp> // for Log
|
#include <webserv/log/Log.hpp> // for Log
|
||||||
|
|
||||||
#include <fstream> // for basic_ifstream, basic_filebuf, basic_ostream::operator<<, ifstream, stringstream
|
#include <fstream> // for basic_ifstream, basic_filebuf, basic_ostream::operator<<, ifstream, stringstream
|
||||||
|
#include <memory>
|
||||||
#include <sstream> // for basic_stringstream
|
#include <sstream> // for basic_stringstream
|
||||||
#include <string> // for basic_string, operator+, allocator, char_traits, string, to_string
|
#include <string> // for basic_string, operator+, allocator, char_traits, string, to_string
|
||||||
|
|
||||||
HttpResponse ErrorHandler::getErrorResponse(int statusCode, AConfig *config)
|
std::unique_ptr<HttpResponse> ErrorHandler::getErrorResponse(int statusCode, AConfig *config)
|
||||||
{
|
{
|
||||||
HttpResponse response;
|
std::string statusMessage = Http::getStatusCodeReason(statusCode);
|
||||||
|
Log::warning("Generating error response: " + std::to_string(statusCode) + " " + statusMessage);
|
||||||
|
|
||||||
|
auto response = std::make_unique<HttpResponse>();
|
||||||
std::string body = generateErrorPage(statusCode, config);
|
std::string body = generateErrorPage(statusCode, config);
|
||||||
response.appendBody(body);
|
response->appendBody(body);
|
||||||
response.setStatus(statusCode);
|
response->setStatus(statusCode);
|
||||||
response.addHeader("Content-Type", "text/html");
|
response->addHeader("Content-Type", "text/html");
|
||||||
response.addHeader("Connection", "close");
|
response->addHeader("Connection", "close");
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,20 +36,20 @@ std::string ErrorHandler::generateErrorPage(int statusCode, AConfig *config)
|
|||||||
}
|
}
|
||||||
if (config != nullptr)
|
if (config != nullptr)
|
||||||
{
|
{
|
||||||
Log::info("Checking for custom error page for status code: " + std::to_string(statusCode));
|
Log::info("Checking for custom error page");
|
||||||
std::string customPage = config->getErrorPage(statusCode);
|
std::string customPage = config->getErrorPage(statusCode);
|
||||||
if (!customPage.empty())
|
if (!customPage.empty())
|
||||||
{
|
{
|
||||||
return getErrorPageFile(customPage);
|
return getErrorPageFile(customPage);
|
||||||
}
|
}
|
||||||
Log::warning("No custom error page found in config for status code: " + std::to_string(statusCode));
|
Log::warning("No custom error page found");
|
||||||
}
|
}
|
||||||
return generateDefaultErrorPage(statusCode);
|
return generateDefaultErrorPage(statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ErrorHandler::generateDefaultErrorPage(int statusCode)
|
std::string ErrorHandler::generateDefaultErrorPage(int statusCode)
|
||||||
{
|
{
|
||||||
Log::info("Generating default error page for status code: " + std::to_string(statusCode));
|
Log::info("Generating default error page");
|
||||||
std::string statusMessage = Http::getStatusCodeReason(statusCode);
|
std::string statusMessage = Http::getStatusCodeReason(statusCode);
|
||||||
std::string html = "<html><head><title>" + std::to_string(statusCode) + " " + statusMessage +
|
std::string html = "<html><head><title>" + std::to_string(statusCode) + " " + statusMessage +
|
||||||
"</title></head><body><h1>" + std::to_string(statusCode) + " " + statusMessage +
|
"</title></head><body><h1>" + std::to_string(statusCode) + " " + statusMessage +
|
||||||
@ -56,7 +59,7 @@ std::string ErrorHandler::generateDefaultErrorPage(int statusCode)
|
|||||||
|
|
||||||
std::string ErrorHandler::getErrorPageFile(const std::string &path)
|
std::string ErrorHandler::getErrorPageFile(const std::string &path)
|
||||||
{
|
{
|
||||||
Log::info("Loading custom error page from: " + path);
|
Log::debug("Loading custom error page from: " + path);
|
||||||
std::ifstream file(path.c_str());
|
std::ifstream file(path.c_str());
|
||||||
if (!file.is_open())
|
if (!file.is_open())
|
||||||
{
|
{
|
||||||
|
|||||||
125
webserv/handler/FileHandler.cpp
Normal file
125
webserv/handler/FileHandler.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#include "webserv/handler/ErrorHandler.hpp"
|
||||||
|
#include "webserv/http/HttpResponse.hpp"
|
||||||
|
|
||||||
|
#include <webserv/config/LocationConfig.hpp>
|
||||||
|
#include <webserv/handler/FileHandler.hpp>
|
||||||
|
#include <webserv/handler/MIMETypes.hpp>
|
||||||
|
#include <webserv/handler/URIParser.hpp>
|
||||||
|
#include <webserv/log/Log.hpp>
|
||||||
|
#include <webserv/utils/FileUtils.hpp>
|
||||||
|
|
||||||
|
#include <cerrno> // for errno
|
||||||
|
#include <cstring> // for strerror, strlen
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <ranges> // for views
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
// for FILE, fopen, fclose, fread, SEEK_END, SEEK
|
||||||
|
#include <sys/stat.h> // for stat, S_ISREG, S_ISDIR
|
||||||
|
|
||||||
|
FileHandler::FileHandler(const LocationConfig *location, const URIParser &uriParser)
|
||||||
|
: location_(location), uriParser_(uriParser)
|
||||||
|
{
|
||||||
|
Log::trace(LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> FileHandler::readBinaryFile(const std::string &filepath)
|
||||||
|
{
|
||||||
|
Log::trace(LOCATION);
|
||||||
|
|
||||||
|
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
Log::error("Failed to open file: " + filepath);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get file size
|
||||||
|
std::streamsize size = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
// Read entire file
|
||||||
|
std::vector<char> buffer(size);
|
||||||
|
if (!file.read(buffer.data(), size))
|
||||||
|
{
|
||||||
|
Log::error("Failed to read file: " + filepath);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FileHandler::readFileAsString(const std::string &filepath)
|
||||||
|
{
|
||||||
|
Log::trace(LOCATION);
|
||||||
|
|
||||||
|
std::ifstream file(filepath, std::ios::binary);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<HttpResponse> FileHandler::getResponse() const
|
||||||
|
{
|
||||||
|
Log::trace(LOCATION);
|
||||||
|
auto response = std::make_unique<HttpResponse>();
|
||||||
|
response->setStatus(200);
|
||||||
|
std::string filepath = uriParser_.getFilePath();
|
||||||
|
if (uriParser_.isFile())
|
||||||
|
{
|
||||||
|
std::string extension = uriParser_.getExtension();
|
||||||
|
std::string mimeType = MIMETypes().getType(extension);
|
||||||
|
response->addHeader("Content-Type", mimeType);
|
||||||
|
|
||||||
|
std::vector<char> fileData = readBinaryFile(filepath);
|
||||||
|
Log::debug("Serving file: " + filepath + " with MIME type: " + mimeType);
|
||||||
|
if (fileData.empty())
|
||||||
|
{
|
||||||
|
return ErrorHandler::getErrorResponse(404);
|
||||||
|
}
|
||||||
|
response->setBody(std::string(fileData.begin(), fileData.end()));
|
||||||
|
}
|
||||||
|
else if (uriParser_.isDirectory() && location_->get<std::vector<std::string>>("index").has_value())
|
||||||
|
{
|
||||||
|
auto possible_indexes = location_->get<std::vector<std::string>>("index").value();
|
||||||
|
std::string indexPath;
|
||||||
|
for (auto &index : possible_indexes)
|
||||||
|
{
|
||||||
|
indexPath = FileUtils::joinPath(filepath, index);
|
||||||
|
Log::debug("Checking for index file: " + indexPath);
|
||||||
|
if (FileUtils::isFile(indexPath))
|
||||||
|
{
|
||||||
|
Log::debug("Found index file: " + indexPath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexPath.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> fileData = readBinaryFile(indexPath);
|
||||||
|
Log::debug("Serving index file: " + indexPath);
|
||||||
|
if (fileData.empty())
|
||||||
|
{
|
||||||
|
return ErrorHandler::getErrorResponse(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string extension = FileUtils::getExtension(indexPath);
|
||||||
|
std::string mimeType = MIMETypes().getType(extension);
|
||||||
|
response->addHeader("Content-Type", mimeType);
|
||||||
|
response->setBody(std::string(fileData.begin(), fileData.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (uriParser_.isDirectory() && location_->get<bool>("autoindex").value_or(false))
|
||||||
|
{
|
||||||
|
Log::debug("Requested path is a directory: " + filepath);
|
||||||
|
return ErrorHandler::getErrorResponse(403);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ErrorHandler::getErrorResponse(404);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
@ -1 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserv/config/LocationConfig.hpp"
|
||||||
|
#include "webserv/handler/URIParser.hpp"
|
||||||
|
#include "webserv/http/HttpResponse.hpp"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class FileHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileHandler(const LocationConfig *location, const URIParser &uriParser);
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<HttpResponse> getResponse() const;
|
||||||
|
static std::vector<char> readBinaryFile(const std ::string &filepath);
|
||||||
|
static std::string readFileAsString(const std::string &filepath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// std::unique_ptr<HttpResponse> response_;
|
||||||
|
const LocationConfig *location_;
|
||||||
|
const URIParser &uriParser_;
|
||||||
|
};
|
||||||
37
webserv/handler/MIMETypes.cpp
Normal file
37
webserv/handler/MIMETypes.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
#include <webserv/handler/MIMETypes.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MIMETypes::MIMETypes() {
|
||||||
|
initializeDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MIMETypes::getType(const std::string& extension) const {
|
||||||
|
auto it = mimeMap.find(extension);
|
||||||
|
if (it != mimeMap.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return "application/octet-stream"; // Default MIME type
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIMETypes::setType(const std::string& extension, const std::string& mimeType) {
|
||||||
|
mimeMap[extension] = mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIMETypes::initializeDefaults() {
|
||||||
|
mimeMap["html"] = "text/html";
|
||||||
|
mimeMap["htm"] = "text/html";
|
||||||
|
mimeMap["css"] = "text/css";
|
||||||
|
mimeMap["js"] = "application/javascript";
|
||||||
|
mimeMap["json"] = "application/json";
|
||||||
|
mimeMap["png"] = "image/png";
|
||||||
|
mimeMap["jpg"] = "image/jpeg";
|
||||||
|
mimeMap["jpeg"] = "image/jpeg";
|
||||||
|
mimeMap["gif"] = "image/gif";
|
||||||
|
mimeMap["svg"] = "image/svg+xml";
|
||||||
|
mimeMap["txt"] = "text/plain";
|
||||||
|
mimeMap["xml"] = "application/xml";
|
||||||
|
mimeMap["pdf"] = "application/pdf";
|
||||||
|
// Add more default MIME types as needed
|
||||||
|
}
|
||||||
24
webserv/handler/MIMETypes.hpp
Normal file
24
webserv/handler/MIMETypes.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef MIMETYPES_HPP
|
||||||
|
#define MIMETYPES_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class MIMETypes {
|
||||||
|
public:
|
||||||
|
MIMETypes();
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the MIME type for a given file extension (e.g., "html" -> "text/html")
|
||||||
|
[[nodiscard]] std::string getType(const std::string& extension) const;
|
||||||
|
|
||||||
|
// Adds or updates a MIME type mapping
|
||||||
|
void setType(const std::string& extension, const std::string& mimeType);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::string> mimeMap;
|
||||||
|
|
||||||
|
void initializeDefaults();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MIMETYPES_HPP
|
||||||
94
webserv/handler/URIParser.cpp
Normal file
94
webserv/handler/URIParser.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include <webserv/config/LocationConfig.hpp>
|
||||||
|
#include <webserv/config/ServerConfig.hpp>
|
||||||
|
#include <webserv/handler/URIParser.hpp>
|
||||||
|
|
||||||
|
#include <sys/stat.h> // for stat, S_ISREG, S_ISDIR
|
||||||
|
|
||||||
|
URIParser::URIParser(const std::string &uri, const ServerConfig &serverConfig) : _locationConfig(nullptr)
|
||||||
|
{
|
||||||
|
const auto &locations = serverConfig.getLocationPaths();
|
||||||
|
size_t maxMatchLength = 0;
|
||||||
|
|
||||||
|
for (const auto &locationPath : locations)
|
||||||
|
{
|
||||||
|
if (uri.starts_with((locationPath == "/") ? locationPath : locationPath + "/"))
|
||||||
|
{ // TODO HMHMMz why does it need to end on a /?
|
||||||
|
if (locationPath.length() > maxMatchLength)
|
||||||
|
{
|
||||||
|
maxMatchLength = locationPath.length();
|
||||||
|
_locationConfig = serverConfig.getLocation(locationPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_ = _locationConfig != nullptr ? _locationConfig->get<std::string>("root").value_or("") : "";
|
||||||
|
if (!root_.empty() && root_.back() == '/' )
|
||||||
|
{
|
||||||
|
root_.pop_back(); // Remove trailing slash to avoid double slashes in path
|
||||||
|
}
|
||||||
|
|
||||||
|
relativePath_ = uri.substr(maxMatchLength);
|
||||||
|
if (relativePath_.empty() || relativePath_[0] != '/')
|
||||||
|
{
|
||||||
|
relativePath_ = "/" + relativePath_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string URIParser::getFilePath() const
|
||||||
|
{
|
||||||
|
return root_ + relativePath_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string URIParser::getFilename() const
|
||||||
|
{
|
||||||
|
size_t lastSlash = relativePath_.find_last_of('/');
|
||||||
|
if (lastSlash == std::string::npos)
|
||||||
|
{
|
||||||
|
return relativePath_; // No slashes, return the whole path
|
||||||
|
}
|
||||||
|
return relativePath_.substr(lastSlash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string URIParser::getExtension() const
|
||||||
|
{
|
||||||
|
std::string filename = getFilename();
|
||||||
|
size_t lastDot = filename.find_last_of('.');
|
||||||
|
if (lastDot == std::string::npos || lastDot == 0 || lastDot == filename.length() - 1)
|
||||||
|
{
|
||||||
|
return ""; // No extension found or dot is at start/end
|
||||||
|
}
|
||||||
|
return filename.substr(lastDot + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LocationConfig const *URIParser::getLocation() const
|
||||||
|
{
|
||||||
|
return _locationConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URIParser::isFile() const
|
||||||
|
{
|
||||||
|
struct stat pathStat{};
|
||||||
|
if (stat(getFilePath().c_str(), &pathStat) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return S_ISREG(pathStat.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URIParser::isDirectory() const
|
||||||
|
{
|
||||||
|
struct stat pathStat{};
|
||||||
|
if (stat(getFilePath().c_str(), &pathStat) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return S_ISDIR(pathStat.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URIParser::isValid() const
|
||||||
|
{
|
||||||
|
struct stat pathStat{};
|
||||||
|
return stat(getFilePath().c_str(), &pathStat) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
29
webserv/handler/URIParser.hpp
Normal file
29
webserv/handler/URIParser.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserv/config/LocationConfig.hpp"
|
||||||
|
#include "webserv/config/ServerConfig.hpp"
|
||||||
|
#include "webserv/server/Server.hpp"
|
||||||
|
|
||||||
|
class URIParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
URIParser(const std::string &uri, const ServerConfig &serverConfig);
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] std::string getFilePath() const;
|
||||||
|
[[nodiscard]] std::string getFilename() const;
|
||||||
|
[[nodiscard]] std::string getExtension() const;
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] const LocationConfig *getLocation() const ;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isFile() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isDirectory() const;
|
||||||
|
[[nodiscard]] bool isValid() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const LocationConfig *_locationConfig;
|
||||||
|
std::string relativePath_;
|
||||||
|
std::string root_;
|
||||||
|
};
|
||||||
@ -1,8 +1,7 @@
|
|||||||
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
|
|
||||||
|
|
||||||
#include <webserv/config/utils.hpp> // for trim
|
|
||||||
#include <webserv/http/HttpConstants.hpp> // for CRLF
|
#include <webserv/http/HttpConstants.hpp> // for CRLF
|
||||||
|
#include <webserv/http/HttpHeaders.hpp> // for HttpHeaders
|
||||||
#include <webserv/log/Log.hpp>
|
#include <webserv/log/Log.hpp>
|
||||||
|
#include <webserv/utils/utils.hpp> // for trim
|
||||||
|
|
||||||
#include <algorithm> // for __transform_fn, transform
|
#include <algorithm> // for __transform_fn, transform
|
||||||
#include <cctype> // for tolower
|
#include <cctype> // for tolower
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
#include <webserv/http/HttpRequest.hpp>
|
|
||||||
|
|
||||||
#include <webserv/client/Client.hpp> // for Client
|
#include <webserv/client/Client.hpp> // for Client
|
||||||
#include <webserv/config/utils.hpp> // for stoul
|
|
||||||
#include <webserv/http/HttpConstants.hpp> // for CRLF, DOUBLE_CRLF, BAD_REQUEST
|
#include <webserv/http/HttpConstants.hpp> // for CRLF, DOUBLE_CRLF, BAD_REQUEST
|
||||||
|
#include <webserv/http/HttpRequest.hpp>
|
||||||
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
#include <webserv/log/Log.hpp> // for Log, LOCATION
|
||||||
|
#include <webserv/utils/utils.hpp> // for stoul
|
||||||
|
|
||||||
#include <map> // for map
|
#include <map> // for map
|
||||||
#include <optional> // for optional
|
#include <optional> // for optional
|
||||||
|
|||||||
@ -15,8 +15,8 @@ int main(int argc, char **argv)
|
|||||||
std::cerr << "Usage: " << argv[0] << " <config_file_path>\n"; // NOLINT
|
std::cerr << "Usage: " << argv[0] << " <config_file_path>\n"; // NOLINT
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Log::setFileChannel("webserv.log", std::ios_base::app, Log::Level::Info);
|
Log::setFileChannel("webserv.log", std::ios_base::trunc, Log::Level::Info);
|
||||||
Log::setStdoutChannel(Log::Level::Info);
|
Log::setStdoutChannel(Log::Level::Trace);
|
||||||
Log::info("\n======================\nStarting webserv...\n======================\n");
|
Log::info("\n======================\nStarting webserv...\n======================\n");
|
||||||
ConfigManager::getInstance().init(argv[1]); // NOLINT
|
ConfigManager::getInstance().init(argv[1]); // NOLINT
|
||||||
ConfigManager &configManager = ConfigManager::getInstance();
|
ConfigManager &configManager = ConfigManager::getInstance();
|
||||||
|
|||||||
@ -2,80 +2,46 @@
|
|||||||
#include "webserv/config/ConfigManager.hpp"
|
#include "webserv/config/ConfigManager.hpp"
|
||||||
#include "webserv/config/ServerConfig.hpp"
|
#include "webserv/config/ServerConfig.hpp"
|
||||||
#include "webserv/handler/ErrorHandler.hpp"
|
#include "webserv/handler/ErrorHandler.hpp"
|
||||||
|
#include "webserv/handler/FileHandler.hpp"
|
||||||
|
#include "webserv/handler/URIParser.hpp"
|
||||||
#include "webserv/http/HttpResponse.hpp"
|
#include "webserv/http/HttpResponse.hpp"
|
||||||
#include "webserv/log/Log.hpp"
|
#include "webserv/log/Log.hpp"
|
||||||
|
|
||||||
#include <webserv/router/Router.hpp>
|
#include <webserv/router/Router.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
Router::Router() {}
|
Router::Router() {}
|
||||||
|
|
||||||
HttpResponse Router::handleRequest(const HttpRequest &request) const
|
std::unique_ptr<HttpResponse> Router::handleRequest(const HttpRequest &request) const
|
||||||
{
|
{
|
||||||
Log::trace(LOCATION);
|
Log::trace(LOCATION);
|
||||||
|
|
||||||
ServerConfig *config =
|
ServerConfig *config =
|
||||||
ConfigManager::getInstance().getMatchingServerConfig(request.getHeaders().getHost().value_or(""));
|
ConfigManager::getInstance().getMatchingServerConfig(request.getHeaders().getHost().value_or(""));
|
||||||
HttpResponse response;
|
|
||||||
|
|
||||||
if (config == nullptr)
|
if (config == nullptr)
|
||||||
{
|
{
|
||||||
Log::warning("No matching server config found");
|
return ErrorHandler::getErrorResponse(400);
|
||||||
handleError(400, response);
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
URIParser uriParser{request.getTarget(), *config};
|
||||||
|
|
||||||
const std::string &target = request.getTarget();
|
const std::string &target = request.getTarget();
|
||||||
const std::string &method = request.getMethod();
|
const std::string &method = request.getMethod();
|
||||||
|
|
||||||
const LocationConfig *location = getLocation(target, *config);
|
const LocationConfig *location = uriParser.getLocation();
|
||||||
if (location == nullptr)
|
if (location == nullptr)
|
||||||
{
|
{
|
||||||
Log::warning("No matching location found for target: " + target);
|
return ErrorHandler::getErrorResponse(404);
|
||||||
handleError(404, response, config);
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response.setStatus(200);
|
FileHandler fileHandler(location, uriParser);
|
||||||
response.addHeader("Content-Type", "text/plain");
|
return fileHandler.getResponse();
|
||||||
response.setBody("Hello, World! You requested " + target + " on " + request.getHeaders().getHost().value_or("") +
|
|
||||||
". Current resource is " + location->getPath());
|
|
||||||
response.setComplete();
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::handleError(int statusCode, HttpResponse &response, AConfig *config) const
|
// void Router::handleError(int statusCode, HttpResponse &response, AConfig *config) const
|
||||||
{
|
// {
|
||||||
response = ErrorHandler::getErrorResponse(statusCode, config);
|
// response = ErrorHandler::getErrorResponse(statusCode, config);
|
||||||
response.setComplete();
|
// response.setComplete();
|
||||||
}
|
// }
|
||||||
|
|
||||||
const LocationConfig *Router::getLocation(const std::string &path, const ServerConfig &serverConfig) const
|
|
||||||
{
|
|
||||||
const LocationConfig *bestMatch = nullptr;
|
|
||||||
size_t maxSize = 0;
|
|
||||||
|
|
||||||
std::vector<std::string> locations = serverConfig.getLocationPaths();
|
|
||||||
|
|
||||||
for (const auto &locPath : locations)
|
|
||||||
{
|
|
||||||
if (!path.starts_with(locPath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (locPath.length() > maxSize &&
|
|
||||||
(path.length() == locPath.length() || locPath.back() == '/' || path[locPath.length()] == '/'))
|
|
||||||
{
|
|
||||||
maxSize = locPath.length();
|
|
||||||
bestMatch = serverConfig.getLocation(locPath);
|
|
||||||
Log::debug("Found new best match: " + locPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bestMatch == nullptr)
|
|
||||||
{
|
|
||||||
Log::warning("No location matched for path: " + path);
|
|
||||||
}
|
|
||||||
return bestMatch;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <webserv/http/HttpRequest.hpp>
|
#include <webserv/http/HttpRequest.hpp>
|
||||||
#include <webserv/http/HttpResponse.hpp>
|
#include <webserv/http/HttpResponse.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Router
|
class Router
|
||||||
@ -12,9 +13,9 @@ class Router
|
|||||||
public:
|
public:
|
||||||
Router();
|
Router();
|
||||||
|
|
||||||
[[nodiscard]] HttpResponse handleRequest(const HttpRequest &request) const;
|
[[nodiscard]] std::unique_ptr<HttpResponse> handleRequest(const HttpRequest &request) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleError(int statusCode, HttpResponse &response, AConfig *config = nullptr) const;
|
// void handleError(int statusCode, HttpResponse &response, AConfig *config = nullptr) const;
|
||||||
[[nodiscard]] const LocationConfig *getLocation(const std::string &path, const ServerConfig &serverConfig) const;
|
[[nodiscard]] const LocationConfig *getLocation(const std::string &path, const ServerConfig &serverConfig) const;
|
||||||
};
|
};
|
||||||
@ -102,8 +102,9 @@ void Server::setupServerSocket(const ServerConfig &config)
|
|||||||
Log::trace(LOCATION);
|
Log::trace(LOCATION);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto host = config.getDirectiveValue<std::string>("host");
|
auto host = config.get<std::string>("host").value_or(std::string()); // TODO should not be a default host
|
||||||
auto port = config.getDirectiveValue<int>("listen");
|
|
||||||
|
auto port = config.get<int>("listen").value_or(0); // TODO should not be a default port
|
||||||
std::unique_ptr<Socket> serverSocket = std::make_unique<Socket>();
|
std::unique_ptr<Socket> serverSocket = std::make_unique<Socket>();
|
||||||
serverSocket->bind(host, port);
|
serverSocket->bind(host, port);
|
||||||
serverSocket->listen(SOMAXCONN);
|
serverSocket->listen(SOMAXCONN);
|
||||||
|
|||||||
61
webserv/utils/FileUtils.cpp
Normal file
61
webserv/utils/FileUtils.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <webserv/utils/FileUtils.hpp>
|
||||||
|
|
||||||
|
#include <cstring> // for strlen
|
||||||
|
#include <string> // for string
|
||||||
|
|
||||||
|
#include <sys/stat.h> // for stat, S_ISREG, S_ISDIR
|
||||||
|
|
||||||
|
namespace FileUtils
|
||||||
|
{
|
||||||
|
bool isDirectory(const std::string &path)
|
||||||
|
{
|
||||||
|
struct stat pathStat{};
|
||||||
|
if (stat(path.c_str(), &pathStat) != 0)
|
||||||
|
{
|
||||||
|
return false; // Could not access path
|
||||||
|
}
|
||||||
|
return S_ISDIR(pathStat.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFile(const std::string &path)
|
||||||
|
{
|
||||||
|
struct stat pathStat{};
|
||||||
|
if (stat(path.c_str(), &pathStat) != 0)
|
||||||
|
{
|
||||||
|
return false; // Could not access path
|
||||||
|
}
|
||||||
|
return S_ISREG(pathStat.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getExtension(const std::string &filename)
|
||||||
|
{
|
||||||
|
size_t dotPos = filename.find_last_of('.');
|
||||||
|
if (dotPos == std::string::npos || dotPos == filename.length() - 1)
|
||||||
|
{
|
||||||
|
return ""; // No extension found
|
||||||
|
}
|
||||||
|
return filename.substr(dotPos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string joinPath(const std::string &base, const std::string &addition) // NOLINT
|
||||||
|
{
|
||||||
|
std::string result = base;
|
||||||
|
if (result.empty())
|
||||||
|
{
|
||||||
|
result = addition;
|
||||||
|
}
|
||||||
|
else if (result.back() == '/' && addition.front() == '/')
|
||||||
|
{
|
||||||
|
result += addition.substr(1);
|
||||||
|
}
|
||||||
|
else if (result.back() != '/' && addition.front() != '/')
|
||||||
|
{
|
||||||
|
result += '/' + addition;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result += addition;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace FileUtils
|
||||||
11
webserv/utils/FileUtils.hpp
Normal file
11
webserv/utils/FileUtils.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace FileUtils
|
||||||
|
{
|
||||||
|
bool isDirectory(const std::string &path);
|
||||||
|
bool isFile(const std::string &path);
|
||||||
|
std::string getExtension(const std::string &filename);
|
||||||
|
std::string joinPath(const std::string &base, const std::string &addition);
|
||||||
|
} // namespace FileUtils
|
||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
#include <webserv/config/utils.hpp>
|
#include <webserv/utils/utils.hpp>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
Loading…
Reference in New Issue
Block a user