2023-05-29 11:36:57 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "http_loop.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
|
|
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
|
|
|
|
2023-05-29 12:03:40 +02:00
|
|
|
static const char *http_response_format = "HTTP/1.1 %i %s\n"
|
2023-05-29 14:48:50 +02:00
|
|
|
"Server: lander/" LANDER_VERSION "\n"
|
2023-05-29 12:03:40 +02:00
|
|
|
"Content-Length: %lu\n\n";
|
|
|
|
|
|
|
|
void http_loop_init_header(http_response *res) {
|
2023-05-29 12:43:50 +02:00
|
|
|
if (res->type == 0) {
|
|
|
|
res->type = http_ok;
|
|
|
|
}
|
|
|
|
|
2023-05-29 12:03:40 +02:00
|
|
|
const char *response_type_name =
|
|
|
|
http_response_type_names[res->type / 100 - 1][res->type % 100];
|
|
|
|
|
|
|
|
// Running snprintf with size 0 prevents it from writing any bytes, while
|
|
|
|
// still letting it calculate how many bytes it would have written
|
|
|
|
int buf_size = snprintf(NULL, 0, http_response_format, res->type,
|
|
|
|
response_type_name, res->body_len);
|
|
|
|
char *buf = malloc(buf_size + 1);
|
|
|
|
sprintf(buf, http_response_format, res->type, response_type_name,
|
|
|
|
res->body_len);
|
|
|
|
|
|
|
|
res->head = buf;
|
|
|
|
res->head_len = buf_size;
|
|
|
|
}
|
|
|
|
|
2023-05-29 11:36:57 +02:00
|
|
|
void http_loop_write_response(event_loop_conn *conn) {
|
|
|
|
http_response *res = &((http_loop_ctx *)conn->ctx)->res;
|
|
|
|
|
|
|
|
// Create head response
|
|
|
|
if (res->head == NULL) {
|
2023-05-29 12:03:40 +02:00
|
|
|
http_loop_init_header(res);
|
2023-05-29 11:36:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// The final iteration marks the end of the response, after which we reset the
|
|
|
|
// context so a next request can be processed
|
|
|
|
if (res->head_written == res->head_len &&
|
|
|
|
res->body_written == res->body_len) {
|
|
|
|
http_loop_ctx_reset(conn->ctx);
|
|
|
|
conn->state = event_loop_conn_state_req;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res->head_written < res->head_len) {
|
|
|
|
size_t bytes_to_write = MIN(res->head_len - res->head_written,
|
|
|
|
EVENT_LOOP_BUFFER_SIZE - conn->wbuf_size);
|
|
|
|
memcpy(&conn->wbuf[conn->wbuf_size], &res->head[res->head_written],
|
|
|
|
bytes_to_write);
|
|
|
|
|
|
|
|
conn->wbuf_size += bytes_to_write;
|
|
|
|
res->head_written += bytes_to_write;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res->body_written < res->body_len) {
|
|
|
|
size_t bytes_to_write = MIN(res->body_len - res->body_written,
|
|
|
|
EVENT_LOOP_BUFFER_SIZE - conn->wbuf_size);
|
|
|
|
memcpy(&conn->wbuf[conn->wbuf_size], &res->body[res->body_written],
|
|
|
|
bytes_to_write);
|
|
|
|
|
|
|
|
conn->wbuf_size += bytes_to_write;
|
|
|
|
res->body_written += bytes_to_write;
|
|
|
|
}
|
|
|
|
}
|
2023-05-29 12:43:50 +02:00
|
|
|
|
|
|
|
void http_loop_res_set_body(http_loop_ctx *ctx, const char *body,
|
|
|
|
size_t body_len, bool owned) {
|
|
|
|
ctx->res.body = body;
|
|
|
|
ctx->res.body_len = body_len;
|
|
|
|
ctx->res.owns_body = owned;
|
|
|
|
}
|