Skip to content

Commit 1a1cfe5

Browse files
committed
wip: refactor event loop and add cgi to epoll
1 parent eecc781 commit 1a1cfe5

File tree

11 files changed

+385
-230
lines changed

11 files changed

+385
-230
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ srcs = \
3737
src/core/server_defaults.hpp \
3838
src/core/signals.cpp \
3939
src/core/signals.hpp \
40+
src/core/virtual_server.cpp \
41+
src/core/virtual_server.hpp \
4042
src/handler/delete_handler.cpp \
4143
src/handler/delete_handler.hpp \
4244
src/handler/error_handler.cpp \

src/core/client.cpp

Lines changed: 238 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,254 @@
11
#include "core/client.hpp"
22

3+
#include "core/virtual_server.hpp"
4+
#include "util/log_message.hpp"
5+
36
#include <fcntl.h>
7+
#include <sys/epoll.h>
48
#include <unistd.h>
59

6-
Client::Client(int fd)
7-
: state_(kReceivingHeaders),
8-
fd_(fd),
10+
#include <cstring>
11+
#include <iostream>
12+
#include <stdexcept>
13+
14+
Client::Client(int fd, const VirtualServer& vs)
15+
: socket_fd_(fd),
16+
vserv_(vs),
17+
state_(kReceivingHeaders),
918
handler_(NULL)
1019
{
1120
}
1221

1322
Client::~Client()
1423
{
15-
if (fd_ != -1) {
16-
close(fd_);
24+
if (socket_fd_ != -1) {
25+
close(socket_fd_);
1726
}
1827
if (handler_) {
1928
delete handler_;
2029
}
2130
}
31+
32+
void Client::handle_read(int fd)
33+
{
34+
if (fd == socket_fd_) {
35+
read_from_socket();
36+
}
37+
else {
38+
LOG(ERROR) << "Client::handle_read: Unknown file descriptor";
39+
}
40+
}
41+
42+
void Client::read_from_socket()
43+
{
44+
receive_bytes_from_socket();
45+
process_bytes_received();
46+
}
47+
48+
// TODO: get rid of this
49+
static void print_raw_data(const char* s, size_t n)
50+
{
51+
std::cout << "< ";
52+
53+
for (size_t i = 0; i < n; ++i) {
54+
char c = s[i];
55+
if (c == '\r') {
56+
std::cout << "\\r";
57+
}
58+
else if (c == '\n') {
59+
std::cout << "\\n\n";
60+
if (i < n - 1) {
61+
std::cout << "< ";
62+
}
63+
}
64+
else {
65+
std::cout.put(c);
66+
}
67+
}
68+
std::cout.flush();
69+
}
70+
71+
void Client::receive_bytes_from_socket()
72+
{
73+
if (state_ != Client::kReceivingHeaders && state_ != Client::kReceivingBody)
74+
return;
75+
76+
char tmp[4096];
77+
78+
ssize_t bytes_received = recv(socket_fd_, tmp, sizeof(tmp), 0);
79+
if (bytes_received == -1) {
80+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
81+
LOG(WARN) << "Client #" << socket_fd_ << ": recv blocked";
82+
return;
83+
}
84+
throw std::runtime_error("recv failed");
85+
}
86+
if (bytes_received == 0) {
87+
LOG(INFO) << "Client #" << socket_fd_ << ": Connection closed by remote client";
88+
set_state(Client::kClosingConnection);
89+
return;
90+
}
91+
92+
parser_.append_data(tmp, bytes_received);
93+
print_raw_data(tmp, bytes_received);
94+
}
95+
96+
void Client::process_bytes_received()
97+
{
98+
process_header_bytes();
99+
process_body_bytes();
100+
}
101+
102+
static void log_request_info(int fd, const HttpRequest& request)
103+
{
104+
LOG(INFO) << "Client #" << fd << ": " << request.method << " " << request.path << " "
105+
<< http_version_to_string(request.http_version);
106+
}
107+
108+
void Client::process_header_bytes()
109+
{
110+
if (state_ != kReceivingHeaders)
111+
return;
112+
113+
if (parser_.state() == HttpParser::kParsingError) {
114+
LOG(ERROR) << "Client #" << socket_fd_ << ": Invalid HTTP request";
115+
set_state(Client::kClosingConnection);
116+
return;
117+
}
118+
if (parser_.state() < HttpParser::kParsingBody) {
119+
return;
120+
}
121+
122+
// We parsed headers successfully and might have some or all body bytes?
123+
log_request_info(socket_fd_, parser_.request());
124+
125+
Handler* h = vserv_.create_handler(parser_.request());
126+
set_handler(h);
127+
128+
if (handler_->needs_input()) {
129+
set_state(Client::kReceivingBody);
130+
}
131+
else if (handler_->has_output()) {
132+
set_state(Client::kSendingResponse);
133+
}
134+
else if (handler_->is_done()) {
135+
LOG(ERROR) << "Client::parse_header_bytes: Unexpected state: 'handler.is_done";
136+
}
137+
else {
138+
LOG(ERROR) << "Client::parse_header_bytes: Unexpected state";
139+
}
140+
}
141+
142+
void Client::process_body_bytes()
143+
{
144+
if (state_ != kReceivingBody)
145+
return;
146+
147+
char tmp[4096];
148+
149+
while (true) {
150+
size_t n = parser_.read_body_chunk(tmp, sizeof(tmp));
151+
if (n == 0)
152+
break;
153+
154+
handler_->write_data(tmp, n);
155+
}
156+
157+
if (handler_->has_output()) {
158+
set_state(Client::kSendingResponse);
159+
}
160+
}
161+
162+
void Client::handle_write(int fd)
163+
{
164+
if (fd == socket_fd_) {
165+
write_to_socket();
166+
}
167+
else {
168+
LOG(ERROR) << "Client::handle_write Unknown file descriptor";
169+
}
170+
}
171+
172+
void Client::write_to_socket()
173+
{
174+
assert(handler_ && "Handler must exist when writing to socket");
175+
176+
send_bytes_to_socket();
177+
finalize_response();
178+
}
179+
180+
void Client::send_bytes_to_socket()
181+
{
182+
if (state_ != Client::kSendingResponse)
183+
return;
184+
185+
char tmp[4096];
186+
187+
// We only read one chunk here
188+
if (handler_->has_output()) {
189+
size_t n = handler_->read_data(tmp, sizeof(tmp));
190+
send_buffer_.append(tmp, n);
191+
}
192+
if (!send_buffer_.empty()) {
193+
ssize_t bytes_sent = send(socket_fd_, send_buffer_.data(), send_buffer_.size(), 0);
194+
if (bytes_sent == -1) {
195+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
196+
LOG(WARN) << "Client #" << socket_fd_ << ": send blocked";
197+
return;
198+
}
199+
LOG(ERROR) << "Client #" << socket_fd_ << ": send failed" << strerror(errno);
200+
set_state(Client::kClosingConnection);
201+
return;
202+
}
203+
if (bytes_sent == 0) {
204+
LOG(WARN) << "Client #" << socket_fd_ << ": Failed to send any bytes!";
205+
return;
206+
}
207+
208+
send_buffer_.erase(0, bytes_sent);
209+
}
210+
}
211+
212+
void Client::finalize_response()
213+
{
214+
if (state_ != kSendingResponse)
215+
return;
216+
217+
// All data has been written to socket - either close or keep going
218+
if (handler_->is_done() && send_buffer_.empty()) {
219+
LOG(DEBUG) << "Client #" << socket_fd_ << ": Response sent";
220+
221+
if (keep_alive()) {
222+
parser_.reset_for_next_request();
223+
delete handler_;
224+
set_handler(NULL);
225+
set_state(Client::kReceivingHeaders);
226+
}
227+
else {
228+
set_state(Client::kClosingConnection);
229+
}
230+
}
231+
}
232+
233+
std::map<int, uint32_t> Client::interest_list()
234+
{
235+
int sock_fd = socket_fd_;
236+
int pipe_stdin = handler_ ? handler_->cgi_read_fd() : -1;
237+
int pipe_stdout = handler_ ? handler_->cgi_write_fd() : -1;
238+
239+
uint32_t mask = EPOLLRDHUP | EPOLLIN;
240+
241+
if (state_ == kSendingResponse) {
242+
if (!send_buffer_.empty() || handler_->has_output())
243+
mask |= EPOLLOUT;
244+
}
245+
fd_map_[sock_fd] = mask;
246+
247+
if (pipe_stdin != -1) {
248+
fd_map_[pipe_stdin] = EPOLLIN;
249+
}
250+
if (pipe_stdout != -1) {
251+
fd_map_[pipe_stdout] = EPOLLOUT;
252+
}
253+
return fd_map_;
254+
}

