feat: started designing http framework

c-web-server
Jef Roosens 2023-05-27 15:38:06 +02:00
parent 90d83bc5d4
commit 8250a5b8b0
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
9 changed files with 96 additions and 50 deletions

View File

@ -9,7 +9,7 @@
#define EVENT_LOOP_BUFFER_SIZE 1024 #define EVENT_LOOP_BUFFER_SIZE 1024
/** /**
* Represents an active connection managed by the event loop * State of a connection
*/ */
typedef enum { typedef enum {
event_loop_conn_state_req = 0, event_loop_conn_state_req = 0,
@ -17,14 +17,17 @@ typedef enum {
event_loop_conn_state_end = 2, event_loop_conn_state_end = 2,
} event_loop_conn_state; } event_loop_conn_state;
/**
* Represents an active connection managed by the event loop
*/
typedef struct event_loop_conn { typedef struct event_loop_conn {
int fd; int fd;
event_loop_conn_state state; event_loop_conn_state state;
// buffer for reading // Read buffer
size_t rbuf_size; size_t rbuf_size;
size_t rbuf_read; size_t rbuf_read;
uint8_t rbuf[EVENT_LOOP_BUFFER_SIZE]; uint8_t rbuf[EVENT_LOOP_BUFFER_SIZE];
// buffer for writing // Write buffer
size_t wbuf_size; size_t wbuf_size;
size_t wbuf_sent; size_t wbuf_sent;
uint8_t wbuf[EVENT_LOOP_BUFFER_SIZE]; uint8_t wbuf[EVENT_LOOP_BUFFER_SIZE];
@ -32,6 +35,7 @@ typedef struct event_loop_conn {
// If true, the server will close the connection after the final write buffer // If true, the server will close the connection after the final write buffer
// has been written // has been written
bool close_after_write; bool close_after_write;
// Context for a request
void *ctx; void *ctx;
} event_loop_conn; } event_loop_conn;
@ -47,23 +51,27 @@ typedef struct event_loop {
void *(*ctx_init)(void *gctx); void *(*ctx_init)(void *gctx);
// Function to free a context for a connection // Function to free a context for a connection
void (*ctx_free)(void *ctx); void (*ctx_free)(void *ctx);
// Function that processes incoming data
bool (*handle_data)(event_loop_conn *conn); bool (*handle_data)(event_loop_conn *conn);
} event_loop; } event_loop;
/* /*
* Initialize a new event_loop_conn struct * Initialize a new connection struct
*/ */
event_loop_conn *event_loop_conn_init(event_loop *el); event_loop_conn *event_loop_conn_init(event_loop *el);
/*
* Free a connection struct
*/
void event_loop_conn_free(event_loop *el, event_loop_conn *conn); void event_loop_conn_free(event_loop *el, event_loop_conn *conn);
/* /*
* Process data on a connection * Handle I/O for a connection, be it reading input or writing output.
*/ */
void event_loop_conn_io(event_loop *el, event_loop_conn *conn); void event_loop_conn_io(event_loop *el, event_loop_conn *conn);
/* /*
* Initialize a new event_loop struct * Initialize a new event loop struct
*/ */
event_loop *event_loop_init(); event_loop *event_loop_init();

View File

@ -6,7 +6,8 @@
#include "picohttpparser.h" #include "picohttpparser.h"
#include "event_loop.h" #include "event_loop.h"
#include "http_req.h"
#define HTTP_MAX_ALLOWED_HEADERS 8
extern const char http_404[]; extern const char http_404[];
extern const size_t http_404_len; extern const size_t http_404_len;
@ -15,6 +16,27 @@ extern const size_t http_405_len;
extern const char http_500[]; extern const char http_500[];
extern const size_t http_500_len; extern const size_t http_500_len;
typedef enum http_request_method {
http_request_method_get = 0,
http_request_method_post = 1,
http_request_method_put = 2,
http_request_method_patch = 3,
http_request_method_delete = 4
} http_request_method;
/*
* Struct representing the specific type of request
*/
typedef struct http_request {
size_t len;
int minor_version;
const char *method;
size_t method_len;
const char *path;
size_t path_len;
struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS];
} http_request;
typedef enum http_parse_error { typedef enum http_parse_error {
http_parse_error_ok = 0, http_parse_error_ok = 0,
http_parse_error_incomplete = 1, http_parse_error_incomplete = 1,
@ -24,7 +46,7 @@ typedef enum http_parse_error {
http_parse_error http_parse_request(http_request *req, const char *path, http_parse_error http_parse_request(http_request *req, const char *path,
size_t path_len); size_t path_len);
void http_route(event_loop_conn *conn); /* void http_route(event_loop_conn *conn); */
typedef enum http_response_type { typedef enum http_response_type {
http_not_found = 404, http_not_found = 404,

View File

@ -1,17 +1,36 @@
#ifndef LANDER_HTTP_LOOP #ifndef LANDER_HTTP_LOOP
#define LANDER_HTTP_LOOP #define LANDER_HTTP_LOOP
#include <regex.h>
#include "event_loop.h" #include "event_loop.h"
#include "http_req.h" #include "http.h"
#include "trie.h" #include "trie.h"
typedef enum http_route_type {
http_route_literal = 0,
http_route_regex = 1,
} http_route_type;
typedef struct http_route {
http_route_type type;
char *path;
regex_t *regex;
size_t step_count;
void (**steps)(event_loop_conn *);
} 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;
Trie *trie; Trie *trie;
} http_loop_gctx; } http_loop_gctx;
/*
* Initialize a new global context
*/
http_loop_gctx *http_loop_gctx_init(); http_loop_gctx *http_loop_gctx_init();
/* /*
@ -19,15 +38,31 @@ http_loop_gctx *http_loop_gctx_init();
*/ */
typedef struct http_loop_ctx { typedef struct http_loop_ctx {
http_request req; http_request req;
http_route *route;
size_t current_step;
http_loop_gctx *g; http_loop_gctx *g;
} http_loop_ctx; } http_loop_ctx;
/*
* Initialize a context struct
*/
http_loop_ctx *http_loop_ctx_init(http_loop_gctx *g); http_loop_ctx *http_loop_ctx_init(http_loop_gctx *g);
/*
* Free a context struct
*/
void http_loop_ctx_free(http_loop_ctx *ctx); void http_loop_ctx_free(http_loop_ctx *ctx);
/**
* Process incoming data as an HTTP request
*/
bool http_loop_handle_request(event_loop_conn *conn); bool http_loop_handle_request(event_loop_conn *conn);
void http_loop_process_request(event_loop_conn *conn);
/**
* Initialize a new http loop
*/
event_loop *http_loop_init(http_loop_gctx *gctx); event_loop *http_loop_init(http_loop_gctx *gctx);
#endif #endif

View File

@ -1,31 +0,0 @@
#ifndef HTTP_REQ
#define HTTP_REQ
#include <stdlib.h>
#include "picohttpparser.h"
#define HTTP_MAX_ALLOWED_HEADERS 16
typedef enum http_request_method {
http_request_method_get = 0,
http_request_method_post = 1,
http_request_method_put = 2,
http_request_method_patch = 3,
http_request_method_delete = 4
} http_request_method;
/*
* Struct representing the specific type of request
*/
typedef struct http_request {
size_t len;
int minor_version;
const char *method;
size_t method_len;
const char *path;
size_t path_len;
struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS];
} http_request;
#endif

View File

@ -172,7 +172,7 @@ void event_loop_run(event_loop *el, int port) {
// poll for active fds // poll for active fds
// the timeout argument doesn't matter here // the timeout argument doesn't matter here
int rv = poll(poll_args, (nfds_t)poll_args_count, 0); int rv = poll(poll_args, (nfds_t)poll_args_count, -1);
if (rv < 0) { if (rv < 0) {
critical(1, "Poll failed, errno: %i", errno); critical(1, "Poll failed, errno: %i", errno);

View File

@ -109,7 +109,6 @@ void event_loop_conn_io(event_loop *el, event_loop_conn *conn) {
case event_loop_conn_state_res: case event_loop_conn_state_res:
event_loop_conn_io_res(conn); event_loop_conn_io_res(conn);
break; break;
case event_loop_conn_state_end: case event_loop_conn_state_end:;
break;
} }
} }

View File

@ -31,7 +31,7 @@ bool http_loop_handle_request(event_loop_conn *conn) {
if (res == http_parse_error_ok) { if (res == http_parse_error_ok) {
// Perform the request // Perform the request
http_route(conn); /* http_route(conn); */
} }
// Both in the case of an invalid HTTP request or one that's larger than the // 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 // read buffer, we cannot determine when the next, possibly valid, HTTP

View File

@ -3,11 +3,11 @@
#include "event_loop.h" #include "event_loop.h"
#include "http.h" #include "http.h"
typedef void (*routing_func)(event_loop_conn *); void http_loop_process_request(event_loop_conn *conn) {}
void http_route(event_loop_conn *conn) { /* void http_route(event_loop_conn *conn) { */
// TODO routing /* // TODO routing */
// Fallthrough is to return a 404 /* // Fallthrough is to return a 404 */
http_write_standard_response(conn, http_not_found); /* http_write_standard_response(conn, http_not_found); */
} /* } */

View File

@ -1,8 +1,21 @@
#include <stdio.h> #include <stdio.h>
#include "http.h"
#include "http_loop.h" #include "http_loop.h"
#include "log.h" #include "log.h"
void http_write_404(event_loop_conn *conn) {
memcpy(conn->wbuf, http_404, http_404_len);
conn->state = event_loop_conn_state_res;
conn->wbuf_size = http_404_len;
conn->wbuf_sent = 0;
}
void (*steps[])(event_loop_conn *) = {http_write_404, NULL};
http_route routes[] = {
{.type = http_route_literal, .path = "/", .step_count = 1, .steps = steps}};
int main() { int main() {
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0);