feat: decouple event loop from http
This commit is contained in:
parent
f3fced908f
commit
68f9227436
12 changed files with 136 additions and 112 deletions
60
src/http_loop/http_loop.c
Normal file
60
src/http_loop/http_loop.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#include "http_loop.h"
|
||||
#include "http.h"
|
||||
|
||||
http_loop_gctx *http_loop_gctx_init() {
|
||||
http_loop_gctx *gctx = calloc(sizeof(http_loop_gctx), 1);
|
||||
|
||||
return gctx;
|
||||
}
|
||||
|
||||
http_loop_ctx *http_loop_ctx_init(http_loop_gctx *g) {
|
||||
http_loop_ctx *ctx = calloc(sizeof(http_loop_ctx), 1);
|
||||
ctx->g = g;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void http_loop_ctx_free(http_loop_ctx *ctx) { free(ctx); }
|
||||
|
||||
bool http_loop_handle_request(event_loop_conn *conn) {
|
||||
// Prevents the request handler function from looping indefinitely without
|
||||
// ever consuming new data
|
||||
if (conn->rbuf_size - conn->rbuf_read == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
http_loop_ctx *ctx = conn->ctx;
|
||||
|
||||
http_parse_error res =
|
||||
http_parse_request(&ctx->req, (const char *)&conn->rbuf[conn->rbuf_read],
|
||||
conn->rbuf_size - conn->rbuf_read);
|
||||
|
||||
if (res == http_parse_error_ok) {
|
||||
// Perform the request
|
||||
http_route(conn);
|
||||
}
|
||||
// Both in the case of an invalid HTTP request or one that's larger than the
|
||||
// read buffer, we cannot determine when the next, possibly valid, HTTP
|
||||
// request begins in the data stream. Therefore, we close the connection,
|
||||
// even if additional pipelined requests are incoming.
|
||||
else if (res == http_parse_error_invalid ||
|
||||
(res == http_parse_error_incomplete &&
|
||||
conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) {
|
||||
conn->state = event_loop_conn_state_end;
|
||||
}
|
||||
|
||||
// TODO in highly concurrent situations, it might actually be better to always
|
||||
// return false here, as this allows cycling better through all connections
|
||||
return conn->state == event_loop_conn_state_req;
|
||||
}
|
||||
|
||||
event_loop *http_loop_init(http_loop_gctx *gctx) {
|
||||
event_loop *el = event_loop_init();
|
||||
|
||||
el->ctx_init = (void *(*)(void *))http_loop_ctx_init;
|
||||
el->ctx_free = (void (*)(void *))http_loop_ctx_free;
|
||||
el->handle_data = http_loop_handle_request;
|
||||
el->gctx = gctx;
|
||||
|
||||
return el;
|
||||
}
|
||||
13
src/http_loop/http_loop_consts.c
Normal file
13
src/http_loop/http_loop_consts.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "http.h"
|
||||
|
||||
const char http_404[] = "HTTP/1.1 404 Not Found\n"
|
||||
"Content-Length: 0\n\n";
|
||||
const size_t http_404_len = sizeof(http_404) - 1;
|
||||
|
||||
const char http_405[] = "HTTP/1.1 405 Method Not Allowed\n"
|
||||
"Content-Length: 0\n\n";
|
||||
const size_t http_405_len = sizeof(http_405) - 1;
|
||||
|
||||
const char http_500[] = "HTTP/1.1 500 Internal Server Error\n"
|
||||
"Content-Length: 0\n\n";
|
||||
const size_t http_500_len = sizeof(http_500) - 1;
|
||||
25
src/http_loop/http_loop_parse.c
Normal file
25
src/http_loop/http_loop_parse.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#include "http.h"
|
||||
#include "picohttpparser.h"
|
||||
|
||||
/*
|
||||
* given the HTTP path, parse the request
|
||||
*/
|
||||
http_parse_error http_parse_request(http_request *req, const char *buf,
|
||||
size_t buf_size) {
|
||||
// First we try to parse the incoming HTTP request
|
||||
size_t num_headers = HTTP_MAX_ALLOWED_HEADERS;
|
||||
|
||||
int res = phr_parse_request(buf, buf_size, &req->method, &req->method_len,
|
||||
&req->path, &req->path_len, &req->minor_version,
|
||||
req->headers, &num_headers, 0);
|
||||
|
||||
if (res == -1) {
|
||||
return http_parse_error_invalid;
|
||||
} else if (res == -2) {
|
||||
return http_parse_error_incomplete;
|
||||
}
|
||||
|
||||
req->len = res;
|
||||
|
||||
return http_parse_error_ok;
|
||||
}
|
||||
13
src/http_loop/http_loop_route.c
Normal file
13
src/http_loop/http_loop_route.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "event_loop.h"
|
||||
#include "http.h"
|
||||
|
||||
typedef void (*routing_func)(event_loop_conn *);
|
||||
|
||||
void http_route(event_loop_conn *conn) {
|
||||
// TODO routing
|
||||
|
||||
// Fallthrough is to return a 404
|
||||
http_write_standard_response(conn, http_not_found);
|
||||
}
|
||||
24
src/http_loop/http_loop_util.c
Normal file
24
src/http_loop/http_loop_util.c
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include "http.h"
|
||||
#include "string.h"
|
||||
|
||||
void http_write_standard_response(event_loop_conn *conn,
|
||||
http_response_type type) {
|
||||
const char *s;
|
||||
size_t len;
|
||||
|
||||
switch (type) {
|
||||
case 404:
|
||||
s = http_404;
|
||||
len = http_404_len;
|
||||
break;
|
||||
case 405:
|
||||
s = http_405;
|
||||
len = http_405_len;
|
||||
}
|
||||
|
||||
memcpy(conn->wbuf, s, len);
|
||||
|
||||
conn->state = event_loop_conn_state_res;
|
||||
conn->wbuf_size = len;
|
||||
conn->wbuf_sent = 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue