Update cHTTP and rewrite web/main.c
This commit is contained in:
@@ -17,7 +17,7 @@ OFILES = $(CFILES:.c=.o)
|
||||
|
||||
.PHONY: all clean coverage coverage-report coverage-html
|
||||
|
||||
all: toastyfs$(EXT) toastyfs_random_test$(EXT) example_async_api$(EXT) example_blocking_api$(EXT) libtoastyfs.a
|
||||
all: toastyfs$(EXT) toastyfs_web$(EXT) toastyfs_random_test$(EXT) example_async_api$(EXT) example_blocking_api$(EXT) libtoastyfs.a
|
||||
|
||||
coverage: toastyfs_random_test_coverage$(EXT)
|
||||
|
||||
@@ -42,6 +42,9 @@ example_async_api$(EXT): libtoastyfs.a examples/async_api.c
|
||||
example_blocking_api$(EXT): libtoastyfs.a examples/blocking_api.c
|
||||
gcc -o $@ examples/blocking_api.c $(CFLAGS) -ltoastyfs $(LFLAGS) -Iinc -L.
|
||||
|
||||
toastyfs_web$(EXT): libtoastyfs.a web/main.c web/chttp.c web/chttp.h
|
||||
gcc -o $@ web/main.c web/chttp.c $(CFLAGS) -ltoastyfs $(LFLAGS) -Iinc -L.
|
||||
|
||||
%.o: %.c $(HFILES)
|
||||
gcc -c -o $@ $< $(CFLAGS) -Iinc
|
||||
|
||||
|
||||
+2572
-3314
File diff suppressed because it is too large
Load Diff
+930
-273
File diff suppressed because it is too large
Load Diff
+296
-271
@@ -1,24 +1,37 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <chttp.h>
|
||||
#include <ToastyFS.h>
|
||||
|
||||
#define MAX_WAITING (1<<10)
|
||||
#define MAX_PENDING (1<<9)
|
||||
#include "chttp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define POLL WSAPoll
|
||||
#else
|
||||
#define POLL poll
|
||||
#endif
|
||||
|
||||
#define UNREACHABLE __builtin_trap()
|
||||
|
||||
typedef enum {
|
||||
OPERATION_FREE,
|
||||
OPERATION_CREATE_DIR,
|
||||
OPERATION_CREATE_FILE,
|
||||
OPERATION_DELETE,
|
||||
OPERATION_READ_DIR,
|
||||
OPERATION_READ_FILE,
|
||||
OPERATION_WRITE,
|
||||
} OperationType;
|
||||
PROXIED_OPERATION_FREE,
|
||||
PROXIED_OPERATION_CREATE_DIR,
|
||||
PROXIED_OPERATION_CREATE_FILE,
|
||||
PROXIED_OPERATION_DELETE,
|
||||
PROXIED_OPERATION_READ_DIR,
|
||||
PROXIED_OPERATION_READ_FILE,
|
||||
PROXIED_OPERATION_WRITE,
|
||||
} ProxiedOperationType;
|
||||
|
||||
typedef struct {
|
||||
OperationType type;
|
||||
ProxiedOperationType type;
|
||||
|
||||
// Don't write the content to the response
|
||||
// when reading a file or directory.
|
||||
bool head_only;
|
||||
|
||||
// Offset of the read/write
|
||||
int offset;
|
||||
|
||||
// Length of the read/write
|
||||
int length;
|
||||
|
||||
// Number of bytes read/written
|
||||
int transferred;
|
||||
@@ -27,291 +40,303 @@ typedef struct {
|
||||
HTTP_ResponseBuilder builder;
|
||||
|
||||
ToastyHandle handle;
|
||||
} Operation;
|
||||
|
||||
static int waiting_head;
|
||||
static int num_waiting;
|
||||
static int num_pending;
|
||||
static Operation waiting[MAX_WAITING];
|
||||
static Operation pending[MAX_PENDING];
|
||||
} ProxiedOperation;
|
||||
|
||||
void worker(Worker *w)
|
||||
#define MAX_PROXIED_OPERATIONS (1<<10)
|
||||
|
||||
static int find_unused_struct(ProxiedOperation *arr, int num)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
ToastyResult result;
|
||||
int ret = toasty_wait_result(toasty, TOASTY_INVALID, &result, -1);
|
||||
// TODO: check return value
|
||||
|
||||
// First, process completed requests. This frees up
|
||||
// space for new ones.
|
||||
//
|
||||
// TODO: What if there was a WAKEUP request and no pending operations
|
||||
// are present?
|
||||
|
||||
int i = 0;
|
||||
while (pending[i].handle != result.handle) {
|
||||
i++;
|
||||
assert(i < MAX_PENDING_OPERATIONS);
|
||||
}
|
||||
|
||||
bool incomplete = false;
|
||||
switch (pending[i].type) {
|
||||
|
||||
int cap;
|
||||
int mincap;
|
||||
char *dst;
|
||||
ToastyString path;
|
||||
|
||||
case OPERATION_CREATE_DIR:
|
||||
case OPERATION_CREATE_FILE:
|
||||
if (result.type == TOASTY_RESULT_CREATE_SUCCESS) {
|
||||
http_response_builder_status(pending[i].builder, 204); // TODO: What is the proper response to a CREATE request?
|
||||
http_response_builder_done(pending[i].builder);
|
||||
} else {
|
||||
http_response_builder_undo(pending[i].builder);
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPERATION_DELETE:
|
||||
if (result.type == TOASTY_RESULT_DELETE_SUCCESS) {
|
||||
http_response_builder_status(pending[i].builder, 204); // TODO: What is the proper response to a DELETE request?
|
||||
http_response_builder_done(pending[i].builder);
|
||||
} else {
|
||||
http_response_builder_undo(pending[i].builder);
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPERATION_READ_DIR:
|
||||
|
||||
// If the listing failed, abort the request
|
||||
if (result.type != TOASTY_RESULT_READ_SUCCESS) {
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
break;
|
||||
}
|
||||
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
for (int i = 0; i < result.listing.count; i++)
|
||||
http_response_builder_body(pending[i].builder, (HTTP_String) {
|
||||
result.listing.items[i].name,
|
||||
result.listing.items[i].name_len
|
||||
});
|
||||
http_response_builder_done(pending[i].builder);
|
||||
|
||||
toasty_free_listing(&result.listing);
|
||||
break;
|
||||
|
||||
case OPERATION_READ_FILE:
|
||||
|
||||
// If the read failed, abort the request
|
||||
if (result.type != TOASTY_RESULT_READ_SUCCESS) {
|
||||
http_response_builder_bodyack(pending[i].builder, 0);
|
||||
http_response_builder_undo(pending[i].builder);
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
break;
|
||||
}
|
||||
|
||||
// First, ACK the byte we just read, even if it's
|
||||
// just 0 bytes (every bodybuf must by paired with
|
||||
// a bodyack).
|
||||
http_response_builder_bodyack(pending[i].builder, result.count);
|
||||
pending[i].transferred += result.count;
|
||||
|
||||
// If we read 0 bytes, there is no more to read.
|
||||
if (result.count == 0) {
|
||||
http_response_builder_done(pending[i].builder);
|
||||
break;
|
||||
}
|
||||
|
||||
// There is more to read, so we need to start a
|
||||
// new read.
|
||||
|
||||
// Make sure there is some free space in the buffer
|
||||
mincap = 1<<10; // TODO: Choose based on overall file size
|
||||
http_response_builder_bodycap(pending[i].builder, mincap);
|
||||
|
||||
// Get the location of that buffer
|
||||
dst = http_response_builder_bodybuf(pending[i].builder, &cap);
|
||||
if (dst == NULL) {
|
||||
http_response_builder_done(pending[i].builder);
|
||||
break;
|
||||
}
|
||||
|
||||
// Begin the read. On error, abort.
|
||||
path = (ToastyString) { pending[i].request->path.ptr, pending[i].request.path.len };
|
||||
pending[i].handle = toasty_begin_read(toasty, path, off, dst, cap);
|
||||
if (pending[i].handle == TOASTY_INVALID) {
|
||||
http_response_builder_undo(pending[i].builder);
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
break;
|
||||
}
|
||||
|
||||
// Most of the time this switch will complete the pending
|
||||
// operation, but not for reads.
|
||||
incomplete = true;
|
||||
break;
|
||||
|
||||
case OPERATION_WRITE:
|
||||
if (pending[i].type != TOASTY_RESULT_WRITE_SUCCESS) {
|
||||
http_response_builder_undo(pending[i].builder);
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
break;
|
||||
}
|
||||
assert(pending[i].transferred == result.count);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // TODO
|
||||
}
|
||||
|
||||
if (!incomplete) {
|
||||
// Free the pending structure
|
||||
pending[i].type = OPERATION_FREE;
|
||||
num_pending--;
|
||||
}
|
||||
|
||||
// Now accept operations
|
||||
for (Operation req; num_pending < MAX_PENDING_OPERATIONS
|
||||
&& wait_queue_pop(&wait_queue, &req); ) {
|
||||
|
||||
int i = 0;
|
||||
while (pending[i].type != PENDING_OPERATION_FREE) {
|
||||
i++;
|
||||
assert(i < MAX_PENDING_OPERATIONS);
|
||||
}
|
||||
pending[i] = req;
|
||||
|
||||
ToastyString path = { pending[i].request->path.ptr, pending[i].request.path.len };
|
||||
ToastyString body = { pending[i].request->body.ptr, pending[i].request.body.len };
|
||||
switch (pending[i].type) {
|
||||
int cap;
|
||||
int mincap;
|
||||
char *dst;
|
||||
uint32_t chunk_size;
|
||||
case OPERATION_CREATE_DIR,
|
||||
pending[i].handle = toasty_begin_create_dir(toasty, path);
|
||||
break;
|
||||
case OPERATION_CREATE_FILE,
|
||||
chunk_size = 1<<10; // TODO: determine a better chunk size
|
||||
pending[i].handle = toasty_begin_create_file(toasty, path, chunk_size);
|
||||
break;
|
||||
case OPERATION_DELETE,
|
||||
pending[i].handle = toasty_begin_delete(toasty, path);
|
||||
break;
|
||||
case OPERATION_READ,
|
||||
http_response_builder_status(pending[i].builder, 200); // TODO: Is statis 200 correct?
|
||||
|
||||
mincap = 1<<10; // TODO: do something smart to choose this
|
||||
http_response_builder_bodycap(pending[i].builder, mincap);
|
||||
|
||||
dst = http_response_builder_bodybuf(pending[i].builder, &cap);
|
||||
if (dst == NULL)
|
||||
break;
|
||||
|
||||
pending[i].handle = toasty_begin_read(toasty, path, off, dst, cap);
|
||||
pending[i].transferred = 0;
|
||||
break;
|
||||
case OPERATION_WRITE:
|
||||
pending[i].handle = toasty_begin_write(toasty, body.ptr, body.len);
|
||||
pending[i].transferred = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pending[i].handle == TOASTY_INVALID) {
|
||||
http_response_builder_undo(pending[i].builder);
|
||||
http_response_builder_status(pending[i].builder, 500);
|
||||
http_response_builder_done(pending[i].builder);
|
||||
pending[i].type = OPERATION_FREE;
|
||||
}
|
||||
num_pending++;
|
||||
}
|
||||
if (num == MAX_PROXIED_OPERATIONS)
|
||||
return -1;
|
||||
int i = 0;
|
||||
while (arr[i].type != PROXIED_OPERATION_FREE) {
|
||||
i++;
|
||||
assert(i < MAX_PROXIED_OPERATIONS);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
http_global_init();
|
||||
ToastyString upstream_addr = TOASTY_STR("127.0.0.1");
|
||||
uint16_t upstream_port = 9000;
|
||||
|
||||
HTTP_String addr = HTTP_STR("127.0.0.1");
|
||||
uint16_t port = 8080;
|
||||
HTTP_String local_addr = HTTP_STR("127.0.0.1");
|
||||
uint16_t local_port = 8080;
|
||||
|
||||
ToastyString backend_addr = TOASTY_STR("127.0.0.1");
|
||||
uint16_t backend_port = 9000;
|
||||
|
||||
HTTP_Server *server = http_server_init(addr, port);
|
||||
if (server == NULL)
|
||||
return -1;
|
||||
|
||||
ToastyFS *toasty = toasty_connect(backend_addr, backend_port);
|
||||
ToastyFS *toasty = toasty_connect(upstream_addr, upstream_port);
|
||||
if (toasty == NULL)
|
||||
return -1;
|
||||
|
||||
HTTP_Server server;
|
||||
if (http_server_init(&server) < 0)
|
||||
return -1;
|
||||
|
||||
http_server_set_reuse_addr(&server, true);
|
||||
http_server_set_trace_bytes(&server, true);
|
||||
|
||||
if (http_server_listen_tcp(&server, local_addr, local_port) < 0)
|
||||
return -1;
|
||||
|
||||
int num_proxied = 0;
|
||||
ProxiedOperation proxied[MAX_PROXIED_OPERATIONS];
|
||||
|
||||
for (;;) {
|
||||
|
||||
#define HTTP_SERVER_POLL_CAPACITY (HTTP_SERVER_CAPACITY+3)
|
||||
#define TOASTY_POLL_CAPACITY (MAX_CONNS+1)
|
||||
|
||||
#define POLL_CAPACITY (HTTP_SERVER_POLL_CAPACITY + TOASTY_POLL_CAPACITY)
|
||||
|
||||
EventRegister reg;
|
||||
void *ptrs[POLL_CAPACITY];
|
||||
struct pollfd polled[POLL_CAPACITY];
|
||||
|
||||
void **http_ptrs = ptrs;
|
||||
struct pollfd *http_polled = polled;
|
||||
|
||||
reg = (EventRegister) {
|
||||
ptrs,
|
||||
polled,
|
||||
POLL_CAPACITY,
|
||||
0
|
||||
};
|
||||
if (http_server_register_events(&server, ®) < 0)
|
||||
return -1;
|
||||
int num_http_polled = reg.num_polled;
|
||||
|
||||
void **toasty_ptrs = ptrs + num_http_polled;
|
||||
struct pollfd *toasty_polled = polled + num_http_polled;
|
||||
int num_toasty_polled = toasty_process_events(toasty, toasty_ptrs, toasty_polled, 0);
|
||||
if (num_toasty_polled < 0)
|
||||
return -1;
|
||||
|
||||
int num_polled = num_http_polled + num_toasty_polled;
|
||||
if (num_polled > 0)
|
||||
POLL(polled, num_polled, -1);
|
||||
|
||||
// First, process toasty events so that we free space
|
||||
// for incoming requests
|
||||
|
||||
if (toasty_process_events(toasty, toasty_ptrs, toasty_polled, num_toasty_polled) < 0)
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
|
||||
ToastyResult result;
|
||||
int ret = toasty_get_result(toasty, TOASTY_INVALID, &result);
|
||||
|
||||
if (ret == 1)
|
||||
break; // No completion
|
||||
|
||||
if (ret < 0)
|
||||
return -1; // Error
|
||||
|
||||
// Completed
|
||||
assert(ret == 0);
|
||||
|
||||
// Find the operation associated to this completion
|
||||
int i = 0;
|
||||
while (proxied[i].handle != result.handle) {
|
||||
i++;
|
||||
assert(i < MAX_PROXIED_OPERATIONS);
|
||||
}
|
||||
|
||||
switch (proxied[i].type) {
|
||||
case PROXIED_OPERATION_CREATE_DIR:
|
||||
case PROXIED_OPERATION_CREATE_FILE:
|
||||
{
|
||||
if (result.type == TOASTY_RESULT_CREATE_SUCCESS) {
|
||||
http_response_builder_status(proxied[i].builder, 201); // Created
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
} else {
|
||||
// TODO: Should differentiate between error conditions
|
||||
http_response_builder_status(proxied[i].builder, 500); // Internal Server Error
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
}
|
||||
proxied[i].type = PROXIED_OPERATION_FREE;
|
||||
num_proxied--;
|
||||
}
|
||||
break;
|
||||
case PROXIED_OPERATION_DELETE:
|
||||
{
|
||||
if (result.type == TOASTY_RESULT_DELETE_SUCCESS) {
|
||||
http_response_builder_status(proxied[i].builder, 204); // No Content
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
} else {
|
||||
// TODO: Should differentiate between error conditions
|
||||
http_response_builder_status(proxied[i].builder, 500); // Internal Server Error
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
}
|
||||
proxied[i].type = PROXIED_OPERATION_FREE;
|
||||
num_proxied--;
|
||||
}
|
||||
break;
|
||||
case PROXIED_OPERATION_READ_DIR:
|
||||
{
|
||||
if (result.type == TOASTY_RESULT_LIST_SUCCESS) {
|
||||
http_response_builder_status(proxied[i].builder, 200);
|
||||
for (int i = 0; i < result.listing.count; i++)
|
||||
http_response_builder_body(proxied[i].builder, (HTTP_String) {
|
||||
result.listing.items[i].name,
|
||||
result.listing.items[i].name_len
|
||||
});
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
toasty_free_listing(&result.listing);
|
||||
} else {
|
||||
// TODO: Should differentiate between error conditions
|
||||
http_response_builder_status(proxied[i].builder, 500); // Internal Server Error
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
}
|
||||
proxied[i].type = PROXIED_OPERATION_FREE;
|
||||
num_proxied--;
|
||||
}
|
||||
break;
|
||||
case PROXIED_OPERATION_READ_FILE:
|
||||
{
|
||||
bool again = false;
|
||||
if (result.type != TOASTY_RESULT_READ_SUCCESS) {
|
||||
http_response_builder_bodyack(proxied[i].builder, 0);
|
||||
http_response_builder_status(proxied[i].builder, 500);
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
} else {
|
||||
|
||||
// First, ACK the byte we just read, even if it's
|
||||
// just 0 bytes (every bodybuf must by paired with
|
||||
// a bodyack).
|
||||
proxied[i].transferred += result.count;
|
||||
int ack = proxied[i].head_only ? 0 : result.count;
|
||||
http_response_builder_bodyack(proxied[i].builder, ack);
|
||||
|
||||
// If we didn't reach the end of the file, start
|
||||
// a new read.
|
||||
if (result.count > 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_bodycap(proxied[i].builder, mincap);
|
||||
|
||||
// Get the location of that buffer
|
||||
int cap;
|
||||
char *dst = http_response_builder_bodybuf(proxied[i].builder, &cap);
|
||||
if (dst == NULL) {
|
||||
assert(0); // TODO
|
||||
}
|
||||
|
||||
proxied[i].handle = toasty_begin_read(toasty, path, off, dst, cap);
|
||||
if (proxied[i].handle == TOASTY_INVALID) {
|
||||
assert(0); // TODO
|
||||
}
|
||||
|
||||
again = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!again) {
|
||||
proxied[i].type = PROXIED_OPERATION_FREE;
|
||||
num_proxied--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROXIED_OPERATION_WRITE:
|
||||
{
|
||||
if (result.type == TOASTY_RESULT_WRITE_SUCCESS) {
|
||||
http_response_builder_status(proxied[i].builder, 201); // Created
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
} else {
|
||||
// TODO: Should differentiate between error conditions
|
||||
http_response_builder_status(proxied[i].builder, 500); // Internal Server Error
|
||||
http_response_builder_send(proxied[i].builder);
|
||||
}
|
||||
proxied[i].type = PROXIED_OPERATION_FREE;
|
||||
num_proxied--;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reg = (EventRegister) { http_ptrs, http_polled, HTTP_SERVER_POLL_CAPACITY, num_http_polled };
|
||||
if (http_server_process_events(&server, ®) < 0)
|
||||
return -1;
|
||||
|
||||
HTTP_Request *request;
|
||||
HTTP_ResponseBuilder builder;
|
||||
int ret = http_server_wait(server, &req, &builder);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
ToastyString path = {
|
||||
req->url.path.ptr,
|
||||
req->url.path.len
|
||||
};
|
||||
|
||||
Operation op;
|
||||
op.type = OPERATION_FREE;
|
||||
|
||||
switch (req->method) {
|
||||
if (http_server_next_request(&server, &request, &builder)) {
|
||||
|
||||
switch (request->method) {
|
||||
case HTTP_METHOD_GET:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
http_response_builder_status(builder, 501); // Not Implemented
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
case HTTP_METHOD_HEAD:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
http_response_builder_status(builder, 501); // Not Implemented
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
case HTTP_METHOD_PUT:
|
||||
// TODO
|
||||
break;
|
||||
{
|
||||
int i = find_unused_struct(proxied, num_proxied);
|
||||
if (i < 0) {
|
||||
http_response_builder_status(builder, 503); // Service Unavailable
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
}
|
||||
|
||||
case HTTP_METHOD_PATCH:
|
||||
// TODO
|
||||
break;
|
||||
ToastyHandle handle = toasty_begin_write(toasty, path, 0, request->body.ptr, request->body.len);
|
||||
if (handle == TOASTY_INVALID) {
|
||||
http_response_builder_status(builder, 500); // Internal Server Error
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
}
|
||||
|
||||
proxied[num_proxied].type = PROXIED_OPERATION_WRITE;
|
||||
proxied[num_proxied].request = request;
|
||||
proxied[num_proxied].builder = builder;
|
||||
proxied[num_proxied].handle = handle;
|
||||
num_proxied++;
|
||||
}
|
||||
break;
|
||||
case HTTP_METHOD_DELETE:
|
||||
// TODO
|
||||
break;
|
||||
{
|
||||
int i = find_unused_struct(proxied, num_proxied);
|
||||
if (i < 0) {
|
||||
http_response_builder_status(builder, 503); // Service Unavailable
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
}
|
||||
|
||||
ToastyHandle handle = toasty_begin_delete(toasty, path);
|
||||
if (handle == TOASTY_INVALID) {
|
||||
http_response_builder_status(builder, 500); // Internal Server Error
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
}
|
||||
|
||||
proxied[num_proxied].type = PROXIED_OPERATION_DELETE;
|
||||
proxied[num_proxied].request = request;
|
||||
proxied[num_proxied].builder = builder;
|
||||
proxied[num_proxied].handle = handle;
|
||||
num_proxied++;
|
||||
}
|
||||
break;
|
||||
case HTTP_METHOD_OPTIONS:
|
||||
http_response_builder_status(builder, 200);
|
||||
http_response_builder_header(builder, HTTP_STR("Allow: GET, HEAD, PUT, PATCH, DELETE, OPTIONS"));
|
||||
http_response_builder_done(builder);
|
||||
break;
|
||||
|
||||
http_response_builder_status(builder, 200); // OK
|
||||
http_response_builder_header(builder, HTTP_STR("Allow: GET, HEAD, PUT, DELETE, OPTIONS"));
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
default:
|
||||
http_response_builder_status(builder, 200); // TODO: use the status code for invalid methods
|
||||
http_response_builder_header(builder, HTTP_STR("Allow: GET, HEAD, PUT, PATCH, DELETE, OPTIONS"));
|
||||
http_response_builder_done(builder);
|
||||
break;
|
||||
}
|
||||
|
||||
if (op.type != OPERATION_FREE) {
|
||||
assert(0); // TODO: Append to the queue
|
||||
http_response_builder_status(builder, 405); // Method not allowed
|
||||
http_response_builder_header(builder, HTTP_STR("Allow: GET, HEAD, PUT, DELETE, OPTIONS"));
|
||||
http_response_builder_send(builder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http_server_free(server);
|
||||
http_global_free();
|
||||
http_server_free(&server);
|
||||
toasty_disconnect(toasty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user