feat(http): add custom processing to responses using response steps
This commit is contained in:
parent
6d74c8c550
commit
afd18d3a37
7 changed files with 128 additions and 66 deletions
|
|
@ -54,7 +54,7 @@ event_loop *http_loop_init(http_route *routes, size_t route_count,
|
|||
el->ctx_init = (void *(*)(void *))http_loop_ctx_init;
|
||||
el->ctx_free = (void (*)(void *))http_loop_ctx_free;
|
||||
el->handle_data = http_loop_handle_request;
|
||||
el->write_data = http_loop_write_response;
|
||||
el->write_data = http_loop_handle_response;
|
||||
|
||||
http_loop_gctx *gctx = http_loop_gctx_init();
|
||||
gctx->c = custom_gctx;
|
||||
|
|
|
|||
|
|
@ -138,13 +138,11 @@ void http_loop_process_request(event_loop_conn *conn) {
|
|||
ctx->current_step++;
|
||||
}
|
||||
|
||||
if (conn->state != event_loop_conn_state_req) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've reached the end of the list of step functions, we report the
|
||||
// request as finished by clearing its route
|
||||
if (ctx->route->steps[ctx->current_step] == NULL) {
|
||||
http_loop_ctx_reset(ctx);
|
||||
// Request processing can stop early by switching the connection state
|
||||
// Either way, we reset the step counter as it will be used by the response
|
||||
// steps
|
||||
if ((conn->state != event_loop_conn_state_req) ||
|
||||
(ctx->route->steps[ctx->current_step] == NULL)) {
|
||||
ctx->current_step = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ void http_loop_init_header(http_response *res) {
|
|||
res->head_len = buf_size + 1;
|
||||
}
|
||||
|
||||
void http_loop_write_response(event_loop_conn *conn) {
|
||||
bool http_loop_step_write_header(event_loop_conn *conn) {
|
||||
http_response *res = &((http_loop_ctx *)conn->ctx)->res;
|
||||
|
||||
// Create head response
|
||||
|
|
@ -56,43 +56,68 @@ void http_loop_write_response(event_loop_conn *conn) {
|
|||
http_loop_init_header(res);
|
||||
}
|
||||
|
||||
// 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.expected_len == res->body.len) {
|
||||
http_loop_ctx_reset(conn->ctx);
|
||||
conn->state = event_loop_conn_state_req;
|
||||
return;
|
||||
// Step has finished its work
|
||||
if (res->head_written == res->head_len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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],
|
||||
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;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool http_loop_step_write_body(event_loop_conn *conn) {
|
||||
http_response *res = &((http_loop_ctx *)conn->ctx)->res;
|
||||
|
||||
if (res->body.expected_len == res->body.len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t bytes_to_write = MIN(res->body.expected_len - res->body.len,
|
||||
EVENT_LOOP_BUFFER_SIZE - conn->wbuf_size);
|
||||
|
||||
size_t bytes_written;
|
||||
|
||||
switch (res->body.type) {
|
||||
case http_body_buf:
|
||||
memcpy(&conn->wbuf[conn->wbuf_size], &(res->body.buf)[res->body.len],
|
||||
bytes_to_write);
|
||||
|
||||
conn->wbuf_size += bytes_to_write;
|
||||
res->head_written += bytes_to_write;
|
||||
res->body.len += bytes_to_write;
|
||||
break;
|
||||
case http_body_file:
|
||||
bytes_written = fread(&conn->wbuf[conn->wbuf_size], sizeof(uint8_t),
|
||||
bytes_to_write, res->body.file);
|
||||
conn->wbuf_size += bytes_written;
|
||||
res->body.len += bytes_written;
|
||||
break;
|
||||
}
|
||||
|
||||
if (res->body.len < res->body.expected_len) {
|
||||
size_t bytes_to_write = MIN(res->body.expected_len - res->body.len,
|
||||
EVENT_LOOP_BUFFER_SIZE - conn->wbuf_size);
|
||||
size_t bytes_written;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (res->body.type) {
|
||||
case http_body_buf:
|
||||
memcpy(&conn->wbuf[conn->wbuf_size], &(res->body.buf)[res->body.len],
|
||||
bytes_to_write);
|
||||
conn->wbuf_size += bytes_to_write;
|
||||
res->body.len += bytes_to_write;
|
||||
break;
|
||||
case http_body_file:
|
||||
bytes_written = fread(&conn->wbuf[conn->wbuf_size], sizeof(uint8_t),
|
||||
bytes_to_write, res->body.file);
|
||||
conn->wbuf_size += bytes_written;
|
||||
res->body.len += bytes_written;
|
||||
break;
|
||||
}
|
||||
void http_loop_handle_response(event_loop_conn *conn) {
|
||||
http_loop_ctx *ctx = conn->ctx;
|
||||
|
||||
while ((conn->state == event_loop_conn_state_res) &&
|
||||
(ctx->route->steps_res[ctx->current_step] != NULL) &&
|
||||
ctx->route->steps_res[ctx->current_step](conn)) {
|
||||
ctx->current_step++;
|
||||
}
|
||||
|
||||
// Response processing can stop early be switching the connection state
|
||||
// After response processing has finished its work, we reset the context to
|
||||
// prepare for a new request
|
||||
if ((conn->state != event_loop_conn_state_res) ||
|
||||
(ctx->route->steps_res[ctx->current_step] == NULL)) {
|
||||
http_loop_ctx_reset(ctx);
|
||||
|
||||
conn->state = event_loop_conn_state_req;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,21 +6,33 @@ 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}},
|
||||
{.type = http_route_regex,
|
||||
.method = http_post,
|
||||
.path = "^/s(l?)/([^/]*)$",
|
||||
.steps = {http_loop_step_auth, http_loop_step_body_to_buf,
|
||||
lander_post_redirect, NULL}},
|
||||
.steps = {lander_get_index, NULL},
|
||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||
NULL}},
|
||||
{
|
||||
.type = http_route_regex,
|
||||
.method = http_get,
|
||||
.path = "^/([^/]+)$",
|
||||
.steps = {lander_get_entry, NULL},
|
||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||
NULL},
|
||||
},
|
||||
{
|
||||
.type = http_route_regex,
|
||||
.method = http_post,
|
||||
.path = "^/s(l?)/([^/]*)$",
|
||||
.steps = {http_loop_step_auth, http_loop_step_body_to_buf,
|
||||
lander_post_redirect, NULL},
|
||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||
NULL},
|
||||
},
|
||||
{.type = http_route_regex,
|
||||
.method = http_post,
|
||||
.path = "^/p(l?)/([^/]*)$",
|
||||
.steps = {http_loop_step_auth, lander_post_paste,
|
||||
http_loop_step_body_to_file, http_loop_step_switch_res, NULL}},
|
||||
http_loop_step_body_to_file, http_loop_step_switch_res, NULL},
|
||||
.steps_res = {http_loop_step_write_header, http_loop_step_write_body,
|
||||
NULL}},
|
||||
};
|
||||
|
||||
void *lander_gctx_init() { return calloc(1, sizeof(lander_gctx)); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue