Files
ToastyFS/web/src/proxy_get.c
T
2025-12-03 00:03:44 +01:00

123 lines
4.2 KiB
C

#include "proxy_get.h"
static bool path_refers_to_dir(ToastyString path)
{
return path.len > 0 && path.ptr[path.len-1] == '/';
}
bool process_request_get(ProxyState *state, ProxyOperation *operation,
HTTP_Request *request, HTTP_ResponseBuilder builder)
{
assert(request->method == HTTP_METHOD_GET
|| request->method == HTTP_METHOD_HEAD);
http_response_builder_status(builder, 200); // OK
http_response_builder_body_cap(builder, 1<<10); // TODO: pick the prealloc better
int cap;
char *dst = http_response_builder_body_buf(builder, &cap);
// TODO: check for NULL dst
ToastyString path = {
request->url.path.ptr,
request->url.path.len
};
ToastyHandle handle;
if (path_refers_to_dir(path)) {
handle = toasty_begin_list(state->backend, path,
TOASTY_VERSION_TAG_EMPTY);
} else {
handle = toasty_begin_read(state->backend, path,
0, dst, cap, TOASTY_VERSION_TAG_EMPTY);
}
if (handle == TOASTY_INVALID) {
http_response_builder_status(builder, 500); // Internal Server Error
http_response_builder_send(builder);
return false;
}
toasty_set_user(state->backend, handle, operation);
operation->type = path_refers_to_dir(path) ? PO_READ_DIR : PO_READ_FILE;
operation->request = request;
operation->builder = builder;
operation->handle = handle;
operation->head_only = (request->method == HTTP_METHOD_HEAD);
operation->transferred = 0;
return true;
}
bool process_request_head(ProxyState *state, ProxyOperation *operation,
HTTP_Request *request, HTTP_ResponseBuilder builder)
{
return process_request_get(state, operation, request, builder);
}
bool process_completion_read_dir(ProxyState *state,
ProxyOperation *operation, ToastyResult completion)
{
if (completion.type == TOASTY_RESULT_LIST_SUCCESS) {
http_response_builder_status(operation->builder, 200);
for (int i = 0; i < completion.listing.count; i++)
http_response_builder_body(operation->builder, (HTTP_String) {
completion.listing.items[i].name, strlen(completion.listing.items[i].name),
});
http_response_builder_send(operation->builder);
toasty_free_listing(&completion.listing);
} else {
// TODO: Should differentiate between error conditions
http_response_builder_status(operation->builder, 500); // Internal Server Error
http_response_builder_send(operation->builder);
}
return true;
}
bool process_completion_read_file(ProxyState *state,
ProxyOperation *operation, ToastyResult completion)
{
bool again = false;
if (completion.type != TOASTY_RESULT_READ_SUCCESS) {
http_response_builder_body_ack(operation->builder, 0);
http_response_builder_status(operation->builder, 500);
http_response_builder_send(operation->builder);
} else {
// First, ACK the byte we just read, even if it's
// just 0 bytes (every bodybuf must by paired with
// a bodyack).
operation->transferred += completion.bytes_read;
int ack = operation->head_only ? 0 : completion.bytes_read;
http_response_builder_body_ack(operation->builder, ack);
// If we didn't reach the end of the file, start
// a new read.
if (completion.bytes_read > 0) {
// Make sure there is some free space in the buffer
int mincap = 1<<10; // TODO: Choose based on overall file size
http_response_builder_body_cap(operation->builder, mincap);
// Get the location of that buffer
int cap;
char *dst = http_response_builder_body_buf(operation->builder, &cap);
if (dst == NULL) {
assert(0); // TODO
}
ToastyString path = {
operation->request->url.path.ptr,
operation->request->url.path.len,
};
operation->handle = toasty_begin_read(state->backend, path,
operation->transferred, dst, cap, TOASTY_VERSION_TAG_EMPTY);
if (operation->handle == TOASTY_INVALID) {
assert(0); // TODO
}
again = true;
}
}
return !again;
}