Files
cHTTP/tinyhttp.h
T

331 lines
9.3 KiB
C

////////////////////////////////////////////////////////////////////////////
// LICENSE //
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2025 Francesco Cozzuto
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////
#include <stddef.h>
#include <stdarg.h>
#ifdef TINYHTTP_CUSTOMCONFIG
#include "tinyhttp_config.h"
#else
#define TINYHTTP_SERVER_ENABLE 1
#define TINYHTTP_ROUTER_ENABLE 0
#define TINYHTTP_HTTPS_ENABLE 0
#define TINYHTTP_ROUTER_MAX_PATH_COMPONENTS 32
#define TINYHTTP_HEADER_LIMIT 32
#define TINYHTTP_SERVER_CONN_LIMIT (1<<10)
#define TINYHTTP_SERVER_EPOLL_BATCH_SIZE (1<<10)
#endif
// Opaque types
typedef struct TinyHTTPServer TinyHTTPServer;
typedef struct TinyHTTPRouter TinyHTTPRouter;
typedef enum {
TINYHTTP_METHOD_GET,
TINYHTTP_METHOD_POST,
} TinyHTTPMethod;
typedef struct {
char *name;
ptrdiff_t name_len;
char *value;
ptrdiff_t value_len;
} TinyHTTPHeader;
typedef struct {
TinyHTTPMethod method;
int minor;
char* path;
ptrdiff_t path_len;
int num_headers;
TinyHTTPHeader headers[TINYHTTP_HEADER_LIMIT];
char* body;
ptrdiff_t body_len;
} TinyHTTPRequest;
typedef struct {
TinyHTTPServer *server;
unsigned short idx;
unsigned short gen;
} TinyHTTPResponse;
typedef struct {
int reuse;
// HTTP
const char *plain_addr;
int plain_port;
int plain_backlog;
// HTTPS
int secure;
const char *secure_addr;
int secure_port;
int secure_backlog;
const char *cert_file;
const char *private_key_file;
} TinyHTTPServerConfig;
typedef enum {
TINYHTTP_MEM_MALLOC,
TINYHTTP_MEM_FREE,
} TinyHTTPMemoryFuncTag;
typedef void*(*TinyHTTPMemoryFunc)(TinyHTTPMemoryFuncTag tag,
void *ptr, int len, void *data);
// See [tinyhttp_stream_state]
enum {
TINYHTTP_STREAM_DIED = 1 << 0,
TINYHTTP_STREAM_READY = 1 << 1,
TINYHTTP_STREAM_RECV = 1 << 2,
TINYHTTP_STREAM_SEND = 1 << 3,
TINYHTTP_STREAM_CLOSE = 1 << 4,
TINYHTTP_STREAM_REUSE = 1 << 5,
TINYHTTP_STREAM_SEND_STARTED = 1 << 6,
TINYHTTP_STREAM_RECV_STARTED = 1 << 7,
};
// Internal use
typedef enum {
TINYHTTP_OUTPUT_STATE_NONE,
TINYHTTP_OUTPUT_STATE_STATUS,
TINYHTTP_OUTPUT_STATE_HEADER,
TINYHTTP_OUTPUT_STATE_BODY,
TINYHTTP_OUTPUT_STATE_ERROR,
} TinyHTTPConnectionOutputState;
// Internal use
enum {
BYTE_QUEUE_ERROR = 1 << 0,
BYTE_QUEUE_LOCK = 1 << 1,
BYTE_QUEUE_READ = 1 << 2,
BYTE_QUEUE_WRITE = 1 << 3,
};
// Internal use
typedef struct {
TinyHTTPMemoryFunc memfunc;
void *memfuncdata;
unsigned long long curs;
unsigned int lock; // TODO: Should this be u64?
char* data;
unsigned int head;
unsigned int size;
unsigned int used;
unsigned int limit;
char* read_target;
unsigned int read_target_size;
int flags;
} TinyHTTPByteQueue;
// Internal use
typedef unsigned long long TinyHTTPByteQueueOffset;
typedef struct {
int state;
int numexch;
int chunked;
int keepalive;
ptrdiff_t reqsize;
unsigned long long bodylimit;
TinyHTTPConnectionOutputState output_state;
TinyHTTPByteQueueOffset content_length_value_offset;
TinyHTTPByteQueueOffset content_length_offset;
TinyHTTPByteQueue in;
TinyHTTPByteQueue out;
TinyHTTPRequest req;
} TinyHTTPStream;
// Initializes an HTTP stream
//
// TODO: Comment on memfunc
void
tinyhttp_stream_init(TinyHTTPStream *stream,
TinyHTTPMemoryFunc memfunc, void *memfuncdata);
// Deinitializes an HTTP stream
//
// This function may be called at any time on a memory
// region where [tinyhttp_stream_init] was called at
// least once.
//
// From the moment this function is called until the
// next call to [tinyhttp_stream_init], all [tinyhttp_stream_*]
// calls become no-ops.
void tinyhttp_stream_free(TinyHTTPStream *stream);
// TODO: Comment
void tinyhttp_stream_kill(TinyHTTPStream *stream);
// Returns the current state of the connection
//
// TODO: List the possible states
//
// Note:
// - Calling this function is always valid on a
// memory region where [tinyhttp_stream_init] was
// called at least once.
int tinyhttp_stream_state(TinyHTTPStream *stream);
// Returns the pointer and capacity of a memory region
// where data should be read from the network.
//
// You can write at least [*cap] bytes at the returned
// pointer, and need to call [tinyhttp_stream_net_recv_ack]
// when the write is complete.
//
// Note:
// - Due to sticky errors, this function may return
// the null pointer and a capacity of 0. The caller
// must not write to the pointer but act as if
// everything went okay.
char *tinyhttp_stream_recv_buf(TinyHTTPStream *stream, ptrdiff_t *cap);
// Acknowledge the bytes written from the network
//
// The write must have been initiated by calling
// [tinyhttp_stream_net_recv_buf].
void tinyhttp_stream_recv_ack(TinyHTTPStream *stream, ptrdiff_t num);
// Returns the pointer and capacity of a memory region
// where data should be written to the network.
//
// When the write is complete, [tinyhttp_stream_net_send_ack]
// should be called with the number of consumed bytes.
char *tinyhttp_stream_send_buf(TinyHTTPStream *stream, ptrdiff_t *len);
// See [tinyhttp_stream_net_send_buf]
void tinyhttp_stream_send_ack(TinyHTTPStream *stream, ptrdiff_t num);
// Enable/disable connection reuse for this HTTP
// connection. This change takes effect at the start
// of the next request.
//
// Note that even if the reuse option is set, the
// connection may still be closed due to errors or
// the client deciding otherwise.
//
// On the other hand, if this option is set the next
// request will definitely be the last.
void tinyhttp_stream_setreuse(TinyHTTPStream *stream, int value);
// TODO: Comment
void tinyhttp_stream_setbodylimit(TinyHTTPStream *stream, unsigned long long value);
// TODO: Comment
void tinyhttp_stream_setinbuflimit(TinyHTTPStream *stream, unsigned int value);
// TODO: Comment
void tinyhttp_stream_setoutbuflimit(TinyHTTPStream *stream, unsigned int value);
// TODO: Comment
TinyHTTPRequest *tinyhttp_stream_request(TinyHTTPStream *stream);
// TODO: Comment
void tinyhttp_stream_response_status(TinyHTTPStream *stream, int status);
// TODO: Comment
void tinyhttp_stream_response_header(TinyHTTPStream *stream, const char *fmt, ...);
// TODO: Comment
void tinyhttp_stream_response_header_fmt(TinyHTTPStream *stream, const char *fmt, va_list args);
// TODO: Comment
// TODO: Implement
void tinyhttp_stream_response_body(TinyHTTPStream *stream, char *src, int len);
// TODO: Comment
void tinyhttp_stream_response_body_setmincap(TinyHTTPStream *stream, ptrdiff_t mincap);
// TODO: Comment
char *tinyhttp_stream_response_body_buf(TinyHTTPStream *stream, ptrdiff_t *cap);
// TODO: Comment
void tinyhttp_stream_response_body_ack(TinyHTTPStream *stream, ptrdiff_t num);
// TODO: Comment
void tinyhttp_stream_response_send(TinyHTTPStream *stream);
// TODO: Comment
void tinyhttp_stream_response_undo(TinyHTTPStream *stream);
// TODO: Comment
TinyHTTPServer *tinyhttp_server_init(TinyHTTPServerConfig config,
TinyHTTPMemoryFunc memfunc, void *memfuncdata);
// TODO: Comment
void tinyhttp_server_free(TinyHTTPServer *server);
// TODO: Comment
int tinyhttp_server_wait(TinyHTTPServer *server, TinyHTTPRequest **req,
TinyHTTPResponse *res, int timeout);
// TODO: Comment
void tinyhttp_response_status(TinyHTTPResponse res, int status);
// TODO: Comment
void tinyhttp_response_header(TinyHTTPResponse res,
const char *fmt, ...);
// TODO: Comment
void tinyhttp_response_header_fmt(TinyHTTPResponse res,
const char *fmt, va_list args);
// TODO: Comment
void tinyhttp_response_body_setmincap(TinyHTTPResponse res,
ptrdiff_t mincap);
// TODO: Comment
char *tinyhttp_response_body_buf(TinyHTTPResponse res, ptrdiff_t *cap);
// TODO: Comment
void tinyhttp_response_body_ack(TinyHTTPResponse res, ptrdiff_t num);
// TODO: Comment
void tinyhttp_response_send(TinyHTTPResponse res);
// TODO: Comment
void tinyhttp_response_undo(TinyHTTPResponse res);
// TODO: Comment
TinyHTTPRouter *tinyhttp_router_init(void);
// TODO: Comment
void tinyhttp_router_free(TinyHTTPRouter *router);
// TODO: Comment
void tinyhttp_router_resolve(TinyHTTPRouter *router, TinyHTTPServer *server, TinyHTTPRequest *request, TinyHTTPResponse response);
// TODO: Comment
void tinyhttp_router_dir(TinyHTTPRouter *router, const char *endpoint, const char *path, int dir_listing);