// cHTTP, an HTTP client and server library! // // This file was generated automatically. Do not modify directly. // // Refer to the end of this file for the license //////////////////////////////////////////////////////////////////////////////////////// // src/includes.h //////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #include #else #include #include #include #include #include #include #include #include #include #include #include #endif #ifdef HTTPS_ENABLED #include #endif //////////////////////////////////////////////////////////////////////////////////////// // src/basic.h //////////////////////////////////////////////////////////////////////////////////////// // String type used throughout cHTTP. typedef struct { char *ptr; int len; } HTTP_String; // Compare two strings and return true iff they have // the same contents. bool http_streq(HTTP_String s1, HTTP_String s2); // Compre two strings case-insensitively (uppercase and // lowercase versions of a letter are considered the same) // and return true iff they have the same contents. bool http_streqcase(HTTP_String s1, HTTP_String s2); // Remove spaces and tabs from the start and the end of // a string. This doesn't change the original string and // the new one references the contents of the original one. HTTP_String http_trim(HTTP_String s); // Print the contents of a byte string with the given prefix. // This is primarily used for debugging purposes. void print_bytes(HTTP_String prefix, HTTP_String src); // Macro to simplify converting string literals to // HTTP_String. // // Instead of doing this: // // char *s = "some string"; // // You do this: // // HTTP_String s = HTTP_STR("some string") // // This is a bit cumbersome, but better than null-terminated // strings, having a pointer and length variable pairs whenever // a function operates on a string. If this wasn't a library // I would have done for // // #define S(X) ... // // But I don't want to cause collisions with user code. #define HTTP_STR(X) ((HTTP_String) {(X), sizeof(X)-1}) // Returns the number of items of a static array. #define HTTP_COUNT(X) (sizeof(X) / sizeof((X)[0])) // Macro to unpack an HTTP_String into its length and pointer components. // Useful for passing HTTP_String to printf-style functions with "%.*s" format. // Example: printf("%.*s", HTTP_UNPACK(str)); #define HTTP_UNPACK(X) (X).len, (X).ptr //////////////////////////////////////////////////////////////////////////////////////// // src/parse.h //////////////////////////////////////////////////////////////////////////////////////// #define HTTP_MAX_HEADERS 32 typedef struct { unsigned int data; } HTTP_IPv4; typedef struct { unsigned short data[8]; } HTTP_IPv6; typedef enum { HTTP_HOST_MODE_VOID = 0, HTTP_HOST_MODE_NAME, HTTP_HOST_MODE_IPV4, HTTP_HOST_MODE_IPV6, } HTTP_HostMode; typedef struct { HTTP_HostMode mode; HTTP_String text; union { HTTP_String name; HTTP_IPv4 ipv4; HTTP_IPv6 ipv6; }; } HTTP_Host; typedef struct { HTTP_String userinfo; HTTP_Host host; int port; } HTTP_Authority; // ZII typedef struct { HTTP_String scheme; HTTP_Authority authority; HTTP_String path; HTTP_String query; HTTP_String fragment; } HTTP_URL; typedef enum { HTTP_METHOD_GET, HTTP_METHOD_HEAD, HTTP_METHOD_POST, HTTP_METHOD_PUT, HTTP_METHOD_DELETE, HTTP_METHOD_CONNECT, HTTP_METHOD_OPTIONS, HTTP_METHOD_TRACE, HTTP_METHOD_PATCH, } HTTP_Method; typedef struct { HTTP_String name; HTTP_String value; } HTTP_Header; typedef struct { bool secure; HTTP_Method method; HTTP_URL url; int minor; int num_headers; HTTP_Header headers[HTTP_MAX_HEADERS]; HTTP_String body; } HTTP_Request; typedef struct { void* context; int minor; int status; HTTP_String reason; int num_headers; HTTP_Header headers[HTTP_MAX_HEADERS]; HTTP_String body; } HTTP_Response; int http_parse_ipv4 (char *src, int len, HTTP_IPv4 *ipv4); int http_parse_ipv6 (char *src, int len, HTTP_IPv6 *ipv6); int http_parse_url (char *src, int len, HTTP_URL *url); int http_parse_request (char *src, int len, HTTP_Request *req); int http_parse_response (char *src, int len, HTTP_Response *res); int http_find_header (HTTP_Header *headers, int num_headers, HTTP_String name); HTTP_String http_get_cookie (HTTP_Request *req, HTTP_String name); HTTP_String http_get_param (HTTP_String body, HTTP_String str, char *mem, int cap); int http_get_param_i (HTTP_String body, HTTP_String str); // Checks whether the request was meant for the host with the given // domain an port. If port is -1, the default value of 80 is assumed. bool http_match_host(HTTP_Request *req, HTTP_String domain, int port); //////////////////////////////////////////////////////////////////////////////////////// // src/thread.h //////////////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 typedef CRITICAL_SECTION Mutex; #else typedef pthread_mutex_t Mutex; #endif int mutex_init(Mutex *mutex); int mutex_free(Mutex *mutex); int mutex_lock(Mutex *mutex); int mutex_unlock(Mutex *mutex); //////////////////////////////////////////////////////////////////////////////////////// // src/secure_context.h //////////////////////////////////////////////////////////////////////////////////////// #ifndef SERVER_CERTIFICATE_LIMIT // Maximum number of certificates that can be // associated to a TLS server. This doesn't include // the default certificate. #define SERVER_CERTIFICATE_LIMIT 8 #endif int global_secure_context_init(void); int global_secure_context_free(void); typedef struct { #ifdef HTTPS_ENABLED SSL_CTX *p; #endif } ClientSecureContext; int client_secure_context_init(ClientSecureContext *ctx); void client_secure_context_free(ClientSecureContext *ctx); typedef struct { #ifdef HTTPS_ENABLED char domain[128]; SSL_CTX *ctx; #endif } ServerCertificate; typedef struct { #ifdef HTTPS_ENABLED SSL_CTX *p; int num_certs; ServerCertificate certs[SERVER_CERTIFICATE_LIMIT]; #endif } ServerSecureContext; int server_secure_context_init(ServerSecureContext *ctx, HTTP_String cert_file, HTTP_String key_file); void server_secure_context_free(ServerSecureContext *ctx); int server_secure_context_add_certificate(ServerSecureContext *ctx, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); //////////////////////////////////////////////////////////////////////////////////////// // src/socket.h //////////////////////////////////////////////////////////////////////////////////////// // This file (and its relative .c file) implements an asynchronous TCP/TLS // server and client abstraction. // // It introduces the concept of a "socket manager", which is a pool of // connection sockets and a listener socket. The listener is managed // internally, which means the manager automatically accepts sockets // from it and adds them to the pool. // // If the listener is configured using the function: // // socket_manager_listen_tcp // // the resulting connections will not use TLS. If instead the listener // is configured using: // // socket_manager_listen_tls // // the listener will use TLS. Note that both functions can be used on // the same manager to allow both plaintext and encrypted connections. // Users may enable zero listeners, in which case only outgoing // connections are allowed (more on this later). // // Once the manager is set up, one can wait for events by following // this pattern: // // struct pollfd polled[...]; // int num_polled = socket_manager_register_events(sm, polled, max_polled); // poll(polled, num_polled, -1); // // #define MAX_EVENTS ... // SocketEvent events[MAX_EVENTS]; // int num_events = socket_manager_translate_events(sm, events, MAX_EVENTS, polled, num_polled); // for (int i = 0; i < num_events; i++) { // ... Here call socket_recv, socket_send, socket_close, ... // } // // Note that from the user's perspective, there is no difference // between connections that use plain TCP and those that use TCP/TLS. // // Users can also establish outgoing connections by calling the // function: // // socket_connect // // Which allows the creation of a connection towards an host given // its domain, IPv4, IPv6, or an array of them. This can be done both // for TCP and TCP/TLS connection. Note that users that only intend // to establish outgoing connection may omit the configuration of // listeners entirely. #ifdef _WIN32 #define NATIVE_SOCKET SOCKET #define NATIVE_SOCKET_INVALID SOCKET_ERROR #define CLOSE_NATIVE_SOCKET closesocket #else #define NATIVE_SOCKET int #define NATIVE_SOCKET_INVALID -1 #define CLOSE_NATIVE_SOCKET close #endif typedef uint32_t SocketHandle; #define SOCKET_HANDLE_INVALID ((SocketHandle) 0) typedef uint16_t Port; typedef enum { SOCKET_EVENT_READY, SOCKET_EVENT_DISCONNECT, } SocketEventType; typedef struct { SocketEventType type; SocketHandle handle; void* user; } SocketEvent; // Internal use only typedef enum { // The Socket struct is unused SOCKET_STATE_FREE, // The state associated to a socket created // by a connect operation that hasn't been // processed yet. SOCKET_STATE_PENDING, // A connect() operation was started but is // still pending. SOCKET_STATE_CONNECTING, // Outgoing connection was established, but // a TLS handshake may need to be performed. SOCKET_STATE_CONNECTED, // Incoming connection was established, but // a TLS handshake may need to be performed. SOCKET_STATE_ACCEPTED, // The connection was esablished, but the user // wants to perform a read or write operation that // would block. SOCKET_STATE_ESTABLISHED_WAIT, // The connection was established and it's possible // to perform read or write operations on it without // blocking. SOCKET_STATE_ESTABLISHED_READY, // The socket was marked to be closed. SOCKET_STATE_SHUTDOWN, // The current socket is was closed. The only // valid thing to do here is free its resources. SOCKET_STATE_DIED, } SocketState; typedef struct { int refs; char data[]; } RegisteredName; // Internal use only typedef struct { union { HTTP_IPv4 ipv4; HTTP_IPv6 ipv6; }; bool is_ipv4; Port port; #ifdef HTTPS_ENABLED // When connecting to a peer using TLS, if the address // was resolved from a registered name, that name is // used to request the correct certificate once the TCP // handshake is established, and therefore need to // store it somewhere until that happens. RegisteredName *name; #endif } AddressAndPort; // Internal use only typedef struct { SocketState state; // OS-specific socket type NATIVE_SOCKET sock; // Native socket events that need to be monitored int events; // Generation counter to invalidate any SocketHandle // referring to this socket when it is freed. // Note that this counter may wrap but always skips // the 0 value to ensure the 0 SocketHandle is always // invalid. uint16_t gen; // User-provided context pointer void *user; // A single connect operation may involve // trying to establish a connection towards // one of a set of addresses. int num_addr; int next_addr; union { AddressAndPort addr; // When num_addr=1 AddressAndPort *addrs; // Dynamically allocated when num_addr>1 }; #ifdef HTTPS_ENABLED ClientSecureContext *client_secure_context; ServerSecureContext *server_secure_context; SSL *ssl; #endif } Socket; // Glorified array of sockets. This structure // is private to the .c file associated to this // header. typedef struct { // This guards access to the main thread using // the manager from other threads calling the // wakeup function. Mutex mutex; // TCP listener sockets. The first is intended // for plaintext, while the second is for TLS. // The socket manager will accept and add new // sockets to the pool automatically. Note that // either may be unset. If both are unset, users // can only create outgoing connections. NATIVE_SOCKET plain_sock; NATIVE_SOCKET secure_sock; // Handles for the self-pipe trick necessary for // other threads to wake up sockets blocked on // poll(). NATIVE_SOCKET wait_sock; NATIVE_SOCKET signal_sock; // TLS contexts. One is used for outgoing connections // (the client context) and one for incoming // connections (server). If the secure_sock is // set, the server context is initialized. If at // least one connect was performed using TLS // (and the flag is set), the client context is // initialized. bool at_least_one_secure_connect; ClientSecureContext client_secure_context; ServerSecureContext server_secure_context; // Array of sockets. Structs with state FREE // are unused. int num_used; int max_used; Socket *sockets; } SocketManager; // Instanciate a socket manager. Returns 0 on // success and -1 on error. int socket_manager_init(SocketManager *sm, Socket *socks, int num_socks); // Deinitialize a socket manager void socket_manager_free(SocketManager *sm); // Configure the socket manager to listen on // the specified interface for TCP connections. // Incoming connections will be automatically // added to the internal pool. This function // can only be used once per manager. // Returns 0 on success, -1 on error. int socket_manager_listen_tcp(SocketManager *sm, HTTP_String addr, Port port, int backlog, bool reuse_addr); // Same as the previous function, but incoming // connections will be interpreted as TLS. You // can only call this function once per manager, // but you can call this and the plaintext variant // on the same manager to accept both plaintext // and secure connections. // Returns 0 on success, -1 on error. int socket_manager_listen_tls(SocketManager *sm, HTTP_String addr, Port port, int backlog, bool reuse_addr, HTTP_String cert_file, HTTP_String key_file); // If the socket manager was configures to accept // TLS connections, this adds additional certificates // the client can use to verify the server's // authenticity. // Returns 0 on success, -1 on error. int socket_manager_add_certificate(SocketManager *sm, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); // When a thread is blocked on a poll() call for // descriptors associated to this socket manager, // other threads can call this function to wake // up that blocked thread. // Returns 0 on success, -1 on error. int socket_manager_wakeup(SocketManager *sm); typedef struct { void **ptrs; struct pollfd *polled; int num_polled; int max_polled; } EventRegister; // Resets the event register with the list of descriptors // the socket manager wants monitored. Returns 0 on // success, -1 if the event register's capacity isn't // large enough. int socket_manager_register_events(SocketManager *sm, EventRegister *reg); // After poll() is called on the previously registered // pollfd array and the revents fields are set, this // function processes those events to produce higher-level // socket events. Returns the number of socket events // written to the output array, or -1 on error. // // The maximum number of events this will write // to the events array is equal to the numero of // socket structs provided to the socket manager // via the init function. int socket_manager_translate_events(SocketManager *sm, SocketEvent *events, EventRegister *reg); typedef enum { CONNECT_TARGET_NAME, CONNECT_TARGET_IPV4, CONNECT_TARGET_IPV6, } ConnectTargetType; typedef struct { ConnectTargetType type; Port port; union { HTTP_IPv4 ipv4; HTTP_IPv6 ipv6; HTTP_String name; }; } ConnectTarget; // Connect to one of the given targets. The socket // manager will try to connecting to addresses until // one succedes. If secure=true, the socket uses TLS. // Returns 0 on success, -1 on error. int socket_connect(SocketManager *sm, int num_targets, ConnectTarget *targets, bool secure, void *user); int socket_recv(SocketManager *sm, SocketHandle handle, char *dst, int max); int socket_send(SocketManager *sm, SocketHandle handle, char *src, int len); int socket_close(SocketManager *sm, SocketHandle handle); // Returns -1 on error, 0 if the socket was accepted // from the plaintext listener, or 1 if it was accepted // by the secure listener. int socket_is_secure(SocketManager *sm, SocketHandle handle); // Set the user pointer of a socket int socket_set_user(SocketManager *sm, SocketHandle handle, void *user); //////////////////////////////////////////////////////////////////////////////////////// // src/byte_queue.h //////////////////////////////////////////////////////////////////////////////////////// // This is the implementation of a byte queue useful // for systems that need to process engs of bytes. // // It features sticky errors, a zero-copy interface, // and a safe mechanism to patch previously written // bytes. // // Only up to 4GB of data can be stored at once. // Internal use only enum { BYTE_QUEUE_ERROR = 1 << 0, BYTE_QUEUE_READ = 1 << 1, BYTE_QUEUE_WRITE = 1 << 2, }; typedef struct { uint8_t *ptr; size_t len; } ByteView; // Fields are for internal use only typedef struct { uint64_t curs; uint8_t* data; uint32_t head; uint32_t size; uint32_t used; uint32_t limit; uint8_t* read_target; uint32_t read_target_size; int flags; } ByteQueue; // Represents an offset inside the queue relative // to the first byte ever appended to the queue, // therefore consuming bytes from the queue does // not invalidate this type of offset. typedef uint64_t ByteQueueOffset; // Initialize the queue with a given capacity limit. // This is just a soft limit. The queue will allocate // dynamically as needed up to this limit and won't // grow further. When the limit is reached, http_queue_full // returns true. void byte_queue_init(ByteQueue *queue, uint32_t limit); // Free resources associated to this queue void byte_queue_free(ByteQueue *queue); // Check whether an error occurred inside the queue int byte_queue_error(ByteQueue *queue); // Returns 1 if the queue has no bytes inside it, // or 0 otherwise. int byte_queue_empty(ByteQueue *queue); // Returns 1 if the queue reached its limit, or 0 // otherwise. int byte_queue_full(ByteQueue *queue); // These two functions are to be used together. // read_buf returns a view into the queue of the // bytes that can be read from it. The caller can // decide how many of those bytes can be removed // by passing the count to the read_ack function. // If an error occurred inside the queue, this // function returns an empty view. // // Note that the calls to read_buf and read_ack // may be far apart. Other operations won't interfere // with the read. The only rule is you can't call // read_buf multiple times before calling read_ack. ByteView byte_queue_read_buf(ByteQueue *queue); void byte_queue_read_ack(ByteQueue *queue, uint32_t num); // Similar to the read_buf/read_ack functions, // but write_buf returns a view of the unused // memory inside the queue, and write_ack is // used to tell the queue how many bytes were // written into it. Note that to ensure there // is a minimum amount of free space in the queue, // the user needs to call byte_queue_setmincap. // If an error occurred inside the queue, this // function returns an empty view. // // Note that the calls to write_buf and write_ack // may be far apart. Other operations won't interfere // with the write (except for other byte_queue_write_* // functions). The only rule is you can't call // write_buf multiple times before calling write_ack. ByteView byte_queue_write_buf(ByteQueue *queue); void byte_queue_write_ack(ByteQueue *queue, uint32_t num); // Sets the minimum capacity for the next write // operation and returns 1 if the content of the // queue was moved, else 0 is returned. // // You must not call this function while a write // is pending. In other words, you must do this: // // byte_queue_write_setmincap(queue, mincap); // dst = byte_queue_write_buf(queue, &cap); // ... // byte_queue_write_ack(num); // // And NOT this: // // dst = byte_queue_write_buf(queue); // byte_queue_write_setmincap(queue, mincap); <-- BAD // ... // byte_queue_write_ack(num); // int byte_queue_write_setmincap(ByteQueue *queue, uint32_t mincap); // Write some bytes to the queue. This is a // short hand for write_buf/memcpy/write_ack void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len); // Write the result of the format into the queue void byte_queue_write_fmt(ByteQueue *queue, const char *fmt, ...); // Write the result of the format into the queue void byte_queue_write_fmt2(ByteQueue *queue, const char *fmt, va_list args); // Returns the current offset inside the queue ByteQueueOffset byte_queue_offset(ByteQueue *queue); // Writes some bytes at the specified offset. It's // the responsibility of the user to make sure that // the offset still refers to content inside the queue. void byte_queue_patch(ByteQueue *queue, ByteQueueOffset off, void *src, uint32_t len); // Returns the number of bytes from the given offset // to the end of the queue. uint32_t byte_queue_size_from_offset(ByteQueue *queue, ByteQueueOffset off); // Removes all bytes from the given offset to the the // end of the queue. void byte_queue_remove_from_offset(ByteQueue *queue, ByteQueueOffset offset); //////////////////////////////////////////////////////////////////////////////////////// // src/cert.h //////////////////////////////////////////////////////////////////////////////////////// // This is an utility to create self-signed certificates // useful when testing HTTPS servers locally. This is only // meant to be used by people starting out with a library // and simplifying the zero to one phase. // // The C, O, and CN are respectively country name, organization name, // and common name of the certificate. For instance: // // C="IT" // O="My Organization" // CN="my_website.com" // // The output is a certificate file in PEM format and a private // key file with the key used to sign the certificate. int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, HTTP_String cert_file, HTTP_String key_file); //////////////////////////////////////////////////////////////////////////////////////// // src/client.h //////////////////////////////////////////////////////////////////////////////////////// #ifndef HTTP_CLIENT_CAPACITY // The maximum ammount of requests that can be performed // in parallel. #define HTTP_CLIENT_CAPACITY (1<<7) #endif typedef enum { HTTP_CLIENT_CONN_FREE, HTTP_CLIENT_CONN_WAIT_LINE, HTTP_CLIENT_CONN_WAIT_HEADER, HTTP_CLIENT_CONN_WAIT_BODY, HTTP_CLIENT_CONN_FLUSHING, HTTP_CLIENT_CONN_BUFFERING, HTTP_CLIENT_CONN_COMPLETE, } HTTP_ClientConnState; // Fields of this struct are private typedef struct HTTP_Client HTTP_Client; typedef struct { HTTP_ClientConnState state; // Handle to the socket SocketHandle handle; // Pointer back to the client HTTP_Client *client; // Generation counter for request builder validation uint16_t gen; // Data received from the server ByteQueue input; // Data being sent to the server ByteQueue output; // HTTP method for the request HTTP_Method method; // Parsed URL for connection establishment HTTP_URL url; // Parsed response once complete HTTP_Response response; } HTTP_ClientConn; // Fields of this struct are private struct HTTP_Client { // Size limit of the input and output buffer of each // connection. uint32_t input_buffer_limit; uint32_t output_buffer_limit; // Array of connections. The counter contains the // number of structs such that state!=FREE. int num_conns; HTTP_ClientConn conns[HTTP_CLIENT_CAPACITY]; // Queue of indices referring to connections that // are in the COMPLETE state. int num_ready; int ready_head; int ready[HTTP_CLIENT_CAPACITY]; // Asynchronous TCP and TLS socket abstraction SocketManager sockets; // The client object doesn't interact with this // field directly, it just initializes the socket // manager with a pointer to it. This allows // allocating the exact number of sockets we // will need. Socket socket_pool[HTTP_CLIENT_CAPACITY]; }; // Initialize an HTTP client object. This allows one to // perform a number of requests in parallel. int http_client_init(HTTP_Client *client); // Release resources associated to a client object. void http_client_free(HTTP_Client *client); // Set input and output buffer size limit for any // given connection. The default value is 1MB void http_client_set_input_limit(HTTP_Client *client, uint32_t limit); void http_client_set_output_limit(HTTP_Client *client, uint32_t limit); // When a thread is blocked waiting for client events, // other threads can call this function to wake it up. int http_client_wakeup(HTTP_Client *client); typedef struct { HTTP_Client *client; uint16_t index; uint16_t gen; } HTTP_RequestBuilder; // Create a new request builder object. If the response // pointer is NULL, a brand new builder is created. If // response isn't NULL (and http_free_response wasn't // called on it yet), the connection associated to that // previous exchange is reused. Note that it's up to the // user to make sure the requests are targeting the same // host. Returns 0 on success, -1 on error. int http_client_get_builder(HTTP_Client *client, HTTP_Response *response, HTTP_RequestBuilder *builder); // Set the method and URL of the current request. This is the first // function of the request builder that the user must call. void http_request_builder_url(HTTP_RequestBuilder builder, HTTP_Method method, HTTP_String url); // After the URL, the user may set zero or more headers. void http_request_builder_header(HTTP_RequestBuilder builder, HTTP_String str); // Append bytes to the request's body. You can call this // any amount of times, as long as it's after having set // the URL. void http_request_builder_body(HTTP_RequestBuilder builder, HTTP_String str); // Mark this request as complete. This invalidates the // builder. // Returns 0 on success, -1 on error. int http_request_builder_send(HTTP_RequestBuilder builder); // Resets the event register with the list of descriptors // the client wants monitored. Returns 0 on success, -1 if // the event register's capacity isn't large enough. int http_client_register_events(HTTP_Client *client, EventRegister *reg); // The caller has waited for poll() to return and some // I/O events to be triggered, so now the HTTP client // can continue its buffering and flushing operations. int http_client_process_events(HTTP_Client *client, EventRegister *reg); // After some I/O events were processes, some responses // may be availabe. This function returns one of the // buffered responses. If a request was available, true // is returned. If no more are avaiable, false is returned. // The returned response must either be freed using the // http_free_response function or reused by passing it // to http_client_get_builder. bool http_client_next_response(HTTP_Client *client, HTTP_Response **response); // Free a response object. You can't access its fields // again after this. void http_free_response(HTTP_Response *response); //////////////////////////////////////////////////////////////////////////////////////// // src/server.h //////////////////////////////////////////////////////////////////////////////////////// #ifndef HTTP_SERVER_CAPACITY // The maximum ammount of requests that can be handled // in parallel. #define HTTP_SERVER_CAPACITY (1<<9) #endif typedef enum { // This struct is unused HTTP_SERVER_CONN_FREE, // No request was buffered yet. HTTP_SERVER_CONN_BUFFERING, // A request was just buffered and is waiting for // the user to build a response. To be specific, // it's waiting for the user to set a response status. HTTP_SERVER_CONN_WAIT_STATUS, // A request is buffered and a status was set. Now // the user can set a header or append the first // bytes of the response body. HTTP_SERVER_CONN_WAIT_HEADER, // A request is buffered and some bytes were appended // to the response. Now the user can either append more // bytes or send out the response. HTTP_SERVER_CONN_WAIT_BODY, // A response has been produced and it's being flushed. HTTP_SERVER_CONN_FLUSHING, } HTTP_ServerConnState; // This structure represents the HTTP connection to // a client. typedef struct { // If false, this struct is unused HTTP_ServerConnState state; // Handle to the socket SocketHandle handle; // Data received by the client ByteQueue input; // Data being sent to the client ByteQueue output; // Generation counter. This is used to invalidate // response builders that refer to this connection. uint16_t gen; // This is set during the WAIT_XXX states or // the FLUSHING state. When the connection // completes flushing and no more bytes are // in the output buffer, it frees the connection // instead of turning it back to BUFFERING. bool closing; // When the state is WAIT_STATUS, WAIT_HEADER, // or WAIT_BODY, this contains the parsed version // of the buffered request. HTTP_Request request; // Length of the buffered request when the request // field is valid. int request_len; // Offset of the first response byte in the output // buffer. This is useful when the user wants to // undo the response it's building and start from // scratch. ByteQueueOffset response_offset; // When the first byte of the response content is // written, before it are prepended special headers, // including Content-Length and Connection. This // offset points to the first byte that comes after // the string "Content-Length: ". ByteQueueOffset content_length_value_offset; // Similarly to the previous field, this one points // to the first byte of the body. This allows calculating // the length of the response content byte subtracting // it from the offset reached when the response is marked // as done. ByteQueueOffset content_length_offset; } HTTP_ServerConn; typedef struct { // Size limit of the input and output buffer of each // connection. uint32_t input_buffer_limit; uint32_t output_buffer_limit; bool trace_bytes; bool reuse_addr; int backlog; // Array of connections. The counter contains the // number of structs such that state=FREE. int num_conns; HTTP_ServerConn conns[HTTP_SERVER_CAPACITY]; // Queue of indices referring to connections that // are in the WAIT_STATUS state. int num_ready; int ready_head; int ready[HTTP_SERVER_CAPACITY]; // Asynchronous TCP and TLS socket abstraction SocketManager sockets; // The server object doesn't interact with this // field directly, it just initializes the socket // manager with a pointer to it. This allows // allocating the exact number of sockets we // will need. Socket socket_pool[HTTP_SERVER_CAPACITY]; } HTTP_Server; // Initialize the HTTP server object. By default, it won't // listen for connections. You need to call // // http_server_listen_tcp // http_server_listen_tls // // to listen for connection. Note that you can have a // single server listening for HTTP and HTTPS requests // by calling both. int http_server_init(HTTP_Server *server); // Release resources associated to the server. void http_server_free(HTTP_Server *server); // Set input and output buffer size limit for any // given connection. The default value is 1MB void http_server_set_input_limit(HTTP_Server *server, uint32_t limit); void http_server_set_output_limit(HTTP_Server *server, uint32_t limit); // TODO: Comment void http_server_set_trace_bytes(HTTP_Server *server, bool value); // TODO: Comment void http_server_set_reuse_addr(HTTP_Server *server, bool reuse); // TODO: comment void http_server_set_backlog(HTTP_Server *server, int backlog); // Enable listening for plain HTTP requests at the // specified interface. int http_server_listen_tcp(HTTP_Server *server, HTTP_String addr, Port port); // Enable listening for HTTPS requests at the specified // interfact, using the specified certificate and key // to verify the connection. int http_server_listen_tls(HTTP_Server *server, HTTP_String addr, Port port, HTTP_String cert_file_name, HTTP_String key_file_name); // Add the certificate for an additional domain when // the server is listening for HTTPS requests. int http_server_add_certificate(HTTP_Server *server, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); // When a thread is blocked waiting for server events, // other threads can call this function to wake it up. int http_server_wakeup(HTTP_Server *server); // Resets the event register with the list of descriptors // the server wants monitored. Returns 0 on success, -1 if // the event register's capacity isn't large enough. int http_server_register_events(HTTP_Server *server, EventRegister *reg); // The caller has waited for poll() to return and some // I/O events to be triggered, so now the HTTP server // can continue its buffering and flushing operations. int http_server_process_events(HTTP_Server *server, EventRegister *reg); typedef struct { HTTP_Server *server; uint16_t index; uint16_t gen; } HTTP_ResponseBuilder; // After some I/O events were processes, some requests // may be availabe. This function returns one of the // buffered requests. If a request was available, true // is returned. If no more are avaiable, false is returned. // Note that It's possible to get multiple requests to // respond in batches. // For each request returned by this function, the user // must build a response using the response builder API. bool http_server_next_request(HTTP_Server *server, HTTP_Request **request, HTTP_ResponseBuilder *builder); // This function is called to set the status code of // a request's response. If this function is called // after the other response builder functions, it will // reset the response and set a new status. void http_response_builder_status(HTTP_ResponseBuilder builder, int status); // Append a header to the response. This can only be // used after having set the status and before appending // to the body. void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str); // Append some bytes to the response's body void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str); // Mark the response as complete. This will invalidate // the response builder handle. void http_response_builder_send(HTTP_ResponseBuilder builder); //////////////////////////////////////////////////////////////////////////////////////// // 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. ////////////////////////////////////////////////////////////////////////////////////////