src/core/client.hpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef CORE_CLIENT_HPP_
22
#define CORE_CLIENT_HPP_
33

4+
#include "core/virtual_server.hpp"
45
#include "handler/handler.hpp"
56
#include "http/http_parser.hpp"
67
#include "http/http_request.hpp"
@@ -13,33 +14,42 @@ class Client {
1314
public:
1415
enum State { kClosingConnection = 0, kReceivingHeaders, kReceivingBody, kSendingResponse };
1516

16-
explicit Client(int fd);
17+
Client(int fd, const VirtualServer& vs);
1718
~Client();
1819

19-
// setters
20-
void set_handler(Handler* handler) { handler_ = handler; }
21-
void set_nonblocking();
22-
void set_state(Client::State state) { state_ = state; }
20+
void handle_read(int fd);
21+
void handle_write(int fd);
22+
std::map<int, uint32_t> interest_list();
2323

24-
// getters
25-
Client::State state() { return state_; }
26-
int fd() const { return fd_; }
27-
bool keep_alive() { return parser_.request().keep_alive; }
28-
std::string& send_buffer() { return send_buffer_; }
29-
HttpParser& parser() { return parser_; }
30-
Handler* handler() const { return handler_; }
24+
int fd() const { return socket_fd_; }
25+
Client::State state() const { return state_; }
3126

3227
private:
33-
Client();
3428
Client(const Client& other);
3529
Client& operator=(const Client& other);
3630

37-
private:
31+
void read_from_socket();
32+
void receive_bytes_from_socket();
33+
void process_bytes_received();
34+
void process_header_bytes();
35+
void process_body_bytes();
36+
37+
void write_to_socket();
38+
void send_bytes_to_socket();
39+
void finalize_response();
40+
41+
void set_state(Client::State state) { state_ = state; }
42+
void set_handler(Handler* handler) { handler_ = handler; }
43+
44+
bool keep_alive() { return parser_.request().keep_alive; }
45+
46+
int socket_fd_;
47+
const VirtualServer& vserv_;
3848
Client::State state_;
39-
int fd_;
4049
std::string send_buffer_;
4150
HttpParser parser_;
4251
Handler* handler_;
52+
std::map<int, uint32_t> fd_map_;
4353
};
4454

4555
#endif // CORE_CLIENT_HPP_

0 commit comments

Comments
 (0)