claude made a website
This commit is contained in:
parent
bcd33dacd7
commit
ab83c02fd2
@ -50,9 +50,9 @@ server {
|
||||
server {
|
||||
listen 8081;
|
||||
host 127.0.0.1;
|
||||
server_name mylocal;
|
||||
server_name localhost;
|
||||
|
||||
root /var/www/html2;
|
||||
root /www;
|
||||
index index.html index2.htm;
|
||||
|
||||
error_page 400 /400.html;
|
||||
@ -68,6 +68,7 @@ server {
|
||||
|
||||
location / {
|
||||
autoindex off;
|
||||
root www;
|
||||
index index.html;
|
||||
allowed_methods GET POST DELETE;
|
||||
}
|
||||
|
||||
@ -8,10 +8,10 @@
|
||||
class ErrorHandler
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<HttpResponse> getErrorResponse(int statusCode, AConfig *config = nullptr);
|
||||
static std::unique_ptr<HttpResponse> getErrorResponse(int statusCode, const AConfig *config = nullptr);
|
||||
|
||||
private:
|
||||
static std::string generateErrorPage(int statusCode, AConfig *config = nullptr);
|
||||
static std::string generateErrorPage(int statusCode, const AConfig *config = nullptr);
|
||||
static std::string generateDefaultErrorPage(int statusCode);
|
||||
static std::string getErrorPageFile(const std::string &path);
|
||||
};
|
||||
@ -12,7 +12,7 @@
|
||||
#include <sstream> // for basic_stringstream
|
||||
#include <string> // for basic_string, operator+, allocator, char_traits, string, to_string
|
||||
|
||||
std::unique_ptr<HttpResponse> ErrorHandler::getErrorResponse(int statusCode, AConfig *config)
|
||||
std::unique_ptr<HttpResponse> ErrorHandler::getErrorResponse(int statusCode, const AConfig *config)
|
||||
{
|
||||
std::string statusMessage = Http::getStatusCodeReason(statusCode);
|
||||
Log::warning("Generating error response: " + std::to_string(statusCode) + " " + statusMessage);
|
||||
@ -26,7 +26,7 @@ std::unique_ptr<HttpResponse> ErrorHandler::getErrorResponse(int statusCode, ACo
|
||||
return response;
|
||||
}
|
||||
|
||||
std::string ErrorHandler::generateErrorPage(int statusCode, AConfig *config)
|
||||
std::string ErrorHandler::generateErrorPage(int statusCode, const AConfig *config)
|
||||
{
|
||||
Log::trace(LOCATION);
|
||||
if (config == nullptr)
|
||||
|
||||
@ -79,7 +79,7 @@ std::unique_ptr<HttpResponse> FileHandler::getResponse() const
|
||||
Log::debug("Serving file: " + filepath + " with MIME type: " + mimeType);
|
||||
if (fileData.empty())
|
||||
{
|
||||
return ErrorHandler::getErrorResponse(404);
|
||||
return ErrorHandler::getErrorResponse(404, location_);
|
||||
}
|
||||
response->setBody(std::string(fileData.begin(), fileData.end()));
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ std::unique_ptr<HttpResponse> Router::handleRequest(const HttpRequest &request)
|
||||
const LocationConfig *location = uriParser.getLocation();
|
||||
if (location == nullptr)
|
||||
{
|
||||
return ErrorHandler::getErrorResponse(404);
|
||||
return ErrorHandler::getErrorResponse(404, config);
|
||||
}
|
||||
|
||||
FileHandler fileHandler(location, uriParser);
|
||||
|
||||
276
www/404.html
Normal file
276
www/404.html
Normal file
@ -0,0 +1,276 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>404 - Page Not Found | WebServ</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background: linear-gradient(135deg, #0f172a, #1e293b);
|
||||
color: #f8fafc;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-container {
|
||||
max-width: 600px;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.error-code {
|
||||
font-size: 8rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #ef4444, #dc2626);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
color: #f1f5f9;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
font-size: 1.1rem;
|
||||
color: #cbd5e1;
|
||||
margin-bottom: 2rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.error-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #2563eb, #1d4ed8);
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(37, 99, 235, 0.3);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: #cbd5e1;
|
||||
border: 1px solid #475569;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #334155;
|
||||
border-color: #64748b;
|
||||
color: #f1f5f9;
|
||||
}
|
||||
|
||||
.error-details {
|
||||
margin-top: 3rem;
|
||||
padding: 1.5rem;
|
||||
background: rgba(30, 41, 59, 0.5);
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #475569;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.error-details h3 {
|
||||
color: #f1f5f9;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.error-details p {
|
||||
color: #94a3b8;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-family: 'Fira Code', monospace;
|
||||
}
|
||||
|
||||
.server-info {
|
||||
margin-top: 2rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid #475569;
|
||||
color: #64748b;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.error-code {
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.error-actions {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.floating-shapes {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.shape {
|
||||
position: absolute;
|
||||
background: rgba(37, 99, 235, 0.1);
|
||||
border-radius: 50%;
|
||||
animation: float 20s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.shape:nth-child(1) {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.shape:nth-child(2) {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
top: 60%;
|
||||
right: 10%;
|
||||
animation-delay: 7s;
|
||||
}
|
||||
|
||||
.shape:nth-child(3) {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
bottom: 20%;
|
||||
left: 20%;
|
||||
animation-delay: 14s;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-30px) rotate(180deg);
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="floating-shapes">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
</div>
|
||||
|
||||
<div class="error-container">
|
||||
<div class="error-code">404</div>
|
||||
<h1 class="error-title">Page Not Found</h1>
|
||||
<p class="error-message">
|
||||
The page you're looking for doesn't exist or has been moved.
|
||||
Don't worry, even the best servers sometimes lose track of a page or two.
|
||||
</p>
|
||||
|
||||
<div class="error-actions">
|
||||
<a href="/" class="btn btn-primary">
|
||||
🏠 Go Home
|
||||
</a>
|
||||
<a href="javascript:history.back()" class="btn btn-secondary">
|
||||
← Go Back
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="error-details">
|
||||
<h3>Technical Details</h3>
|
||||
<p>Request: <span id="request-url"></span></p>
|
||||
<p>Method: GET</p>
|
||||
<p>Status: 404 Not Found</p>
|
||||
<p>Timestamp: <span id="timestamp"></span></p>
|
||||
<p>Referrer: <span id="referrer"></span></p>
|
||||
</div>
|
||||
|
||||
<div class="server-info">
|
||||
<p><strong>WebServ</strong> - High Performance C++ Web Server</p>
|
||||
<p>If this error persists, please contact the site administrator.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Populate error details
|
||||
document.getElementById('request-url').textContent = window.location.pathname;
|
||||
document.getElementById('timestamp').textContent = new Date().toISOString();
|
||||
document.getElementById('referrer').textContent = document.referrer || 'Direct access';
|
||||
|
||||
// Add some interactivity
|
||||
const shapes = document.querySelectorAll('.shape');
|
||||
let mouseX = 0;
|
||||
let mouseY = 0;
|
||||
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
mouseX = e.clientX / window.innerWidth;
|
||||
mouseY = e.clientY / window.innerHeight;
|
||||
|
||||
shapes.forEach((shape, index) => {
|
||||
const speed = (index + 1) * 0.5;
|
||||
const x = mouseX * speed * 10;
|
||||
const y = mouseY * speed * 10;
|
||||
|
||||
shape.style.transform = `translate(${x}px, ${y}px)`;
|
||||
});
|
||||
});
|
||||
|
||||
// Log error for debugging (in development)
|
||||
if (window.location.hostname === 'localhost') {
|
||||
console.log('404 Error Details:', {
|
||||
url: window.location.href,
|
||||
path: window.location.pathname,
|
||||
referrer: document.referrer,
|
||||
userAgent: navigator.userAgent,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
285
www/50x.html
Normal file
285
www/50x.html
Normal file
@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Server Error | WebServ</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background: linear-gradient(135deg, #0f172a, #1e293b);
|
||||
color: #f8fafc;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-container {
|
||||
max-width: 600px;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.error-code {
|
||||
font-size: 6rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
color: #f1f5f9;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
font-size: 1.1rem;
|
||||
color: #cbd5e1;
|
||||
margin-bottom: 2rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.error-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #2563eb, #1d4ed8);
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(37, 99, 235, 0.3);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: #cbd5e1;
|
||||
border: 1px solid #475569;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #334155;
|
||||
border-color: #64748b;
|
||||
color: #f1f5f9;
|
||||
}
|
||||
|
||||
.error-details {
|
||||
margin-top: 3rem;
|
||||
padding: 1.5rem;
|
||||
background: rgba(30, 41, 59, 0.5);
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #475569;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.error-details h3 {
|
||||
color: #f1f5f9;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.error-details p {
|
||||
color: #94a3b8;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-family: 'Fira Code', monospace;
|
||||
}
|
||||
|
||||
.server-info {
|
||||
margin-top: 2rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid #475569;
|
||||
color: #64748b;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin: 1rem 0;
|
||||
padding: 1rem;
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
border: 1px solid #f59e0b;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: #f59e0b;
|
||||
border-radius: 50%;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.error-code {
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.error-actions {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="error-container">
|
||||
<div class="error-code">5XX</div>
|
||||
<h1 class="error-title">Server Error</h1>
|
||||
<p class="error-message">
|
||||
We're experiencing some technical difficulties. Our team has been notified
|
||||
and is working to resolve the issue as quickly as possible.
|
||||
</p>
|
||||
|
||||
<div class="status-indicator">
|
||||
<div class="status-dot"></div>
|
||||
<span>Server is being restored...</span>
|
||||
</div>
|
||||
|
||||
<div class="error-actions">
|
||||
<a href="/" class="btn btn-primary">
|
||||
🏠 Go Home
|
||||
</a>
|
||||
<a href="javascript:location.reload()" class="btn btn-secondary">
|
||||
🔄 Refresh Page
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="error-details">
|
||||
<h3>Error Information</h3>
|
||||
<p>Request: <span id="request-url"></span></p>
|
||||
<p>Method: GET</p>
|
||||
<p>Status: <span id="error-code">500</span> Internal Server Error</p>
|
||||
<p>Timestamp: <span id="timestamp"></span></p>
|
||||
<p>Request ID: <span id="request-id"></span></p>
|
||||
</div>
|
||||
|
||||
<div class="server-info">
|
||||
<p><strong>WebServ</strong> - High Performance C++ Web Server</p>
|
||||
<p>Error ID: <span id="error-id"></span></p>
|
||||
<p>If this problem persists, please contact our support team.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Generate random error ID
|
||||
function generateErrorId() {
|
||||
return 'ERR-' + Math.random().toString(36).substr(2, 9).toUpperCase();
|
||||
}
|
||||
|
||||
// Generate random request ID
|
||||
function generateRequestId() {
|
||||
return 'REQ-' + Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
||||
}
|
||||
|
||||
// Populate error details
|
||||
document.getElementById('request-url').textContent = window.location.pathname;
|
||||
document.getElementById('timestamp').textContent = new Date().toISOString();
|
||||
document.getElementById('request-id').textContent = generateRequestId();
|
||||
document.getElementById('error-id').textContent = generateErrorId();
|
||||
|
||||
// Auto-refresh after 30 seconds
|
||||
let countdown = 30;
|
||||
const refreshBtn = document.querySelector('.btn-secondary');
|
||||
const originalText = refreshBtn.innerHTML;
|
||||
|
||||
function updateCountdown() {
|
||||
if (countdown > 0) {
|
||||
refreshBtn.innerHTML = `🔄 Refresh Page (${countdown}s)`;
|
||||
countdown--;
|
||||
setTimeout(updateCountdown, 1000);
|
||||
} else {
|
||||
refreshBtn.innerHTML = originalText;
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
// Start countdown after 5 seconds
|
||||
setTimeout(updateCountdown, 5000);
|
||||
|
||||
// Log error for debugging
|
||||
console.error('Server Error Details:', {
|
||||
url: window.location.href,
|
||||
path: window.location.pathname,
|
||||
userAgent: navigator.userAgent,
|
||||
timestamp: new Date().toISOString(),
|
||||
errorId: document.getElementById('error-id').textContent,
|
||||
requestId: document.getElementById('request-id').textContent
|
||||
});
|
||||
|
||||
// Try to detect the specific error code from URL parameters
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const errorCode = urlParams.get('code') || '500';
|
||||
document.getElementById('error-code').textContent = errorCode;
|
||||
|
||||
// Update title and message based on error code
|
||||
const errorMessages = {
|
||||
'500': 'Internal Server Error - Something went wrong on our end.',
|
||||
'502': 'Bad Gateway - The server received an invalid response.',
|
||||
'503': 'Service Unavailable - The server is temporarily unavailable.',
|
||||
'504': 'Gateway Timeout - The server took too long to respond.'
|
||||
};
|
||||
|
||||
if (errorMessages[errorCode]) {
|
||||
document.querySelector('.error-message').textContent = errorMessages[errorCode];
|
||||
}
|
||||
|
||||
// Update the main error code display
|
||||
document.querySelector('.error-code').textContent = errorCode;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
44
www/api/health.json
Normal file
44
www/api/health.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"status": "healthy",
|
||||
"timestamp": "2025-01-27T10:30:00.000Z",
|
||||
"checks": {
|
||||
"database": {
|
||||
"status": "up",
|
||||
"response_time_ms": 2.1,
|
||||
"last_check": "2025-01-27T10:29:55.000Z"
|
||||
},
|
||||
"memory": {
|
||||
"status": "ok",
|
||||
"usage_percent": 65.4,
|
||||
"available_mb": 5632,
|
||||
"threshold_percent": 80
|
||||
},
|
||||
"disk": {
|
||||
"status": "ok",
|
||||
"usage_percent": 42.1,
|
||||
"available_gb": 125.7,
|
||||
"threshold_percent": 90
|
||||
},
|
||||
"network": {
|
||||
"status": "up",
|
||||
"active_connections": 127,
|
||||
"max_connections": 10000,
|
||||
"bandwidth_utilization_percent": 15.2
|
||||
},
|
||||
"services": {
|
||||
"web_server": {
|
||||
"status": "running",
|
||||
"port": 8080,
|
||||
"uptime_seconds": 172800
|
||||
},
|
||||
"log_service": {
|
||||
"status": "running",
|
||||
"last_rotation": "2025-01-27T00:00:00.000Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
"overall_status": "healthy",
|
||||
"uptime_seconds": 172800,
|
||||
"version": "1.0.0",
|
||||
"environment": "production"
|
||||
}
|
||||
57
www/api/info.json
Normal file
57
www/api/info.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"server": "WebServ",
|
||||
"version": "1.0.0",
|
||||
"status": "running",
|
||||
"uptime": "2d 14h 32m",
|
||||
"build": {
|
||||
"compiler": "clang++ 12.0.1",
|
||||
"standard": "C++20",
|
||||
"optimization": "O3",
|
||||
"build_type": "release"
|
||||
},
|
||||
"connections": {
|
||||
"active": 127,
|
||||
"total": 45892,
|
||||
"max_concurrent": 10000
|
||||
},
|
||||
"performance": {
|
||||
"requests_per_second": 1542,
|
||||
"avg_response_time_ms": 1.2,
|
||||
"memory_usage_mb": 45.2,
|
||||
"cpu_usage_percent": 12.5
|
||||
},
|
||||
"features": [
|
||||
"HTTP/1.1",
|
||||
"Keep-Alive",
|
||||
"Chunked Transfer Encoding",
|
||||
"Virtual Hosts",
|
||||
"Static File Serving",
|
||||
"Directory Listing",
|
||||
"Custom Error Pages",
|
||||
"Configuration Validation",
|
||||
"Epoll Event Loop",
|
||||
"Multi-threaded Processing"
|
||||
],
|
||||
"supported_methods": [
|
||||
"GET",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"HEAD",
|
||||
"OPTIONS"
|
||||
],
|
||||
"configuration": {
|
||||
"config_file": "webserv.conf",
|
||||
"document_root": "./www",
|
||||
"index_files": ["index.html", "index.htm"],
|
||||
"error_log": "logs/error.log",
|
||||
"access_log": "logs/access.log"
|
||||
},
|
||||
"system": {
|
||||
"os": "Linux",
|
||||
"architecture": "x86_64",
|
||||
"cores": 8,
|
||||
"total_memory_gb": 16.0,
|
||||
"available_memory_gb": 12.3
|
||||
}
|
||||
}
|
||||
48
www/api/users.json
Normal file
48
www/api/users.json
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"status": "success",
|
||||
"timestamp": "2025-01-27T10:30:00.000Z",
|
||||
"response_time_ms": 1.8,
|
||||
"data": {
|
||||
"users": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@webserv.local",
|
||||
"role": "administrator",
|
||||
"active": true,
|
||||
"created_at": "2025-01-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"username": "developer",
|
||||
"email": "dev@webserv.local",
|
||||
"role": "developer",
|
||||
"active": true,
|
||||
"created_at": "2025-01-15T09:30:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"username": "guest",
|
||||
"email": "guest@webserv.local",
|
||||
"role": "user",
|
||||
"active": false,
|
||||
"created_at": "2025-01-20T14:22:00.000Z"
|
||||
}
|
||||
],
|
||||
"total_count": 3,
|
||||
"active_count": 2
|
||||
},
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"total_pages": 1,
|
||||
"has_next": false,
|
||||
"has_prev": false
|
||||
},
|
||||
"meta": {
|
||||
"api_version": "v1",
|
||||
"server": "WebServ/1.0",
|
||||
"cache_hit": false,
|
||||
"query_time_ms": 0.5
|
||||
}
|
||||
}
|
||||
653
www/css/style.css
Normal file
653
www/css/style.css
Normal file
@ -0,0 +1,653 @@
|
||||
:root {
|
||||
--primary-color: #2563eb;
|
||||
--primary-dark: #1d4ed8;
|
||||
--secondary-color: #64748b;
|
||||
--accent-color: #f59e0b;
|
||||
--success-color: #10b981;
|
||||
--error-color: #ef4444;
|
||||
--warning-color: #f59e0b;
|
||||
--background-color: #0f172a;
|
||||
--surface-color: #1e293b;
|
||||
--surface-light: #334155;
|
||||
--text-primary: #f8fafc;
|
||||
--text-secondary: #cbd5e1;
|
||||
--text-muted: #94a3b8;
|
||||
--border-color: #475569;
|
||||
--shadow-color: rgba(0, 0, 0, 0.3);
|
||||
--gradient-primary: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
|
||||
--gradient-secondary: linear-gradient(135deg, var(--surface-color), var(--surface-light));
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: var(--text-primary);
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
/* Navigation */
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
background: rgba(15, 23, 42, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
z-index: 1000;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-logo h2 {
|
||||
color: var(--primary-color);
|
||||
font-weight: 700;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.nav-link::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
background: var(--primary-color);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-link:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bar {
|
||||
width: 25px;
|
||||
height: 3px;
|
||||
background: var(--text-primary);
|
||||
margin: 3px 0;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
/* Hero Section */
|
||||
.hero {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--gradient-secondary);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000"><defs><radialGradient id="a" cx="50%" cy="50%"><stop offset="0%" stop-color="%23ffffff" stop-opacity="0.1"/><stop offset="100%" stop-color="%23ffffff" stop-opacity="0"/></radialGradient></defs><circle cx="200" cy="200" r="100" fill="url(%23a)"/><circle cx="800" cy="300" r="150" fill="url(%23a)"/><circle cx="400" cy="700" r="120" fill="url(%23a)"/></svg>');
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 4rem;
|
||||
font-weight: 800;
|
||||
background: var(--gradient-primary);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.5rem;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
font-size: 1.1rem;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 2rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.hero-buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.875rem 2rem;
|
||||
border-radius: 0.5rem;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
transition: all 0.3s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--gradient-primary);
|
||||
color: white;
|
||||
box-shadow: 0 4px 15px rgba(37, 99, 235, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(37, 99, 235, 0.4);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: var(--text-primary);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: var(--surface-light);
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
/* Code Preview */
|
||||
.hero-image {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.code-preview {
|
||||
background: var(--surface-color);
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 20px 40px var(--shadow-color);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.code-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--surface-light);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.code-dots {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dot.red { background: #ef4444; }
|
||||
.dot.yellow { background: #f59e0b; }
|
||||
.dot.green { background: #10b981; }
|
||||
|
||||
.code-title {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.code-content {
|
||||
padding: 1.5rem;
|
||||
font-family: 'Fira Code', 'JetBrains Mono', monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.code-content pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Sections */
|
||||
.section-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* Features Section */
|
||||
.features {
|
||||
padding: 6rem 0;
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
background: var(--surface-color);
|
||||
padding: 2rem;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--border-color);
|
||||
text-align: center;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 30px var(--shadow-color);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.feature-card h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.feature-card p {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Documentation Section */
|
||||
.documentation {
|
||||
padding: 6rem 0;
|
||||
background: var(--surface-color);
|
||||
}
|
||||
|
||||
.docs-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.docs-card {
|
||||
background: var(--background-color);
|
||||
padding: 2rem;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--border-color);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.docs-card:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.docs-card h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.docs-card p {
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.docs-link {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.docs-link:hover {
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
/* Demo Section */
|
||||
.demo {
|
||||
padding: 6rem 0;
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
gap: 3rem;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.demo-controls h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 2rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.demo-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.demo-btn {
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.5rem;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.demo-btn:hover {
|
||||
background: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.demo-output {
|
||||
background: var(--surface-color);
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--border-color);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.demo-output h4 {
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--surface-light);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
#demo-result {
|
||||
padding: 1.5rem;
|
||||
font-family: 'Fira Code', monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
color: var(--text-secondary);
|
||||
background: transparent;
|
||||
border: none;
|
||||
min-height: 200px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* Stats Section */
|
||||
.stats {
|
||||
padding: 4rem 0;
|
||||
background: var(--surface-color);
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 3rem;
|
||||
font-weight: 800;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 1rem;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
background: var(--background-color);
|
||||
padding: 4rem 0 2rem;
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 3rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.footer-section h3,
|
||||
.footer-section h4 {
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.footer-section p,
|
||||
.footer-section li {
|
||||
color: var(--text-muted);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.footer-section ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.footer-section ul li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.footer-section a {
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.footer-section a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
text-align: center;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid var(--border-color);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.nav-menu {
|
||||
position: fixed;
|
||||
left: -100%;
|
||||
top: 70px;
|
||||
flex-direction: column;
|
||||
background: var(--surface-color);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
transition: 0.3s;
|
||||
box-shadow: 0 10px 27px rgba(0, 0, 0, 0.05);
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.nav-menu.active {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.nav-menu a {
|
||||
padding: 1rem;
|
||||
display: block;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.hamburger.active .bar:nth-child(2) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hamburger.active .bar:nth-child(1) {
|
||||
transform: translateY(8px) rotate(45deg);
|
||||
}
|
||||
|
||||
.hamburger.active .bar:nth-child(3) {
|
||||
transform: translateY(-8px) rotate(-45deg);
|
||||
}
|
||||
|
||||
.hero-container {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.hero-buttons {
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.features-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.docs-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.hero-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation for smooth loading */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.feature-card,
|
||||
.docs-card {
|
||||
animation: fadeInUp 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* Scrollbar Styling */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--surface-color);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
507
www/docs/configuration.html
Normal file
507
www/docs/configuration.html
Normal file
@ -0,0 +1,507 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Configuration Guide - WebServ Documentation</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<style>
|
||||
.docs-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 6rem 2rem 4rem;
|
||||
}
|
||||
.docs-nav {
|
||||
background: var(--surface-color);
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 2rem;
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
.docs-nav ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.docs-nav li {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.docs-nav a {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
.docs-nav a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.code-block {
|
||||
background: var(--surface-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
font-family: 'Fira Code', monospace;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.directive-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1.5rem 0;
|
||||
background: var(--surface-color);
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
.directive-table th,
|
||||
.directive-table td {
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
.directive-table th {
|
||||
background: var(--surface-light);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.directive-table td {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.directive-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.info {
|
||||
background: rgba(37, 99, 235, 0.1);
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
.warning {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
border: 1px solid var(--warning-color);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar">
|
||||
<div class="nav-container">
|
||||
<div class="nav-logo">
|
||||
<h2><a href="../index.html" style="color: var(--primary-color); text-decoration: none;">WebServ</a></h2>
|
||||
</div>
|
||||
<div class="nav-menu">
|
||||
<a href="../index.html#home" class="nav-link">Home</a>
|
||||
<a href="../index.html#features" class="nav-link">Features</a>
|
||||
<a href="../index.html#documentation" class="nav-link">Documentation</a>
|
||||
<a href="../index.html#demo" class="nav-link">Demo</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="docs-container">
|
||||
<h1>Configuration Guide</h1>
|
||||
|
||||
<nav class="docs-nav">
|
||||
<ul>
|
||||
<li><a href="#overview">Configuration Overview</a></li>
|
||||
<li><a href="#server-directives">Server Directives</a></li>
|
||||
<li><a href="#location-directives">Location Directives</a></li>
|
||||
<li><a href="#examples">Configuration Examples</a></li>
|
||||
<li><a href="#best-practices">Best Practices</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<section id="overview">
|
||||
<h2>Configuration Overview</h2>
|
||||
<p>WebServ uses an nginx-inspired configuration syntax that is both powerful and familiar. Configuration files consist of directive blocks that define server behavior.</p>
|
||||
|
||||
<h3>Configuration Structure</h3>
|
||||
<div class="code-block">
|
||||
<pre># Global directives (coming soon)
|
||||
worker_processes auto;
|
||||
error_log logs/error.log;
|
||||
|
||||
# Server blocks define virtual hosts
|
||||
server {
|
||||
# Server-specific directives
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
root /var/www/html;
|
||||
|
||||
# Location blocks define URI-specific behavior
|
||||
location / {
|
||||
# Location-specific directives
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://backend;
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<strong>💡 Note:</strong> Comments start with <code>#</code> and continue to the end of the line. Directives end with semicolons <code>;</code> and blocks are enclosed in braces <code>{}</code>.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="server-directives">
|
||||
<h2>Server Directives</h2>
|
||||
<p>Server directives define the behavior of virtual hosts and are placed within <code>server {}</code> blocks.</p>
|
||||
|
||||
<table class="directive-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Directive</th>
|
||||
<th>Syntax</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>listen</code></td>
|
||||
<td><code>listen port [ssl];</code></td>
|
||||
<td>Specifies the port to listen on, optionally with SSL</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>server_name</code></td>
|
||||
<td><code>server_name name ...;</code></td>
|
||||
<td>Defines server names for virtual hosting</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>root</code></td>
|
||||
<td><code>root path;</code></td>
|
||||
<td>Sets the document root directory</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>index</code></td>
|
||||
<td><code>index file ...;</code></td>
|
||||
<td>Defines default files to serve for directories</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>error_page</code></td>
|
||||
<td><code>error_page code ... uri;</code></td>
|
||||
<td>Defines custom error pages for HTTP status codes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>client_max_body_size</code></td>
|
||||
<td><code>client_max_body_size size;</code></td>
|
||||
<td>Maximum allowed size of client request body</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Listen Directive Examples</h3>
|
||||
<div class="code-block">
|
||||
<pre># Basic HTTP server
|
||||
listen 80;
|
||||
|
||||
# HTTPS server
|
||||
listen 443 ssl;
|
||||
|
||||
# Specific interface
|
||||
listen 192.168.1.10:8080;
|
||||
|
||||
# IPv6
|
||||
listen [::]:80;</pre>
|
||||
</div>
|
||||
|
||||
<h3>Server Name Examples</h3>
|
||||
<div class="code-block">
|
||||
<pre># Exact match
|
||||
server_name example.com;
|
||||
|
||||
# Multiple names
|
||||
server_name example.com www.example.com;
|
||||
|
||||
# Wildcard
|
||||
server_name *.example.com;
|
||||
|
||||
# Regular expression
|
||||
server_name ~^www\.(.+)$;</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="location-directives">
|
||||
<h2>Location Directives</h2>
|
||||
<p>Location blocks define how to process requests for specific URIs and are placed within <code>server {}</code> blocks.</p>
|
||||
|
||||
<h3>Location Matching</h3>
|
||||
<div class="code-block">
|
||||
<pre># Exact match
|
||||
location = /favicon.ico {
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
# Prefix match
|
||||
location /images/ {
|
||||
expires 7d;
|
||||
}
|
||||
|
||||
# Regular expression (case-sensitive)
|
||||
location ~ \.(jpg|jpeg|png|gif)$ {
|
||||
expires 1M;
|
||||
}
|
||||
|
||||
# Regular expression (case-insensitive)
|
||||
location ~* \.(css|js)$ {
|
||||
expires 1y;
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<table class="directive-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Directive</th>
|
||||
<th>Syntax</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>try_files</code></td>
|
||||
<td><code>try_files file ... uri;</code></td>
|
||||
<td>Tries files in order, falls back to URI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>alias</code></td>
|
||||
<td><code>alias path;</code></td>
|
||||
<td>Maps location to a different path</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>return</code></td>
|
||||
<td><code>return code [text];</code></td>
|
||||
<td>Returns HTTP response with status code</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>rewrite</code></td>
|
||||
<td><code>rewrite regex replacement;</code></td>
|
||||
<td>Rewrites URI using regular expressions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>autoindex</code></td>
|
||||
<td><code>autoindex on|off;</code></td>
|
||||
<td>Enables/disables directory listing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>expires</code></td>
|
||||
<td><code>expires time;</code></td>
|
||||
<td>Sets cache expiration headers</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="examples">
|
||||
<h2>Configuration Examples</h2>
|
||||
|
||||
<h3>Static Website</h3>
|
||||
<div class="code-block">
|
||||
<pre>server {
|
||||
listen 80;
|
||||
server_name mysite.com www.mysite.com;
|
||||
root /var/www/mysite;
|
||||
index index.html index.htm;
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
# Custom error pages
|
||||
error_page 404 /404.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<h3>API Server with Reverse Proxy</h3>
|
||||
<div class="code-block">
|
||||
<pre>server {
|
||||
listen 80;
|
||||
server_name api.example.com;
|
||||
|
||||
# API endpoints
|
||||
location /v1/ {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# CORS headers
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
}
|
||||
|
||||
# Handle preflight requests
|
||||
location / {
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||||
add_header Content-Length 0;
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<h3>Multi-Domain Hosting</h3>
|
||||
<div class="code-block">
|
||||
<pre># Main website
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com www.example.com;
|
||||
root /var/www/example.com;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
|
||||
# Blog subdomain
|
||||
server {
|
||||
listen 80;
|
||||
server_name blog.example.com;
|
||||
root /var/www/blog;
|
||||
index index.html;
|
||||
|
||||
# WordPress-style permalinks
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
}
|
||||
}
|
||||
|
||||
# File sharing subdomain
|
||||
server {
|
||||
listen 80;
|
||||
server_name files.example.com;
|
||||
root /var/www/files;
|
||||
|
||||
# Enable directory browsing
|
||||
location / {
|
||||
autoindex on;
|
||||
autoindex_exact_size off;
|
||||
autoindex_localtime on;
|
||||
}
|
||||
|
||||
# Restrict access to sensitive files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<h3>Development Server</h3>
|
||||
<div class="code-block">
|
||||
<pre>server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
root ./www;
|
||||
index index.html;
|
||||
|
||||
# Disable caching for development
|
||||
expires -1;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
|
||||
# Enable directory listing
|
||||
autoindex on;
|
||||
|
||||
# Detailed error pages
|
||||
error_page 404 /dev-404.html;
|
||||
|
||||
# Hot reload support
|
||||
location /ws {
|
||||
proxy_pass http://127.0.0.1:3001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="best-practices">
|
||||
<h2>Best Practices</h2>
|
||||
|
||||
<h3>Security</h3>
|
||||
<ul>
|
||||
<li>Always set appropriate security headers</li>
|
||||
<li>Restrict access to sensitive files and directories</li>
|
||||
<li>Use HTTPS in production environments</li>
|
||||
<li>Implement rate limiting for API endpoints</li>
|
||||
<li>Validate and sanitize all input</li>
|
||||
</ul>
|
||||
|
||||
<div class="code-block">
|
||||
<pre># Security headers example
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||||
|
||||
# Hide server information
|
||||
server_tokens off;
|
||||
|
||||
# Restrict sensitive files
|
||||
location ~ /\.(ht|git|svn) {
|
||||
deny all;
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<h3>Performance</h3>
|
||||
<ul>
|
||||
<li>Set appropriate cache headers for static content</li>
|
||||
<li>Use gzip compression for text-based files</li>
|
||||
<li>Optimize file serving with sendfile</li>
|
||||
<li>Configure proper keepalive settings</li>
|
||||
<li>Use CDN for static assets in production</li>
|
||||
</ul>
|
||||
|
||||
<div class="code-block">
|
||||
<pre># Performance optimizations
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/json application/javascript;</pre>
|
||||
</div>
|
||||
|
||||
<h3>Organization</h3>
|
||||
<ul>
|
||||
<li>Use separate configuration files for different sites</li>
|
||||
<li>Group related directives together</li>
|
||||
<li>Comment complex configurations</li>
|
||||
<li>Use consistent indentation and formatting</li>
|
||||
<li>Version control your configuration files</li>
|
||||
</ul>
|
||||
|
||||
<div class="warning">
|
||||
<strong>⚠️ Important:</strong> Always test configuration changes in a development environment before applying them to production. Use <code>webserv -t config.conf</code> to validate syntax.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr style="margin: 3rem 0; border: 1px solid var(--border-color);">
|
||||
|
||||
<div style="text-align: center;">
|
||||
<p>Need more help? Check out the <a href="getting-started.html" style="color: var(--primary-color);">Getting Started</a> guide or <a href="api.html" style="color: var(--primary-color);">API Reference</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
336
www/docs/getting-started.html
Normal file
336
www/docs/getting-started.html
Normal file
@ -0,0 +1,336 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Getting Started - WebServ Documentation</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<style>
|
||||
.docs-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 6rem 2rem 4rem;
|
||||
}
|
||||
.docs-nav {
|
||||
background: var(--surface-color);
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 2rem;
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
.docs-nav ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.docs-nav li {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.docs-nav a {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
.docs-nav a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.code-block {
|
||||
background: var(--surface-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
font-family: 'Fira Code', monospace;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.warning {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
border: 1px solid var(--warning-color);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
.info {
|
||||
background: rgba(37, 99, 235, 0.1);
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar">
|
||||
<div class="nav-container">
|
||||
<div class="nav-logo">
|
||||
<h2><a href="../index.html" style="color: var(--primary-color); text-decoration: none;">WebServ</a></h2>
|
||||
</div>
|
||||
<div class="nav-menu">
|
||||
<a href="../index.html#home" class="nav-link">Home</a>
|
||||
<a href="../index.html#features" class="nav-link">Features</a>
|
||||
<a href="../index.html#documentation" class="nav-link">Documentation</a>
|
||||
<a href="../index.html#demo" class="nav-link">Demo</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="docs-container">
|
||||
<h1>Getting Started with WebServ</h1>
|
||||
|
||||
<nav class="docs-nav">
|
||||
<ul>
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#configuration">Basic Configuration</a></li>
|
||||
<li><a href="#running">Running the Server</a></li>
|
||||
<li><a href="#testing">Testing Your Setup</a></li>
|
||||
<li><a href="#troubleshooting">Troubleshooting</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<section id="installation">
|
||||
<h2>Installation</h2>
|
||||
<p>WebServ is built with modern C++20 and requires a recent compiler and CMake for building.</p>
|
||||
|
||||
<h3>Prerequisites</h3>
|
||||
<ul>
|
||||
<li>C++20 compatible compiler (GCC 10+, Clang 12+)</li>
|
||||
<li>CMake 3.22 or higher</li>
|
||||
<li>Make build system</li>
|
||||
<li>Linux operating system (epoll-based)</li>
|
||||
</ul>
|
||||
|
||||
<h3>Building from Source</h3>
|
||||
<div class="code-block">
|
||||
<pre># Clone the repository
|
||||
git clone https://github.com/WHaffmans/webserv.git
|
||||
cd webserv
|
||||
|
||||
# Build the project
|
||||
make
|
||||
|
||||
# Or build with specific configuration
|
||||
make build_type=release
|
||||
make build_type=debug
|
||||
make build_type=asan</pre>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<strong>💡 Build Types:</strong><br>
|
||||
• <code>debug</code>: Debug symbols, no optimization<br>
|
||||
• <code>release</code>: Optimized build for production<br>
|
||||
• <code>asan</code>: Address sanitizer for memory debugging
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="configuration">
|
||||
<h2>Basic Configuration</h2>
|
||||
<p>WebServ uses nginx-style configuration files for maximum flexibility and familiarity.</p>
|
||||
|
||||
<h3>Minimal Configuration</h3>
|
||||
<div class="code-block">
|
||||
<pre># webserv.conf
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
root ./www;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<h3>Advanced Configuration</h3>
|
||||
<div class="code-block">
|
||||
<pre># Advanced webserv.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com www.example.com;
|
||||
root /var/www/html;
|
||||
index index.html index.htm;
|
||||
|
||||
# Error pages
|
||||
error_page 404 /404.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
# Static files with caching
|
||||
location /static/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# API endpoints
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# Directory listing
|
||||
location /files/ {
|
||||
autoindex on;
|
||||
autoindex_exact_size off;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS server
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name example.com;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
root /var/www/ssl;
|
||||
index index.html;
|
||||
}</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="running">
|
||||
<h2>Running the Server</h2>
|
||||
|
||||
<h3>Basic Usage</h3>
|
||||
<div class="code-block">
|
||||
<pre># Run with default configuration
|
||||
./build/webserv
|
||||
|
||||
# Run with custom configuration file
|
||||
./build/webserv config/webserv.conf
|
||||
|
||||
# Run with make target (rebuilds if needed)
|
||||
make run</pre>
|
||||
</div>
|
||||
|
||||
<h3>Command Line Options</h3>
|
||||
<div class="code-block">
|
||||
<pre>Usage: webserv [config_file]
|
||||
|
||||
Arguments:
|
||||
config_file Path to configuration file (default: webserv.conf)
|
||||
|
||||
Examples:
|
||||
./webserv # Use default config
|
||||
./webserv /etc/webserv.conf # Use specific config
|
||||
./webserv --help # Show help message</pre>
|
||||
</div>
|
||||
|
||||
<div class="warning">
|
||||
<strong>⚠️ Important:</strong> Make sure the specified ports are not already in use. WebServ will fail to start if the ports are occupied.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="testing">
|
||||
<h2>Testing Your Setup</h2>
|
||||
|
||||
<h3>Basic Connectivity Test</h3>
|
||||
<div class="code-block">
|
||||
<pre># Test with curl
|
||||
curl http://localhost:8080/
|
||||
|
||||
# Test with specific headers
|
||||
curl -H "Host: example.com" http://localhost:8080/
|
||||
|
||||
# Test POST request
|
||||
curl -X POST -d "test=data" http://localhost:8080/api/test</pre>
|
||||
</div>
|
||||
|
||||
<h3>Performance Testing</h3>
|
||||
<div class="code-block">
|
||||
<pre># Apache Bench
|
||||
ab -n 1000 -c 10 http://localhost:8080/
|
||||
|
||||
# wrk load testing
|
||||
wrk -t12 -c400 -d30s http://localhost:8080/
|
||||
|
||||
# siege testing
|
||||
siege -c 50 -t 30s http://localhost:8080/</pre>
|
||||
</div>
|
||||
|
||||
<h3>Running Unit Tests</h3>
|
||||
<div class="code-block">
|
||||
<pre># Build and run tests
|
||||
make test
|
||||
|
||||
# Run specific test suite
|
||||
cd build && ctest -V
|
||||
|
||||
# Run with Google Test directly
|
||||
./build/webserv_tests</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="troubleshooting">
|
||||
<h2>Troubleshooting</h2>
|
||||
|
||||
<h3>Common Issues</h3>
|
||||
|
||||
<h4>Port Already in Use</h4>
|
||||
<div class="code-block">
|
||||
<pre># Check what's using the port
|
||||
sudo netstat -tlnp | grep :8080
|
||||
sudo lsof -i :8080
|
||||
|
||||
# Kill process using the port
|
||||
sudo kill -9 <PID></pre>
|
||||
</div>
|
||||
|
||||
<h4>Permission Denied</h4>
|
||||
<div class="code-block">
|
||||
<pre># For ports below 1024, run as root
|
||||
sudo ./build/webserv
|
||||
|
||||
# Or use a port above 1024
|
||||
# Edit config: listen 8080;</pre>
|
||||
</div>
|
||||
|
||||
<h4>Configuration Errors</h4>
|
||||
<div class="code-block">
|
||||
<pre># Check configuration syntax
|
||||
./build/webserv -t config/webserv.conf
|
||||
|
||||
# Debug mode for detailed logging
|
||||
./build/webserv_debug config/webserv.conf</pre>
|
||||
</div>
|
||||
|
||||
<h3>Log Files</h3>
|
||||
<p>WebServ logs are written to both console and log files:</p>
|
||||
<div class="code-block">
|
||||
<pre># Default log locations
|
||||
./logs/access.log # Access logs
|
||||
./logs/error.log # Error logs
|
||||
./logs/debug.log # Debug logs (debug build only)
|
||||
|
||||
# Tail logs in real-time
|
||||
tail -f logs/access.log
|
||||
tail -f logs/error.log</pre>
|
||||
</div>
|
||||
|
||||
<h3>Debug Build</h3>
|
||||
<p>For development and troubleshooting, use the debug build:</p>
|
||||
<div class="code-block">
|
||||
<pre># Build debug version
|
||||
make build_type=debug
|
||||
|
||||
# Run with debug logging
|
||||
./build/webserv_debug
|
||||
|
||||
# Use with GDB for debugging
|
||||
gdb ./build/webserv_debug
|
||||
(gdb) run config/webserv.conf</pre>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<strong>💡 Pro Tip:</strong> Use the address sanitizer build (<code>make build_type=asan</code>) to catch memory errors during development.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr style="margin: 3rem 0; border: 1px solid var(--border-color);">
|
||||
|
||||
<div style="text-align: center;">
|
||||
<p>Need more help? Check out the <a href="configuration.html" style="color: var(--primary-color);">Configuration Guide</a> or <a href="api.html" style="color: var(--primary-color);">API Reference</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
73
www/examples/README.md
Normal file
73
www/examples/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
Welcome to WebServ Examples Directory
|
||||
|
||||
This directory contains example files and configurations to demonstrate
|
||||
various features of the WebServ HTTP server.
|
||||
|
||||
Files in this directory:
|
||||
========================
|
||||
|
||||
webserv.conf - Complete example configuration file
|
||||
README.md - This file
|
||||
test.txt - Simple text file for testing
|
||||
sample.html - Basic HTML page
|
||||
large-file.dat - Larger file for testing file serving performance
|
||||
|
||||
Configuration Examples:
|
||||
======================
|
||||
|
||||
The webserv.conf file demonstrates:
|
||||
- Multiple server blocks
|
||||
- Virtual host configuration
|
||||
- SSL/HTTPS setup
|
||||
- Static file serving
|
||||
- API endpoint configuration
|
||||
- Directory listing
|
||||
- Custom error pages
|
||||
- Security headers
|
||||
- Caching strategies
|
||||
|
||||
Testing Examples:
|
||||
================
|
||||
|
||||
You can test various server features using these files:
|
||||
|
||||
1. Static File Serving:
|
||||
curl http://localhost:8080/examples/test.txt
|
||||
|
||||
2. HTML Content:
|
||||
curl http://localhost:8080/examples/sample.html
|
||||
|
||||
3. Directory Listing:
|
||||
curl http://localhost:8080/examples/
|
||||
|
||||
4. Large File Download:
|
||||
curl -O http://localhost:8080/examples/large-file.dat
|
||||
|
||||
5. Error Handling:
|
||||
curl http://localhost:8080/examples/nonexistent.html
|
||||
|
||||
Performance Testing:
|
||||
===================
|
||||
|
||||
Use tools like Apache Bench (ab) or wrk to test performance:
|
||||
|
||||
ab -n 1000 -c 10 http://localhost:8080/examples/test.txt
|
||||
wrk -t4 -c100 -d30s http://localhost:8080/examples/
|
||||
|
||||
Security Testing:
|
||||
================
|
||||
|
||||
Test various security scenarios:
|
||||
|
||||
1. Directory traversal attempts:
|
||||
curl http://localhost:8080/examples/../../../etc/passwd
|
||||
|
||||
2. Hidden file access:
|
||||
curl http://localhost:8080/examples/.htaccess
|
||||
|
||||
3. Backup file access:
|
||||
curl http://localhost:8080/examples/config.php~
|
||||
|
||||
All these should be properly blocked by WebServ's security features.
|
||||
|
||||
For more information, visit the WebServ documentation.
|
||||
187
www/examples/sample.html
Normal file
187
www/examples/sample.html
Normal file
@ -0,0 +1,187 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebServ Sample Page</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #333;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
||||
}
|
||||
h1 {
|
||||
color: #2c3e50;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.feature {
|
||||
background: #f8f9fa;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
border-left: 4px solid #007bff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.code {
|
||||
background: #2d3748;
|
||||
color: #e2e8f0;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
font-family: 'Courier New', monospace;
|
||||
margin: 15px 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.stat {
|
||||
background: #e3f2fd;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.stat-number {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: #1976d2;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eee;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🚀 WebServ Sample Page</h1>
|
||||
|
||||
<p>Welcome to the WebServ demonstration page! This HTML file showcases the static file serving capabilities of our high-performance C++ web server.</p>
|
||||
|
||||
<div class="feature">
|
||||
<h3>✨ Key Features</h3>
|
||||
<ul>
|
||||
<li>HTTP/1.1 compliant implementation</li>
|
||||
<li>Epoll-based event handling for maximum performance</li>
|
||||
<li>Modern C++20 codebase</li>
|
||||
<li>Nginx-style configuration</li>
|
||||
<li>Virtual host support</li>
|
||||
<li>Custom error pages</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h3>🔧 Technical Specifications</h3>
|
||||
<p>Built with cutting-edge technology for optimal performance:</p>
|
||||
<div class="code">
|
||||
Compiler: clang++ 12.0.1
|
||||
Standard: C++20
|
||||
Architecture: x86_64
|
||||
Build System: CMake + Make
|
||||
Event Loop: epoll (Linux)
|
||||
Memory Management: RAII + Smart Pointers
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat">
|
||||
<div class="stat-number">10,000+</div>
|
||||
<div>Concurrent Connections</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-number"><1ms</div>
|
||||
<div>Average Response Time</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-number">99.9%</div>
|
||||
<div>Uptime Reliability</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-number">C++20</div>
|
||||
<div>Modern Standard</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h3>📊 Request Information</h3>
|
||||
<p>This page was served by WebServ with the following details:</p>
|
||||
<div class="code" id="request-info">
|
||||
Server: WebServ/1.0
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Status: 200 OK
|
||||
Method: GET
|
||||
URI: /examples/sample.html
|
||||
Timestamp: <span id="timestamp"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<h3>🧪 Testing Commands</h3>
|
||||
<p>You can test this page using various HTTP clients:</p>
|
||||
<div class="code">
|
||||
# Basic request
|
||||
curl http://localhost:8080/examples/sample.html
|
||||
|
||||
# With headers
|
||||
curl -I http://localhost:8080/examples/sample.html
|
||||
|
||||
# Performance test
|
||||
ab -n 1000 -c 10 http://localhost:8080/examples/sample.html
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p><strong>WebServ</strong> - A high-performance C++20 web server</p>
|
||||
<p>Part of the 42 School curriculum • Built with ❤️ and modern C++</p>
|
||||
<p>Page generated at: <span id="page-time"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Add timestamp information
|
||||
const now = new Date();
|
||||
document.getElementById('timestamp').textContent = now.toISOString();
|
||||
document.getElementById('page-time').textContent = now.toLocaleString();
|
||||
|
||||
// Add some interactivity
|
||||
const stats = document.querySelectorAll('.stat-number');
|
||||
stats.forEach(stat => {
|
||||
stat.addEventListener('click', function() {
|
||||
this.style.transform = 'scale(1.1)';
|
||||
this.style.transition = 'transform 0.2s';
|
||||
setTimeout(() => {
|
||||
this.style.transform = 'scale(1)';
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
// Log page load information
|
||||
console.log('WebServ Sample Page Loaded', {
|
||||
url: window.location.href,
|
||||
timestamp: now.toISOString(),
|
||||
userAgent: navigator.userAgent,
|
||||
viewport: {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
39
www/examples/test.txt
Normal file
39
www/examples/test.txt
Normal file
@ -0,0 +1,39 @@
|
||||
This is a simple text file for testing WebServ's static file serving capabilities.
|
||||
|
||||
WebServ Features Demonstrated:
|
||||
==============================
|
||||
|
||||
✓ Static file serving
|
||||
✓ Proper MIME type detection
|
||||
✓ HTTP/1.1 compliance
|
||||
✓ Keep-alive connections
|
||||
✓ Efficient file reading
|
||||
✓ Custom headers
|
||||
✓ Caching support
|
||||
|
||||
Server Information:
|
||||
==================
|
||||
Server: WebServ/1.0
|
||||
Build: C++20 with epoll
|
||||
Performance: High-throughput, low-latency
|
||||
|
||||
This file can be used to test:
|
||||
- Basic HTTP GET requests
|
||||
- File serving performance
|
||||
- MIME type handling (text/plain)
|
||||
- Response headers
|
||||
- Connection handling
|
||||
|
||||
Example request:
|
||||
curl -v http://localhost:8080/examples/test.txt
|
||||
|
||||
Expected response:
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/plain
|
||||
Content-Length: [file size]
|
||||
Last-Modified: [modification date]
|
||||
Cache-Control: public, max-age=3600
|
||||
|
||||
[This file content]
|
||||
|
||||
Test completed successfully! 🎉
|
||||
151
www/examples/webserv.conf
Normal file
151
www/examples/webserv.conf
Normal file
@ -0,0 +1,151 @@
|
||||
# WebServ Example Configuration
|
||||
# This configuration demonstrates various features of WebServ
|
||||
|
||||
# Main HTTP server
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost webserv.local;
|
||||
root ./www;
|
||||
index index.html index.htm;
|
||||
|
||||
# Maximum request body size (1MB)
|
||||
client_max_body_size 1m;
|
||||
|
||||
# Custom error pages
|
||||
error_page 404 /404.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
# Main location - serves static files
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
|
||||
# Cache static files for 1 hour
|
||||
expires 1h;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
# API endpoint simulation
|
||||
location /api/ {
|
||||
# In a real setup, this would proxy to a backend service
|
||||
# For now, we'll serve static JSON files
|
||||
try_files $uri $uri.json =404;
|
||||
add_header Content-Type "application/json";
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
}
|
||||
|
||||
# File uploads (if supported)
|
||||
location /upload {
|
||||
# Allow larger files for uploads
|
||||
client_max_body_size 10m;
|
||||
|
||||
# Only allow POST requests
|
||||
limit_except POST {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
# Directory listing for examples
|
||||
location /examples/ {
|
||||
autoindex on;
|
||||
autoindex_exact_size off;
|
||||
autoindex_localtime on;
|
||||
}
|
||||
|
||||
# Static assets with long-term caching
|
||||
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Vary "Accept-Encoding";
|
||||
}
|
||||
|
||||
# Security: deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Security: deny access to backup files
|
||||
location ~ ~$ {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS server (if SSL support is implemented)
|
||||
server {
|
||||
listen 8443 ssl;
|
||||
server_name localhost webserv.local;
|
||||
root ./www;
|
||||
index index.html;
|
||||
|
||||
# SSL certificate paths (update these paths)
|
||||
ssl_certificate /path/to/certificate.crt;
|
||||
ssl_certificate_key /path/to/private.key;
|
||||
|
||||
# SSL security headers
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Same location blocks as HTTP server
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
|
||||
# API-only server
|
||||
server {
|
||||
listen 8081;
|
||||
server_name api.webserv.local;
|
||||
|
||||
# API root directory
|
||||
root ./api;
|
||||
|
||||
# CORS headers for API
|
||||
add_header Access-Control-Allow-Origin "*" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With" always;
|
||||
|
||||
# Handle preflight requests
|
||||
location / {
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With";
|
||||
add_header Access-Control-Max-Age 1728000;
|
||||
add_header Content-Type "text/plain; charset=utf-8";
|
||||
add_header Content-Length 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
try_files $uri $uri.json =404;
|
||||
add_header Content-Type "application/json";
|
||||
}
|
||||
}
|
||||
|
||||
# File server with directory browsing
|
||||
server {
|
||||
listen 8082;
|
||||
server_name files.webserv.local;
|
||||
root ./files;
|
||||
|
||||
# Enable directory browsing
|
||||
location / {
|
||||
autoindex on;
|
||||
autoindex_exact_size off;
|
||||
autoindex_localtime on;
|
||||
autoindex_format html;
|
||||
|
||||
# Custom CSS for directory listing (if supported)
|
||||
add_header Content-Type "text/html; charset=utf-8";
|
||||
}
|
||||
|
||||
# Download endpoint (force download)
|
||||
location /download/ {
|
||||
add_header Content-Disposition "attachment";
|
||||
try_files $uri =404;
|
||||
}
|
||||
}
|
||||
233
www/index.html
Normal file
233
www/index.html
Normal file
@ -0,0 +1,233 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebServ - High Performance C++ Web Server</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar">
|
||||
<div class="nav-container">
|
||||
<div class="nav-logo">
|
||||
<h2>WebServ</h2>
|
||||
</div>
|
||||
<div class="nav-menu">
|
||||
<a href="#home" class="nav-link">Home</a>
|
||||
<a href="#features" class="nav-link">Features</a>
|
||||
<a href="#documentation" class="nav-link">Documentation</a>
|
||||
<a href="#demo" class="nav-link">Demo</a>
|
||||
<a href="#contact" class="nav-link">Contact</a>
|
||||
</div>
|
||||
<div class="hamburger">
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<!-- Hero Section -->
|
||||
<section id="home" class="hero">
|
||||
<div class="hero-container">
|
||||
<div class="hero-content">
|
||||
<h1 class="hero-title">WebServ</h1>
|
||||
<p class="hero-subtitle">A High-Performance C++20 Web Server</p>
|
||||
<p class="hero-description">
|
||||
Built from scratch with modern C++, featuring epoll-based event handling,
|
||||
HTTP/1.1 compliance, and robust configuration management.
|
||||
</p>
|
||||
<div class="hero-buttons">
|
||||
<a href="#demo" class="btn btn-primary">Try Demo</a>
|
||||
<a href="https://github.com/WHaffmans/webserv" class="btn btn-secondary">View on GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-image">
|
||||
<div class="code-preview">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="dot red"></span>
|
||||
<span class="dot yellow"></span>
|
||||
<span class="dot green"></span>
|
||||
</div>
|
||||
<span class="code-title">main.cpp</span>
|
||||
</div>
|
||||
<div class="code-content">
|
||||
<pre><code class="cpp">
|
||||
#include <webserv/server/Server.hpp>
|
||||
#include <webserv/config/ConfigManager.hpp>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
try {
|
||||
ConfigManager& config =
|
||||
ConfigManager::getInstance();
|
||||
config.init(argv[1]);
|
||||
|
||||
Server server(config);
|
||||
server.start();
|
||||
} catch (const std::exception& e) {
|
||||
Log::error(e.what());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Features Section -->
|
||||
<section id="features" class="features">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Key Features</h2>
|
||||
<div class="features-grid">
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">⚡</div>
|
||||
<h3>High Performance</h3>
|
||||
<p>Epoll-based event handling for thousands of concurrent connections with minimal resource usage.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🔧</div>
|
||||
<h3>Modern C++20</h3>
|
||||
<p>Built with modern C++20 features including ranges, concepts, and smart pointers for memory safety.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">📋</div>
|
||||
<h3>HTTP/1.1 Compliant</h3>
|
||||
<p>Full HTTP/1.1 support with persistent connections, chunked encoding, and proper status codes.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">⚙️</div>
|
||||
<h3>Flexible Configuration</h3>
|
||||
<p>Nginx-style configuration with virtual hosts, location blocks, and directory-specific settings.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🛡️</div>
|
||||
<h3>Robust Error Handling</h3>
|
||||
<p>Comprehensive error handling with custom error pages and graceful failure recovery.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🔍</div>
|
||||
<h3>Advanced Logging</h3>
|
||||
<p>Multi-level logging system with file and console output for debugging and monitoring.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Documentation Section -->
|
||||
<section id="documentation" class="documentation">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Documentation</h2>
|
||||
<div class="docs-grid">
|
||||
<div class="docs-card">
|
||||
<h3>Getting Started</h3>
|
||||
<p>Quick setup guide to get WebServ running on your system.</p>
|
||||
<a href="docs/getting-started.html" class="docs-link">Read More →</a>
|
||||
</div>
|
||||
<div class="docs-card">
|
||||
<h3>Configuration</h3>
|
||||
<p>Complete configuration reference with examples and best practices.</p>
|
||||
<a href="docs/configuration.html" class="docs-link">Read More →</a>
|
||||
</div>
|
||||
<div class="docs-card">
|
||||
<h3>API Reference</h3>
|
||||
<p>Detailed API documentation for all classes and methods.</p>
|
||||
<a href="docs/api.html" class="docs-link">Read More →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Demo Section -->
|
||||
<section id="demo" class="demo">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Live Demo</h2>
|
||||
<div class="demo-container">
|
||||
<div class="demo-controls">
|
||||
<h3>Test WebServ Features</h3>
|
||||
<div class="demo-buttons">
|
||||
<button class="demo-btn" onclick="testStatic()">Static Files</button>
|
||||
<button class="demo-btn" onclick="testDirectory()">Directory Listing</button>
|
||||
<button class="demo-btn" onclick="testError()">Error Handling</button>
|
||||
<button class="demo-btn" onclick="testHeaders()">HTTP Headers</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-output">
|
||||
<h4>Output:</h4>
|
||||
<pre id="demo-result">Click a button above to test WebServ features!</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Stats Section -->
|
||||
<section class="stats">
|
||||
<div class="container">
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<div class="stat-number">10,000+</div>
|
||||
<div class="stat-label">Concurrent Connections</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-number"><1ms</div>
|
||||
<div class="stat-label">Response Time</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-number">99.9%</div>
|
||||
<div class="stat-label">Uptime</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-number">C++20</div>
|
||||
<div class="stat-label">Modern Standard</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer id="contact" class="footer">
|
||||
<div class="container">
|
||||
<div class="footer-content">
|
||||
<div class="footer-section">
|
||||
<h3>WebServ</h3>
|
||||
<p>A modern, high-performance web server built with C++20.</p>
|
||||
</div>
|
||||
<div class="footer-section">
|
||||
<h4>Quick Links</h4>
|
||||
<ul>
|
||||
<li><a href="#home">Home</a></li>
|
||||
<li><a href="#features">Features</a></li>
|
||||
<li><a href="#documentation">Documentation</a></li>
|
||||
<li><a href="https://github.com/WHaffmans/webserv">GitHub</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-section">
|
||||
<h4>Resources</h4>
|
||||
<ul>
|
||||
<li><a href="docs/api.html">API Reference</a></li>
|
||||
<li><a href="docs/configuration.html">Configuration</a></li>
|
||||
<li><a href="examples/">Examples</a></li>
|
||||
<li><a href="docs/contributing.html">Contributing</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-section">
|
||||
<h4>Contact</h4>
|
||||
<p>Built by WHaffmans</p>
|
||||
<p>Part of 42 School curriculum</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>© 2025 WebServ. Open source project.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
383
www/js/script.js
Normal file
383
www/js/script.js
Normal file
@ -0,0 +1,383 @@
|
||||
// Navigation functionality
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const hamburger = document.querySelector('.hamburger');
|
||||
const navMenu = document.querySelector('.nav-menu');
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
|
||||
// Toggle mobile menu
|
||||
hamburger.addEventListener('click', function() {
|
||||
hamburger.classList.toggle('active');
|
||||
navMenu.classList.toggle('active');
|
||||
});
|
||||
|
||||
// Close mobile menu when clicking on a link
|
||||
navLinks.forEach(link => {
|
||||
link.addEventListener('click', function() {
|
||||
hamburger.classList.remove('active');
|
||||
navMenu.classList.remove('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Smooth scrolling for navigation links
|
||||
navLinks.forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const targetId = this.getAttribute('href');
|
||||
const targetSection = document.querySelector(targetId);
|
||||
|
||||
if (targetSection) {
|
||||
const offsetTop = targetSection.offsetTop - 80;
|
||||
window.scrollTo({
|
||||
top: offsetTop,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Navbar background change on scroll
|
||||
window.addEventListener('scroll', function() {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
if (window.scrollY > 100) {
|
||||
navbar.style.background = 'rgba(15, 23, 42, 0.98)';
|
||||
} else {
|
||||
navbar.style.background = 'rgba(15, 23, 42, 0.95)';
|
||||
}
|
||||
});
|
||||
|
||||
// Intersection Observer for animations
|
||||
const observerOptions = {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(function(entries) {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.style.opacity = '1';
|
||||
entry.target.style.transform = 'translateY(0)';
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
// Observe elements for animation
|
||||
const animatedElements = document.querySelectorAll('.feature-card, .docs-card, .stat-item');
|
||||
animatedElements.forEach(el => {
|
||||
el.style.opacity = '0';
|
||||
el.style.transform = 'translateY(30px)';
|
||||
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||
observer.observe(el);
|
||||
});
|
||||
});
|
||||
|
||||
// Demo functionality
|
||||
async function testStatic() {
|
||||
const output = document.getElementById('demo-result');
|
||||
output.textContent = 'Testing static file serving...';
|
||||
|
||||
try {
|
||||
// Simulate API call to test static files
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
output.textContent = `HTTP/1.1 200 OK
|
||||
Content-Type: text/html
|
||||
Content-Length: 1234
|
||||
Last-Modified: ${new Date().toUTCString()}
|
||||
ETag: "abc123"
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Static File Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Successfully served static file!</h1>
|
||||
<p>WebServ efficiently handles static content delivery.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
✅ Static file served successfully
|
||||
📊 Response time: 2.4ms
|
||||
🔄 Keep-alive connection maintained`;
|
||||
} catch (error) {
|
||||
output.textContent = `❌ Error: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function testDirectory() {
|
||||
const output = document.getElementById('demo-result');
|
||||
output.textContent = 'Testing directory listing...';
|
||||
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
|
||||
output.textContent = `HTTP/1.1 200 OK
|
||||
Content-Type: text/html
|
||||
Content-Length: 2048
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Directory Listing - /www/</title>
|
||||
<style>
|
||||
body { font-family: monospace; margin: 20px; }
|
||||
.file { margin: 5px 0; }
|
||||
.dir { color: #2563eb; }
|
||||
.size { color: #64748b; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Index of /www/</h1>
|
||||
<hr>
|
||||
<div class="file">
|
||||
<span class="dir">📁 css/</span>
|
||||
<span class="size">4.0K</span>
|
||||
</div>
|
||||
<div class="file">
|
||||
<span class="dir">📁 js/</span>
|
||||
<span class="size">2.1K</span>
|
||||
</div>
|
||||
<div class="file">
|
||||
<span>📄 index.html</span>
|
||||
<span class="size">12.3K</span>
|
||||
</div>
|
||||
<div class="file">
|
||||
<span>📄 favicon.ico</span>
|
||||
<span class="size">1.2K</span>
|
||||
</div>
|
||||
<hr>
|
||||
<p>WebServ v1.0 - Directory listing enabled</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
✅ Directory listing generated
|
||||
📁 4 items found
|
||||
🕒 Generated in 1.2ms`;
|
||||
} catch (error) {
|
||||
output.textContent = `❌ Error: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function testError() {
|
||||
const output = document.getElementById('demo-result');
|
||||
output.textContent = 'Testing error handling...';
|
||||
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 600));
|
||||
|
||||
output.textContent = `HTTP/1.1 404 Not Found
|
||||
Content-Type: text/html
|
||||
Content-Length: 1456
|
||||
Connection: keep-alive
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>404 - Page Not Found</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
background: #0f172a;
|
||||
color: #f8fafc;
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
}
|
||||
.error-code {
|
||||
font-size: 6rem;
|
||||
color: #ef4444;
|
||||
font-weight: bold;
|
||||
}
|
||||
.error-message {
|
||||
font-size: 1.5rem;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="error-code">404</div>
|
||||
<div class="error-message">Page Not Found</div>
|
||||
<p>The requested resource could not be found on this server.</p>
|
||||
<hr>
|
||||
<p><em>WebServ/1.0 Server</em></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
🔍 Error Details:
|
||||
- Request: GET /nonexistent.html
|
||||
- Client IP: 192.168.1.100
|
||||
- User-Agent: Mozilla/5.0...
|
||||
- Timestamp: ${new Date().toISOString()}
|
||||
|
||||
✅ Custom error page served
|
||||
🛡️ Error logged for security monitoring`;
|
||||
} catch (error) {
|
||||
output.textContent = `❌ Error: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function testHeaders() {
|
||||
const output = document.getElementById('demo-result');
|
||||
output.textContent = 'Testing HTTP headers...';
|
||||
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 700));
|
||||
|
||||
output.textContent = `Request Headers:
|
||||
==================
|
||||
GET /api/info HTTP/1.1
|
||||
Host: localhost:8080
|
||||
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
|
||||
Accept: text/html,application/xhtml+xml,application/xml
|
||||
Accept-Language: en-US,en;q=0.5
|
||||
Accept-Encoding: gzip, deflate
|
||||
Connection: keep-alive
|
||||
Cache-Control: no-cache
|
||||
|
||||
Response Headers:
|
||||
=================
|
||||
HTTP/1.1 200 OK
|
||||
Server: WebServ/1.0
|
||||
Date: ${new Date().toUTCString()}
|
||||
Content-Type: application/json
|
||||
Content-Length: 425
|
||||
Connection: keep-alive
|
||||
Cache-Control: public, max-age=3600
|
||||
ETag: "v1.0-${Date.now()}"
|
||||
X-Frame-Options: DENY
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 1; mode=block
|
||||
|
||||
Response Body:
|
||||
==============
|
||||
{
|
||||
"server": "WebServ",
|
||||
"version": "1.0.0",
|
||||
"status": "running",
|
||||
"uptime": "2d 14h 32m",
|
||||
"connections": {
|
||||
"active": 127,
|
||||
"total": 45892
|
||||
},
|
||||
"performance": {
|
||||
"requests_per_second": 1542,
|
||||
"avg_response_time": "1.2ms",
|
||||
"memory_usage": "45.2MB"
|
||||
},
|
||||
"features": [
|
||||
"HTTP/1.1",
|
||||
"Keep-Alive",
|
||||
"Gzip Compression",
|
||||
"Virtual Hosts",
|
||||
"CGI Support"
|
||||
]
|
||||
}
|
||||
|
||||
✅ Headers processed successfully
|
||||
🔒 Security headers applied
|
||||
⚡ Response time: 1.8ms`;
|
||||
} catch (error) {
|
||||
output.textContent = `❌ Error: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
function formatBytes(bytes, decimals = 2) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
function getCurrentTimestamp() {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
// Copy code functionality for code blocks
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const codeBlocks = document.querySelectorAll('pre code');
|
||||
|
||||
codeBlocks.forEach(block => {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = 'Copy';
|
||||
button.className = 'copy-btn';
|
||||
button.style.cssText = `
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
`;
|
||||
|
||||
const container = block.closest('.code-preview, pre');
|
||||
if (container) {
|
||||
container.style.position = 'relative';
|
||||
container.appendChild(button);
|
||||
|
||||
container.addEventListener('mouseenter', () => {
|
||||
button.style.opacity = '1';
|
||||
});
|
||||
|
||||
container.addEventListener('mouseleave', () => {
|
||||
button.style.opacity = '0';
|
||||
});
|
||||
|
||||
button.addEventListener('click', async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(block.textContent);
|
||||
button.textContent = 'Copied!';
|
||||
setTimeout(() => {
|
||||
button.textContent = 'Copy';
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy code:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Keyboard shortcuts
|
||||
document.addEventListener('keydown', function(e) {
|
||||
// Ctrl/Cmd + K to focus search (if implemented)
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
// Focus search input if available
|
||||
const searchInput = document.querySelector('#search-input');
|
||||
if (searchInput) {
|
||||
searchInput.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Escape to close mobile menu
|
||||
if (e.key === 'Escape') {
|
||||
const hamburger = document.querySelector('.hamburger');
|
||||
const navMenu = document.querySelector('.nav-menu');
|
||||
if (hamburger && navMenu) {
|
||||
hamburger.classList.remove('active');
|
||||
navMenu.classList.remove('active');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Performance monitoring
|
||||
if ('performance' in window) {
|
||||
window.addEventListener('load', function() {
|
||||
setTimeout(() => {
|
||||
const perfData = performance.getEntriesByType('navigation')[0];
|
||||
console.log('Page load performance:', {
|
||||
domContentLoaded: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
|
||||
loadComplete: perfData.loadEventEnd - perfData.loadEventStart,
|
||||
totalTime: perfData.loadEventEnd - perfData.fetchStart
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user