feat: basic http routing
parent
8250a5b8b0
commit
7ece0eb4e5
|
@ -16,15 +16,15 @@ typedef struct http_route {
|
||||||
http_route_type type;
|
http_route_type type;
|
||||||
char *path;
|
char *path;
|
||||||
regex_t *regex;
|
regex_t *regex;
|
||||||
size_t step_count;
|
bool (*steps[5])(event_loop_conn *);
|
||||||
void (**steps)(event_loop_conn *);
|
|
||||||
} http_route;
|
} http_route;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global context passed to every connection using the same pointer
|
* Global context passed to every connection using the same pointer
|
||||||
*/
|
*/
|
||||||
typedef struct http_loop_gctx {
|
typedef struct http_loop_gctx {
|
||||||
http_route **routes;
|
http_route *routes;
|
||||||
|
size_t route_count;
|
||||||
Trie *trie;
|
Trie *trie;
|
||||||
} http_loop_gctx;
|
} http_loop_gctx;
|
||||||
|
|
||||||
|
@ -58,6 +58,8 @@ void http_loop_ctx_free(http_loop_ctx *ctx);
|
||||||
*/
|
*/
|
||||||
bool http_loop_handle_request(event_loop_conn *conn);
|
bool http_loop_handle_request(event_loop_conn *conn);
|
||||||
|
|
||||||
|
bool http_loop_route_request(event_loop_conn *conn);
|
||||||
|
|
||||||
void http_loop_process_request(event_loop_conn *conn);
|
void http_loop_process_request(event_loop_conn *conn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,24 +25,28 @@ bool http_loop_handle_request(event_loop_conn *conn) {
|
||||||
|
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
|
|
||||||
http_parse_error res =
|
// If route is defined, we're currently processing a request
|
||||||
http_parse_request(&ctx->req, (const char *)&conn->rbuf[conn->rbuf_read],
|
if (ctx->route == NULL) {
|
||||||
conn->rbuf_size - conn->rbuf_read);
|
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) {
|
if (res == http_parse_error_invalid ||
|
||||||
// Perform the request
|
(res == http_parse_error_incomplete &&
|
||||||
/* http_route(conn); */
|
conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) {
|
||||||
}
|
conn->state = event_loop_conn_state_end;
|
||||||
// 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
|
return false;
|
||||||
// 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 ||
|
// If the routing fails, we exit the handler
|
||||||
(res == http_parse_error_incomplete &&
|
if (!http_loop_route_request(conn)) {
|
||||||
conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) {
|
return false;
|
||||||
conn->state = event_loop_conn_state_end;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http_loop_process_request(conn);
|
||||||
|
|
||||||
// TODO in highly concurrent situations, it might actually be better to always
|
// TODO in highly concurrent situations, it might actually be better to always
|
||||||
// return false here, as this allows cycling better through all connections
|
// return false here, as this allows cycling better through all connections
|
||||||
return conn->state == event_loop_conn_state_req;
|
return conn->state == event_loop_conn_state_req;
|
||||||
|
|
|
@ -1,13 +1,48 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "event_loop.h"
|
#include "http_loop.h"
|
||||||
#include "http.h"
|
|
||||||
|
|
||||||
void http_loop_process_request(event_loop_conn *conn) {}
|
void http_loop_process_request(event_loop_conn *conn) {
|
||||||
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
|
|
||||||
/* void http_route(event_loop_conn *conn) { */
|
// The end of the list of steps is marked with a NULL. When this is reached,
|
||||||
/* // TODO routing */
|
// we simply set the route to NULL, letting the http loop know a new request
|
||||||
|
// can be handled.
|
||||||
|
if (ctx->route->steps[ctx->current_step] == NULL) {
|
||||||
|
ctx->route = NULL;
|
||||||
|
ctx->current_step = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* // Fallthrough is to return a 404 */
|
// We execute the next step
|
||||||
/* http_write_standard_response(conn, http_not_found); */
|
// NOTE can/should we execute more than one step at once here?
|
||||||
/* } */
|
if (ctx->route->steps[ctx->current_step](conn)) {
|
||||||
|
ctx->current_step++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool http_loop_route_request(event_loop_conn *conn) {
|
||||||
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
|
http_loop_gctx *gctx = ctx->g;
|
||||||
|
|
||||||
|
http_route *route;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gctx->route_count; i++) {
|
||||||
|
route = &gctx->routes[i];
|
||||||
|
|
||||||
|
switch (route->type) {
|
||||||
|
case http_route_literal:
|
||||||
|
if (strncmp(route->path, ctx->req.method, ctx->req.method_len)) {
|
||||||
|
ctx->route = route;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
case http_route_regex:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallthrough is to write a 404
|
||||||
|
http_write_standard_response(conn, http_not_found);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
13
src/main.c
13
src/main.c
|
@ -4,17 +4,18 @@
|
||||||
#include "http_loop.h"
|
#include "http_loop.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
void http_write_404(event_loop_conn *conn) {
|
bool http_write_404(event_loop_conn *conn) {
|
||||||
memcpy(conn->wbuf, http_404, http_404_len);
|
memcpy(conn->wbuf, http_405, http_405_len);
|
||||||
|
|
||||||
conn->state = event_loop_conn_state_res;
|
conn->state = event_loop_conn_state_res;
|
||||||
conn->wbuf_size = http_404_len;
|
conn->wbuf_size = http_405_len;
|
||||||
conn->wbuf_sent = 0;
|
conn->wbuf_sent = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*steps[])(event_loop_conn *) = {http_write_404, NULL};
|
|
||||||
http_route routes[] = {
|
http_route routes[] = {
|
||||||
{.type = http_route_literal, .path = "/", .step_count = 1, .steps = steps}};
|
{.type = http_route_literal, .path = "/", .steps = {http_write_404, NULL}}};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
@ -32,6 +33,8 @@ int main() {
|
||||||
|
|
||||||
http_loop_gctx *gctx = http_loop_gctx_init();
|
http_loop_gctx *gctx = http_loop_gctx_init();
|
||||||
gctx->trie = trie;
|
gctx->trie = trie;
|
||||||
|
gctx->routes = routes;
|
||||||
|
gctx->route_count = sizeof(routes) / sizeof(routes[0]);
|
||||||
event_loop *el = http_loop_init(gctx);
|
event_loop *el = http_loop_init(gctx);
|
||||||
|
|
||||||
event_loop_run(el, 8000);
|
event_loop_run(el, 8000);
|
||||||
|
|
Loading…
Reference in New Issue