feat: separate lander code into separate module
parent
7af4be12ff
commit
ff0795bb55
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LANDER
|
||||
#define LANDER
|
||||
|
||||
#include "http_loop.h"
|
||||
|
||||
extern http_route lander_routes[2];
|
||||
|
||||
#endif
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
|
@ -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}}};
|
63
src/main.c
63
src/main.c
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue