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;
|
} http_response_body_type;
|
||||||
|
|
||||||
typedef struct http_response {
|
typedef struct http_response {
|
||||||
http_response_type type;
|
http_response_type status;
|
||||||
const char *head;
|
const char *head;
|
||||||
size_t head_len;
|
size_t head_len;
|
||||||
size_t head_written;
|
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 <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const static char charset[] =
|
static const char charset[] =
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
const static size_t charset_len = sizeof(charset) - 1;
|
static const size_t charset_len = sizeof(charset) - 1;
|
||||||
|
|
||||||
// Length of randomly generated keys
|
// Length of randomly generated keys
|
||||||
#define RANDOM_KEY_LENGTH_SHORT 4
|
#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
|
// It's fun to respond with extremely specific error messages
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501
|
||||||
if (res == http_parse_error_unknown_method) {
|
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;
|
conn->state = event_loop_conn_state_res;
|
||||||
} else {
|
} else {
|
||||||
http_loop_route_request(conn);
|
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.header_count = 0;
|
||||||
|
|
||||||
ctx->res.type = 0;
|
ctx->res.status = 0;
|
||||||
ctx->res.head_len = 0;
|
ctx->res.head_len = 0;
|
||||||
ctx->res.head_written = 0;
|
ctx->res.head_written = 0;
|
||||||
ctx->res.body_len = 0;
|
ctx->res.body_len = 0;
|
||||||
|
|
|
@ -92,7 +92,6 @@ void http_loop_route_request(event_loop_conn *conn) {
|
||||||
|
|
||||||
http_route *route;
|
http_route *route;
|
||||||
bool path_matched = false;
|
bool path_matched = false;
|
||||||
char c;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < gctx->route_count; i++) {
|
for (size_t i = 0; i < gctx->route_count; i++) {
|
||||||
route = &gctx->routes[i];
|
route = &gctx->routes[i];
|
||||||
|
@ -123,7 +122,7 @@ void http_loop_route_request(event_loop_conn *conn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallthrough case
|
// 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;
|
conn->state = event_loop_conn_state_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "http_loop.h"
|
#include "http_loop.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
@ -17,15 +14,15 @@ static const char *http_response_format = "HTTP/1.1 %i %s\n"
|
||||||
* written.
|
* written.
|
||||||
*/
|
*/
|
||||||
void http_loop_init_header(http_response *res) {
|
void http_loop_init_header(http_response *res) {
|
||||||
if (res->type == 0) {
|
if (res->status == 0) {
|
||||||
res->type = http_ok;
|
res->status = http_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *response_type_name =
|
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
|
// 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);
|
response_type_name, res->body_len);
|
||||||
|
|
||||||
// We add each header's required size
|
// 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
|
// The + 1 is required to store the final null byte, but we will replace it
|
||||||
// with the required final newline
|
// with the required final newline
|
||||||
char *buf = malloc(buf_size + 1);
|
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);
|
res->body_len);
|
||||||
|
|
||||||
for (size_t i = 0; i < res->header_count; i++) {
|
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) {
|
switch (res->body_type) {
|
||||||
case http_response_body_buf:
|
case http_response_body_buf:
|
||||||
memcpy(&conn->wbuf[conn->wbuf_size], &res->body[res->body_written],
|
memcpy(&conn->wbuf[conn->wbuf_size],
|
||||||
bytes_to_write);
|
&((const char *)res->body)[res->body_written], bytes_to_write);
|
||||||
conn->wbuf_size += bytes_to_write;
|
conn->wbuf_size += bytes_to_write;
|
||||||
res->body_written += bytes_to_write;
|
res->body_written += bytes_to_write;
|
||||||
break;
|
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 <stdio.h>
|
||||||
|
|
||||||
#include "http.h"
|
#include "lander.h"
|
||||||
#include "http_loop.h"
|
|
||||||
#include "log.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() {
|
int main() {
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
@ -76,8 +19,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->routes = lander_routes;
|
||||||
gctx->route_count = sizeof(routes) / sizeof(routes[0]);
|
gctx->route_count = sizeof(lander_routes) / sizeof(lander_routes[0]);
|
||||||
event_loop *el = http_loop_init(gctx);
|
event_loop *el = http_loop_init(gctx);
|
||||||
|
|
||||||
http_loop_run(el, 8000);
|
http_loop_run(el, 8000);
|
||||||
|
|
Loading…
Reference in New Issue