mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 06:14:59 +00:00
code: request,nextjs,hpp (4 files)
This commit is contained in:
63
dbal/cpp/src/daemon/http/request_handler.hpp
Normal file
63
dbal/cpp/src/daemon/http/request_handler.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @file request_handler.hpp
|
||||
* @brief HTTP request routing and handling
|
||||
*
|
||||
* Routes incoming requests to appropriate handlers.
|
||||
*/
|
||||
#ifndef DBAL_REQUEST_HANDLER_HPP
|
||||
#define DBAL_REQUEST_HANDLER_HPP
|
||||
|
||||
#include "http_types.hpp"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace dbal {
|
||||
namespace daemon {
|
||||
namespace http {
|
||||
|
||||
/**
|
||||
* Process HTTP request and generate response
|
||||
*
|
||||
* @param request Parsed HTTP request
|
||||
* @param server_address Server address for status endpoint
|
||||
* @return HTTP response
|
||||
*/
|
||||
inline HttpResponse processRequest(const HttpRequest& request, const std::string& server_address) {
|
||||
HttpResponse response;
|
||||
|
||||
// Health check endpoint (for nginx health checks)
|
||||
if (request.path == "/health" || request.path == "/healthz") {
|
||||
response.status_code = 200;
|
||||
response.status_text = "OK";
|
||||
response.body = R"({"status":"healthy","service":"dbal"})";
|
||||
return response;
|
||||
}
|
||||
|
||||
// API endpoints
|
||||
if (request.path == "/api/version" || request.path == "/version") {
|
||||
response.body = R"({"version":"1.0.0","service":"DBAL Daemon"})";
|
||||
return response;
|
||||
}
|
||||
|
||||
if (request.path == "/api/status" || request.path == "/status") {
|
||||
std::ostringstream body;
|
||||
body << R"({"status":"running","address":")" << server_address << R"(")"
|
||||
<< R"(,"real_ip":")" << request.realIP() << R"(")"
|
||||
<< R"(,"forwarded_proto":")" << request.forwardedProto() << R"(")"
|
||||
<< "}";
|
||||
response.body = body.str();
|
||||
return response;
|
||||
}
|
||||
|
||||
// Default 404
|
||||
response.status_code = 404;
|
||||
response.status_text = "Not Found";
|
||||
response.body = R"({"error":"Not Found","path":")" + request.path + "\"}";
|
||||
return response;
|
||||
}
|
||||
|
||||
} // namespace http
|
||||
} // namespace daemon
|
||||
} // namespace dbal
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* @file request_parser.hpp
|
||||
* @brief HTTP request parser with security validations
|
||||
*
|
||||
* Parses raw HTTP requests with protection against CVE-style attacks.
|
||||
*/
|
||||
#ifndef DBAL_REQUEST_PARSER_HPP
|
||||
#define DBAL_REQUEST_PARSER_HPP
|
||||
|
||||
#include "http_types.hpp"
|
||||
#include "security_limits.hpp"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <limits>
|
||||
|
||||
// Cross-platform socket headers
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
namespace dbal {
|
||||
namespace daemon {
|
||||
namespace http {
|
||||
|
||||
/**
|
||||
* Parse HTTP request from socket with security validations
|
||||
*
|
||||
* @param client_fd Socket file descriptor
|
||||
* @param request Output request structure
|
||||
* @param error_response Output error response if parsing fails
|
||||
* @return true if parsing succeeded, false otherwise
|
||||
*/
|
||||
inline bool parseRequest(socket_t client_fd, HttpRequest& request, HttpResponse& error_response) {
|
||||
// Use larger buffer but still enforce limits
|
||||
std::string request_data;
|
||||
request_data.reserve(8192);
|
||||
|
||||
char buffer[8192];
|
||||
size_t total_read = 0;
|
||||
bool headers_complete = false;
|
||||
|
||||
// Read request with size limit
|
||||
while (total_read < MAX_REQUEST_SIZE && !headers_complete) {
|
||||
#ifdef _WIN32
|
||||
int bytes_read = recv(client_fd, buffer, sizeof(buffer), 0);
|
||||
#else
|
||||
ssize_t bytes_read = recv(client_fd, buffer, sizeof(buffer), 0);
|
||||
#endif
|
||||
|
||||
if (bytes_read <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
request_data.append(buffer, bytes_read);
|
||||
total_read += bytes_read;
|
||||
|
||||
// Check if headers are complete
|
||||
if (request_data.find("\r\n\r\n") != std::string::npos) {
|
||||
headers_complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if request is too large
|
||||
if (total_read >= MAX_REQUEST_SIZE && !headers_complete) {
|
||||
error_response = HttpResponse::error(413, "Request Entity Too Large", "Request too large");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse request line
|
||||
size_t line_end = request_data.find("\r\n");
|
||||
if (line_end == std::string::npos) {
|
||||
error_response = HttpResponse::error(400, "Bad Request", "Invalid request format");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string request_line = request_data.substr(0, line_end);
|
||||
std::istringstream line_stream(request_line);
|
||||
line_stream >> request.method >> request.path >> request.version;
|
||||
|
||||
// Validate method, path, and version
|
||||
if (request.method.empty() || request.path.empty() || request.version.empty()) {
|
||||
error_response = HttpResponse::error(400, "Bad Request", "Invalid request line");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for null bytes in path (CVE pattern)
|
||||
if (request.path.find('\0') != std::string::npos) {
|
||||
error_response = HttpResponse::error(400, "Bad Request", "Null byte in path");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate path length
|
||||
if (request.path.length() > MAX_PATH_LENGTH) {
|
||||
error_response = HttpResponse::error(414, "URI Too Long", "Path too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse headers
|
||||
size_t pos = line_end + 2;
|
||||
size_t header_count = 0;
|
||||
bool has_content_length = false;
|
||||
bool has_transfer_encoding = false;
|
||||
size_t content_length = 0;
|
||||
|
||||
while (pos < request_data.length()) {
|
||||
line_end = request_data.find("\r\n", pos);
|
||||
if (line_end == std::string::npos) break;
|
||||
|
||||
std::string header_line = request_data.substr(pos, line_end - pos);
|
||||
if (header_line.empty()) {
|
||||
// End of headers
|
||||
pos = line_end + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check header bomb protection
|
||||
if (++header_count > MAX_HEADERS) {
|
||||
error_response = HttpResponse::error(431, "Request Header Fields Too Large", "Too many headers");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check header size
|
||||
if (header_line.length() > MAX_HEADER_SIZE) {
|
||||
error_response = HttpResponse::error(431, "Request Header Fields Too Large", "Header too large");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t colon = header_line.find(':');
|
||||
if (colon != std::string::npos) {
|
||||
std::string key = header_line.substr(0, colon);
|
||||
std::string value = header_line.substr(colon + 1);
|
||||
|
||||
// Trim whitespace
|
||||
while (!value.empty() && value[0] == ' ') value = value.substr(1);
|
||||
while (!value.empty() && value[value.length()-1] == ' ') value.pop_back();
|
||||
|
||||
// Check for CRLF injection in header values
|
||||
if (value.find("\r\n") != std::string::npos) {
|
||||
error_response = HttpResponse::error(400, "Bad Request", "CRLF in header value");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for null bytes in headers
|
||||
if (value.find('\0') != std::string::npos) {
|
||||
error_response = HttpResponse::error(400, "Bad Request", "Null byte in header");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detect duplicate Content-Length headers (CVE-2024-1135 pattern)
|
||||
std::string key_lower = key;
|
||||
std::transform(key_lower.begin(), key_lower.end(), key_lower.begin(), ::tolower);
|
||||
|
||||
if (key_lower == "content-length") {
|
||||
if (has_content_length) {
|
||||
// Multiple Content-Length headers - request smuggling attempt
|
||||
error_response = HttpResponse::error(400, "Bad Request", "Multiple Content-Length headers");
|
||||
return false;
|
||||
}
|
||||
has_content_length = true;
|
||||
|
||||
// Validate Content-Length is a valid number
|
||||
try {
|
||||
// Check for integer overflow
|
||||
unsigned long long cl = std::stoull(value);
|
||||
if (cl > MAX_BODY_SIZE) {
|
||||
error_response = HttpResponse::error(413, "Request Entity Too Large", "Content-Length too large");
|
||||
return false;
|
||||
}
|
||||
// Validate fits in size_t (platform dependent)
|
||||
if (cl > std::numeric_limits<size_t>::max()) {
|
||||
error_response = HttpResponse::error(413, "Request Entity Too Large", "Content-Length exceeds platform limit");
|
||||
return false;
|
||||
}
|
||||
content_length = static_cast<size_t>(cl);
|
||||
} catch (...) {
|
||||
error_response = HttpResponse::error(400, "Bad Request", "Invalid Content-Length");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect Transfer-Encoding header (CVE-2024-23452 pattern)
|
||||
if (key_lower == "transfer-encoding") {
|
||||
has_transfer_encoding = true;
|
||||
}
|
||||
|
||||
request.headers[key] = value;
|
||||
}
|
||||
|
||||
pos = line_end + 2;
|
||||
}
|
||||
|
||||
// Check for request smuggling: Transfer-Encoding + Content-Length
|
||||
if (has_transfer_encoding && has_content_length) {
|
||||
error_response = HttpResponse::error(400, "Bad Request", "Both Transfer-Encoding and Content-Length present");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't support Transfer-Encoding (chunked), return 501 Not Implemented
|
||||
if (has_transfer_encoding) {
|
||||
error_response = HttpResponse::error(501, "Not Implemented", "Transfer-Encoding not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse body if present
|
||||
if (pos < request_data.length()) {
|
||||
request.body = request_data.substr(pos);
|
||||
}
|
||||
|
||||
// Suppress unused variable warning
|
||||
(void)content_length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace http
|
||||
} // namespace daemon
|
||||
} // namespace dbal
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@ export { useGitHubFetcher } from './useGitHubFetcher'
|
||||
export { useKV } from './useKV'
|
||||
export { useIsMobile } from './use-mobile'
|
||||
export { useResolvedUser } from './useResolvedUser'
|
||||
export { useLevelRouting } from './useLevelRouting'
|
||||
|
||||
export type { AuthUser, AuthState, UseAuthReturn } from './auth/auth-types'
|
||||
export type { EditorFile } from './useCodeEditor'
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
export async function loadPackageSeedJson<T>(
|
||||
packageId: string,
|
||||
relativePath: string,
|
||||
fallback: T
|
||||
): Promise<T> {
|
||||
try {
|
||||
const response = await fetch(`/packages/${packageId}/${relativePath}`)
|
||||
if (!response.ok) return fallback
|
||||
return (await response.json()) as T
|
||||
} catch (error) {
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user