reactie van server
This commit is contained in:
@@ -56,7 +56,7 @@ SRCS := src/Log.cpp src/main.cpp src/Server.cpp \
|
||||
src/config/Config.cpp src/config/ConfigurationParser.cpp src/config/LocationConfig.cpp src/config/ServerConfig.cpp \
|
||||
src/event/Epoll.cpp src/event/EventToken.cpp \
|
||||
src/net/ByteBuffer.cpp src/net/Connection.cpp src/net/FileDescriptor.cpp src/net/Listener.cpp src/net/ListenerPlan.cpp src/net/PauseMask.cpp src/net/SlotPool.cpp \
|
||||
src/http/Request.cpp src/http/RequestParser.cpp
|
||||
src/http/Request.cpp src/http/RequestParser.cpp src/http/Response.cpp
|
||||
|
||||
|
||||
OBJS := $(SRCS:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
|
||||
@@ -66,7 +66,7 @@ SRCS := src/Log.cpp src/main.cpp src/Server.cpp \
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
HDRS := include/config/Config.hpp include/config/ConfigurationParser.hpp include/config/LocationConfig.hpp include/config/ServerConfig.hpp \
|
||||
include/event/Epoll.hpp include/event/EventToken.hpp \
|
||||
include/http/HttpStatus.hpp include/http/Request.hpp include/http/RequestParser.hpp \
|
||||
include/http/HttpStatus.hpp include/http/Request.hpp include/http/RequestParser.hpp include/http/Response.hpp \
|
||||
include/net/ByteBuffer.hpp include/net/Connection.hpp include/net/FileDescriptor.hpp include/net/Listener.hpp include/net/ListenerPlan.hpp include/net/PauseMask.hpp include/net/SlotPool.hpp \
|
||||
include/Log.hpp include/Result.hpp include/Server.hpp \
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*********************************/
|
||||
/* */
|
||||
/* o.riabenkyi@gmail.com */
|
||||
/* */
|
||||
/*********************************/
|
||||
|
||||
#ifndef RESPONSE_HPP
|
||||
#define RESPONSE_HPP
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "http/HttpStatus.hpp"
|
||||
|
||||
namespace webserv {
|
||||
|
||||
const char* reasonPhrase(HttpStatus status) noexcept;
|
||||
|
||||
struct Response {
|
||||
HttpStatus status;
|
||||
std::vector<std::pair<std::string, std::string>> headers;
|
||||
std::vector<char> body;
|
||||
};
|
||||
|
||||
std::vector<char> serialize(const Response& response);
|
||||
|
||||
} // namespace webserv
|
||||
|
||||
#endif
|
||||
@@ -29,15 +29,9 @@ class Connection final {
|
||||
std::uint32_t desiredEvents;
|
||||
};
|
||||
|
||||
// ByteBuffer::CAPACITY is 64 KiB.
|
||||
// At most 16 KiB are copied per 48 KiB appended: 16 / 48 = 1 / 3.
|
||||
// A lower threshold reduces copying but leaves less unread work available.
|
||||
// The 16 KiB value is a fixed compromise, not a measured optimum.
|
||||
static constexpr std::size_t LOW_WATERMARK = 16uz * 1024;
|
||||
|
||||
explicit Connection(FileDescriptor socket);
|
||||
|
||||
// Each Connection has a unique identity and remains in its original slot.
|
||||
Connection(const Connection&) = delete;
|
||||
Connection& operator=(const Connection&) = delete;
|
||||
Connection(Connection&&) = delete;
|
||||
@@ -52,14 +46,8 @@ class Connection final {
|
||||
void close() noexcept { socket_.reset(); }
|
||||
|
||||
private:
|
||||
// recv() returning zero means the client has finished sending data.
|
||||
// readClosed_ records this. receive() still returns true because this
|
||||
// is not an error and the socket may still send its buffered response.
|
||||
// Only a recv() error returns false.
|
||||
bool receive();
|
||||
bool transmit();
|
||||
// TEMP echo path: queues received bytes unchanged for sending back to
|
||||
// the client.
|
||||
void forwardReceivedBytes();
|
||||
|
||||
FileDescriptor socket_;
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*********************************/
|
||||
/* */
|
||||
/* o.riabenkyi@gmail.com */
|
||||
/* */
|
||||
/*********************************/
|
||||
|
||||
#include "http/Response.hpp"
|
||||
|
||||
#include <format>
|
||||
|
||||
namespace webserv {
|
||||
|
||||
const char* reasonPhrase(HttpStatus status) noexcept {
|
||||
switch (status) {
|
||||
case HttpStatus::Ok:
|
||||
return "OK";
|
||||
case HttpStatus::Created:
|
||||
return "Created";
|
||||
case HttpStatus::NoContent:
|
||||
return "No Content";
|
||||
case HttpStatus::MovedPermanently:
|
||||
return "Moved Permanently";
|
||||
case HttpStatus::Found:
|
||||
return "Found";
|
||||
case HttpStatus::SeeOther:
|
||||
return "See Other";
|
||||
case HttpStatus::TemporaryRedirect:
|
||||
return "Temporary Redirect";
|
||||
case HttpStatus::PermanentRedirect:
|
||||
return "Permanent Redirect";
|
||||
case HttpStatus::BadRequest:
|
||||
return "Bad Request";
|
||||
case HttpStatus::Forbidden:
|
||||
return "Forbidden";
|
||||
case HttpStatus::NotFound:
|
||||
return "Not Found";
|
||||
case HttpStatus::MethodNotAllowed:
|
||||
return "Method Not Allowed";
|
||||
case HttpStatus::RequestTimeout:
|
||||
return "Request Timeout";
|
||||
case HttpStatus::LengthRequired:
|
||||
return "Length Required";
|
||||
case HttpStatus::ContentTooLarge:
|
||||
return "Content Too Large";
|
||||
case HttpStatus::UriTooLong:
|
||||
return "URI Too Long";
|
||||
case HttpStatus::RequestHeaderFieldsTooLarge:
|
||||
return "Request Header Fields Too Large";
|
||||
case HttpStatus::InternalServerError:
|
||||
return "Internal Server Error";
|
||||
case HttpStatus::NotImplemented:
|
||||
return "Not Implemented";
|
||||
case HttpStatus::BadGateway:
|
||||
return "Bad Gateway";
|
||||
case HttpStatus::ServiceUnavailable:
|
||||
return "Service Unavailable";
|
||||
case HttpStatus::GatewayTimeout:
|
||||
return "Gateway Timeout";
|
||||
case HttpStatus::HttpVersionNotSupported:
|
||||
return "HTTP Version Not Supported";
|
||||
}
|
||||
return "Unknown Status";
|
||||
}
|
||||
|
||||
std::vector<char> serialize(const Response& response) {
|
||||
std::string head = std::format("HTTP/1.1 {} {}\r\n", static_cast<int>(response.status),
|
||||
reasonPhrase(response.status));
|
||||
for (const auto& [name, value] : response.headers) {
|
||||
head += std::format("{}: {}\r\n", name, value);
|
||||
}
|
||||
head += std::format("Content-Length: {}\r\n\r\n", response.body.size());
|
||||
|
||||
std::vector<char> bytes(head.begin(), head.end());
|
||||
bytes.insert(bytes.end(), response.body.begin(), response.body.end());
|
||||
return bytes;
|
||||
}
|
||||
|
||||
} // namespace webserv
|
||||
@@ -24,16 +24,6 @@ namespace webserv {
|
||||
|
||||
namespace {
|
||||
|
||||
// Writable tail still has space -> keep using it
|
||||
//
|
||||
// Writable tail is exhausted, but more than 16 KiB are still live
|
||||
// -> wait for more bytes to be consumed because moving them is not worth it
|
||||
//
|
||||
// Writable tail is exhausted and at most 16 KiB are still live
|
||||
// -> move the live bytes to the start and recover the writable tail
|
||||
//
|
||||
// Before: [ 48 KiB consumed ][ 16 KiB live ]
|
||||
// After: [ 16 KiB live ][ 48 KiB writable tail ]
|
||||
void compactIfDrained(ByteBuffer& buffer) {
|
||||
if (buffer.writableTail().empty() &&
|
||||
buffer.readable().size() <= Connection::LOW_WATERMARK) {
|
||||
@@ -45,10 +35,6 @@ void compactIfDrained(ByteBuffer& buffer) {
|
||||
|
||||
Connection::Connection(FileDescriptor socket) : socket_(std::move(socket)) {}
|
||||
|
||||
// Client can still send data -> Alive
|
||||
// Read side closed, buffered data remains -> Alive
|
||||
// Read side closed, both buffers empty -> Done
|
||||
// recv() or send() failed -> Fatal
|
||||
Connection::Outcome Connection::onClientEvent(std::uint32_t events) {
|
||||
// 1) Interpret the readiness reported by epoll.
|
||||
// EPOLLIN says recv() may progress.
|
||||
|
||||
Reference in New Issue
Block a user