feat: support serving files

c-web-server
Jef Roosens 2023-05-29 17:53:57 +02:00
parent 34ecb7eb40
commit 095f86ad72
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 54 additions and 16 deletions

View File

@ -126,12 +126,18 @@ 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 type; http_response_type type;
const char *head; const char *head;
size_t head_len; size_t head_len;
size_t head_written; size_t head_written;
const char *body; http_response_body_type body_type;
void *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

View File

@ -94,9 +94,11 @@ void http_loop_process_request(event_loop_conn *conn);
* Set the request body to the given buffer. If owned is set to true, the body * Set the request body to the given buffer. If owned is set to true, the body
* buffer will be free'd after the request has finished. * buffer will be free'd after the request has finished.
*/ */
void http_loop_res_set_body(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);
void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename);
void http_loop_res_add_header(http_loop_ctx *ctx, http_header type, void http_loop_res_add_header(http_loop_ctx *ctx, http_header type,
const char *value, bool owned); const char *value, bool owned);

View File

@ -1,3 +1,5 @@
#include <stdio.h>
#include "http.h" #include "http.h"
#include "http_loop.h" #include "http_loop.h"
@ -29,9 +31,15 @@ void http_loop_ctx_reset(http_loop_ctx *ctx) {
ctx->res.head = NULL; ctx->res.head = NULL;
} }
if (ctx->res.owns_body && ctx->res.body != NULL) { if (ctx->res.body != NULL) {
if (ctx->res.body_type == http_response_body_buf && ctx->res.owns_body) {
free((void *)ctx->res.body); free((void *)ctx->res.body);
} else if (ctx->res.body_type == http_response_body_file) {
fclose(ctx->res.body);
} }
}
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) {
@ -41,8 +49,6 @@ void http_loop_ctx_reset(http_loop_ctx *ctx) {
ctx->res.header_count = 0; ctx->res.header_count = 0;
ctx->res.body = NULL;
ctx->res.type = 0; ctx->res.type = 0;
ctx->res.head_len = 0; ctx->res.head_len = 0;
ctx->res.head_written = 0; ctx->res.head_written = 0;

View File

@ -1,4 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h>
#include "http_loop.h" #include "http_loop.h"
#include "log.h" #include "log.h"
@ -82,21 +83,45 @@ void http_loop_write_response(event_loop_conn *conn) {
if (res->body_written < res->body_len) { if (res->body_written < res->body_len) {
size_t bytes_to_write = MIN(res->body_len - res->body_written, size_t bytes_to_write = MIN(res->body_len - res->body_written,
EVENT_LOOP_BUFFER_SIZE - conn->wbuf_size); EVENT_LOOP_BUFFER_SIZE - conn->wbuf_size);
size_t bytes_written;
switch (res->body_type) {
case http_response_body_buf:
memcpy(&conn->wbuf[conn->wbuf_size], &res->body[res->body_written], memcpy(&conn->wbuf[conn->wbuf_size], &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;
case http_response_body_file:
bytes_written = fread(&conn->wbuf[conn->wbuf_size], sizeof(uint8_t),
bytes_to_write, res->body);
conn->wbuf_size += bytes_written;
res->body_written += bytes_written;
break;
}
} }
} }
void http_loop_res_set_body(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 = body; ctx->res.body_type = http_response_body_buf;
ctx->res.body = (void *)body;
ctx->res.body_len = body_len; ctx->res.body_len = body_len;
ctx->res.owns_body = owned; 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, void http_loop_res_add_header(http_loop_ctx *ctx, http_header type,
const char *value, bool owned) { const char *value, bool owned) {
ctx->res.headers[ctx->res.header_count].type = type; ctx->res.headers[ctx->res.header_count].type = type;

View File

@ -17,8 +17,7 @@ const char index_page[] =
bool lander_get_index(event_loop_conn *conn) { bool lander_get_index(event_loop_conn *conn) {
http_loop_ctx *ctx = conn->ctx; http_loop_ctx *ctx = conn->ctx;
http_loop_res_set_body(ctx, index_page, sizeof(index_page) - 1, false); http_loop_res_set_body_file(ctx, "Dockerfile");
http_loop_res_add_header(ctx, http_header_connection, "close", false);
conn->state = event_loop_conn_state_res; conn->state = event_loop_conn_state_res;