First batch of tests

This commit is contained in:
2025-04-20 15:57:56 +02:00
parent e1dca84a44
commit 3a4f4b5351
3 changed files with 290 additions and 74 deletions
+191 -9
View File
@@ -23,28 +23,161 @@ typedef struct {
int body_len; int body_len;
} Response; } Response;
// Memory function used to initialize TinyHTTPStream
static void *memfunc(TinyHTTPMemoryFuncTag tag, void *ptr, int len, void *data); static void *memfunc(TinyHTTPMemoryFuncTag tag, void *ptr, int len, void *data);
// Moves the request "str" into the stream, checks that the stream
// became ready and that it parsed the request correctly. When this
// functions returns the stream is ready for a response.
static void send_request(TinyHTTPStream *stream, const char *str); static void send_request(TinyHTTPStream *stream, const char *str);
// Copies into the "dst" buffer the output bytes from the stream
// (up to "cap" bytes) and parses them as an HTTP response into
// "res".
static void recv_response(TinyHTTPStream *stream, Response *res, char *dst, int cap); static void recv_response(TinyHTTPStream *stream, Response *res, char *dst, int cap);
static int header_exists(Response *res, TinyHTTPString name);
static int header_exists_with_value(Response *res, TinyHTTPString name, TinyHTTPString value);
#define TEST(X) {if (!(X)) { printf("Test failed at %s:%d\n", __FILE__, __LINE__); fflush(stdout); __builtin_trap(); }} #define TEST(X) {if (!(X)) { printf("Test failed at %s:%d\n", __FILE__, __LINE__); fflush(stdout); __builtin_trap(); }}
#define TEST_START printf("Test %s:%d\n", __FILE__, __LINE__);
#define TEST_END
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
// TEST CASES // TEST CASES
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
static void basic_request(void) // Plain HTTP 1.1 request string with no Connection header
#define BASIC_REQUEST_STRING \
"GET / HTTP/1.1\r\n" \
"Host: 127.0.0.1:8080\r\n" \
"User-Agent: curl/7.81.0\r\n" \
"Accept: */*\r\n" \
"\r\n"
static void test_init(void)
{ {
TinyHTTPStream stream; TinyHTTPStream stream;
TEST_START
tinyhttp_stream_init(&stream, memfunc, NULL); tinyhttp_stream_init(&stream, memfunc, NULL);
int state = tinyhttp_stream_state(&stream);
// These flags must be set on init
TEST(state & TINYHTTP_STREAM_RECV);
// These must be unset
TEST(!(state & TINYHTTP_STREAM_DIED));
TEST(!(state & TINYHTTP_STREAM_READY));
TEST(!(state & TINYHTTP_STREAM_REUSE));
TEST(!(state & TINYHTTP_STREAM_RECV_STARTED));
TEST(!(state & TINYHTTP_STREAM_SEND_STARTED));
tinyhttp_stream_free(&stream);
TEST_END
}
static void test_setreuse(void)
{
TinyHTTPStream stream;
TEST_START
tinyhttp_stream_init(&stream, memfunc, NULL);
TEST(!(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_REUSE));
tinyhttp_stream_setreuse(&stream, 1);
TEST(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_REUSE);
tinyhttp_stream_setreuse(&stream, 0);
TEST(!(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_REUSE));
tinyhttp_stream_setreuse(&stream, 5847295);
TEST(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_REUSE);
tinyhttp_stream_free(&stream);
TEST_END
}
static void
test_recv_started_flag(void)
{
ptrdiff_t cap;
TinyHTTPStream stream;
TEST_START
tinyhttp_stream_init(&stream, memfunc, NULL);
TEST(!(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_RECV_STARTED));
tinyhttp_stream_recv_buf(&stream, &cap);
TEST(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_RECV_STARTED);
tinyhttp_stream_recv_ack(&stream, 0);
TEST(!(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_RECV_STARTED));
tinyhttp_stream_free(&stream);
TEST_END
}
static void test_kill(void)
{
TinyHTTPStream stream;
TEST_START
tinyhttp_stream_init(&stream, memfunc, NULL);
TEST(!(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_DIED));
tinyhttp_stream_kill(&stream);
TEST(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_DIED);
tinyhttp_stream_free(&stream);
TEST_END
}
static void
test_send_started_flag(void)
{
ptrdiff_t cap;
TinyHTTPStream stream;
TEST_START
tinyhttp_stream_init(&stream, memfunc, NULL);
TEST(!(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_SEND_STARTED));
tinyhttp_stream_send_buf(&stream, &cap);
TEST(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_SEND_STARTED);
tinyhttp_stream_send_ack(&stream, 0);
TEST(!(tinyhttp_stream_state(&stream) & TINYHTTP_STREAM_SEND_STARTED));
tinyhttp_stream_free(&stream);
TEST_END
}
static void test_exchange(int reuse)
{
TinyHTTPStream stream;
TEST_START
tinyhttp_stream_init(&stream, memfunc, NULL);
tinyhttp_stream_setreuse(&stream, reuse);
// Send request // Send request
send_request(&stream, send_request(&stream, BASIC_REQUEST_STRING);
"GET / HTTP/1.1\r\n"
"Host: 127.0.0.1:8080\r\n"
"User-Agent: curl/7.81.0\r\n"
"Accept: */*\r\n"
"\r\n");
// Build response // Build response
tinyhttp_stream_response_status(&stream, 200); tinyhttp_stream_response_status(&stream, 200);
@@ -55,9 +188,27 @@ static void basic_request(void)
Response res; Response res;
recv_response(&stream, &res, buf, sizeof(buf)); recv_response(&stream, &res, buf, sizeof(buf));
// TODO // We expect the status line:
// HTTP/1.1 200 OK
TEST(res.minor == 1);
TEST(res.status_code == 200);
TEST(tinyhttp_streq(res.status_text, TINYHTTP_STRING("OK")));
if (reuse) {
// If we allowed connection reuse on this stream, we expect
// the connection to be kept alive. The response must therefore
// contain the "Connection: Keep-Alive" header or no "Connection"
// header at all since "Keep-Alive" is the default.
TEST(!header_exists(&res, TINYHTTP_STRING("Connection")) ||
header_exists_with_value(&res, TINYHTTP_STRING("Connection"), TINYHTTP_STRING("Keep-Alive")));
} else {
// If we didn't allow connection reuse, then the response must
// contain the "Connection: Close" header
TEST(header_exists_with_value(&res, TINYHTTP_STRING("Connection"), TINYHTTP_STRING("Close")));
}
tinyhttp_stream_free(&stream); tinyhttp_stream_free(&stream);
TEST_END
} }
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
@@ -66,7 +217,14 @@ static void basic_request(void)
int main(void) int main(void)
{ {
basic_request(); test_init();
test_setreuse();
test_kill();
test_recv_started_flag();
test_send_started_flag();
test_exchange(0);
test_exchange(1);
printf("OK\n");
return 0; return 0;
} }
@@ -109,11 +267,14 @@ buffer_into_stream(TinyHTTPStream *stream, const char *src, int len)
memcpy(dst, src + copied, cpy); memcpy(dst, src + copied, cpy);
tinyhttp_printbytes(" >> ", src + copied, cpy);
copied += cpy; copied += cpy;
tinyhttp_stream_recv_ack(stream, cpy); tinyhttp_stream_recv_ack(stream, cpy);
state = tinyhttp_stream_state(stream); state = tinyhttp_stream_state(stream);
} }
printf("\n");
return copied; return copied;
} }
@@ -136,11 +297,14 @@ stream_into_buffer(TinyHTTPStream *stream, char *dst, int cap)
memcpy(dst + copied, src, cpy); memcpy(dst + copied, src, cpy);
tinyhttp_printbytes(" << ", src, cpy);
copied += cpy; copied += cpy;
tinyhttp_stream_send_ack(stream, cpy); tinyhttp_stream_send_ack(stream, cpy);
state = tinyhttp_stream_state(stream); state = tinyhttp_stream_state(stream);
} }
printf("\n");
return copied; return copied;
} }
@@ -285,6 +449,24 @@ recv_response(TinyHTTPStream *stream, Response *res, char *dst, int cap)
parse_response((TinyHTTPString) { dst, len }, res); parse_response((TinyHTTPString) { dst, len }, res);
} }
static int
header_exists(Response *res, TinyHTTPString name)
{
for (int i = 0; i < res->num_headers; i++)
if (tinyhttp_streqcase(res->headers[i].name, name))
return 1;
return 0;
}
static int
header_exists_with_value(Response *res, TinyHTTPString name, TinyHTTPString value)
{
for (int i = 0; i < res->num_headers; i++)
if (tinyhttp_streqcase(res->headers[i].name, name))
return tinyhttp_streqcase(res->headers[i].value, value);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
// THE END // THE END
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
+81 -65
View File
@@ -70,16 +70,46 @@
#endif #endif
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
// DEBUG UTILITIES // // UTILITIES //
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
#if DUMP_IO // TODO: Only allow this when not compiled in stand-alone mode
#include <stdio.h> static int print(const char *src, int len)
static void {
print_bytes(char *prefix, char *src, int len) if (len < 0)
len = strlen(src);
#if defined(_WIN32)
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
int num = 0;
while (num < len) {
DWORD cpy;
if (!WriteFile(handle, src + num, len - num, &cpy, NULL))
return -1;
num += cpy;
}
return 0;
#elif defined(__linux__)
int fd = STDOUT_FILENO;
int num = 0;
while (num < len) {
int ret = write(fd, src + num, len - num);
if (ret < 0) {
if (ret == EINTR)
continue;
return -1;
}
num += ret;
}
return 0;
#endif
}
void tinyhttp_printbytes(char *prefix, const char *src, int len)
{ {
if (src == NULL) { if (src == NULL) {
printf("%s (null)\n", prefix); print(prefix, -1);
print(" (null)\n", -1);
return; return;
} }
@@ -90,64 +120,57 @@ print_bytes(char *prefix, char *src, int len)
while (cur < len && src[cur] != '\n' && src[cur] != '\r') while (cur < len && src[cur] != '\n' && src[cur] != '\r')
cur++; cur++;
if (newline) { if (newline) {
printf("%s", prefix); print(prefix, -1);
newline = 0; newline = 0;
} }
printf("%.*s", cur - start, src + start); print(src + start, cur - start);
if (cur < len) { if (cur < len) {
if (src[cur] == '\r') if (src[cur] == '\r')
printf("\\r"); print("\\r", -1);
else { else {
printf("\\n\n"); print("\\n\n", -1);
newline = 1; newline = 1;
} }
cur++; cur++;
} }
} }
if (cur > 0 && src[cur-1] != '\n') if (cur > 0 && src[cur-1] != '\n')
printf("\n"); print("\n", -1);
} }
#endif
#if DUMP_IO void tinyhttp_printstate_(int state, const char *file, const char *line)
static void
dump_state(int state, const char *file, int line)
{ {
printf("state = "); print("state = ", -1);
if (state & TINYHTTP_STREAM_DIED) if (state & TINYHTTP_STREAM_DIED)
printf("DIED "); print("DIED ", -1);
if (state & TINYHTTP_STREAM_SEND) if (state & TINYHTTP_STREAM_SEND)
printf("SEND "); print("SEND ", -1);
if (state & TINYHTTP_STREAM_RECV) if (state & TINYHTTP_STREAM_RECV)
printf("RECV "); print("RECV ", -1);
if (state & TINYHTTP_STREAM_READY) if (state & TINYHTTP_STREAM_READY)
printf("READY "); print("READY ", -1);
if (state & TINYHTTP_STREAM_CLOSE) if (state & TINYHTTP_STREAM_CLOSE)
printf("CLOSE "); print("CLOSE ", -1);
if (state & TINYHTTP_STREAM_REUSE) if (state & TINYHTTP_STREAM_REUSE)
printf("REUSE "); print("REUSE ", -1);
if (state & TINYHTTP_STREAM_SEND_STARTED) if (state & TINYHTTP_STREAM_SEND_STARTED)
printf("SEND_STARTED "); print("SEND_STARTED ", -1);
if (state & TINYHTTP_STREAM_RECV_STARTED) if (state & TINYHTTP_STREAM_RECV_STARTED)
printf("RECV_STARTED "); print("RECV_STARTED ", -1);
printf(" (in %s:%d)\n", file, line); print(" (in ", -1);
print(file, -1);
print(":", -1);
print(line, -1);
print(")\n", -1);
} }
#define DUMP_STATE(state) dump_state(state, __FILE__, __LINE__);
#else
#define DUMP_STATE(...)
#endif
////////////////////////////////////////////////////////////////////////////////////
// UTILITIES //
////////////////////////////////////////////////////////////////////////////////////
static char static char
to_lower(char c) to_lower(char c)
@@ -177,6 +200,25 @@ int tinyhttp_streqcase(TinyHTTPString s1, TinyHTTPString s2)
return 1; return 1;
} }
static TinyHTTPString trim(TinyHTTPString s)
{
int i = 0;
while (i < s.len && (s.ptr[i] == ' ' || s.ptr[i] == '\t'))
i++;
if (i == s.len) {
s.ptr = NULL;
s.len = 0;
} else {
s.ptr += i;
s.len -= i;
while (s.ptr[s.len-1] == ' ' || s.ptr[s.len-1] == '\n')
s.len--;
}
return s;
}
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
// HTTP REQUEST PARSER // // HTTP REQUEST PARSER //
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
@@ -266,6 +308,7 @@ parse_request_head(char *src, ptrdiff_t len, TinyHTTPRequest *req)
while (cur < len && src[cur] != ':') // TODO: robust while (cur < len && src[cur] != ':') // TODO: robust
cur++; cur++;
TinyHTTPString name = { src + name_off, cur - name_off }; TinyHTTPString name = { src + name_off, cur - name_off };
name = trim(name);
if (cur == len) if (cur == len)
return -400; return -400;
@@ -275,6 +318,7 @@ parse_request_head(char *src, ptrdiff_t len, TinyHTTPRequest *req)
while (cur < len && src[cur] != '\r') while (cur < len && src[cur] != '\r')
cur++; cur++;
TinyHTTPString value = { src + value_off, cur - value_off }; TinyHTTPString value = { src + value_off, cur - value_off };
value = trim(value);
if (cur == len) if (cur == len)
return -400; return -400;
@@ -557,7 +601,7 @@ byte_queue_peek(TinyHTTPByteQueue *queue, ptrdiff_t *len)
static char* static char*
byte_queue_read_buf(TinyHTTPByteQueue *queue, ptrdiff_t *len) byte_queue_read_buf(TinyHTTPByteQueue *queue, ptrdiff_t *len)
{ {
if ((queue->flags & (BYTE_QUEUE_ERROR)) || queue->data == NULL) { if (queue->flags & BYTE_QUEUE_ERROR) {
*len = 0; *len = 0;
return NULL; return NULL;
} }
@@ -568,6 +612,8 @@ byte_queue_read_buf(TinyHTTPByteQueue *queue, ptrdiff_t *len)
queue->read_target_size = queue->size; queue->read_target_size = queue->size;
*len = queue->used; *len = queue->used;
if (queue->data == NULL)
return NULL;
return queue->data + queue->head; return queue->data + queue->head;
} }
@@ -1399,8 +1445,6 @@ void tinyhttp_stream_response_send(TinyHTTPStream *stream)
stream->output_state = TINYHTTP_OUTPUT_STATE_BODY; stream->output_state = TINYHTTP_OUTPUT_STATE_BODY;
} }
DUMP_STATE(tinyhttp_stream_state(stream));
if (stream->output_state == TINYHTTP_OUTPUT_STATE_BODY) { if (stream->output_state == TINYHTTP_OUTPUT_STATE_BODY) {
if (stream->chunked) if (stream->chunked)
byte_queue_write(&stream->out, "0\r\n\r\n"); byte_queue_write(&stream->out, "0\r\n\r\n");
@@ -1427,15 +1471,13 @@ void tinyhttp_stream_response_send(TinyHTTPStream *stream)
tmp[9] = '0' + content_length; tmp[9] = '0' + content_length;
int i = 0; int i = 0;
while (i < 8 && tmp[i] == '0') while (i < 9 && tmp[i] == '0')
i++; i++;
byte_queue_patch(&stream->out, stream->content_length_value_offset, tmp + i, 10 - i); byte_queue_patch(&stream->out, stream->content_length_value_offset, tmp + i, 10 - i);
} }
} }
DUMP_STATE(tinyhttp_stream_state(stream));
if (stream->output_state == TINYHTTP_OUTPUT_STATE_ERROR) { if (stream->output_state == TINYHTTP_OUTPUT_STATE_ERROR) {
byte_queue_remove_after_lock(&stream->out); byte_queue_remove_after_lock(&stream->out);
byte_queue_write(&stream->out, byte_queue_write(&stream->out,
@@ -1446,15 +1488,11 @@ void tinyhttp_stream_response_send(TinyHTTPStream *stream)
); );
} }
DUMP_STATE(tinyhttp_stream_state(stream));
if (byte_queue_error(&stream->out)) { if (byte_queue_error(&stream->out)) {
stream->state |= TINYHTTP_STREAM_DIED; stream->state |= TINYHTTP_STREAM_DIED;
return; return;
} }
DUMP_STATE(tinyhttp_stream_state(stream));
#if DUMP_IO #if DUMP_IO
ptrdiff_t ressize = (byte_queue_offset(&stream->out) - stream->out.lock); ptrdiff_t ressize = (byte_queue_offset(&stream->out) - stream->out.lock);
print_bytes("R << ", stream->out.data + stream->out.head, ressize); print_bytes("R << ", stream->out.data + stream->out.head, ressize);
@@ -1464,11 +1502,7 @@ void tinyhttp_stream_response_send(TinyHTTPStream *stream)
byte_queue_read_unlock(&stream->out); byte_queue_read_unlock(&stream->out);
stream->reqsize = 0; stream->reqsize = 0;
DUMP_STATE(tinyhttp_stream_state(stream));
process_next_request(stream); process_next_request(stream);
DUMP_STATE(tinyhttp_stream_state(stream));
} }
// See tinyhttp.h // See tinyhttp.h
@@ -2000,8 +2034,6 @@ start_stream_operations(TinyHTTPStream *stream, SOCKET sock,
{ {
int state = tinyhttp_stream_state(stream); int state = tinyhttp_stream_state(stream);
DUMP_STATE(tinyhttp_stream_state(stream));
if ((state & TINYHTTP_STREAM_RECV) && !(state & TINYHTTP_STREAM_RECV_STARTED)) { if ((state & TINYHTTP_STREAM_RECV) && !(state & TINYHTTP_STREAM_RECV_STARTED)) {
ptrdiff_t cap; ptrdiff_t cap;
char *dst = tinyhttp_stream_recv_buf(stream, &cap); char *dst = tinyhttp_stream_recv_buf(stream, &cap);
@@ -2014,8 +2046,6 @@ start_stream_operations(TinyHTTPStream *stream, SOCKET sock,
#endif #endif
} }
DUMP_STATE(tinyhttp_stream_state(stream));
if (state & TINYHTTP_STREAM_SEND && !(state & TINYHTTP_STREAM_SEND_STARTED)) { if (state & TINYHTTP_STREAM_SEND && !(state & TINYHTTP_STREAM_SEND_STARTED)) {
ptrdiff_t len; ptrdiff_t len;
char *src = tinyhttp_stream_send_buf(stream, &len); char *src = tinyhttp_stream_send_buf(stream, &len);
@@ -2028,8 +2058,6 @@ start_stream_operations(TinyHTTPStream *stream, SOCKET sock,
#endif #endif
} }
DUMP_STATE(tinyhttp_stream_state(stream));
return 0; return 0;
} }
@@ -2064,8 +2092,6 @@ intern_accepted_socket(TinyHTTPServer *server, SOCKET accepted_socket, int secur
if (server->num_conns < TINYHTTP_SERVER_CONN_LIMIT * 0.7) if (server->num_conns < TINYHTTP_SERVER_CONN_LIMIT * 0.7)
tinyhttp_stream_setreuse(stream, 1); tinyhttp_stream_setreuse(stream, 1);
DUMP_STATE(tinyhttp_stream_state(stream));
if (CreateIoCompletionPort((HANDLE) accepted_socket, server->iocp, 0, 0) == NULL) { if (CreateIoCompletionPort((HANDLE) accepted_socket, server->iocp, 0, 0) == NULL) {
tinyhttp_stream_free(stream); tinyhttp_stream_free(stream);
server->stream_sockets[idx] = INVALID_SOCKET; server->stream_sockets[idx] = INVALID_SOCKET;
@@ -2082,8 +2108,6 @@ intern_accepted_socket(TinyHTTPServer *server, SOCKET accepted_socket, int secur
return; return;
} }
DUMP_STATE(tinyhttp_stream_state(stream));
if (secure) { if (secure) {
// TODO // TODO
} }
@@ -2186,8 +2210,6 @@ process_network_events(TinyHTTPServer *server, int timeout)
int old_state = tinyhttp_stream_state(stream); int old_state = tinyhttp_stream_state(stream);
DUMP_STATE(tinyhttp_stream_state(stream));
if (!result) { if (!result) {
// A read or write operation failed // A read or write operation failed
tinyhttp_stream_kill(stream); tinyhttp_stream_kill(stream);
@@ -2214,8 +2236,6 @@ process_network_events(TinyHTTPServer *server, int timeout)
tinyhttp_stream_kill(stream); tinyhttp_stream_kill(stream);
} }
DUMP_STATE(tinyhttp_stream_state(stream));
int state = tinyhttp_stream_state(stream); int state = tinyhttp_stream_state(stream);
if ((state & TINYHTTP_STREAM_READY) && (old_state & TINYHTTP_STREAM_READY) == 0) { if ((state & TINYHTTP_STREAM_READY) && (old_state & TINYHTTP_STREAM_READY) == 0) {
@@ -2224,8 +2244,6 @@ process_network_events(TinyHTTPServer *server, int timeout)
server->ready_count++; server->ready_count++;
} }
DUMP_STATE(tinyhttp_stream_state(stream));
if (state & TINYHTTP_STREAM_DIED) { if (state & TINYHTTP_STREAM_DIED) {
tinyhttp_stream_free(stream); tinyhttp_stream_free(stream);
remove_from_ready_queue(server, idx); remove_from_ready_queue(server, idx);
@@ -2235,8 +2253,6 @@ process_network_events(TinyHTTPServer *server, int timeout)
server->num_conns--; server->num_conns--;
} }
DUMP_STATE(tinyhttp_stream_state(stream));
return 0; return 0;
} }
#endif #endif
+18
View File
@@ -39,6 +39,10 @@
#define TINYHTTP_SERVER_EPOLL_BATCH_SIZE (1<<10) #define TINYHTTP_SERVER_EPOLL_BATCH_SIZE (1<<10)
#endif #endif
#define TINYHTTP_LINESTR_HELPER1(X) #X
#define TINYHTTP_LINESTR_HELPER2(X) TINYHTTP_LINESTR_HELPER1(X)
#define TINYHTTP_LINESTR TINYHTTP_LINESTR_HELPER2(__LINE__)
// Opaque types // Opaque types
typedef struct TinyHTTPServer TinyHTTPServer; typedef struct TinyHTTPServer TinyHTTPServer;
typedef struct TinyHTTPRouter TinyHTTPRouter; typedef struct TinyHTTPRouter TinyHTTPRouter;
@@ -171,9 +175,21 @@ typedef struct {
TinyHTTPRequest req; TinyHTTPRequest req;
} TinyHTTPStream; } TinyHTTPStream;
// TODO: Comment
int tinyhttp_streq(TinyHTTPString s1, TinyHTTPString s2); int tinyhttp_streq(TinyHTTPString s1, TinyHTTPString s2);
// TODO: Comment
int tinyhttp_streqcase(TinyHTTPString s1, TinyHTTPString s2); int tinyhttp_streqcase(TinyHTTPString s1, TinyHTTPString s2);
// TODO: Comment
void tinyhttp_printbytes(char *prefix, const char *src, int len);
// TODO: Comment
void tinyhttp_printstate_(int state, const char *file, const char *line);
// TODO: Comment
#define tinyhttp_printstate(state) tinyhttp_printstate_(state, __FILE__, TINYHTTP_LINESTR)
// Initializes an HTTP stream // Initializes an HTTP stream
// //
// TODO: Comment on memfunc // TODO: Comment on memfunc
@@ -245,6 +261,8 @@ void tinyhttp_stream_send_ack(TinyHTTPStream *stream, ptrdiff_t num);
// //
// On the other hand, if this option is set the next // On the other hand, if this option is set the next
// request will definitely be the last. // request will definitely be the last.
//
// NOTE: This is turned off by default
void tinyhttp_stream_setreuse(TinyHTTPStream *stream, int value); void tinyhttp_stream_setreuse(TinyHTTPStream *stream, int value);
// TODO: Comment // TODO: Comment