feat: paved the way for uploading pastes
parent
94b07caeb3
commit
dfbd179c7a
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "picohttpparser.h"
|
#include "picohttpparser.h"
|
||||||
|
@ -24,6 +25,11 @@ typedef enum http_request_method {
|
||||||
extern const char *request_method_names[];
|
extern const char *request_method_names[];
|
||||||
extern const size_t request_method_names_len;
|
extern const size_t request_method_names_len;
|
||||||
|
|
||||||
|
typedef enum http_body_type {
|
||||||
|
http_body_buf = 0,
|
||||||
|
http_body_file = 1
|
||||||
|
} http_body_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Struct representing the specific type of request
|
* Struct representing the specific type of request
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +41,11 @@ typedef struct http_request {
|
||||||
size_t path_len;
|
size_t path_len;
|
||||||
const char *query;
|
const char *query;
|
||||||
size_t query_len;
|
size_t query_len;
|
||||||
char *body;
|
http_body_type body_type;
|
||||||
|
union {
|
||||||
|
char *buf;
|
||||||
|
FILE *file;
|
||||||
|
} body;
|
||||||
size_t body_len;
|
size_t body_len;
|
||||||
size_t body_received;
|
size_t body_received;
|
||||||
regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS];
|
regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS];
|
||||||
|
@ -130,18 +140,16 @@ typedef struct http_response_header {
|
||||||
bool owned;
|
bool owned;
|
||||||
} http_response_header;
|
} http_response_header;
|
||||||
|
|
||||||
typedef enum http_response_body_type {
|
|
||||||
http_response_body_buf = 0,
|
|
||||||
http_response_body_file = 1
|
|
||||||
} http_response_body_type;
|
|
||||||
|
|
||||||
typedef struct http_response {
|
typedef struct http_response {
|
||||||
http_response_type status;
|
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;
|
||||||
http_response_body_type body_type;
|
http_body_type body_type;
|
||||||
void *body;
|
union {
|
||||||
|
char *buf;
|
||||||
|
FILE *file;
|
||||||
|
} body;
|
||||||
size_t body_len;
|
size_t body_len;
|
||||||
size_t body_written;
|
size_t body_written;
|
||||||
// If false, the body won't be freed
|
// If false, the body won't be freed
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
extern http_route lander_routes[3];
|
extern http_route lander_routes[3];
|
||||||
|
|
||||||
|
bool lander_get_index(event_loop_conn *conn);
|
||||||
|
|
||||||
|
bool lander_get_entry(event_loop_conn *conn);
|
||||||
|
|
||||||
bool lander_post_redirect(event_loop_conn *conn);
|
bool lander_post_redirect(event_loop_conn *conn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,9 +26,13 @@ void http_loop_ctx_reset(http_loop_ctx *ctx) {
|
||||||
ctx->route = NULL;
|
ctx->route = NULL;
|
||||||
ctx->current_step = 0;
|
ctx->current_step = 0;
|
||||||
|
|
||||||
if (ctx->req.body != NULL) {
|
if (ctx->req.body_type == http_body_buf && ctx->req.body.buf != NULL) {
|
||||||
free((void *)ctx->req.body);
|
free(ctx->req.body.buf);
|
||||||
ctx->req.body = NULL;
|
ctx->req.body.buf = NULL;
|
||||||
|
} else if (ctx->req.body_type == http_body_file &&
|
||||||
|
ctx->req.body.file != NULL) {
|
||||||
|
fclose(ctx->req.body.file);
|
||||||
|
ctx->req.body.file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->res.head != NULL) {
|
if (ctx->res.head != NULL) {
|
||||||
|
@ -36,15 +40,14 @@ void http_loop_ctx_reset(http_loop_ctx *ctx) {
|
||||||
ctx->res.head = NULL;
|
ctx->res.head = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->res.body != NULL) {
|
if (ctx->res.body_type == http_body_buf && ctx->res.body.buf != NULL) {
|
||||||
if (ctx->res.body_type == http_response_body_buf && ctx->res.owns_body) {
|
free(ctx->res.body.buf);
|
||||||
free((void *)ctx->res.body);
|
ctx->res.body.buf = NULL;
|
||||||
} else if (ctx->res.body_type == http_response_body_file) {
|
} else if (ctx->res.body_type == http_body_file &&
|
||||||
fclose(ctx->res.body);
|
ctx->res.body.file != NULL) {
|
||||||
|
fclose(ctx->res.body.file);
|
||||||
|
ctx->res.body.file = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ctx->res.body = NULL;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ctx->res.header_count; i++) {
|
for (size_t i = 0; i < ctx->res.header_count; i++) {
|
||||||
if (ctx->res.headers[i].owned) {
|
if (ctx->res.headers[i].owned) {
|
||||||
|
|
|
@ -81,15 +81,15 @@ void http_loop_write_response(event_loop_conn *conn) {
|
||||||
size_t bytes_written;
|
size_t bytes_written;
|
||||||
|
|
||||||
switch (res->body_type) {
|
switch (res->body_type) {
|
||||||
case http_response_body_buf:
|
case http_body_buf:
|
||||||
memcpy(&conn->wbuf[conn->wbuf_size],
|
memcpy(&conn->wbuf[conn->wbuf_size], &(res->body.buf)[res->body_written],
|
||||||
&((const char *)res->body)[res->body_written], bytes_to_write);
|
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;
|
||||||
case http_response_body_file:
|
case http_body_file:
|
||||||
bytes_written = fread(&conn->wbuf[conn->wbuf_size], sizeof(uint8_t),
|
bytes_written = fread(&conn->wbuf[conn->wbuf_size], sizeof(uint8_t),
|
||||||
bytes_to_write, res->body);
|
bytes_to_write, res->body.file);
|
||||||
conn->wbuf_size += bytes_written;
|
conn->wbuf_size += bytes_written;
|
||||||
res->body_written += bytes_written;
|
res->body_written += bytes_written;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body,
|
void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body,
|
||||||
size_t body_len, bool owned) {
|
size_t body_len, bool owned) {
|
||||||
ctx->res.body_type = http_response_body_buf;
|
ctx->res.body_type = http_body_buf;
|
||||||
ctx->res.body = (void *)body;
|
ctx->res.body.buf = (char *)body;
|
||||||
ctx->res.body_len = body_len;
|
ctx->res.body_len = body_len;
|
||||||
ctx->res.owns_body = owned;
|
ctx->res.owns_body = owned;
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename) {
|
||||||
// TODO error handling
|
// TODO error handling
|
||||||
FILE *f = fopen(filename, "r");
|
FILE *f = fopen(filename, "r");
|
||||||
|
|
||||||
ctx->res.body_type = http_response_body_file;
|
ctx->res.body_type = http_body_file;
|
||||||
ctx->res.body = f;
|
ctx->res.body.file = f;
|
||||||
ctx->res.body_len = st.st_size;
|
ctx->res.body_len = st.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,14 +85,15 @@ bool http_loop_step_body_to_buf(event_loop_conn *conn) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->req.body = malloc(ctx->req.body_len * sizeof(uint8_t));
|
ctx->req.body_type = http_body_buf;
|
||||||
|
ctx->req.body.buf = malloc(ctx->req.body_len * sizeof(uint8_t));
|
||||||
ctx->req.body_received = 0;
|
ctx->req.body_received = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytes_to_copy = MIN(conn->rbuf_size - conn->rbuf_read,
|
size_t bytes_to_copy = MIN(conn->rbuf_size - conn->rbuf_read,
|
||||||
ctx->req.body_len - ctx->req.body_received);
|
ctx->req.body_len - ctx->req.body_received);
|
||||||
memcpy(&ctx->req.body[ctx->req.body_received], &conn->rbuf[conn->rbuf_read],
|
memcpy(&ctx->req.body.buf[ctx->req.body_received],
|
||||||
bytes_to_copy);
|
&conn->rbuf[conn->rbuf_read], bytes_to_copy);
|
||||||
ctx->req.body_received += bytes_to_copy;
|
ctx->req.body_received += bytes_to_copy;
|
||||||
|
|
||||||
return ctx->req.body_received == ctx->req.body_len;
|
return ctx->req.body_received == ctx->req.body_len;
|
||||||
|
|
|
@ -2,51 +2,6 @@
|
||||||
|
|
||||||
#include "lander.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[] = {
|
http_route lander_routes[] = {
|
||||||
{.type = http_route_literal,
|
{.type = http_route_literal,
|
||||||
.method = http_get,
|
.method = http_get,
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ bool lander_post_redirect(event_loop_conn *conn) {
|
||||||
|
|
||||||
// Allocate a new buffer to pass to the trie
|
// Allocate a new buffer to pass to the trie
|
||||||
char *url = malloc(ctx->req.body_len + 1);
|
char *url = malloc(ctx->req.body_len + 1);
|
||||||
memcpy(url, ctx->req.body, ctx->req.body_len);
|
memcpy(url, ctx->req.body.buf, ctx->req.body_len);
|
||||||
url[ctx->req.body_len] = '\0';
|
url[ctx->req.body_len] = '\0';
|
||||||
|
|
||||||
char *key;
|
char *key;
|
||||||
|
|
Loading…
Reference in New Issue