Web/context.c
2025-09-15 12:57:54 -05:00

146 lines
3.5 KiB
C

#include "context.h"
#include <string.h>
#include <stdio.h>
// context_new creates a new context for a connection.
context_t* context_new(conn_t *conn) {
// Use connection's arena for all allocations
arena_t *arena = conn->arena;
context_t *ctx = arena_alloc(arena, sizeof(context_t));
if (!ctx) return NULL;
ctx->conn = conn;
ctx->arena = arena;
ctx->data = NULL;
// Create request
ctx->request = request_new(arena);
if (!ctx->request) return NULL;
// Parse request from connection buffer
if (request_parse(ctx->request, conn->rbuf, conn->rlen) < 0) {
return NULL;
}
// Create response
ctx->response = response_new();
if (!ctx->response) return NULL;
return ctx;
}
// context_free frees the context.
void context_free(context_t *ctx) {
if (!ctx) return;
// Response is malloced separately
response_free(ctx->response);
// Everything else is in arena and will be freed with connection
}
// context_set stores data in context.
void context_set(context_t *ctx, const char *key, void *value) {
context_data_t *d = arena_alloc(ctx->arena, sizeof(context_data_t));
if (!d) return;
d->key = arena_strdup(ctx->arena, key, strlen(key));
d->value = value;
d->next = ctx->data;
ctx->data = d;
}
// context_get retrieves data from context.
void* context_get(context_t *ctx, const char *key) {
context_data_t *d = ctx->data;
while (d) {
if (strcmp(d->key, key) == 0) {
return d->value;
}
d = d->next;
}
return NULL;
}
// Request helpers
const char* ctx_param(context_t *ctx, const char *name) {
return request_param(ctx->request, name);
}
const char* ctx_query(context_t *ctx, const char *name) {
return request_query(ctx->request, name);
}
const char* ctx_header(context_t *ctx, const char *name) {
return request_header(ctx->request, name);
}
const char* ctx_cookie(context_t *ctx, const char *name) {
return request_cookie(ctx->request, name);
}
const char* ctx_body(context_t *ctx) {
return request_body(ctx->request);
}
// Response helpers
void ctx_status(context_t *ctx, int code) {
response_status(ctx->response, code);
}
void ctx_header_set(context_t *ctx, const char *name, const char *value) {
response_header(ctx->response, name, value);
}
// ctx_text sends plain text response.
void ctx_text(context_t *ctx, int status, const char *text) {
response_text(ctx->response, status, text);
ctx_send(ctx);
}
// ctx_html sends HTML response.
void ctx_html(context_t *ctx, int status, const char *html) {
response_html(ctx->response, status, html);
ctx_send(ctx);
}
// ctx_json sends JSON response.
void ctx_json(context_t *ctx, int status, const char *json) {
response_json(ctx->response, status, json);
ctx_send(ctx);
}
// ctx_redirect sends redirect response.
void ctx_redirect(context_t *ctx, const char *url) {
response_redirect(ctx->response, url, 302);
ctx_send(ctx);
}
// ctx_error sends error response.
void ctx_error(context_t *ctx, int status, const char *message) {
// Check if client expects JSON
if (request_expects_json(ctx->request)) {
char json[256];
snprintf(json, sizeof(json), "{\"error\":\"%s\"}",
message ? message : "Unknown error");
response_json(ctx->response, status, json);
} else {
response_text(ctx->response, status,
message ? message : "Error");
}
ctx_send(ctx);
}
// ctx_send sends the response to client.
int ctx_send(context_t *ctx) {
conn_t *c = ctx->conn;
// Serialize response to connection write buffer
c->wlen = response_serialize(ctx->response, c->wbuf, c->wsize);
c->wpos = 0;
return 0;
}