feat: separate lander code into separate module

c-web-server
Jef Roosens 2023-05-29 21:46:05 +02:00
parent 7af4be12ff
commit ff0795bb55
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
11 changed files with 114 additions and 106 deletions

View File

@ -132,7 +132,7 @@ typedef enum http_response_body_type {
} http_response_body_type;
typedef struct http_response {
http_response_type type;
http_response_type status;
const char *head;
size_t head_len;
size_t head_written;

8
include/lander.h 100644
View File

@ -0,0 +1,8 @@
#ifndef LANDER
#define LANDER
#include "http_loop.h"
extern http_route lander_routes[2];
#endif

View File

@ -19,9 +19,9 @@
#include <stddef.h>
#include <string.h>
const static char charset[] =
static const char charset[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const static size_t charset_len = sizeof(charset) - 1;
static const size_t charset_len = sizeof(charset) - 1;
// Length of randomly generated keys
#define RANDOM_KEY_LENGTH_SHORT 4

View File

@ -30,7 +30,7 @@ bool http_loop_handle_request(event_loop_conn *conn) {
// It's fun to respond with extremely specific error messages
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501
if (res == http_parse_error_unknown_method) {
ctx->res.type = http_method_not_implemented;
ctx->res.status = http_method_not_implemented;
conn->state = event_loop_conn_state_res;
} else {
http_loop_route_request(conn);

View File

@ -49,7 +49,7 @@ void http_loop_ctx_reset(http_loop_ctx *ctx) {
ctx->res.header_count = 0;
ctx->res.type = 0;
ctx->res.status = 0;
ctx->res.head_len = 0;
ctx->res.head_written = 0;
ctx->res.body_len = 0;

View File

@ -92,7 +92,6 @@ void http_loop_route_request(event_loop_conn *conn) {
http_route *route;
bool path_matched = false;
char c;
for (size_t i = 0; i < gctx->route_count; i++) {
route = &gctx->routes[i];
@ -123,7 +122,7 @@ void http_loop_route_request(event_loop_conn *conn) {
}
// Fallthrough case
ctx->res.type = path_matched ? http_method_not_allowed : http_not_found;
ctx->res.status = path_matched ? http_method_not_allowed : http_not_found;
conn->state = event_loop_conn_state_res;
}

View File

@ -1,6 +1,3 @@
#include <stdio.h>
#include <sys/stat.h>
#include "http_loop.h"
#include "log.h"
@ -17,15 +14,15 @@ static const char *http_response_format = "HTTP/1.1 %i %s\n"
* written.
*/
void http_loop_init_header(http_response *res) {
if (res->type == 0) {
res->type = http_ok;
if (res->status == 0) {
res->status = http_ok;
}
const char *response_type_name =
http_response_type_names[res->type / 100 - 1][res->type % 100];
http_response_type_names[res->status / 100 - 1][res->status % 100];
// First we calculate the size of the start of the header
int buf_size = snprintf(NULL, 0, http_response_format, res->type,
int buf_size = snprintf(NULL, 0, http_response_format, res->status,
response_type_name, res->body_len);
// We add each header's required size
@ -38,7 +35,7 @@ void http_loop_init_header(http_response *res) {
// The + 1 is required to store the final null byte, but we will replace it
// with the required final newline
char *buf = malloc(buf_size + 1);
buf_size = sprintf(buf, http_response_format, res->type, response_type_name,
buf_size = sprintf(buf, http_response_format, res->status, response_type_name,
res->body_len);
for (size_t i = 0; i < res->header_count; i++) {
@ -87,8 +84,8 @@ void http_loop_write_response(event_loop_conn *conn) {
switch (res->body_type) {
case http_response_body_buf:
memcpy(&conn->wbuf[conn->wbuf_size], &res->body[res->body_written],
bytes_to_write);
memcpy(&conn->wbuf[conn->wbuf_size],
&((const char *)res->body)[res->body_written], bytes_to_write);
conn->wbuf_size += bytes_to_write;
res->body_written += bytes_to_write;
break;
@ -101,32 +98,3 @@ void http_loop_write_response(event_loop_conn *conn) {
}
}
}
void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body,
size_t body_len, bool owned) {
ctx->res.body_type = http_response_body_buf;
ctx->res.body = (void *)body;
ctx->res.body_len = body_len;
ctx->res.owns_body = owned;
}
void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename) {
struct stat st;
stat(filename, &st);
// TODO error handling
FILE *f = fopen(filename, "r");
ctx->res.body_type = http_response_body_file;
ctx->res.body = f;
ctx->res.body_len = st.st_size;
}
void http_loop_res_add_header(http_loop_ctx *ctx, http_header type,
const char *value, bool owned) {
ctx->res.headers[ctx->res.header_count].type = type;
ctx->res.headers[ctx->res.header_count].value = value;
ctx->res.headers[ctx->res.header_count].owned = owned;
ctx->res.header_count++;
}

View File

@ -0,0 +1,33 @@
#include <stdio.h>
#include <sys/stat.h>
#include "http_loop.h"
void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body,
size_t body_len, bool owned) {
ctx->res.body_type = http_response_body_buf;
ctx->res.body = (void *)body;
ctx->res.body_len = body_len;
ctx->res.owns_body = owned;
}
void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename) {
struct stat st;
stat(filename, &st);
// TODO error handling
FILE *f = fopen(filename, "r");
ctx->res.body_type = http_response_body_file;
ctx->res.body = f;
ctx->res.body_len = st.st_size;
}
void http_loop_res_add_header(http_loop_ctx *ctx, http_header type,
const char *value, bool owned) {
ctx->res.headers[ctx->res.header_count].type = type;
ctx->res.headers[ctx->res.header_count].value = value;
ctx->res.headers[ctx->res.header_count].owned = owned;
ctx->res.header_count++;
}

View File

@ -0,0 +1,57 @@
#include <stdio.h>
#include "lander.h"
static const char index_page[] =
"<!DOCTYPE html>\n"
"<html>\n"
" <body>\n"
" <h1>r8r.be</h1>\n"
" <p>This is the URL shortener and pastebin accompanying my site, <a "
"href=\"https://rustybever.be\">The Rusty Bever</a>.</p>\n"
" </body>\n"
"</html>\n";
bool lander_get_index(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
http_loop_res_set_body_buf(ctx, index_page, sizeof(index_page) - 1, false);
conn->state = event_loop_conn_state_res;
return true;
}
bool lander_get_entry(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
const char *key = &ctx->req.path[ctx->req.regex_groups[1].rm_so];
int key_len = ctx->req.regex_groups[1].rm_eo - ctx->req.regex_groups[1].rm_so;
Entry *entry;
TrieExitCode res = trie_search_len(ctx->g->trie, &entry, key, key_len);
if (res == NotFound) {
ctx->res.status = http_not_found;
} else if (entry->type == Redirect) {
ctx->res.status = http_moved_permanently;
http_loop_res_add_header(ctx, http_header_location, entry->string, false);
} else if (entry->type == Paste) {
char fname[8 + key_len];
sprintf(fname, "pastes/%.*s", key_len, key);
http_loop_res_set_body_file(ctx, fname);
}
conn->state = event_loop_conn_state_res;
return true;
}
http_route lander_routes[] = {{.type = http_route_literal,
.method = http_get,
.path = "/",
.steps = {lander_get_index, NULL}},
{.type = http_route_regex,
.method = http_get,
.path = "^/\\([^/]\\+\\)$",
.steps = {lander_get_entry, NULL}}};

View File

View File

@ -1,65 +1,8 @@
#include <stdio.h>
#include "http.h"
#include "http_loop.h"
#include "lander.h"
#include "log.h"
const char index_page[] =
"<!DOCTYPE html>\n"
"<html>\n"
" <body>\n"
" <h1>r8r.be</h1>\n"
" <p>This is the URL shortener and pastebin accompanying my site, <a "
"href=\"https://rustybever.be\">The Rusty Bever</a>.</p>\n"
" </body>\n"
"</html>\n";
bool lander_get_index(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
http_loop_res_set_body_file(ctx, "Dockerfile");
conn->state = event_loop_conn_state_res;
return true;
}
bool lander_get_entry(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx;
const char *key = &ctx->req.path[ctx->req.regex_groups[1].rm_so];
int key_len =
ctx->req.regex_groups[1].rm_eo - ctx->req.regex_groups[1].rm_so;
Entry *entry;
TrieExitCode res = trie_search_len(ctx->g->trie, &entry, key, key_len);
if (res == NotFound) {
ctx->res.type = http_not_found;
} else if (entry->type == Redirect) {
ctx->res.type = http_moved_permanently;
http_loop_res_add_header(ctx, http_header_location, entry->string, false);
} else if (entry->type == Paste) {
char fname[8 + key_len];
sprintf(fname, "pastes/%.*s", key_len, key);
http_loop_res_set_body_file(ctx, fname);
}
conn->state = event_loop_conn_state_res;
return true;
}
http_route routes[] = {{.type = http_route_literal,
.method = http_get,
.path = "/",
.steps = {lander_get_index, NULL}},
{.type = http_route_regex,
.method = http_get,
.path = "^/\\([^/]\\+\\)$",
.steps = {lander_get_entry, NULL}}};
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
@ -76,8 +19,8 @@ int main() {
http_loop_gctx *gctx = http_loop_gctx_init();
gctx->trie = trie;
gctx->routes = routes;
gctx->route_count = sizeof(routes) / sizeof(routes[0]);
gctx->routes = lander_routes;
gctx->route_count = sizeof(lander_routes) / sizeof(lander_routes[0]);
event_loop *el = http_loop_init(gctx);
http_loop_run(el, 8000);