|
1 | 1 | #include "core/server.hpp" |
2 | 2 |
|
3 | 3 | #include "core/signals.hpp" |
4 | | -#include "handler/get_handler.hpp" |
5 | 4 | #include "http/http_request.hpp" |
6 | | -#include "http/http_response.hpp" |
7 | 5 | #include "router/router.hpp" |
8 | 6 | #include "util/syscall_error.hpp" |
9 | 7 |
|
|
12 | 10 | #include <netinet/in.h> |
13 | 11 | #include <stdlib.h> |
14 | 12 | #include <string.h> |
| 13 | +#include <sys/epoll.h> |
15 | 14 | #include <sys/socket.h> |
16 | 15 | #include <sys/stat.h> |
17 | 16 | #include <unistd.h> |
@@ -125,28 +124,6 @@ void Server::accept_connection() |
125 | 124 | add_connection(client); |
126 | 125 | } |
127 | 126 |
|
128 | | -static void print_http_request(const std::string& s) |
129 | | -{ |
130 | | - std::cout << "< "; |
131 | | - |
132 | | - for (size_t i = 0; i < s.size(); ++i) { |
133 | | - char c = s[i]; |
134 | | - if (c == '\r') { |
135 | | - std::cout << "\\r"; |
136 | | - } |
137 | | - else if (c == '\n') { |
138 | | - std::cout << "\\n\n"; |
139 | | - if (i < s.size() - 1) { |
140 | | - std::cout << "< "; |
141 | | - } |
142 | | - } |
143 | | - else { |
144 | | - std::cout.put(c); |
145 | | - } |
146 | | - } |
147 | | - std::cout.flush(); |
148 | | -} |
149 | | - |
150 | 127 | void Server::run() |
151 | 128 | { |
152 | 129 | while (!g_sigint_received) { |
@@ -178,64 +155,84 @@ void Server::run() |
178 | 155 | } |
179 | 156 | } |
180 | 157 |
|
181 | | -void Server::handle_events(Client* conn, uint32_t events) |
| 158 | +// Dirty hack |
| 159 | +static void print_raw_data(const std::string& s) |
182 | 160 | { |
183 | | - if (events & EPOLLIN) { |
184 | | - receive_request(conn); |
185 | | - } |
186 | | - if (events & EPOLLOUT) { |
187 | | - send_response(conn); |
| 161 | + std::cout << "< "; |
| 162 | + |
| 163 | + for (size_t i = 0; i < s.size(); ++i) { |
| 164 | + char c = s[i]; |
| 165 | + if (c == '\r') { |
| 166 | + std::cout << "\\r"; |
| 167 | + } |
| 168 | + else if (c == '\n') { |
| 169 | + std::cout << "\\n\n"; |
| 170 | + if (i < s.size() - 1) { |
| 171 | + std::cout << "< "; |
| 172 | + } |
| 173 | + } |
| 174 | + else { |
| 175 | + std::cout.put(c); |
| 176 | + } |
188 | 177 | } |
| 178 | + std::cout.flush(); |
189 | 179 | } |
190 | 180 |
|
191 | | -// also chunked requests will need to be handled |
192 | | -void Server::receive_request(Client* conn) |
| 181 | +void Server::handle_events(Client* conn, uint32_t events) |
193 | 182 | { |
194 | 183 | int client_fd = conn->fd(); |
195 | | - char buf[4096]; |
| 184 | + char tmp[4096]; |
196 | 185 |
|
197 | | - int n_bytes = recv(client_fd, buf, sizeof(buf), 0); |
198 | | - conn->recv_buffer().append(buf, n_bytes); |
| 186 | + // No handler yet, assume it's a new request (hardcoded for now) |
| 187 | + if (!conn->handler()) { |
| 188 | + HttpRequest req; |
| 189 | + req.method = "GET"; |
| 190 | + req.path = "/files/42.txt"; |
| 191 | + conn->set_request(req); |
199 | 192 |
|
200 | | - std::cout << "* Request received\n"; |
| 193 | + Handler* h = router_.handle_request(conn->req()); |
| 194 | + conn->set_handler(h); |
| 195 | + } |
201 | 196 |
|
202 | | - print_http_request(conn->recv_buffer()); |
| 197 | + // Can read from socket |
| 198 | + if (events & EPOLLIN) { |
| 199 | + int n = recv(client_fd, tmp, sizeof(tmp), 0); |
| 200 | + if (n == 0) { |
| 201 | + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, client_fd, NULL); |
| 202 | + remove_connection(conn); |
| 203 | + return; |
| 204 | + } |
| 205 | + if (n > 0) { |
| 206 | + conn->recv_buffer().append(tmp, n); |
203 | 207 |
|
204 | | - epoll_event ev; |
205 | | - ev.events = EPOLLOUT; |
206 | | - ev.data.ptr = conn; |
207 | | - epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, client_fd, &ev); |
208 | | - |
209 | | - // reading from socket and storing request in Client (TO DO : IBOUKHSS) |
210 | | - // for dev, mimic a http request and call the routing function |
211 | | - HttpRequest req; |
212 | | - req.method = "GET"; |
213 | | - req.path = "/files/42.txt"; |
214 | | - |
215 | | - conn->set_request(req); |
216 | | - |
217 | | - // DHE: adding full_path variable to run make lint. The router_.handle_request() call needs to |
218 | | - // be moved out |
219 | | - std::string full_path; |
220 | | - if (!router_.handle_request(conn, req, full_path)) |
221 | | - return; // bad request |
222 | | - if (req.method == "GET") { |
223 | | - // add handler to conn |
224 | | - // conn.handler = New GetHandler(full_path); |
| 208 | + std::cout << "* Received from socket\n"; |
| 209 | + print_raw_data(conn->recv_buffer()); |
| 210 | + |
| 211 | + epoll_event ev; |
| 212 | + ev.events = EPOLLOUT; |
| 213 | + ev.data.ptr = conn; |
| 214 | + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, client_fd, &ev); |
| 215 | + } |
225 | 216 | } |
226 | | -} |
227 | 217 |
|
228 | | -void Server::send_response(Client* conn) |
229 | | -{ |
230 | | - int client_fd = conn->fd(); |
231 | | - HttpResponse res = conn->res(); |
232 | | - std::string raw = res.to_string(); |
| 218 | + // Can write to socket |
| 219 | + if (events & EPOLLOUT) { |
| 220 | + if (conn->handler()->is_readable()) { |
| 221 | + int n = conn->handler()->read_data(tmp, sizeof(tmp)); |
| 222 | + if (n > 0) |
| 223 | + conn->send_buffer().append(tmp, n); |
| 224 | + } |
233 | 225 |
|
234 | | - send(client_fd, raw.data(), raw.size(), 0); |
| 226 | + if (!conn->send_buffer().empty()) { |
| 227 | + int n = send(client_fd, conn->send_buffer().data(), conn->send_buffer().size(), 0); |
| 228 | + if (n > 0) |
| 229 | + conn->send_buffer().erase(0, n); |
| 230 | + } |
235 | 231 |
|
236 | | - if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, client_fd, NULL) == -1) { |
237 | | - throw UnrecoverableError("epoll_ctl", errno); |
| 232 | + if (conn->handler()->is_done() && conn->send_buffer().empty()) { |
| 233 | + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, client_fd, NULL); |
| 234 | + remove_connection(conn); |
| 235 | + return; |
| 236 | + } |
238 | 237 | } |
239 | | - |
240 | | - remove_connection(conn); |
241 | 238 | } |
0 commit comments