feat: started designing http framework
parent
90d83bc5d4
commit
8250a5b8b0
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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); */
|
||||||
}
|
/* } */
|
||||||
|
|
13
src/main.c
13
src/main.c
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue