Replace http_/HTTP_ prefixes with chttp_/CHTTP_

This commit is contained in:
2025-12-09 12:12:21 +01:00
parent db030b3834
commit 04deae62d6
25 changed files with 1703 additions and 1703 deletions
+518 -518
View File
File diff suppressed because it is too large Load Diff
+246 -246
View File
@@ -1,5 +1,5 @@
#ifndef HTTP_INCLUDED #ifndef CHTTP_INCLUDED
#define HTTP_INCLUDED #define CHTTP_INCLUDED
// cHTTP, an HTTP client and server library! // cHTTP, an HTTP client and server library!
// //
// This file was generated automatically. Do not modify directly. // This file was generated automatically. Do not modify directly.
@@ -45,56 +45,56 @@
enum { enum {
HTTP_OK = 0, CHTTP_OK = 0,
// A generic error occurred // A generic error occurred
HTTP_ERROR_UNSPECIFIED = -1, CHTTP_ERROR_UNSPECIFIED = -1,
// Out of memory // Out of memory
HTTP_ERROR_OOM = -2, CHTTP_ERROR_OOM = -2,
// Invalid URL // Invalid URL
HTTP_ERROR_BADURL = -3, CHTTP_ERROR_BADURL = -3,
// Parallel request limit reached // Parallel request limit reached
HTTP_ERROR_REQLIMIT = -4, CHTTP_ERROR_REQLIMIT = -4,
// Invalid handle // Invalid handle
HTTP_ERROR_BADHANDLE = -5, CHTTP_ERROR_BADHANDLE = -5,
// TLS support not built-in // TLS support not built-in
HTTP_ERROR_NOTLS = -6, CHTTP_ERROR_NOTLS = -6,
}; };
// String type used throughout cHTTP. // String type used throughout cHTTP.
typedef struct { typedef struct {
char *ptr; char *ptr;
int len; int len;
} HTTP_String; } CHTTP_String;
// Compare two strings and return true iff they have // Compare two strings and return true iff they have
// the same contents. // the same contents.
bool http_streq(HTTP_String s1, HTTP_String s2); bool chttp_streq(CHTTP_String s1, CHTTP_String s2);
// Compre two strings case-insensitively (uppercase and // Compre two strings case-insensitively (uppercase and
// lowercase versions of a letter are considered the same) // lowercase versions of a letter are considered the same)
// and return true iff they have the same contents. // and return true iff they have the same contents.
bool http_streqcase(HTTP_String s1, HTTP_String s2); bool chttp_streqcase(CHTTP_String s1, CHTTP_String s2);
// Remove spaces and tabs from the start and the end of // Remove spaces and tabs from the start and the end of
// a string. This doesn't change the original string and // a string. This doesn't change the original string and
// the new one references the contents of the original one. // the new one references the contents of the original one.
HTTP_String http_trim(HTTP_String s); CHTTP_String chttp_trim(CHTTP_String s);
// Print the contents of a byte string with the given prefix. // Print the contents of a byte string with the given prefix.
// This is primarily used for debugging purposes. // This is primarily used for debugging purposes.
void print_bytes(HTTP_String prefix, HTTP_String src); void print_bytes(CHTTP_String prefix, CHTTP_String src);
// TODO: comment // TODO: comment
char *http_strerror(int code); char *chttp_strerror(int code);
// Macro to simplify converting string literals to // Macro to simplify converting string literals to
// HTTP_String. // CHTTP_String.
// //
// Instead of doing this: // Instead of doing this:
// //
@@ -102,7 +102,7 @@ char *http_strerror(int code);
// //
// You do this: // You do this:
// //
// HTTP_String s = HTTP_STR("some string") // CHTTP_String s = CHTTP_STR("some string")
// //
// This is a bit cumbersome, but better than null-terminated // This is a bit cumbersome, but better than null-terminated
// strings, having a pointer and length variable pairs whenever // strings, having a pointer and length variable pairs whenever
@@ -112,177 +112,177 @@ char *http_strerror(int code);
// #define S(X) ... // #define S(X) ...
// //
// But I don't want to cause collisions with user code. // But I don't want to cause collisions with user code.
#define HTTP_STR(X) ((HTTP_String) {(X), sizeof(X)-1}) #define CHTTP_STR(X) ((CHTTP_String) {(X), sizeof(X)-1})
// Returns the number of items of a static array. // Returns the number of items of a static array.
#define HTTP_COUNT(X) (int) (sizeof(X) / sizeof((X)[0])) #define CHTTP_COUNT(X) (int) (sizeof(X) / sizeof((X)[0]))
// Macro to unpack an HTTP_String into its length and pointer components. // Macro to unpack an CHTTP_String into its length and pointer components.
// Useful for passing HTTP_String to printf-style functions with "%.*s" format. // Useful for passing CHTTP_String to printf-style functions with "%.*s" format.
// Example: printf("%.*s", HTTP_UNPACK(str)); // Example: printf("%.*s", CHTTP_UNPACK(str));
#define HTTP_UNPACK(X) (X).len, (X).ptr #define CHTTP_UNPACK(X) (X).len, (X).ptr
// TODO: comment // TODO: comment
#define HTTP_UNREACHABLE __builtin_trap() #define CHTTP_UNREACHABLE __builtin_trap()
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/parse.h // src/parse.h
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
#define HTTP_MAX_HEADERS 32 #define CHTTP_MAX_HEADERS 32
typedef struct { typedef struct {
unsigned int data; unsigned int data;
} HTTP_IPv4; } CHTTP_IPv4;
typedef struct { typedef struct {
unsigned short data[8]; unsigned short data[8];
} HTTP_IPv6; } CHTTP_IPv6;
typedef enum { typedef enum {
HTTP_HOST_MODE_VOID = 0, CHTTP_HOST_MODE_VOID = 0,
HTTP_HOST_MODE_NAME, CHTTP_HOST_MODE_NAME,
HTTP_HOST_MODE_IPV4, CHTTP_HOST_MODE_IPV4,
HTTP_HOST_MODE_IPV6, CHTTP_HOST_MODE_IPV6,
} HTTP_HostMode; } CHTTP_HostMode;
typedef struct { typedef struct {
HTTP_HostMode mode; CHTTP_HostMode mode;
HTTP_String text; CHTTP_String text;
union { union {
HTTP_String name; CHTTP_String name;
HTTP_IPv4 ipv4; CHTTP_IPv4 ipv4;
HTTP_IPv6 ipv6; CHTTP_IPv6 ipv6;
}; };
} HTTP_Host; } CHTTP_Host;
typedef struct { typedef struct {
HTTP_String userinfo; CHTTP_String userinfo;
HTTP_Host host; CHTTP_Host host;
int port; int port;
} HTTP_Authority; } CHTTP_Authority;
// ZII // ZII
typedef struct { typedef struct {
HTTP_String scheme; CHTTP_String scheme;
HTTP_Authority authority; CHTTP_Authority authority;
HTTP_String path; CHTTP_String path;
HTTP_String query; CHTTP_String query;
HTTP_String fragment; CHTTP_String fragment;
} HTTP_URL; } CHTTP_URL;
typedef enum { typedef enum {
HTTP_METHOD_GET, CHTTP_METHOD_GET,
HTTP_METHOD_HEAD, CHTTP_METHOD_HEAD,
HTTP_METHOD_POST, CHTTP_METHOD_POST,
HTTP_METHOD_PUT, CHTTP_METHOD_PUT,
HTTP_METHOD_DELETE, CHTTP_METHOD_DELETE,
HTTP_METHOD_CONNECT, CHTTP_METHOD_CONNECT,
HTTP_METHOD_OPTIONS, CHTTP_METHOD_OPTIONS,
HTTP_METHOD_TRACE, CHTTP_METHOD_TRACE,
HTTP_METHOD_PATCH, CHTTP_METHOD_PATCH,
} HTTP_Method; } CHTTP_Method;
typedef struct { typedef struct {
HTTP_String name; CHTTP_String name;
HTTP_String value; CHTTP_String value;
} HTTP_Header; } CHTTP_Header;
typedef struct { typedef struct {
bool secure; bool secure;
HTTP_Method method; CHTTP_Method method;
HTTP_URL url; CHTTP_URL url;
int minor; int minor;
int num_headers; int num_headers;
HTTP_Header headers[HTTP_MAX_HEADERS]; CHTTP_Header headers[CHTTP_MAX_HEADERS];
HTTP_String body; CHTTP_String body;
} HTTP_Request; } CHTTP_Request;
typedef struct { typedef struct {
void* context; void* context;
int minor; int minor;
int status; int status;
HTTP_String reason; CHTTP_String reason;
int num_headers; int num_headers;
HTTP_Header headers[HTTP_MAX_HEADERS]; CHTTP_Header headers[CHTTP_MAX_HEADERS];
HTTP_String body; CHTTP_String body;
} HTTP_Response; } CHTTP_Response;
int http_parse_ipv4 (char *src, int len, HTTP_IPv4 *ipv4); int chttp_parse_ipv4 (char *src, int len, CHTTP_IPv4 *ipv4);
int http_parse_ipv6 (char *src, int len, HTTP_IPv6 *ipv6); int chttp_parse_ipv6 (char *src, int len, CHTTP_IPv6 *ipv6);
int http_parse_url (char *src, int len, HTTP_URL *url); int chttp_parse_url (char *src, int len, CHTTP_URL *url);
int http_parse_request (char *src, int len, HTTP_Request *req); int chttp_parse_request (char *src, int len, CHTTP_Request *req);
int http_parse_response (char *src, int len, HTTP_Response *res); int chttp_parse_response (char *src, int len, CHTTP_Response *res);
int http_find_header (HTTP_Header *headers, int num_headers, HTTP_String name); int chttp_find_header (CHTTP_Header *headers, int num_headers, CHTTP_String name);
HTTP_String http_get_cookie (HTTP_Request *req, HTTP_String name); CHTTP_String chttp_get_cookie (CHTTP_Request *req, CHTTP_String name);
HTTP_String http_get_param (HTTP_String body, HTTP_String str, char *mem, int cap); CHTTP_String chttp_get_param (CHTTP_String body, CHTTP_String str, char *mem, int cap);
int http_get_param_i (HTTP_String body, HTTP_String str); int chttp_get_param_i (CHTTP_String body, CHTTP_String str);
// Checks whether the request was meant for the host with the given // 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. // 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); bool chttp_match_host(CHTTP_Request *req, CHTTP_String domain, int port);
// Date and cookie types for Set-Cookie header parsing // Date and cookie types for Set-Cookie header parsing
typedef enum { typedef enum {
HTTP_WEEKDAY_MON, CHTTP_WEEKDAY_MON,
HTTP_WEEKDAY_TUE, CHTTP_WEEKDAY_TUE,
HTTP_WEEKDAY_WED, CHTTP_WEEKDAY_WED,
HTTP_WEEKDAY_THU, CHTTP_WEEKDAY_THU,
HTTP_WEEKDAY_FRI, CHTTP_WEEKDAY_FRI,
HTTP_WEEKDAY_SAT, CHTTP_WEEKDAY_SAT,
HTTP_WEEKDAY_SUN, CHTTP_WEEKDAY_SUN,
} HTTP_WeekDay; } CHTTP_WeekDay;
typedef enum { typedef enum {
HTTP_MONTH_JAN, CHTTP_MONTH_JAN,
HTTP_MONTH_FEB, CHTTP_MONTH_FEB,
HTTP_MONTH_MAR, CHTTP_MONTH_MAR,
HTTP_MONTH_APR, CHTTP_MONTH_APR,
HTTP_MONTH_MAY, CHTTP_MONTH_MAY,
HTTP_MONTH_JUN, CHTTP_MONTH_JUN,
HTTP_MONTH_JUL, CHTTP_MONTH_JUL,
HTTP_MONTH_AUG, CHTTP_MONTH_AUG,
HTTP_MONTH_SEP, CHTTP_MONTH_SEP,
HTTP_MONTH_OCT, CHTTP_MONTH_OCT,
HTTP_MONTH_NOV, CHTTP_MONTH_NOV,
HTTP_MONTH_DEC, CHTTP_MONTH_DEC,
} HTTP_Month; } CHTTP_Month;
typedef struct { typedef struct {
HTTP_WeekDay week_day; CHTTP_WeekDay week_day;
int day; int day;
HTTP_Month month; CHTTP_Month month;
int year; int year;
int hour; int hour;
int minute; int minute;
int second; int second;
} HTTP_Date; } CHTTP_Date;
typedef struct { typedef struct {
HTTP_String name; CHTTP_String name;
HTTP_String value; CHTTP_String value;
bool secure; bool secure;
bool http_only; bool chttp_only;
bool have_date; bool have_date;
HTTP_Date date; CHTTP_Date date;
bool have_max_age; bool have_max_age;
uint32_t max_age; uint32_t max_age;
bool have_domain; bool have_domain;
HTTP_String domain; CHTTP_String domain;
bool have_path; bool have_path;
HTTP_String path; CHTTP_String path;
} HTTP_SetCookie; } CHTTP_SetCookie;
// Parses a Set-Cookie header value // Parses a Set-Cookie header value
// Returns 0 on success, -1 on error // Returns 0 on success, -1 on error
int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out); int chttp_parse_set_cookie(CHTTP_String str, CHTTP_SetCookie *out);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/secure_context.h // src/secure_context.h
@@ -323,10 +323,10 @@ typedef struct {
} ServerSecureContext; } ServerSecureContext;
int server_secure_context_init(ServerSecureContext *ctx, int server_secure_context_init(ServerSecureContext *ctx,
HTTP_String cert_file, HTTP_String key_file); CHTTP_String cert_file, CHTTP_String key_file);
void server_secure_context_free(ServerSecureContext *ctx); void server_secure_context_free(ServerSecureContext *ctx);
int server_secure_context_add_certificate(ServerSecureContext *ctx, int server_secure_context_add_certificate(ServerSecureContext *ctx,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/socket.h // src/socket.h
@@ -456,8 +456,8 @@ typedef struct {
// Internal use only // Internal use only
typedef struct { typedef struct {
union { union {
HTTP_IPv4 ipv4; CHTTP_IPv4 ipv4;
HTTP_IPv6 ipv6; CHTTP_IPv6 ipv6;
}; };
bool is_ipv4; bool is_ipv4;
Port port; Port port;
@@ -574,7 +574,7 @@ void socket_manager_free(SocketManager *sm);
// can only be used once per manager. // can only be used once per manager.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tcp(SocketManager *sm, int socket_manager_listen_tcp(SocketManager *sm,
HTTP_String addr, Port port, int backlog, CHTTP_String addr, Port port, int backlog,
bool reuse_addr); bool reuse_addr);
// Same as the previous function, but incoming // Same as the previous function, but incoming
@@ -585,9 +585,9 @@ int socket_manager_listen_tcp(SocketManager *sm,
// and secure connections. // and secure connections.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tls(SocketManager *sm, int socket_manager_listen_tls(SocketManager *sm,
HTTP_String addr, Port port, int backlog, CHTTP_String addr, Port port, int backlog,
bool reuse_addr, HTTP_String cert_file, bool reuse_addr, CHTTP_String cert_file,
HTTP_String key_file); CHTTP_String key_file);
// If the socket manager was configures to accept // If the socket manager was configures to accept
// TLS connections, this adds additional certificates // TLS connections, this adds additional certificates
@@ -595,7 +595,7 @@ int socket_manager_listen_tls(SocketManager *sm,
// authenticity. // authenticity.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_add_certificate(SocketManager *sm, int socket_manager_add_certificate(SocketManager *sm,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
// When a thread is blocked on a poll() call for // When a thread is blocked on a poll() call for
// descriptors associated to this socket manager, // descriptors associated to this socket manager,
@@ -638,9 +638,9 @@ typedef struct {
ConnectTargetType type; ConnectTargetType type;
Port port; Port port;
union { union {
HTTP_IPv4 ipv4; CHTTP_IPv4 ipv4;
HTTP_IPv6 ipv6; CHTTP_IPv6 ipv6;
HTTP_String name; CHTTP_String name;
}; };
} ConnectTarget; } ConnectTarget;
@@ -721,7 +721,7 @@ typedef uint64_t ByteQueueOffset;
// Initialize the queue with a given capacity limit. // Initialize the queue with a given capacity limit.
// This is just a soft limit. The queue will allocate // This is just a soft limit. The queue will allocate
// dynamically as needed up to this limit and won't // dynamically as needed up to this limit and won't
// grow further. When the limit is reached, http_queue_full // grow further. When the limit is reached, chttp_queue_full
// returns true. // returns true.
void byte_queue_init(ByteQueue *queue, uint32_t limit); void byte_queue_init(ByteQueue *queue, uint32_t limit);
@@ -837,35 +837,35 @@ void byte_queue_remove_from_offset(ByteQueue *queue, ByteQueueOffset offset);
// //
// The output is a certificate file in PEM format and a private // The output is a certificate file in PEM format and a private
// key file with the key used to sign the certificate. // key file with the key used to sign the certificate.
int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, int chttp_create_test_certificate(CHTTP_String C, CHTTP_String O, CHTTP_String CN,
HTTP_String cert_file, HTTP_String key_file); CHTTP_String cert_file, CHTTP_String key_file);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/client.h // src/client.h
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
#ifndef HTTP_CLIENT_CAPACITY #ifndef CHTTP_CLIENT_CAPACITY
// The maximum ammount of requests that can be performed // The maximum ammount of requests that can be performed
// in parallel. // in parallel.
#define HTTP_CLIENT_CAPACITY (1<<7) #define CHTTP_CLIENT_CAPACITY (1<<7)
#endif #endif
// Maximum number of descriptors the client will want // Maximum number of descriptors the client will want
// to wait on. It's one per connection plus the wakeup // to wait on. It's one per connection plus the wakeup
// self-pipe. // self-pipe.
#define HTTP_CLIENT_POLL_CAPACITY (HTTP_CLIENT_CAPACITY+1) #define CHTTP_CLIENT_POLL_CAPACITY (CHTTP_CLIENT_CAPACITY+1)
#ifndef HTTP_COOKIE_JAR_CAPACITY #ifndef CHTTP_COOKIE_JAR_CAPACITY
// Maximum number of cookies that can be associated to a // Maximum number of cookies that can be associated to a
// single client. // single client.
#define HTTP_COOKIE_JAR_CAPACITY 128 #define CHTTP_COOKIE_JAR_CAPACITY 128
#endif #endif
typedef struct { typedef struct {
// Cookie name and value // Cookie name and value
HTTP_String name; CHTTP_String name;
HTTP_String value; CHTTP_String value;
// If the "exact_domain" is true, the cookie // If the "exact_domain" is true, the cookie
// can only be sent to the exact domain referred // can only be sent to the exact domain referred
@@ -873,7 +873,7 @@ typedef struct {
// "exact_domain" is false, then the cookie is // "exact_domain" is false, then the cookie is
// compatible with subdomains. // compatible with subdomains.
bool exact_domain; bool exact_domain;
HTTP_String domain; CHTTP_String domain;
// If "exact_path" is set, the cookie is only // If "exact_path" is set, the cookie is only
// compatible with requests to paths that match // compatible with requests to paths that match
@@ -881,40 +881,40 @@ typedef struct {
// then any path that starts with "path" is // then any path that starts with "path" is
// compatible with the cookie. // compatible with the cookie.
bool exact_path; bool exact_path;
HTTP_String path; CHTTP_String path;
// This cookie can only be sent over HTTPS // This cookie can only be sent over HTTPS
bool secure; bool secure;
} HTTP_CookieJarEntry; } CHTTP_CookieJarEntry;
typedef struct { typedef struct {
int count; int count;
HTTP_CookieJarEntry items[HTTP_COOKIE_JAR_CAPACITY]; CHTTP_CookieJarEntry items[CHTTP_COOKIE_JAR_CAPACITY];
} HTTP_CookieJar; } CHTTP_CookieJar;
typedef enum { typedef enum {
HTTP_CLIENT_CONN_FREE, CHTTP_CLIENT_CONN_FREE,
HTTP_CLIENT_CONN_WAIT_METHOD, CHTTP_CLIENT_CONN_WAIT_METHOD,
HTTP_CLIENT_CONN_WAIT_URL, CHTTP_CLIENT_CONN_WAIT_URL,
HTTP_CLIENT_CONN_WAIT_HEADER, CHTTP_CLIENT_CONN_WAIT_HEADER,
HTTP_CLIENT_CONN_WAIT_BODY, CHTTP_CLIENT_CONN_WAIT_BODY,
HTTP_CLIENT_CONN_FLUSHING, CHTTP_CLIENT_CONN_FLUSHING,
HTTP_CLIENT_CONN_BUFFERING, CHTTP_CLIENT_CONN_BUFFERING,
HTTP_CLIENT_CONN_COMPLETE, CHTTP_CLIENT_CONN_COMPLETE,
} HTTP_ClientConnState; } CHTTP_ClientConnState;
// Fields of this struct are private // Fields of this struct are private
typedef struct HTTP_Client HTTP_Client; typedef struct CHTTP_Client CHTTP_Client;
typedef struct { typedef struct {
HTTP_ClientConnState state; CHTTP_ClientConnState state;
// Handle to the socket // Handle to the socket
SocketHandle handle; SocketHandle handle;
// Pointer back to the client // Pointer back to the client
HTTP_Client *client; CHTTP_Client *client;
// Generation counter for request builder validation // Generation counter for request builder validation
uint16_t gen; uint16_t gen;
@@ -930,11 +930,11 @@ typedef struct {
bool dont_verify_cert; bool dont_verify_cert;
// Allocated copy of the URL string // Allocated copy of the URL string
HTTP_String url_buffer; CHTTP_String url_buffer;
// Parsed URL for connection establishment // Parsed URL for connection establishment
// All url.* pointers reference into url_buffer // All url.* pointers reference into url_buffer
HTTP_URL url; CHTTP_URL url;
// Data received from the server // Data received from the server
ByteQueue input; ByteQueue input;
@@ -949,7 +949,7 @@ typedef struct {
int result; int result;
// Parsed response once complete // Parsed response once complete
HTTP_Response response; CHTTP_Response response;
// This offset points to the first byte that comes // This offset points to the first byte that comes
// after the string "Content-Length: ". // after the string "Content-Length: ".
@@ -960,10 +960,10 @@ typedef struct {
// content byte subtracting it from the offset reached // content byte subtracting it from the offset reached
// when the request is marked as done. // when the request is marked as done.
ByteQueueOffset content_length_offset; ByteQueueOffset content_length_offset;
} HTTP_ClientConn; } CHTTP_ClientConn;
// Fields of this struct are private // Fields of this struct are private
struct HTTP_Client { struct CHTTP_Client {
// Size limit of the input and output buffer of each // Size limit of the input and output buffer of each
// connection. // connection.
@@ -971,18 +971,18 @@ struct HTTP_Client {
uint32_t output_buffer_limit; uint32_t output_buffer_limit;
// List of cookies created during this session // List of cookies created during this session
HTTP_CookieJar cookie_jar; CHTTP_CookieJar cookie_jar;
// Array of connections. The counter contains the // Array of connections. The counter contains the
// number of structs such that state!=FREE. // number of structs such that state!=FREE.
int num_conns; int num_conns;
HTTP_ClientConn conns[HTTP_CLIENT_CAPACITY]; CHTTP_ClientConn conns[CHTTP_CLIENT_CAPACITY];
// Queue of indices referring to connections that // Queue of indices referring to connections that
// are in the COMPLETE state. // are in the COMPLETE state.
int num_ready; int num_ready;
int ready_head; int ready_head;
int ready[HTTP_CLIENT_CAPACITY]; int ready[CHTTP_CLIENT_CAPACITY];
// Asynchronous TCP and TLS socket abstraction // Asynchronous TCP and TLS socket abstraction
SocketManager sockets; SocketManager sockets;
@@ -992,80 +992,80 @@ struct HTTP_Client {
// manager with a pointer to it. This allows // manager with a pointer to it. This allows
// allocating the exact number of sockets we // allocating the exact number of sockets we
// will need. // will need.
Socket socket_pool[HTTP_CLIENT_CAPACITY]; Socket socket_pool[CHTTP_CLIENT_CAPACITY];
}; };
// Initialize an HTTP client object. This allows one to // Initialize an HTTP client object. This allows one to
// perform a number of requests in parallel. // perform a number of requests in parallel.
int http_client_init(HTTP_Client *client); int chttp_client_init(CHTTP_Client *client);
// Release resources associated to a client object. // Release resources associated to a client object.
void http_client_free(HTTP_Client *client); void chttp_client_free(CHTTP_Client *client);
// Set input and output buffer size limit for any // Set input and output buffer size limit for any
// given connection. The default value is 1MB // given connection. The default value is 1MB
void http_client_set_input_limit(HTTP_Client *client, uint32_t limit); void chttp_client_set_input_limit(CHTTP_Client *client, uint32_t limit);
void http_client_set_output_limit(HTTP_Client *client, uint32_t limit); void chttp_client_set_output_limit(CHTTP_Client *client, uint32_t limit);
// When a thread is blocked waiting for client events, // When a thread is blocked waiting for client events,
// other threads can call this function to wake it up. // other threads can call this function to wake it up.
int http_client_wakeup(HTTP_Client *client); int chttp_client_wakeup(CHTTP_Client *client);
typedef struct { typedef struct {
HTTP_Client *client; CHTTP_Client *client;
uint16_t index; uint16_t index;
uint16_t gen; uint16_t gen;
} HTTP_RequestBuilder; } CHTTP_RequestBuilder;
// Create a new request builder object. // Create a new request builder object.
HTTP_RequestBuilder http_client_get_builder(HTTP_Client *client); CHTTP_RequestBuilder chttp_client_get_builder(CHTTP_Client *client);
// TODO: comment // TODO: comment
void http_request_builder_set_user(HTTP_RequestBuilder builder, void chttp_request_builder_set_user(CHTTP_RequestBuilder builder,
void *user); void *user);
// TODO: comment // TODO: comment
void http_request_builder_trace(HTTP_RequestBuilder builder, void chttp_request_builder_trace(CHTTP_RequestBuilder builder,
bool trace_bytes); bool trace_bytes);
// TODO: comment // TODO: comment
void http_request_builder_insecure(HTTP_RequestBuilder builder, void chttp_request_builder_insecure(CHTTP_RequestBuilder builder,
bool insecure); bool insecure);
// Set the method of the current request. This is the first // Set the method of the current request. This is the first
// function of the request builder that the user must call. // function of the request builder that the user must call.
void http_request_builder_method(HTTP_RequestBuilder builder, void chttp_request_builder_method(CHTTP_RequestBuilder builder,
HTTP_Method method); CHTTP_Method method);
// Set the URL of the current request. This must be set after // Set the URL of the current request. This must be set after
// the method and before any header/body // the method and before any header/body
void http_request_builder_target(HTTP_RequestBuilder builder, void chttp_request_builder_target(CHTTP_RequestBuilder builder,
HTTP_String url); CHTTP_String url);
// After the URL, the user may set zero or more headers. // After the URL, the user may set zero or more headers.
void http_request_builder_header(HTTP_RequestBuilder builder, void chttp_request_builder_header(CHTTP_RequestBuilder builder,
HTTP_String str); CHTTP_String str);
// Append bytes to the request's body. You can call this // Append bytes to the request's body. You can call this
// any amount of times, as long as it's after having set // any amount of times, as long as it's after having set
// the URL. // the URL.
void http_request_builder_body(HTTP_RequestBuilder builder, void chttp_request_builder_body(CHTTP_RequestBuilder builder,
HTTP_String str); CHTTP_String str);
// Mark this request as complete. This invalidates the // Mark this request as complete. This invalidates the
// builder. // builder.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int http_request_builder_send(HTTP_RequestBuilder builder); int chttp_request_builder_send(CHTTP_RequestBuilder builder);
// Resets the event register with the list of descriptors // Resets the event register with the list of descriptors
// the client wants monitored. // the client wants monitored.
void http_client_register_events(HTTP_Client *client, void chttp_client_register_events(CHTTP_Client *client,
EventRegister *reg); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP client // I/O events to be triggered, so now the HTTP client
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
void http_client_process_events(HTTP_Client *client, void chttp_client_process_events(CHTTP_Client *client,
EventRegister reg); EventRegister reg);
// After some I/O events were processes, some responses // After some I/O events were processes, some responses
@@ -1073,86 +1073,86 @@ void http_client_process_events(HTTP_Client *client,
// buffered responses. If a request was available, true // buffered responses. If a request was available, true
// is returned. If no more are avaiable, false is returned. // is returned. If no more are avaiable, false is returned.
// The returned response must be freed using the // The returned response must be freed using the
// http_free_response function. // chttp_free_response function.
// TODO: Better comment talking about output arguments // TODO: Better comment talking about output arguments
bool http_client_next_response(HTTP_Client *client, bool chttp_client_next_response(CHTTP_Client *client,
int *result, void **user, HTTP_Response **response); int *result, void **user, CHTTP_Response **response);
// TODO: comment // TODO: comment
void http_client_wait_response(HTTP_Client *client, void chttp_client_wait_response(CHTTP_Client *client,
int *result, void **user, HTTP_Response **response); int *result, void **user, CHTTP_Response **response);
// Free a response object. You can't access its fields // Free a response object. You can't access its fields
// again after this. // again after this.
void http_free_response(HTTP_Response *response); void chttp_free_response(CHTTP_Response *response);
// Perform a blocking GET request // Perform a blocking GET request
int http_get(HTTP_String url, HTTP_String *headers, int chttp_get(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_Response **response); int num_headers, CHTTP_Response **response);
// Perform a blocking POST request // Perform a blocking POST request
int http_post(HTTP_String url, HTTP_String *headers, int chttp_post(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_String body, int num_headers, CHTTP_String body,
HTTP_Response **response); CHTTP_Response **response);
// Perform a blocking PUT request // Perform a blocking PUT request
int http_put(HTTP_String url, HTTP_String *headers, int chttp_put(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_String body, int num_headers, CHTTP_String body,
HTTP_Response **response); CHTTP_Response **response);
// Perform a blocking DELETE request // Perform a blocking DELETE request
int http_delete(HTTP_String url, HTTP_String *headers, int chttp_delete(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_Response **response); int num_headers, CHTTP_Response **response);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/server.h // src/server.h
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
#ifndef HTTP_SERVER_CAPACITY #ifndef CHTTP_SERVER_CAPACITY
// The maximum ammount of requests that can be handled // The maximum ammount of requests that can be handled
// in parallel. // in parallel.
#define HTTP_SERVER_CAPACITY (1<<9) #define CHTTP_SERVER_CAPACITY (1<<9)
#endif #endif
// Maximum number of descriptors the server will want // Maximum number of descriptors the server will want
// to wait on. It's one per connection plus two for the // to wait on. It's one per connection plus two for the
// TCP and TLS listener, plus one for the wakeup self-pipe. // TCP and TLS listener, plus one for the wakeup self-pipe.
#define HTTP_SERVER_POLL_CAPACITY (HTTP_SERVER_CAPACITY+3) #define CHTTP_SERVER_POLL_CAPACITY (CHTTP_SERVER_CAPACITY+3)
typedef enum { typedef enum {
// This struct is unused // This struct is unused
HTTP_SERVER_CONN_FREE, CHTTP_SERVER_CONN_FREE,
// No request was buffered yet. // No request was buffered yet.
HTTP_SERVER_CONN_BUFFERING, CHTTP_SERVER_CONN_BUFFERING,
// A request was just buffered and is waiting for // A request was just buffered and is waiting for
// the user to build a response. To be specific, // the user to build a response. To be specific,
// it's waiting for the user to set a response status. // it's waiting for the user to set a response status.
HTTP_SERVER_CONN_WAIT_STATUS, CHTTP_SERVER_CONN_WAIT_STATUS,
// A request is buffered and a status was set. Now // A request is buffered and a status was set. Now
// the user can set a header or append the first // the user can set a header or append the first
// bytes of the response body. // bytes of the response body.
HTTP_SERVER_CONN_WAIT_HEADER, CHTTP_SERVER_CONN_WAIT_HEADER,
// A request is buffered and some bytes were appended // A request is buffered and some bytes were appended
// to the response. Now the user can either append more // to the response. Now the user can either append more
// bytes or send out the response. // bytes or send out the response.
HTTP_SERVER_CONN_WAIT_BODY, CHTTP_SERVER_CONN_WAIT_BODY,
// A response has been produced and it's being flushed. // A response has been produced and it's being flushed.
HTTP_SERVER_CONN_FLUSHING, CHTTP_SERVER_CONN_FLUSHING,
} HTTP_ServerConnState; } CHTTP_ServerConnState;
// This structure represents the HTTP connection to // This structure represents the HTTP connection to
// a client. // a client.
typedef struct { typedef struct {
// If false, this struct is unused // If false, this struct is unused
HTTP_ServerConnState state; CHTTP_ServerConnState state;
// Handle to the socket // Handle to the socket
SocketHandle handle; SocketHandle handle;
@@ -1177,7 +1177,7 @@ typedef struct {
// When the state is WAIT_STATUS, WAIT_HEADER, // When the state is WAIT_STATUS, WAIT_HEADER,
// or WAIT_BODY, this contains the parsed version // or WAIT_BODY, this contains the parsed version
// of the buffered request. // of the buffered request.
HTTP_Request request; CHTTP_Request request;
// Length of the buffered request when the request // Length of the buffered request when the request
// field is valid. // field is valid.
@@ -1202,7 +1202,7 @@ typedef struct {
// it from the offset reached when the response is marked // it from the offset reached when the response is marked
// as done. // as done.
ByteQueueOffset content_length_offset; ByteQueueOffset content_length_offset;
} HTTP_ServerConn; } CHTTP_ServerConn;
typedef struct { typedef struct {
@@ -1218,13 +1218,13 @@ typedef struct {
// Array of connections. The counter contains the // Array of connections. The counter contains the
// number of structs such that state=FREE. // number of structs such that state=FREE.
int num_conns; int num_conns;
HTTP_ServerConn conns[HTTP_SERVER_CAPACITY]; CHTTP_ServerConn conns[CHTTP_SERVER_CAPACITY];
// Queue of indices referring to connections that // Queue of indices referring to connections that
// are in the WAIT_STATUS state. // are in the WAIT_STATUS state.
int num_ready; int num_ready;
int ready_head; int ready_head;
int ready[HTTP_SERVER_CAPACITY]; int ready[CHTTP_SERVER_CAPACITY];
// Asynchronous TCP and TLS socket abstraction // Asynchronous TCP and TLS socket abstraction
SocketManager sockets; SocketManager sockets;
@@ -1234,74 +1234,74 @@ typedef struct {
// manager with a pointer to it. This allows // manager with a pointer to it. This allows
// allocating the exact number of sockets we // allocating the exact number of sockets we
// will need. // will need.
Socket socket_pool[HTTP_SERVER_CAPACITY]; Socket socket_pool[CHTTP_SERVER_CAPACITY];
} HTTP_Server; } CHTTP_Server;
// Initialize the HTTP server object. By default, it won't // Initialize the HTTP server object. By default, it won't
// listen for connections. You need to call // listen for connections. You need to call
// //
// http_server_listen_tcp // chttp_server_listen_tcp
// http_server_listen_tls // chttp_server_listen_tls
// //
// to listen for connection. Note that you can have a // to listen for connection. Note that you can have a
// single server listening for HTTP and HTTPS requests // single server listening for HTTP and HTTPS requests
// by calling both. // by calling both.
int http_server_init(HTTP_Server *server); int chttp_server_init(CHTTP_Server *server);
// Release resources associated to the server. // Release resources associated to the server.
void http_server_free(HTTP_Server *server); void chttp_server_free(CHTTP_Server *server);
// Set input and output buffer size limit for any // Set input and output buffer size limit for any
// given connection. The default value is 1MB // given connection. The default value is 1MB
void http_server_set_input_limit(HTTP_Server *server, uint32_t limit); void chttp_server_set_input_limit(CHTTP_Server *server, uint32_t limit);
void http_server_set_output_limit(HTTP_Server *server, uint32_t limit); void chttp_server_set_output_limit(CHTTP_Server *server, uint32_t limit);
// TODO: Comment // TODO: Comment
void http_server_set_trace_bytes(HTTP_Server *server, bool value); void chttp_server_set_trace_bytes(CHTTP_Server *server, bool value);
// TODO: Comment // TODO: Comment
void http_server_set_reuse_addr(HTTP_Server *server, bool reuse); void chttp_server_set_reuse_addr(CHTTP_Server *server, bool reuse);
// TODO: comment // TODO: comment
void http_server_set_backlog(HTTP_Server *server, int backlog); void chttp_server_set_backlog(CHTTP_Server *server, int backlog);
// Enable listening for plain HTTP requests at the // Enable listening for plain HTTP requests at the
// specified interface. // specified interface.
int http_server_listen_tcp(HTTP_Server *server, int chttp_server_listen_tcp(CHTTP_Server *server,
HTTP_String addr, Port port); CHTTP_String addr, Port port);
// Enable listening for HTTPS requests at the specified // Enable listening for HTTPS requests at the specified
// interfact, using the specified certificate and key // interfact, using the specified certificate and key
// to verify the connection. // to verify the connection.
int http_server_listen_tls(HTTP_Server *server, HTTP_String addr, Port port, int chttp_server_listen_tls(CHTTP_Server *server, CHTTP_String addr, Port port,
HTTP_String cert_file_name, HTTP_String key_file_name); CHTTP_String cert_file_name, CHTTP_String key_file_name);
// Add the certificate for an additional domain when // Add the certificate for an additional domain when
// the server is listening for HTTPS requests. // the server is listening for HTTPS requests.
int http_server_add_certificate(HTTP_Server *server, int chttp_server_add_certificate(CHTTP_Server *server,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
// When a thread is blocked waiting for server events, // When a thread is blocked waiting for server events,
// other threads can call this function to wake it up. // other threads can call this function to wake it up.
int http_server_wakeup(HTTP_Server *server); int chttp_server_wakeup(CHTTP_Server *server);
// Resets the event register with the list of descriptors // Resets the event register with the list of descriptors
// the server wants monitored. // the server wants monitored.
void http_server_register_events(HTTP_Server *server, void chttp_server_register_events(CHTTP_Server *server,
EventRegister *reg); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP server // I/O events to be triggered, so now the HTTP server
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
void http_server_process_events(HTTP_Server *server, void chttp_server_process_events(CHTTP_Server *server,
EventRegister reg); EventRegister reg);
typedef struct { typedef struct {
HTTP_Server *server; CHTTP_Server *server;
uint16_t index; uint16_t index;
uint16_t gen; uint16_t gen;
} HTTP_ResponseBuilder; } CHTTP_ResponseBuilder;
// After some I/O events were processes, some requests // After some I/O events were processes, some requests
// may be availabe. This function returns one of the // may be availabe. This function returns one of the
@@ -1311,35 +1311,35 @@ typedef struct {
// respond in batches. // respond in batches.
// For each request returned by this function, the user // For each request returned by this function, the user
// must build a response using the response builder API. // must build a response using the response builder API.
bool http_server_next_request(HTTP_Server *server, bool chttp_server_next_request(CHTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder); CHTTP_Request **request, CHTTP_ResponseBuilder *builder);
// TODO: comment // TODO: comment
void http_server_wait_request(HTTP_Server *server, void chttp_server_wait_request(CHTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder); CHTTP_Request **request, CHTTP_ResponseBuilder *builder);
// This function is called to set the status code of // This function is called to set the status code of
// a request's response. If this function is called // a request's response. If this function is called
// after the other response builder functions, it will // after the other response builder functions, it will
// reset the response and set a new status. // reset the response and set a new status.
void http_response_builder_status(HTTP_ResponseBuilder builder, int status); void chttp_response_builder_status(CHTTP_ResponseBuilder builder, int status);
// Append a header to the response. This can only be // Append a header to the response. This can only be
// used after having set the status and before appending // used after having set the status and before appending
// to the body. // to the body.
void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str); void chttp_response_builder_header(CHTTP_ResponseBuilder builder, CHTTP_String str);
// Append some bytes to the response's body // Append some bytes to the response's body
void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str); void chttp_response_builder_body(CHTTP_ResponseBuilder builder, CHTTP_String str);
// TODO: comment // TODO: comment
void http_response_builder_body_cap(HTTP_ResponseBuilder builder, int cap); void chttp_response_builder_body_cap(CHTTP_ResponseBuilder builder, int cap);
char *http_response_builder_body_buf(HTTP_ResponseBuilder builder, int *cap); char *chttp_response_builder_body_buf(CHTTP_ResponseBuilder builder, int *cap);
void http_response_builder_body_ack(HTTP_ResponseBuilder builder, int num); void chttp_response_builder_body_ack(CHTTP_ResponseBuilder builder, int num);
// Mark the response as complete. This will invalidate // Mark the response as complete. This will invalidate
// the response builder handle. // the response builder handle.
void http_response_builder_send(HTTP_ResponseBuilder builder); void chttp_response_builder_send(CHTTP_ResponseBuilder builder);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2025 Francesco Cozzuto // Copyright 2025 Francesco Cozzuto
@@ -1365,4 +1365,4 @@ void http_response_builder_send(HTTP_ResponseBuilder builder);
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
#endif // HTTP_INCLUDED #endif // CHTTP_INCLUDED
+5 -5
View File
@@ -2,14 +2,14 @@
int main(void) int main(void)
{ {
HTTP_Response *response; CHTTP_Response *response;
int ret = http_get(HTTP_STR("http://coz.is/"), NULL, 0, &response); int ret = chttp_get(CHTTP_STR("http://coz.is/"), NULL, 0, &response);
if (ret == HTTP_OK) { if (ret == CHTTP_OK) {
printf("Received %d bytes\n", response->body.len); printf("Received %d bytes\n", response->body.len);
http_free_response(response); chttp_free_response(response);
} else { } else {
printf("Request failure: %s\n", http_strerror(ret)); printf("Request failure: %s\n", chttp_strerror(ret));
} }
return 0; return 0;
} }
+14 -14
View File
@@ -4,33 +4,33 @@ int main(void)
{ {
int ret; int ret;
HTTP_Server server; CHTTP_Server server;
ret = http_server_init(&server); ret = chttp_server_init(&server);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't initialize server (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't initialize server (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
http_server_set_reuse_addr(&server, true); chttp_server_set_reuse_addr(&server, true);
http_server_set_trace_bytes(&server, true); chttp_server_set_trace_bytes(&server, true);
ret = http_server_listen_tcp(&server, HTTP_STR("127.0.0.1"), 8080); ret = chttp_server_listen_tcp(&server, CHTTP_STR("127.0.0.1"), 8080);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't start listening (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't start listening (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
for (;;) { for (;;) {
HTTP_Request *request; CHTTP_Request *request;
HTTP_ResponseBuilder builder; CHTTP_ResponseBuilder builder;
http_server_wait_request(&server, &request, &builder); chttp_server_wait_request(&server, &request, &builder);
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello, world!")); chttp_response_builder_body(builder, CHTTP_STR("Hello, world!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} }
http_server_free(&server); chttp_server_free(&server);
return 0; return 0;
} }
+48 -48
View File
@@ -13,41 +13,41 @@ int main()
{ {
int ret; int ret;
HTTP_String remote = HTTP_STR("http://coz.is"); CHTTP_String remote = CHTTP_STR("http://coz.is");
HTTP_Client client; CHTTP_Client client;
ret = http_client_init(&client); ret = chttp_client_init(&client);
if (ret < 0) { if (ret < 0) {
printf("Couldn't initialize client (%s)\n", http_strerror(ret)); printf("Couldn't initialize client (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
HTTP_Server server; CHTTP_Server server;
ret = http_server_init(&server); ret = chttp_server_init(&server);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't initialize server (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't initialize server (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
http_server_set_reuse_addr(&server, true); chttp_server_set_reuse_addr(&server, true);
http_server_set_trace_bytes(&server, true); chttp_server_set_trace_bytes(&server, true);
ret = http_server_listen_tcp(&server, HTTP_STR("127.0.0.1"), 8080); ret = chttp_server_listen_tcp(&server, CHTTP_STR("127.0.0.1"), 8080);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't start listening (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't start listening (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
bool used[HTTP_SERVER_CAPACITY]; bool used[CHTTP_SERVER_CAPACITY];
for (int i = 0; i < HTTP_SERVER_CAPACITY; i++) for (int i = 0; i < CHTTP_SERVER_CAPACITY; i++)
used[i] = false; used[i] = false;
HTTP_ResponseBuilder pending[HTTP_SERVER_CAPACITY]; CHTTP_ResponseBuilder pending[CHTTP_SERVER_CAPACITY];
int num_pending = 0; int num_pending = 0;
for (;;) { for (;;) {
#define POLL_CAPACITY (HTTP_CLIENT_POLL_CAPACITY + HTTP_SERVER_POLL_CAPACITY) #define POLL_CAPACITY (CHTTP_CLIENT_POLL_CAPACITY + CHTTP_SERVER_POLL_CAPACITY)
void *ptrs[POLL_CAPACITY]; void *ptrs[POLL_CAPACITY];
struct pollfd polled[POLL_CAPACITY]; struct pollfd polled[POLL_CAPACITY];
@@ -57,14 +57,14 @@ int main()
polled, polled,
0 0
}; };
http_server_register_events(&server, &server_reg); chttp_server_register_events(&server, &server_reg);
EventRegister client_reg = { EventRegister client_reg = {
ptrs + server_reg.num_polled, ptrs + server_reg.num_polled,
polled + server_reg.num_polled, polled + server_reg.num_polled,
0 0
}; };
http_client_register_events(&client, &client_reg); chttp_client_register_events(&client, &client_reg);
if (server_reg.num_polled > 0 || if (server_reg.num_polled > 0 ||
client_reg.num_polled > 0) { client_reg.num_polled > 0) {
@@ -75,62 +75,62 @@ int main()
int result; int result;
void *user; void *user;
HTTP_Response *response; CHTTP_Response *response;
http_client_process_events(&client, client_reg); chttp_client_process_events(&client, client_reg);
while (http_client_next_response(&client, &result, &user, &response)) { while (chttp_client_next_response(&client, &result, &user, &response)) {
HTTP_ResponseBuilder *builder = (HTTP_ResponseBuilder*) user; CHTTP_ResponseBuilder *builder = (CHTTP_ResponseBuilder*) user;
int i = builder - pending; int i = builder - pending;
assert(i > -1); assert(i > -1);
assert(i < HTTP_SERVER_CAPACITY); assert(i < CHTTP_SERVER_CAPACITY);
if (result == HTTP_OK) { if (result == CHTTP_OK) {
http_response_builder_status(*builder, response->status); chttp_response_builder_status(*builder, response->status);
http_response_builder_body(*builder, response->body); chttp_response_builder_body(*builder, response->body);
http_response_builder_send(*builder); chttp_response_builder_send(*builder);
} else { } else {
http_response_builder_status(*builder, 500); chttp_response_builder_status(*builder, 500);
http_response_builder_send(*builder); chttp_response_builder_send(*builder);
} }
used[i] = false; used[i] = false;
num_pending--; num_pending--;
} }
HTTP_Request *request; CHTTP_Request *request;
HTTP_ResponseBuilder response_builder; CHTTP_ResponseBuilder response_builder;
http_server_process_events(&server, server_reg); chttp_server_process_events(&server, server_reg);
while (http_server_next_request(&server, &request, &response_builder)) { while (chttp_server_next_request(&server, &request, &response_builder)) {
int i = 0; int i = 0;
while (used[i]) { while (used[i]) {
i++; i++;
assert(i < HTTP_SERVER_CAPACITY); assert(i < CHTTP_SERVER_CAPACITY);
} }
HTTP_String path = request->url.path; CHTTP_String path = request->url.path;
if (path.len == 0) if (path.len == 0)
path = HTTP_STR("/"); path = CHTTP_STR("/");
char target[1<<10]; char target[1<<10];
int target_len = snprintf(target, sizeof(target), int target_len = snprintf(target, sizeof(target),
"%.*s%.*s", HTTP_UNPACK(remote), HTTP_UNPACK(path)); "%.*s%.*s", CHTTP_UNPACK(remote), CHTTP_UNPACK(path));
if (target_len < 0 || target_len >= (int) sizeof(target)) { if (target_len < 0 || target_len >= (int) sizeof(target)) {
http_response_builder_status(response_builder, 500); chttp_response_builder_status(response_builder, 500);
http_response_builder_send(response_builder); chttp_response_builder_send(response_builder);
continue; continue;
} }
HTTP_RequestBuilder request_builder = http_client_get_builder(&client); CHTTP_RequestBuilder request_builder = chttp_client_get_builder(&client);
http_request_builder_set_user(request_builder, &pending[i]); chttp_request_builder_set_user(request_builder, &pending[i]);
http_request_builder_trace(request_builder, true); chttp_request_builder_trace(request_builder, true);
http_request_builder_method(request_builder, request->method); chttp_request_builder_method(request_builder, request->method);
http_request_builder_target(request_builder, (HTTP_String) { target, target_len }); chttp_request_builder_target(request_builder, (CHTTP_String) { target, target_len });
ret = http_request_builder_send(request_builder); ret = chttp_request_builder_send(request_builder);
if (ret < 0) { if (ret < 0) {
http_response_builder_status(response_builder, 500); chttp_response_builder_status(response_builder, 500);
http_response_builder_send(response_builder); chttp_response_builder_send(response_builder);
continue; continue;
} }
@@ -140,7 +140,7 @@ int main()
} }
} }
http_server_free(&server); chttp_server_free(&server);
http_client_free(&client); chttp_client_free(&client);
return 0; return 0;
} }
+23 -23
View File
@@ -16,21 +16,21 @@ int main(void)
int ret; int ret;
HTTP_Server server; CHTTP_Server server;
ret = http_server_init(&server); ret = chttp_server_init(&server);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't initialize server (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't initialize server (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
http_server_set_reuse_addr(&server, true); chttp_server_set_reuse_addr(&server, true);
http_server_set_trace_bytes(&server, true); chttp_server_set_trace_bytes(&server, true);
HTTP_String local_addr = HTTP_STR("127.0.0.1"); CHTTP_String local_addr = CHTTP_STR("127.0.0.1");
uint16_t local_port = 8080; uint16_t local_port = 8080;
ret = http_server_listen_tcp(&server, local_addr, local_port); ret = chttp_server_listen_tcp(&server, local_addr, local_port);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't start listening (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't start listening (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
@@ -48,29 +48,29 @@ int main(void)
for (;;) { for (;;) {
HTTP_Request *req; CHTTP_Request *req;
HTTP_ResponseBuilder builder; CHTTP_ResponseBuilder builder;
http_server_wait_request(&server, &req, &builder); chttp_server_wait_request(&server, &req, &builder);
if (http_match_host(req, HTTP_STR("websiteB.com"), local_port)) { if (chttp_match_host(req, CHTTP_STR("websiteB.com"), local_port)) {
// Website B // Website B
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello from websiteB.com!")); chttp_response_builder_body(builder, CHTTP_STR("Hello from websiteB.com!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} else if (http_match_host(req, HTTP_STR("websiteC.com"), local_port)) { } else if (chttp_match_host(req, CHTTP_STR("websiteC.com"), local_port)) {
// Website C // Website C
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello from websiteC.com!")); chttp_response_builder_body(builder, CHTTP_STR("Hello from websiteC.com!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} else { } else {
// Serve websiteA by default // Serve websiteA by default
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello from websiteA.com!")); chttp_response_builder_body(builder, CHTTP_STR("Hello from websiteA.com!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} }
} }
http_server_free(&server); chttp_server_free(&server);
return 0; return 0;
} }
+17 -17
View File
@@ -4,39 +4,39 @@
int main(void) int main(void)
{ {
HTTP_String local_addr = HTTP_STR("127.0.0.1"); CHTTP_String local_addr = CHTTP_STR("127.0.0.1");
uint16_t local_port = 8443; uint16_t local_port = 8443;
HTTP_String cert_file = HTTP_STR("websiteA_cert.pem"); CHTTP_String cert_file = CHTTP_STR("websiteA_cert.pem");
HTTP_String key_file = HTTP_STR("websiteA_key.pem"); CHTTP_String key_file = CHTTP_STR("websiteA_key.pem");
HTTP_Server server; CHTTP_Server server;
int ret = http_server_init(&server); int ret = chttp_server_init(&server);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't initialize server (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't initialize server (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
http_server_set_reuse_addr(&server, true); chttp_server_set_reuse_addr(&server, true);
http_server_set_trace_bytes(&server, true); chttp_server_set_trace_bytes(&server, true);
ret = http_server_listen_tls(&server, local_addr, local_port, cert_file, key_file); ret = chttp_server_listen_tls(&server, local_addr, local_port, cert_file, key_file);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't start listening (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't start listening (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
for (;;) { for (;;) {
HTTP_Request *req; CHTTP_Request *req;
HTTP_ResponseBuilder builder; CHTTP_ResponseBuilder builder;
http_server_wait_request(&server, &req, &builder); chttp_server_wait_request(&server, &req, &builder);
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello from websiteA.com!")); chttp_response_builder_body(builder, CHTTP_STR("Hello from websiteA.com!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} }
http_server_free(&server); chttp_server_free(&server);
return 0; return 0;
} }
+53 -53
View File
@@ -38,47 +38,47 @@ int main(void)
if (ret < 0) if (ret < 0)
return -1; return -1;
HTTP_Server server; CHTTP_Server server;
ret = http_server_init(&server); ret = chttp_server_init(&server);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't initialize server (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't initialize server (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
http_server_set_reuse_addr(&server, true); chttp_server_set_reuse_addr(&server, true);
http_server_set_trace_bytes(&server, true); chttp_server_set_trace_bytes(&server, true);
// First, set up an HTTPS server instance with one // First, set up an HTTPS server instance with one
// of the certificate. This will act as default certificate // of the certificate. This will act as default certificate
// when ecrypted connections don't target a specific domain. // when ecrypted connections don't target a specific domain.
HTTP_String local_addr = HTTP_STR("127.0.0.1"); CHTTP_String local_addr = CHTTP_STR("127.0.0.1");
uint16_t local_port = 8443; uint16_t local_port = 8443;
HTTP_String cert_file = HTTP_STR("websiteA_cert.pem"); CHTTP_String cert_file = CHTTP_STR("websiteA_cert.pem");
HTTP_String key_file = HTTP_STR("websiteA_key.pem"); CHTTP_String key_file = CHTTP_STR("websiteA_key.pem");
ret = http_server_listen_tls(&server, local_addr, local_port, cert_file, key_file); ret = chttp_server_listen_tls(&server, local_addr, local_port, cert_file, key_file);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Couldn't start listening (%s)\n", http_strerror(ret)); fprintf(stderr, "Couldn't start listening (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
// Then we can add an arbitrary number of additional // Then we can add an arbitrary number of additional
// certificates using the add_website function // certificates using the add_website function
ret = http_server_add_certificate(&server, ret = chttp_server_add_certificate(&server,
HTTP_STR("websiteB.com"), CHTTP_STR("websiteB.com"),
HTTP_STR("websiteB_cert.pem"), CHTTP_STR("websiteB_cert.pem"),
HTTP_STR("websiteB_key.pem")); CHTTP_STR("websiteB_key.pem"));
if (ret < 0) if (ret < 0)
return -1; return -1;
ret = http_server_add_certificate(&server, ret = chttp_server_add_certificate(&server,
HTTP_STR("websiteC.com"), CHTTP_STR("websiteC.com"),
HTTP_STR("websiteC_cert.pem"), CHTTP_STR("websiteC_cert.pem"),
HTTP_STR("websiteC_key.pem")); CHTTP_STR("websiteC_key.pem"));
if (ret < 0) if (ret < 0)
return -1; return -1;
@@ -109,67 +109,67 @@ int main(void)
for (;;) { for (;;) {
HTTP_Request *req; CHTTP_Request *req;
HTTP_ResponseBuilder builder; CHTTP_ResponseBuilder builder;
http_server_wait_request(&server, &req, &builder); chttp_server_wait_request(&server, &req, &builder);
if (http_match_host(req, HTTP_STR("websiteB.com"), 8080) || if (chttp_match_host(req, CHTTP_STR("websiteB.com"), 8080) ||
http_match_host(req, HTTP_STR("websiteB.com"), 8443)) { chttp_match_host(req, CHTTP_STR("websiteB.com"), 8443)) {
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello from websiteB.com!")); chttp_response_builder_body(builder, CHTTP_STR("Hello from websiteB.com!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} else if (http_match_host(req, HTTP_STR("websiteC.com"), 8080) || } else if (chttp_match_host(req, CHTTP_STR("websiteC.com"), 8080) ||
http_match_host(req, HTTP_STR("websiteC.com"), 8443)) { chttp_match_host(req, CHTTP_STR("websiteC.com"), 8443)) {
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello from websiteC.com!")); chttp_response_builder_body(builder, CHTTP_STR("Hello from websiteC.com!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} else { } else {
// Serve websiteA.com by default to be consistent // Serve websiteA.com by default to be consistent
// with the certificate setup // with the certificate setup
http_response_builder_status(builder, 200); chttp_response_builder_status(builder, 200);
http_response_builder_body(builder, HTTP_STR("Hello from websiteA.com!")); chttp_response_builder_body(builder, CHTTP_STR("Hello from websiteA.com!"));
http_response_builder_send(builder); chttp_response_builder_send(builder);
} }
} }
http_server_free(&server); chttp_server_free(&server);
return 0; return 0;
} }
int setup_test_certificates(void) int setup_test_certificates(void)
{ {
int ret = http_create_test_certificate( int ret = chttp_create_test_certificate(
HTTP_STR("IT"), CHTTP_STR("IT"),
HTTP_STR("Organization A"), CHTTP_STR("Organization A"),
HTTP_STR("websiteA.com"), CHTTP_STR("websiteA.com"),
HTTP_STR("websiteA_cert.pem"), CHTTP_STR("websiteA_cert.pem"),
HTTP_STR("websiteA_key.pem") CHTTP_STR("websiteA_key.pem")
); );
if (ret < 0) if (ret < 0)
return -1; return -1;
ret = http_create_test_certificate( ret = chttp_create_test_certificate(
HTTP_STR("IT"), CHTTP_STR("IT"),
HTTP_STR("Organization B"), CHTTP_STR("Organization B"),
HTTP_STR("websiteB.com"), CHTTP_STR("websiteB.com"),
HTTP_STR("websiteB_cert.pem"), CHTTP_STR("websiteB_cert.pem"),
HTTP_STR("websiteB_key.pem") CHTTP_STR("websiteB_key.pem")
); );
if (ret < 0) if (ret < 0)
return -1; return -1;
ret = http_create_test_certificate( ret = chttp_create_test_certificate(
HTTP_STR("IT"), CHTTP_STR("IT"),
HTTP_STR("Organization C"), CHTTP_STR("Organization C"),
HTTP_STR("websiteC.com"), CHTTP_STR("websiteC.com"),
HTTP_STR("websiteC_cert.pem"), CHTTP_STR("websiteC_cert.pem"),
HTTP_STR("websiteC_key.pem") CHTTP_STR("websiteC_key.pem")
); );
if (ret < 0) if (ret < 0)
return -1; return -1;
+15 -15
View File
@@ -4,37 +4,37 @@ int main(void)
{ {
int ret; int ret;
HTTP_Client client; CHTTP_Client client;
ret = http_client_init(&client); ret = chttp_client_init(&client);
if (ret < 0) { if (ret < 0) {
printf("Couldn't initialize client (%s)\n", http_strerror(ret)); printf("Couldn't initialize client (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
HTTP_RequestBuilder builder = http_client_get_builder(&client); CHTTP_RequestBuilder builder = chttp_client_get_builder(&client);
http_request_builder_method(builder, HTTP_METHOD_GET); chttp_request_builder_method(builder, CHTTP_METHOD_GET);
http_request_builder_target(builder, HTTP_STR("http://coz.is")); chttp_request_builder_target(builder, CHTTP_STR("http://coz.is"));
http_request_builder_header(builder, HTTP_STR("Greeting: Hello from the cHTTP example!")); chttp_request_builder_header(builder, CHTTP_STR("Greeting: Hello from the cHTTP example!"));
ret = http_request_builder_send(builder); ret = chttp_request_builder_send(builder);
if (ret < 0) { if (ret < 0) {
printf("Couldn't build request (%s)\n", http_strerror(ret)); printf("Couldn't build request (%s)\n", chttp_strerror(ret));
return -1; return -1;
} }
int result; int result;
void *user; void *user;
HTTP_Response *response; CHTTP_Response *response;
http_client_wait_response(&client, &result, &user, &response); chttp_client_wait_response(&client, &result, &user, &response);
if (result == HTTP_OK) { if (result == CHTTP_OK) {
printf("Received %d bytes\n", response->body.len); printf("Received %d bytes\n", response->body.len);
} else { } else {
printf("Couldn't receive response (%s)\n", http_strerror(result)); printf("Couldn't receive response (%s)\n", chttp_strerror(result));
} }
http_free_response(response); chttp_free_response(response);
http_client_free(&client); chttp_client_free(&client);
return 0; return 0;
} }
+4 -4
View File
@@ -53,8 +53,8 @@ license = """
""" """
header = Amalgamator() header = Amalgamator()
header.append_text("#ifndef HTTP_INCLUDED\n") header.append_text("#ifndef CHTTP_INCLUDED\n")
header.append_text("#define HTTP_INCLUDED\n") header.append_text("#define CHTTP_INCLUDED\n")
header.append_text(desc) header.append_text(desc)
header.append_file("src/includes.h") header.append_file("src/includes.h")
header.append_file("src/basic.h") header.append_file("src/basic.h")
@@ -66,13 +66,13 @@ header.append_file("src/cert.h")
header.append_file("src/client.h") header.append_file("src/client.h")
header.append_file("src/server.h") header.append_file("src/server.h")
header.append_text(license) header.append_text(license)
header.append_text("#endif // HTTP_INCLUDED\n") header.append_text("#endif // CHTTP_INCLUDED\n")
header.save("chttp.h") header.save("chttp.h")
source = Amalgamator() source = Amalgamator()
source.append_text(desc) source.append_text(desc)
source.append_text("\n") source.append_text("\n")
source.append_text("#ifndef HTTP_DONT_INCLUDE\n") source.append_text("#ifndef CHTTP_DONT_INCLUDE\n")
source.append_text('#include "chttp.h"\n') source.append_text('#include "chttp.h"\n')
source.append_text("#endif\n") source.append_text("#endif\n")
source.append_file("src/basic.c") source.append_file("src/basic.c")
+12 -12
View File
@@ -1,5 +1,5 @@
bool http_streq(HTTP_String s1, HTTP_String s2) bool chttp_streq(CHTTP_String s1, CHTTP_String s2)
{ {
if (s1.len != s2.len) if (s1.len != s2.len)
return false; return false;
@@ -18,7 +18,7 @@ static char to_lower(char c)
return c; return c;
} }
bool http_streqcase(HTTP_String s1, HTTP_String s2) bool chttp_streqcase(CHTTP_String s1, CHTTP_String s2)
{ {
if (s1.len != s2.len) if (s1.len != s2.len)
return false; return false;
@@ -30,7 +30,7 @@ bool http_streqcase(HTTP_String s1, HTTP_String s2)
return true; return true;
} }
HTTP_String http_trim(HTTP_String s) CHTTP_String chttp_trim(CHTTP_String s)
{ {
int i = 0; int i = 0;
while (i < s.len && (s.ptr[i] == ' ' || s.ptr[i] == '\t')) while (i < s.len && (s.ptr[i] == ' ' || s.ptr[i] == '\t'))
@@ -54,7 +54,7 @@ static bool is_printable(char c)
return c >= ' ' && c <= '~'; return c >= ' ' && c <= '~';
} }
void print_bytes(HTTP_String prefix, HTTP_String src) void print_bytes(CHTTP_String prefix, CHTTP_String src)
{ {
if (src.len == 0) if (src.len == 0)
return; return;
@@ -95,16 +95,16 @@ void print_bytes(HTTP_String prefix, HTTP_String src)
putc('\n', stream); putc('\n', stream);
} }
char *http_strerror(int code) char *chttp_strerror(int code)
{ {
switch (code) { switch (code) {
case HTTP_OK: return "No error"; case CHTTP_OK: return "No error";
case HTTP_ERROR_UNSPECIFIED: return "Unspecified error"; case CHTTP_ERROR_UNSPECIFIED: return "Unspecified error";
case HTTP_ERROR_OOM: return "Out of memory"; case CHTTP_ERROR_OOM: return "Out of memory";
case HTTP_ERROR_BADURL: return "Invalid URL"; case CHTTP_ERROR_BADURL: return "Invalid URL";
case HTTP_ERROR_REQLIMIT: return "Parallel request limit reached"; case CHTTP_ERROR_REQLIMIT: return "Parallel request limit reached";
case HTTP_ERROR_BADHANDLE: return "Invalid handle"; case CHTTP_ERROR_BADHANDLE: return "Invalid handle";
case HTTP_ERROR_NOTLS: return "TLS support not built-in"; case CHTTP_ERROR_NOTLS: return "TLS support not built-in";
} }
return "???"; return "???";
} }
+22 -22
View File
@@ -1,56 +1,56 @@
enum { enum {
HTTP_OK = 0, CHTTP_OK = 0,
// A generic error occurred // A generic error occurred
HTTP_ERROR_UNSPECIFIED = -1, CHTTP_ERROR_UNSPECIFIED = -1,
// Out of memory // Out of memory
HTTP_ERROR_OOM = -2, CHTTP_ERROR_OOM = -2,
// Invalid URL // Invalid URL
HTTP_ERROR_BADURL = -3, CHTTP_ERROR_BADURL = -3,
// Parallel request limit reached // Parallel request limit reached
HTTP_ERROR_REQLIMIT = -4, CHTTP_ERROR_REQLIMIT = -4,
// Invalid handle // Invalid handle
HTTP_ERROR_BADHANDLE = -5, CHTTP_ERROR_BADHANDLE = -5,
// TLS support not built-in // TLS support not built-in
HTTP_ERROR_NOTLS = -6, CHTTP_ERROR_NOTLS = -6,
}; };
// String type used throughout cHTTP. // String type used throughout cHTTP.
typedef struct { typedef struct {
char *ptr; char *ptr;
int len; int len;
} HTTP_String; } CHTTP_String;
// Compare two strings and return true iff they have // Compare two strings and return true iff they have
// the same contents. // the same contents.
bool http_streq(HTTP_String s1, HTTP_String s2); bool chttp_streq(CHTTP_String s1, CHTTP_String s2);
// Compre two strings case-insensitively (uppercase and // Compre two strings case-insensitively (uppercase and
// lowercase versions of a letter are considered the same) // lowercase versions of a letter are considered the same)
// and return true iff they have the same contents. // and return true iff they have the same contents.
bool http_streqcase(HTTP_String s1, HTTP_String s2); bool chttp_streqcase(CHTTP_String s1, CHTTP_String s2);
// Remove spaces and tabs from the start and the end of // Remove spaces and tabs from the start and the end of
// a string. This doesn't change the original string and // a string. This doesn't change the original string and
// the new one references the contents of the original one. // the new one references the contents of the original one.
HTTP_String http_trim(HTTP_String s); CHTTP_String chttp_trim(CHTTP_String s);
// Print the contents of a byte string with the given prefix. // Print the contents of a byte string with the given prefix.
// This is primarily used for debugging purposes. // This is primarily used for debugging purposes.
void print_bytes(HTTP_String prefix, HTTP_String src); void print_bytes(CHTTP_String prefix, CHTTP_String src);
// TODO: comment // TODO: comment
char *http_strerror(int code); char *chttp_strerror(int code);
// Macro to simplify converting string literals to // Macro to simplify converting string literals to
// HTTP_String. // CHTTP_String.
// //
// Instead of doing this: // Instead of doing this:
// //
@@ -58,7 +58,7 @@ char *http_strerror(int code);
// //
// You do this: // You do this:
// //
// HTTP_String s = HTTP_STR("some string") // CHTTP_String s = CHTTP_STR("some string")
// //
// This is a bit cumbersome, but better than null-terminated // This is a bit cumbersome, but better than null-terminated
// strings, having a pointer and length variable pairs whenever // strings, having a pointer and length variable pairs whenever
@@ -68,15 +68,15 @@ char *http_strerror(int code);
// #define S(X) ... // #define S(X) ...
// //
// But I don't want to cause collisions with user code. // But I don't want to cause collisions with user code.
#define HTTP_STR(X) ((HTTP_String) {(X), sizeof(X)-1}) #define CHTTP_STR(X) ((CHTTP_String) {(X), sizeof(X)-1})
// Returns the number of items of a static array. // Returns the number of items of a static array.
#define HTTP_COUNT(X) (int) (sizeof(X) / sizeof((X)[0])) #define CHTTP_COUNT(X) (int) (sizeof(X) / sizeof((X)[0]))
// Macro to unpack an HTTP_String into its length and pointer components. // Macro to unpack an CHTTP_String into its length and pointer components.
// Useful for passing HTTP_String to printf-style functions with "%.*s" format. // Useful for passing CHTTP_String to printf-style functions with "%.*s" format.
// Example: printf("%.*s", HTTP_UNPACK(str)); // Example: printf("%.*s", CHTTP_UNPACK(str));
#define HTTP_UNPACK(X) (X).len, (X).ptr #define CHTTP_UNPACK(X) (X).len, (X).ptr
// TODO: comment // TODO: comment
#define HTTP_UNREACHABLE __builtin_trap() #define CHTTP_UNREACHABLE __builtin_trap()
+1 -1
View File
@@ -41,7 +41,7 @@ typedef uint64_t ByteQueueOffset;
// Initialize the queue with a given capacity limit. // Initialize the queue with a given capacity limit.
// This is just a soft limit. The queue will allocate // This is just a soft limit. The queue will allocate
// dynamically as needed up to this limit and won't // dynamically as needed up to this limit and won't
// grow further. When the limit is reached, http_queue_full // grow further. When the limit is reached, chttp_queue_full
// returns true. // returns true.
void byte_queue_init(ByteQueue *queue, uint32_t limit); void byte_queue_init(ByteQueue *queue, uint32_t limit);
+7 -7
View File
@@ -27,7 +27,7 @@ static EVP_PKEY *generate_rsa_key_pair(int key_bits)
return pkey; return pkey;
} }
static X509 *create_certificate(EVP_PKEY *pkey, HTTP_String C, HTTP_String O, HTTP_String CN, int days) static X509 *create_certificate(EVP_PKEY *pkey, CHTTP_String C, CHTTP_String O, CHTTP_String CN, int days)
{ {
X509 *x509 = X509_new(); X509 *x509 = X509_new();
if (!x509) if (!x509)
@@ -63,7 +63,7 @@ static X509 *create_certificate(EVP_PKEY *pkey, HTTP_String C, HTTP_String O, HT
return x509; return x509;
} }
static int save_private_key(EVP_PKEY *pkey, HTTP_String file) static int save_private_key(EVP_PKEY *pkey, CHTTP_String file)
{ {
char copy[1<<10]; char copy[1<<10];
if (file.len >= (int) sizeof(copy)) if (file.len >= (int) sizeof(copy))
@@ -85,7 +85,7 @@ static int save_private_key(EVP_PKEY *pkey, HTTP_String file)
return 0; return 0;
} }
static int save_certificate(X509 *x509, HTTP_String file) static int save_certificate(X509 *x509, CHTTP_String file)
{ {
char copy[1<<10]; char copy[1<<10];
if (file.len >= (int) sizeof(copy)) if (file.len >= (int) sizeof(copy))
@@ -107,8 +107,8 @@ static int save_certificate(X509 *x509, HTTP_String file)
return 0; return 0;
} }
int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, int chttp_create_test_certificate(CHTTP_String C, CHTTP_String O, CHTTP_String CN,
HTTP_String cert_file, HTTP_String key_file) CHTTP_String cert_file, CHTTP_String key_file)
{ {
EVP_PKEY *pkey = generate_rsa_key_pair(2048); EVP_PKEY *pkey = generate_rsa_key_pair(2048);
if (pkey == NULL) if (pkey == NULL)
@@ -139,8 +139,8 @@ int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN,
#else #else
int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, int chttp_create_test_certificate(CHTTP_String C, CHTTP_String O, CHTTP_String CN,
HTTP_String cert_file, HTTP_String key_file) CHTTP_String cert_file, CHTTP_String key_file)
{ {
(void) C; (void) C;
(void) O; (void) O;
+2 -2
View File
@@ -12,5 +12,5 @@
// //
// The output is a certificate file in PEM format and a private // The output is a certificate file in PEM format and a private
// key file with the key used to sign the certificate. // key file with the key used to sign the certificate.
int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN, int chttp_create_test_certificate(CHTTP_String C, CHTTP_String O, CHTTP_String CN,
HTTP_String cert_file, HTTP_String key_file); CHTTP_String cert_file, CHTTP_String key_file);
+185 -185
View File
@@ -1,11 +1,11 @@
static void http_client_conn_free(HTTP_ClientConn *conn) static void chttp_client_conn_free(CHTTP_ClientConn *conn)
{ {
byte_queue_free(&conn->output); byte_queue_free(&conn->output);
byte_queue_free(&conn->input); byte_queue_free(&conn->input);
} }
int http_client_init(HTTP_Client *client) int chttp_client_init(CHTTP_Client *client)
{ {
client->input_buffer_limit = 1<<20; client->input_buffer_limit = 1<<20;
client->output_buffer_limit = 1<<20; client->output_buffer_limit = 1<<20;
@@ -13,8 +13,8 @@ int http_client_init(HTTP_Client *client)
client->cookie_jar.count = 0; client->cookie_jar.count = 0;
client->num_conns = 0; client->num_conns = 0;
for (int i = 0; i < HTTP_CLIENT_CAPACITY; i++) { for (int i = 0; i < CHTTP_CLIENT_CAPACITY; i++) {
client->conns[i].state = HTTP_CLIENT_CONN_FREE; client->conns[i].state = CHTTP_CLIENT_CONN_FREE;
client->conns[i].gen = 0; client->conns[i].gen = 0;
} }
@@ -22,10 +22,10 @@ int http_client_init(HTTP_Client *client)
client->ready_head = 0; client->ready_head = 0;
return socket_manager_init(&client->sockets, return socket_manager_init(&client->sockets,
client->socket_pool, HTTP_CLIENT_CAPACITY); client->socket_pool, CHTTP_CLIENT_CAPACITY);
} }
void http_client_free(HTTP_Client *client) void chttp_client_free(CHTTP_Client *client)
{ {
socket_manager_free(&client->sockets); socket_manager_free(&client->sockets);
@@ -33,63 +33,63 @@ void http_client_free(HTTP_Client *client)
free(client->cookie_jar.items[i].name.ptr); free(client->cookie_jar.items[i].name.ptr);
for (int i = 0, j = 0; j < client->num_conns; i++) { for (int i = 0, j = 0; j < client->num_conns; i++) {
HTTP_ClientConn *conn = &client->conns[i]; CHTTP_ClientConn *conn = &client->conns[i];
if (conn->state == HTTP_CLIENT_CONN_FREE) if (conn->state == CHTTP_CLIENT_CONN_FREE)
continue; continue;
j++; j++;
http_client_conn_free(conn); chttp_client_conn_free(conn);
} }
} }
void http_client_set_input_limit(HTTP_Client *client, uint32_t limit) void chttp_client_set_input_limit(CHTTP_Client *client, uint32_t limit)
{ {
client->input_buffer_limit = limit; client->input_buffer_limit = limit;
} }
void http_client_set_output_limit(HTTP_Client *client, uint32_t limit) void chttp_client_set_output_limit(CHTTP_Client *client, uint32_t limit)
{ {
client->output_buffer_limit = limit; client->output_buffer_limit = limit;
} }
int http_client_wakeup(HTTP_Client *client) int chttp_client_wakeup(CHTTP_Client *client)
{ {
return socket_manager_wakeup(&client->sockets); return socket_manager_wakeup(&client->sockets);
} }
// Get a connection pointer from a request builder. // Get a connection pointer from a request builder.
// If the builder is invalid, returns NULL. // If the builder is invalid, returns NULL.
static HTTP_ClientConn* static CHTTP_ClientConn*
request_builder_to_conn(HTTP_RequestBuilder builder) request_builder_to_conn(CHTTP_RequestBuilder builder)
{ {
HTTP_Client *client = builder.client; CHTTP_Client *client = builder.client;
if (client == NULL) if (client == NULL)
return NULL; return NULL;
if (builder.index >= HTTP_CLIENT_CAPACITY) if (builder.index >= CHTTP_CLIENT_CAPACITY)
return NULL; return NULL;
HTTP_ClientConn *conn = &client->conns[builder.index]; CHTTP_ClientConn *conn = &client->conns[builder.index];
if (builder.gen != conn->gen) if (builder.gen != conn->gen)
return NULL; return NULL;
return conn; return conn;
} }
HTTP_RequestBuilder http_client_get_builder(HTTP_Client *client) CHTTP_RequestBuilder chttp_client_get_builder(CHTTP_Client *client)
{ {
// Find a free connection slot // Find a free connection slot
if (client->num_conns == HTTP_CLIENT_CAPACITY) if (client->num_conns == CHTTP_CLIENT_CAPACITY)
return (HTTP_RequestBuilder) { NULL, -1, -1 }; return (CHTTP_RequestBuilder) { NULL, -1, -1 };
int i = 0; int i = 0;
while (client->conns[i].state != HTTP_CLIENT_CONN_FREE) { while (client->conns[i].state != CHTTP_CLIENT_CONN_FREE) {
i++; i++;
assert(i < HTTP_CLIENT_CAPACITY); assert(i < CHTTP_CLIENT_CAPACITY);
} }
client->num_conns++; client->num_conns++;
client->conns[i].state = HTTP_CLIENT_CONN_WAIT_METHOD; client->conns[i].state = CHTTP_CLIENT_CONN_WAIT_METHOD;
client->conns[i].handle = SOCKET_HANDLE_INVALID; client->conns[i].handle = SOCKET_HANDLE_INVALID;
client->conns[i].client = client; client->conns[i].client = client;
client->conns[i].user = NULL; client->conns[i].user = NULL;
@@ -97,30 +97,30 @@ HTTP_RequestBuilder http_client_get_builder(HTTP_Client *client)
byte_queue_init(&client->conns[i].input, client->input_buffer_limit); byte_queue_init(&client->conns[i].input, client->input_buffer_limit);
byte_queue_init(&client->conns[i].output, client->output_buffer_limit); byte_queue_init(&client->conns[i].output, client->output_buffer_limit);
return (HTTP_RequestBuilder) { client, i, client->conns[i].gen }; return (CHTTP_RequestBuilder) { client, i, client->conns[i].gen };
} }
// TODO: test this function // TODO: test this function
static bool is_subdomain(HTTP_String domain, HTTP_String subdomain) static bool is_subdomain(CHTTP_String domain, CHTTP_String subdomain)
{ {
if (http_streq(domain, subdomain)) if (chttp_streq(domain, subdomain))
return true; // Exact match return true; // Exact match
if (domain.len > subdomain.len) if (domain.len > subdomain.len)
return false; return false;
HTTP_String subdomain_suffix = { CHTTP_String subdomain_suffix = {
subdomain.ptr + subdomain.len - domain.len, subdomain.ptr + subdomain.len - domain.len,
domain.len domain.len
}; };
if (subdomain_suffix.ptr[-1] != '.' || !http_streq(domain, subdomain_suffix)) if (subdomain_suffix.ptr[-1] != '.' || !chttp_streq(domain, subdomain_suffix))
return false; return false;
return true; return true;
} }
// TODO: test this function // TODO: test this function
static bool is_subpath(HTTP_String path, HTTP_String subpath) static bool is_subpath(CHTTP_String path, CHTTP_String subpath)
{ {
if (path.len > subpath.len) if (path.len > subpath.len)
return false; return false;
@@ -129,16 +129,16 @@ static bool is_subpath(HTTP_String path, HTTP_String subpath)
return false; return false;
subpath.len = path.len; subpath.len = path.len;
return http_streq(path, subpath); return chttp_streq(path, subpath);
} }
static bool should_send_cookie(HTTP_CookieJarEntry entry, HTTP_URL url) static bool should_send_cookie(CHTTP_CookieJarEntry entry, CHTTP_URL url)
{ {
// TODO: If the cookie is expired, ignore it regardless // TODO: If the cookie is expired, ignore it regardless
if (entry.exact_domain) { if (entry.exact_domain) {
// Cookie domain and URL domain must match exactly // Cookie domain and URL domain must match exactly
if (!http_streq(entry.domain, url.authority.host.text)) if (!chttp_streq(entry.domain, url.authority.host.text))
return false; return false;
} else { } else {
// The URL's domain must match or be a subdomain of the cookie's domain // The URL's domain must match or be a subdomain of the cookie's domain
@@ -148,7 +148,7 @@ static bool should_send_cookie(HTTP_CookieJarEntry entry, HTTP_URL url)
if (entry.exact_path) { if (entry.exact_path) {
// Cookie path and URL path must match exactly // Cookie path and URL path must match exactly
if (!http_streq(entry.path, url.path)) if (!chttp_streq(entry.path, url.path))
return false; return false;
} else { } else {
if (!is_subpath(entry.path, url.path)) if (!is_subpath(entry.path, url.path))
@@ -156,41 +156,41 @@ static bool should_send_cookie(HTTP_CookieJarEntry entry, HTTP_URL url)
} }
if (entry.secure) { if (entry.secure) {
if (!http_streq(url.scheme, HTTP_STR("https"))) if (!chttp_streq(url.scheme, CHTTP_STR("https")))
return false; // Cookie was marked as secure but the target URL is not HTTPS return false; // Cookie was marked as secure but the target URL is not HTTPS
} }
return true; return true;
} }
static HTTP_String get_method_string(HTTP_Method method) static CHTTP_String get_method_string(CHTTP_Method method)
{ {
switch (method) { switch (method) {
case HTTP_METHOD_GET : return HTTP_STR("GET"); case CHTTP_METHOD_GET : return CHTTP_STR("GET");
case HTTP_METHOD_HEAD : return HTTP_STR("HEAD"); case CHTTP_METHOD_HEAD : return CHTTP_STR("HEAD");
case HTTP_METHOD_POST : return HTTP_STR("POST"); case CHTTP_METHOD_POST : return CHTTP_STR("POST");
case HTTP_METHOD_PUT : return HTTP_STR("PUT"); case CHTTP_METHOD_PUT : return CHTTP_STR("PUT");
case HTTP_METHOD_DELETE : return HTTP_STR("DELETE"); case CHTTP_METHOD_DELETE : return CHTTP_STR("DELETE");
case HTTP_METHOD_CONNECT: return HTTP_STR("CONNECT"); case CHTTP_METHOD_CONNECT: return CHTTP_STR("CONNECT");
case HTTP_METHOD_OPTIONS: return HTTP_STR("OPTIONS"); case CHTTP_METHOD_OPTIONS: return CHTTP_STR("OPTIONS");
case HTTP_METHOD_TRACE : return HTTP_STR("TRACE"); case CHTTP_METHOD_TRACE : return CHTTP_STR("TRACE");
case HTTP_METHOD_PATCH : return HTTP_STR("PATCH"); case CHTTP_METHOD_PATCH : return CHTTP_STR("PATCH");
} }
return HTTP_STR("???"); return CHTTP_STR("???");
} }
void http_request_builder_set_user(HTTP_RequestBuilder builder, void *user) void chttp_request_builder_set_user(CHTTP_RequestBuilder builder, void *user)
{ {
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; // Invalid builder return; // Invalid builder
conn->user = user; conn->user = user;
} }
void http_request_builder_trace(HTTP_RequestBuilder builder, bool trace_bytes) void chttp_request_builder_trace(CHTTP_RequestBuilder builder, bool trace_bytes)
{ {
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; // Invalid builder return; // Invalid builder
@@ -198,47 +198,47 @@ void http_request_builder_trace(HTTP_RequestBuilder builder, bool trace_bytes)
} }
// TODO: comment // TODO: comment
void http_request_builder_insecure(HTTP_RequestBuilder builder, void chttp_request_builder_insecure(CHTTP_RequestBuilder builder,
bool insecure) bool insecure)
{ {
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; // Invalid builder return; // Invalid builder
conn->dont_verify_cert = insecure; conn->dont_verify_cert = insecure;
} }
void http_request_builder_method(HTTP_RequestBuilder builder, void chttp_request_builder_method(CHTTP_RequestBuilder builder,
HTTP_Method method) CHTTP_Method method)
{ {
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; // Invalid builder return; // Invalid builder
if (conn->state != HTTP_CLIENT_CONN_WAIT_METHOD) if (conn->state != CHTTP_CLIENT_CONN_WAIT_METHOD)
return; // Request line already written return; // Request line already written
// Write method // Write method
HTTP_String method_str = get_method_string(method); CHTTP_String method_str = get_method_string(method);
byte_queue_write(&conn->output, method_str.ptr, method_str.len); byte_queue_write(&conn->output, method_str.ptr, method_str.len);
byte_queue_write(&conn->output, " ", 1); byte_queue_write(&conn->output, " ", 1);
conn->state = HTTP_CLIENT_CONN_WAIT_URL; conn->state = CHTTP_CLIENT_CONN_WAIT_URL;
} }
void http_request_builder_target(HTTP_RequestBuilder builder, void chttp_request_builder_target(CHTTP_RequestBuilder builder,
HTTP_String url) CHTTP_String url)
{ {
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; // Invalid builder return; // Invalid builder
if (conn->state != HTTP_CLIENT_CONN_WAIT_URL) if (conn->state != CHTTP_CLIENT_CONN_WAIT_URL)
return; // Request line already written return; // Request line already written
if (url.len == 0) { if (url.len == 0) {
conn->state = HTTP_CLIENT_CONN_COMPLETE; conn->state = CHTTP_CLIENT_CONN_COMPLETE;
conn->result = HTTP_ERROR_BADURL; conn->result = CHTTP_ERROR_BADURL;
return; return;
} }
@@ -246,8 +246,8 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
// URL pointers remain valid // URL pointers remain valid
char *url_copy = malloc(url.len); char *url_copy = malloc(url.len);
if (url_copy == NULL) { if (url_copy == NULL) {
conn->state = HTTP_CLIENT_CONN_COMPLETE; conn->state = CHTTP_CLIENT_CONN_COMPLETE;
conn->result = HTTP_ERROR_OOM; conn->result = CHTTP_ERROR_OOM;
return; return;
} }
memcpy(url_copy, url.ptr, url.len); memcpy(url_copy, url.ptr, url.len);
@@ -256,16 +256,16 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
conn->url_buffer.len = url.len; conn->url_buffer.len = url.len;
// Parse the copied URL (all url.* pointers will reference url_buffer) // Parse the copied URL (all url.* pointers will reference url_buffer)
if (http_parse_url(conn->url_buffer.ptr, conn->url_buffer.len, &conn->url) < 0) { if (chttp_parse_url(conn->url_buffer.ptr, conn->url_buffer.len, &conn->url) < 0) {
conn->state = HTTP_CLIENT_CONN_COMPLETE; conn->state = CHTTP_CLIENT_CONN_COMPLETE;
conn->result = HTTP_ERROR_BADURL; conn->result = CHTTP_ERROR_BADURL;
return; return;
} }
if (!http_streq(conn->url.scheme, HTTP_STR("http")) && if (!chttp_streq(conn->url.scheme, CHTTP_STR("http")) &&
!http_streq(conn->url.scheme, HTTP_STR("https"))) { !chttp_streq(conn->url.scheme, CHTTP_STR("https"))) {
conn->state = HTTP_CLIENT_CONN_COMPLETE; conn->state = CHTTP_CLIENT_CONN_COMPLETE;
conn->result = HTTP_ERROR_BADURL; conn->result = CHTTP_ERROR_BADURL;
return; return;
} }
@@ -278,13 +278,13 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
conn->url.path.len); conn->url.path.len);
// Write query string // Write query string
HTTP_String query = conn->url.query; CHTTP_String query = conn->url.query;
if (query.len > 0) { if (query.len > 0) {
byte_queue_write(&conn->output, "?", 1); byte_queue_write(&conn->output, "?", 1);
byte_queue_write(&conn->output, query.ptr, query.len); byte_queue_write(&conn->output, query.ptr, query.len);
} }
HTTP_String version = HTTP_STR(" HTTP/1.1"); CHTTP_String version = CHTTP_STR(" HTTP/1.1");
byte_queue_write(&conn->output, version.ptr, version.len); byte_queue_write(&conn->output, version.ptr, version.len);
byte_queue_write(&conn->output, "\r\n", 2); byte_queue_write(&conn->output, "\r\n", 2);
@@ -300,10 +300,10 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
// Find all entries from the cookie jar that should // Find all entries from the cookie jar that should
// be sent to this server and append headers for them // be sent to this server and append headers for them
HTTP_Client *client = builder.client; CHTTP_Client *client = builder.client;
HTTP_CookieJar *cookie_jar = &client->cookie_jar; CHTTP_CookieJar *cookie_jar = &client->cookie_jar;
for (int i = 0; i < cookie_jar->count; i++) { for (int i = 0; i < cookie_jar->count; i++) {
HTTP_CookieJarEntry entry = cookie_jar->items[i]; CHTTP_CookieJarEntry entry = cookie_jar->items[i];
if (should_send_cookie(entry, conn->url)) { if (should_send_cookie(entry, conn->url)) {
// TODO: Adding one header per cookie may cause the number of // TODO: Adding one header per cookie may cause the number of
// headers to increase significantly. Should probably group // headers to increase significantly. Should probably group
@@ -316,12 +316,12 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
} }
} }
HTTP_String s; CHTTP_String s;
s = HTTP_STR("Connection: Close\r\n"); s = CHTTP_STR("Connection: Close\r\n");
byte_queue_write(&conn->output, s.ptr, s.len); byte_queue_write(&conn->output, s.ptr, s.len);
s = HTTP_STR("Content-Length: "); s = CHTTP_STR("Content-Length: ");
byte_queue_write(&conn->output, s.ptr, s.len); byte_queue_write(&conn->output, s.ptr, s.len);
conn->content_length_value_offset = byte_queue_offset(&conn->output); conn->content_length_value_offset = byte_queue_offset(&conn->output);
@@ -329,20 +329,20 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
#define TEN_SPACES " " #define TEN_SPACES " "
_Static_assert(sizeof(TEN_SPACES) == 10+1); _Static_assert(sizeof(TEN_SPACES) == 10+1);
s = HTTP_STR(TEN_SPACES "\r\n"); s = CHTTP_STR(TEN_SPACES "\r\n");
byte_queue_write(&conn->output, s.ptr, s.len); byte_queue_write(&conn->output, s.ptr, s.len);
conn->state = HTTP_CLIENT_CONN_WAIT_HEADER; conn->state = CHTTP_CLIENT_CONN_WAIT_HEADER;
} }
void http_request_builder_header(HTTP_RequestBuilder builder, void chttp_request_builder_header(CHTTP_RequestBuilder builder,
HTTP_String str) CHTTP_String str)
{ {
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->state != HTTP_CLIENT_CONN_WAIT_HEADER) if (conn->state != CHTTP_CLIENT_CONN_WAIT_HEADER)
return; return;
// Validate header: must contain a colon and no control characters // Validate header: must contain a colon and no control characters
@@ -362,33 +362,33 @@ void http_request_builder_header(HTTP_RequestBuilder builder,
byte_queue_write(&conn->output, "\r\n", 2); byte_queue_write(&conn->output, "\r\n", 2);
} }
void http_request_builder_body(HTTP_RequestBuilder builder, void chttp_request_builder_body(CHTTP_RequestBuilder builder,
HTTP_String str) CHTTP_String str)
{ {
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
// Transition from WAIT_HEADER to WAIT_BODY if needed // Transition from WAIT_HEADER to WAIT_BODY if needed
if (conn->state == HTTP_CLIENT_CONN_WAIT_HEADER) { if (conn->state == CHTTP_CLIENT_CONN_WAIT_HEADER) {
byte_queue_write(&conn->output, "\r\n", 2); byte_queue_write(&conn->output, "\r\n", 2);
conn->content_length_offset = byte_queue_offset(&conn->output); conn->content_length_offset = byte_queue_offset(&conn->output);
conn->state = HTTP_CLIENT_CONN_WAIT_BODY; conn->state = CHTTP_CLIENT_CONN_WAIT_BODY;
} }
if (conn->state != HTTP_CLIENT_CONN_WAIT_BODY) if (conn->state != CHTTP_CLIENT_CONN_WAIT_BODY)
return; return;
byte_queue_write(&conn->output, str.ptr, str.len); byte_queue_write(&conn->output, str.ptr, str.len);
} }
static ConnectTarget url_to_connect_target(HTTP_URL url) static ConnectTarget url_to_connect_target(CHTTP_URL url)
{ {
HTTP_Authority authority = url.authority; CHTTP_Authority authority = url.authority;
ConnectTarget target; ConnectTarget target;
if (authority.port < 1) { if (authority.port < 1) {
if (http_streq(url.scheme, HTTP_STR("https"))) if (chttp_streq(url.scheme, CHTTP_STR("https")))
target.port = 443; target.port = 443;
else else
target.port = 80; target.port = 80;
@@ -396,42 +396,42 @@ static ConnectTarget url_to_connect_target(HTTP_URL url)
target.port = authority.port; target.port = authority.port;
} }
if (authority.host.mode == HTTP_HOST_MODE_NAME) { if (authority.host.mode == CHTTP_HOST_MODE_NAME) {
target.type = CONNECT_TARGET_NAME; target.type = CONNECT_TARGET_NAME;
target.name = authority.host.name; target.name = authority.host.name;
} else if (authority.host.mode == HTTP_HOST_MODE_IPV4) { } else if (authority.host.mode == CHTTP_HOST_MODE_IPV4) {
target.type = CONNECT_TARGET_IPV4; target.type = CONNECT_TARGET_IPV4;
target.ipv4 = authority.host.ipv4; target.ipv4 = authority.host.ipv4;
} else if (authority.host.mode == HTTP_HOST_MODE_IPV6) { } else if (authority.host.mode == CHTTP_HOST_MODE_IPV6) {
target.type = CONNECT_TARGET_IPV6; target.type = CONNECT_TARGET_IPV6;
target.ipv6 = authority.host.ipv6; target.ipv6 = authority.host.ipv6;
} else { } else {
HTTP_UNREACHABLE; CHTTP_UNREACHABLE;
} }
return target; return target;
} }
int http_request_builder_send(HTTP_RequestBuilder builder) int chttp_request_builder_send(CHTTP_RequestBuilder builder)
{ {
HTTP_Client *client = builder.client; CHTTP_Client *client = builder.client;
if (client == NULL) if (client == NULL)
return HTTP_ERROR_REQLIMIT; return CHTTP_ERROR_REQLIMIT;
HTTP_ClientConn *conn = request_builder_to_conn(builder); CHTTP_ClientConn *conn = request_builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return HTTP_ERROR_BADHANDLE; return CHTTP_ERROR_BADHANDLE;
if (conn->state == HTTP_CLIENT_CONN_COMPLETE) if (conn->state == CHTTP_CLIENT_CONN_COMPLETE)
goto error; // Early completion due to an error goto error; // Early completion due to an error
if (conn->state == HTTP_CLIENT_CONN_WAIT_HEADER) { if (conn->state == CHTTP_CLIENT_CONN_WAIT_HEADER) {
byte_queue_write(&conn->output, "\r\n", 2); byte_queue_write(&conn->output, "\r\n", 2);
conn->content_length_offset = byte_queue_offset(&conn->output); conn->content_length_offset = byte_queue_offset(&conn->output);
conn->state = HTTP_CLIENT_CONN_WAIT_BODY; conn->state = CHTTP_CLIENT_CONN_WAIT_BODY;
} }
if (conn->state != HTTP_CLIENT_CONN_WAIT_BODY) if (conn->state != CHTTP_CLIENT_CONN_WAIT_BODY)
goto error; goto error;
if (byte_queue_error(&conn->output)) if (byte_queue_error(&conn->output))
@@ -446,16 +446,16 @@ int http_request_builder_send(HTTP_RequestBuilder builder)
byte_queue_patch(&conn->output, conn->content_length_value_offset, tmp, len); byte_queue_patch(&conn->output, conn->content_length_value_offset, tmp, len);
ConnectTarget target = url_to_connect_target(conn->url); ConnectTarget target = url_to_connect_target(conn->url);
bool secure = http_streq(conn->url.scheme, HTTP_STR("https")); bool secure = chttp_streq(conn->url.scheme, CHTTP_STR("https"));
if (socket_connect(&client->sockets, 1, &target, secure, conn->dont_verify_cert, conn) < 0) if (socket_connect(&client->sockets, 1, &target, secure, conn->dont_verify_cert, conn) < 0)
goto error; goto error;
conn->state = HTTP_CLIENT_CONN_FLUSHING; conn->state = CHTTP_CLIENT_CONN_FLUSHING;
conn->gen++; conn->gen++;
return HTTP_OK; return CHTTP_OK;
error: error:
conn->state = HTTP_CLIENT_CONN_FREE; conn->state = CHTTP_CLIENT_CONN_FREE;
free(conn->url_buffer.ptr); free(conn->url_buffer.ptr);
byte_queue_free(&conn->input); byte_queue_free(&conn->input);
byte_queue_free(&conn->output); byte_queue_free(&conn->output);
@@ -463,17 +463,17 @@ error:
return conn->result; return conn->result;
} }
static void save_one_cookie(HTTP_CookieJar *cookie_jar, static void save_one_cookie(CHTTP_CookieJar *cookie_jar,
HTTP_Header set_cookie, HTTP_String domain, HTTP_String path) CHTTP_Header set_cookie, CHTTP_String domain, CHTTP_String path)
{ {
if (cookie_jar->count == HTTP_COOKIE_JAR_CAPACITY) if (cookie_jar->count == CHTTP_COOKIE_JAR_CAPACITY)
return; // Cookie jar capacity reached return; // Cookie jar capacity reached
HTTP_SetCookie parsed; CHTTP_SetCookie parsed;
if (http_parse_set_cookie(set_cookie.value, &parsed) < 0) if (chttp_parse_set_cookie(set_cookie.value, &parsed) < 0)
return; // Ignore invalid Set-Cookie headers return; // Ignore invalid Set-Cookie headers
HTTP_CookieJarEntry entry; CHTTP_CookieJarEntry entry;
entry.name = parsed.name; entry.name = parsed.name;
entry.value = parsed.value; entry.value = parsed.value;
@@ -522,32 +522,32 @@ static void save_one_cookie(HTTP_CookieJar *cookie_jar,
cookie_jar->items[cookie_jar->count++] = entry; cookie_jar->items[cookie_jar->count++] = entry;
} }
static void save_cookies(HTTP_CookieJar *cookie_jar, static void save_cookies(CHTTP_CookieJar *cookie_jar,
HTTP_Header *headers, int num_headers, CHTTP_Header *headers, int num_headers,
HTTP_String domain, HTTP_String path) CHTTP_String domain, CHTTP_String path)
{ {
// TODO: remove expired cookies // TODO: remove expired cookies
for (int i = 0; i < num_headers; i++) for (int i = 0; i < num_headers; i++)
if (http_streqcase(headers[i].name, HTTP_STR("Set-Cookie"))) // TODO: headers are case-insensitive, right? if (chttp_streqcase(headers[i].name, CHTTP_STR("Set-Cookie"))) // TODO: headers are case-insensitive, right?
save_one_cookie(cookie_jar, headers[i], domain, path); save_one_cookie(cookie_jar, headers[i], domain, path);
} }
void http_client_register_events(HTTP_Client *client, void chttp_client_register_events(CHTTP_Client *client,
EventRegister *reg) EventRegister *reg)
{ {
socket_manager_register_events(&client->sockets, reg); socket_manager_register_events(&client->sockets, reg);
} }
void http_client_process_events(HTTP_Client *client, void chttp_client_process_events(CHTTP_Client *client,
EventRegister reg) EventRegister reg)
{ {
SocketEvent events[HTTP_CLIENT_CAPACITY]; SocketEvent events[CHTTP_CLIENT_CAPACITY];
int num_events = socket_manager_translate_events(&client->sockets, events, reg); int num_events = socket_manager_translate_events(&client->sockets, events, reg);
for (int i = 0; i < num_events; i++) { for (int i = 0; i < num_events; i++) {
HTTP_ClientConn *conn = events[i].user; CHTTP_ClientConn *conn = events[i].user;
if (conn == NULL) if (conn == NULL)
continue; // If a socket is not couple to a connection, continue; // If a socket is not couple to a connection,
// it means the response was already returned // it means the response was already returned
@@ -555,7 +555,7 @@ void http_client_process_events(HTTP_Client *client,
if (events[i].type == SOCKET_EVENT_DISCONNECT) { if (events[i].type == SOCKET_EVENT_DISCONNECT) {
conn->state = HTTP_CLIENT_CONN_COMPLETE; conn->state = CHTTP_CLIENT_CONN_COMPLETE;
conn->result = -1; conn->result = -1;
} else if (events[i].type == SOCKET_EVENT_READY) { } else if (events[i].type == SOCKET_EVENT_READY) {
@@ -566,7 +566,7 @@ void http_client_process_events(HTTP_Client *client,
while (socket_ready(&client->sockets, conn->handle)) { while (socket_ready(&client->sockets, conn->handle)) {
if (conn->state == HTTP_CLIENT_CONN_FLUSHING) { if (conn->state == CHTTP_CLIENT_CONN_FLUSHING) {
ByteView src = byte_queue_read_buf(&conn->output); ByteView src = byte_queue_read_buf(&conn->output);
@@ -575,7 +575,7 @@ void http_client_process_events(HTTP_Client *client,
num = socket_send(&client->sockets, conn->handle, src.ptr, src.len); num = socket_send(&client->sockets, conn->handle, src.ptr, src.len);
if (conn->trace_bytes) if (conn->trace_bytes)
print_bytes(HTTP_STR("<< "), (HTTP_String){src.ptr, num}); print_bytes(CHTTP_STR("<< "), (CHTTP_String){src.ptr, num});
byte_queue_read_ack(&conn->output, num); byte_queue_read_ack(&conn->output, num);
@@ -586,10 +586,10 @@ void http_client_process_events(HTTP_Client *client,
// Request fully sent, now wait for response // Request fully sent, now wait for response
if (byte_queue_empty(&conn->output)) if (byte_queue_empty(&conn->output))
conn->state = HTTP_CLIENT_CONN_BUFFERING; conn->state = CHTTP_CLIENT_CONN_BUFFERING;
} }
if (conn->state == HTTP_CLIENT_CONN_BUFFERING) { if (conn->state == CHTTP_CLIENT_CONN_BUFFERING) {
// Receive response data // Receive response data
int min_recv = 1<<10; int min_recv = 1<<10;
@@ -602,7 +602,7 @@ void http_client_process_events(HTTP_Client *client,
num = socket_recv(&client->sockets, conn->handle, dst.ptr, dst.len); num = socket_recv(&client->sockets, conn->handle, dst.ptr, dst.len);
if (conn->trace_bytes) if (conn->trace_bytes)
print_bytes(HTTP_STR(">> "), (HTTP_String){dst.ptr, num}); print_bytes(CHTTP_STR(">> "), (CHTTP_String){dst.ptr, num});
byte_queue_write_ack(&conn->input, num); byte_queue_write_ack(&conn->input, num);
@@ -612,7 +612,7 @@ void http_client_process_events(HTTP_Client *client,
} }
ByteView src = byte_queue_read_buf(&conn->input); ByteView src = byte_queue_read_buf(&conn->input);
int ret = http_parse_response(src.ptr, src.len, &conn->response); int ret = chttp_parse_response(src.ptr, src.len, &conn->response);
if (ret == 0) { if (ret == 0) {
// Still waiting // Still waiting
@@ -635,7 +635,7 @@ void http_client_process_events(HTTP_Client *client,
// Ready // Ready
assert(ret > 0); assert(ret > 0);
conn->state = HTTP_CLIENT_CONN_COMPLETE; conn->state = CHTTP_CLIENT_CONN_COMPLETE;
conn->result = 0; conn->result = 0;
conn->response.context = client; conn->response.context = client;
@@ -653,36 +653,36 @@ void http_client_process_events(HTTP_Client *client,
} }
} }
if (conn->state == HTTP_CLIENT_CONN_COMPLETE) { if (conn->state == CHTTP_CLIENT_CONN_COMPLETE) {
// Decouple from the socket // Decouple from the socket
socket_set_user(&client->sockets, events[i].handle, NULL); socket_set_user(&client->sockets, events[i].handle, NULL);
socket_close(&client->sockets, events[i].handle); socket_close(&client->sockets, events[i].handle);
// Push to the ready queue // Push to the ready queue
assert(client->num_ready < HTTP_CLIENT_CAPACITY); assert(client->num_ready < CHTTP_CLIENT_CAPACITY);
int tail = (client->ready_head + client->num_ready) % HTTP_CLIENT_CAPACITY; int tail = (client->ready_head + client->num_ready) % CHTTP_CLIENT_CAPACITY;
client->ready[tail] = conn - client->conns; client->ready[tail] = conn - client->conns;
client->num_ready++; client->num_ready++;
} }
} }
} }
bool http_client_next_response(HTTP_Client *client, bool chttp_client_next_response(CHTTP_Client *client,
int *result, void **user, HTTP_Response **response) int *result, void **user, CHTTP_Response **response)
{ {
if (client->num_ready == 0) if (client->num_ready == 0)
return false; return false;
HTTP_ClientConn *conn = &client->conns[client->ready[client->ready_head]]; CHTTP_ClientConn *conn = &client->conns[client->ready[client->ready_head]];
client->ready_head = (client->ready_head + 1) % HTTP_CLIENT_CAPACITY; client->ready_head = (client->ready_head + 1) % CHTTP_CLIENT_CAPACITY;
client->num_ready--; client->num_ready--;
assert(conn->state == HTTP_CLIENT_CONN_COMPLETE); assert(conn->state == CHTTP_CLIENT_CONN_COMPLETE);
*result = conn->result; *result = conn->result;
*user = conn->user; *user = conn->user;
if (conn->result == HTTP_OK) { if (conn->result == CHTTP_OK) {
*response = &conn->response; *response = &conn->response;
} else { } else {
*response = NULL; *response = NULL;
@@ -691,17 +691,17 @@ bool http_client_next_response(HTTP_Client *client,
return true; return true;
} }
void http_free_response(HTTP_Response *response) void chttp_free_response(CHTTP_Response *response)
{ {
if (response == NULL || response->context == NULL) if (response == NULL || response->context == NULL)
return; return;
HTTP_Client *client = response->context; CHTTP_Client *client = response->context;
response->context = NULL; response->context = NULL;
// TODO: I'm positive there is a better way to do this. // TODO: I'm positive there is a better way to do this.
// It should just be a bouds check + subtraction. // It should just be a bouds check + subtraction.
HTTP_ClientConn *conn = NULL; CHTTP_ClientConn *conn = NULL;
for (int i = 0; i < HTTP_CLIENT_CAPACITY; i++) for (int i = 0; i < CHTTP_CLIENT_CAPACITY; i++)
if (&client->conns[i].response == response) { if (&client->conns[i].response == response) {
conn = &client->conns[i]; conn = &client->conns[i];
break; break;
@@ -709,7 +709,7 @@ void http_free_response(HTTP_Response *response)
if (conn == NULL) if (conn == NULL)
return; return;
conn->state = HTTP_CLIENT_CONN_FREE; conn->state = CHTTP_CLIENT_CONN_FREE;
free(conn->url_buffer.ptr); free(conn->url_buffer.ptr);
byte_queue_free(&conn->input); byte_queue_free(&conn->input);
byte_queue_free(&conn->output); byte_queue_free(&conn->output);
@@ -722,86 +722,86 @@ void http_free_response(HTTP_Response *response)
#define POLL poll #define POLL poll
#endif #endif
void http_client_wait_response(HTTP_Client *client, void chttp_client_wait_response(CHTTP_Client *client,
int *result, void **user, HTTP_Response **response) int *result, void **user, CHTTP_Response **response)
{ {
for (;;) { for (;;) {
void *ptrs[HTTP_CLIENT_POLL_CAPACITY]; void *ptrs[CHTTP_CLIENT_POLL_CAPACITY];
struct pollfd polled[HTTP_CLIENT_POLL_CAPACITY]; struct pollfd polled[CHTTP_CLIENT_POLL_CAPACITY];
EventRegister reg = { ptrs, polled, 0 }; EventRegister reg = { ptrs, polled, 0 };
http_client_register_events(client, &reg); chttp_client_register_events(client, &reg);
if (reg.num_polled > 0) if (reg.num_polled > 0)
POLL(reg.polled, reg.num_polled, -1); POLL(reg.polled, reg.num_polled, -1);
http_client_process_events(client, reg); chttp_client_process_events(client, reg);
if (http_client_next_response(client, result, user, response)) if (chttp_client_next_response(client, result, user, response))
break; break;
} }
} }
static _Thread_local HTTP_Client *implicit_client; static _Thread_local CHTTP_Client *implicit_client;
static int perform_request(HTTP_Method method, static int perform_request(CHTTP_Method method,
HTTP_String url, HTTP_String *headers, CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_String body, int num_headers, CHTTP_String body,
HTTP_Response **response) CHTTP_Response **response)
{ {
if (implicit_client == NULL) { if (implicit_client == NULL) {
implicit_client = malloc(sizeof(HTTP_Client)); implicit_client = malloc(sizeof(CHTTP_Client));
if (implicit_client == NULL) if (implicit_client == NULL)
return HTTP_ERROR_OOM; return CHTTP_ERROR_OOM;
int ret = http_client_init(implicit_client); int ret = chttp_client_init(implicit_client);
if (ret < 0) { if (ret < 0) {
free(implicit_client); free(implicit_client);
implicit_client = NULL; implicit_client = NULL;
return ret; return ret;
} }
} }
HTTP_Client *client = implicit_client; CHTTP_Client *client = implicit_client;
HTTP_RequestBuilder builder = http_client_get_builder(client); CHTTP_RequestBuilder builder = chttp_client_get_builder(client);
http_request_builder_method(builder, method); chttp_request_builder_method(builder, method);
http_request_builder_target(builder, url); chttp_request_builder_target(builder, url);
for (int i = 0; i < num_headers; i++) for (int i = 0; i < num_headers; i++)
http_request_builder_header(builder, headers[i]); chttp_request_builder_header(builder, headers[i]);
http_request_builder_body(builder, body); chttp_request_builder_body(builder, body);
int ret = http_request_builder_send(builder); int ret = chttp_request_builder_send(builder);
if (ret < 0) return ret; if (ret < 0) return ret;
int result; int result;
void *user; void *user;
http_client_wait_response(client, &result, &user, response); chttp_client_wait_response(client, &result, &user, response);
return result; return result;
} }
int http_get(HTTP_String url, HTTP_String *headers, int chttp_get(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_Response **response) int num_headers, CHTTP_Response **response)
{ {
return perform_request(HTTP_METHOD_GET, url, headers, num_headers, HTTP_STR(""), response); return perform_request(CHTTP_METHOD_GET, url, headers, num_headers, CHTTP_STR(""), response);
} }
int http_post(HTTP_String url, HTTP_String *headers, int chttp_post(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_String body, int num_headers, CHTTP_String body,
HTTP_Response **response) CHTTP_Response **response)
{ {
return perform_request(HTTP_METHOD_POST, url, headers, num_headers, body, response); return perform_request(CHTTP_METHOD_POST, url, headers, num_headers, body, response);
} }
int http_put(HTTP_String url, HTTP_String *headers, int chttp_put(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_String body, int num_headers, CHTTP_String body,
HTTP_Response **response) CHTTP_Response **response)
{ {
return perform_request(HTTP_METHOD_PUT, url, headers, num_headers, body, response); return perform_request(CHTTP_METHOD_PUT, url, headers, num_headers, body, response);
} }
int http_delete(HTTP_String url, HTTP_String *headers, int chttp_delete(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_Response **response) int num_headers, CHTTP_Response **response)
{ {
return perform_request(HTTP_METHOD_DELETE, url, headers, num_headers, HTTP_STR(""), response); return perform_request(CHTTP_METHOD_DELETE, url, headers, num_headers, CHTTP_STR(""), response);
} }
+71 -71
View File
@@ -1,26 +1,26 @@
#ifndef HTTP_CLIENT_CAPACITY #ifndef CHTTP_CLIENT_CAPACITY
// The maximum ammount of requests that can be performed // The maximum ammount of requests that can be performed
// in parallel. // in parallel.
#define HTTP_CLIENT_CAPACITY (1<<7) #define CHTTP_CLIENT_CAPACITY (1<<7)
#endif #endif
// Maximum number of descriptors the client will want // Maximum number of descriptors the client will want
// to wait on. It's one per connection plus the wakeup // to wait on. It's one per connection plus the wakeup
// self-pipe. // self-pipe.
#define HTTP_CLIENT_POLL_CAPACITY (HTTP_CLIENT_CAPACITY+1) #define CHTTP_CLIENT_POLL_CAPACITY (CHTTP_CLIENT_CAPACITY+1)
#ifndef HTTP_COOKIE_JAR_CAPACITY #ifndef CHTTP_COOKIE_JAR_CAPACITY
// Maximum number of cookies that can be associated to a // Maximum number of cookies that can be associated to a
// single client. // single client.
#define HTTP_COOKIE_JAR_CAPACITY 128 #define CHTTP_COOKIE_JAR_CAPACITY 128
#endif #endif
typedef struct { typedef struct {
// Cookie name and value // Cookie name and value
HTTP_String name; CHTTP_String name;
HTTP_String value; CHTTP_String value;
// If the "exact_domain" is true, the cookie // If the "exact_domain" is true, the cookie
// can only be sent to the exact domain referred // can only be sent to the exact domain referred
@@ -28,7 +28,7 @@ typedef struct {
// "exact_domain" is false, then the cookie is // "exact_domain" is false, then the cookie is
// compatible with subdomains. // compatible with subdomains.
bool exact_domain; bool exact_domain;
HTTP_String domain; CHTTP_String domain;
// If "exact_path" is set, the cookie is only // If "exact_path" is set, the cookie is only
// compatible with requests to paths that match // compatible with requests to paths that match
@@ -36,40 +36,40 @@ typedef struct {
// then any path that starts with "path" is // then any path that starts with "path" is
// compatible with the cookie. // compatible with the cookie.
bool exact_path; bool exact_path;
HTTP_String path; CHTTP_String path;
// This cookie can only be sent over HTTPS // This cookie can only be sent over HTTPS
bool secure; bool secure;
} HTTP_CookieJarEntry; } CHTTP_CookieJarEntry;
typedef struct { typedef struct {
int count; int count;
HTTP_CookieJarEntry items[HTTP_COOKIE_JAR_CAPACITY]; CHTTP_CookieJarEntry items[CHTTP_COOKIE_JAR_CAPACITY];
} HTTP_CookieJar; } CHTTP_CookieJar;
typedef enum { typedef enum {
HTTP_CLIENT_CONN_FREE, CHTTP_CLIENT_CONN_FREE,
HTTP_CLIENT_CONN_WAIT_METHOD, CHTTP_CLIENT_CONN_WAIT_METHOD,
HTTP_CLIENT_CONN_WAIT_URL, CHTTP_CLIENT_CONN_WAIT_URL,
HTTP_CLIENT_CONN_WAIT_HEADER, CHTTP_CLIENT_CONN_WAIT_HEADER,
HTTP_CLIENT_CONN_WAIT_BODY, CHTTP_CLIENT_CONN_WAIT_BODY,
HTTP_CLIENT_CONN_FLUSHING, CHTTP_CLIENT_CONN_FLUSHING,
HTTP_CLIENT_CONN_BUFFERING, CHTTP_CLIENT_CONN_BUFFERING,
HTTP_CLIENT_CONN_COMPLETE, CHTTP_CLIENT_CONN_COMPLETE,
} HTTP_ClientConnState; } CHTTP_ClientConnState;
// Fields of this struct are private // Fields of this struct are private
typedef struct HTTP_Client HTTP_Client; typedef struct CHTTP_Client CHTTP_Client;
typedef struct { typedef struct {
HTTP_ClientConnState state; CHTTP_ClientConnState state;
// Handle to the socket // Handle to the socket
SocketHandle handle; SocketHandle handle;
// Pointer back to the client // Pointer back to the client
HTTP_Client *client; CHTTP_Client *client;
// Generation counter for request builder validation // Generation counter for request builder validation
uint16_t gen; uint16_t gen;
@@ -85,11 +85,11 @@ typedef struct {
bool dont_verify_cert; bool dont_verify_cert;
// Allocated copy of the URL string // Allocated copy of the URL string
HTTP_String url_buffer; CHTTP_String url_buffer;
// Parsed URL for connection establishment // Parsed URL for connection establishment
// All url.* pointers reference into url_buffer // All url.* pointers reference into url_buffer
HTTP_URL url; CHTTP_URL url;
// Data received from the server // Data received from the server
ByteQueue input; ByteQueue input;
@@ -104,7 +104,7 @@ typedef struct {
int result; int result;
// Parsed response once complete // Parsed response once complete
HTTP_Response response; CHTTP_Response response;
// This offset points to the first byte that comes // This offset points to the first byte that comes
// after the string "Content-Length: ". // after the string "Content-Length: ".
@@ -115,10 +115,10 @@ typedef struct {
// content byte subtracting it from the offset reached // content byte subtracting it from the offset reached
// when the request is marked as done. // when the request is marked as done.
ByteQueueOffset content_length_offset; ByteQueueOffset content_length_offset;
} HTTP_ClientConn; } CHTTP_ClientConn;
// Fields of this struct are private // Fields of this struct are private
struct HTTP_Client { struct CHTTP_Client {
// Size limit of the input and output buffer of each // Size limit of the input and output buffer of each
// connection. // connection.
@@ -126,18 +126,18 @@ struct HTTP_Client {
uint32_t output_buffer_limit; uint32_t output_buffer_limit;
// List of cookies created during this session // List of cookies created during this session
HTTP_CookieJar cookie_jar; CHTTP_CookieJar cookie_jar;
// Array of connections. The counter contains the // Array of connections. The counter contains the
// number of structs such that state!=FREE. // number of structs such that state!=FREE.
int num_conns; int num_conns;
HTTP_ClientConn conns[HTTP_CLIENT_CAPACITY]; CHTTP_ClientConn conns[CHTTP_CLIENT_CAPACITY];
// Queue of indices referring to connections that // Queue of indices referring to connections that
// are in the COMPLETE state. // are in the COMPLETE state.
int num_ready; int num_ready;
int ready_head; int ready_head;
int ready[HTTP_CLIENT_CAPACITY]; int ready[CHTTP_CLIENT_CAPACITY];
// Asynchronous TCP and TLS socket abstraction // Asynchronous TCP and TLS socket abstraction
SocketManager sockets; SocketManager sockets;
@@ -147,80 +147,80 @@ struct HTTP_Client {
// manager with a pointer to it. This allows // manager with a pointer to it. This allows
// allocating the exact number of sockets we // allocating the exact number of sockets we
// will need. // will need.
Socket socket_pool[HTTP_CLIENT_CAPACITY]; Socket socket_pool[CHTTP_CLIENT_CAPACITY];
}; };
// Initialize an HTTP client object. This allows one to // Initialize an HTTP client object. This allows one to
// perform a number of requests in parallel. // perform a number of requests in parallel.
int http_client_init(HTTP_Client *client); int chttp_client_init(CHTTP_Client *client);
// Release resources associated to a client object. // Release resources associated to a client object.
void http_client_free(HTTP_Client *client); void chttp_client_free(CHTTP_Client *client);
// Set input and output buffer size limit for any // Set input and output buffer size limit for any
// given connection. The default value is 1MB // given connection. The default value is 1MB
void http_client_set_input_limit(HTTP_Client *client, uint32_t limit); void chttp_client_set_input_limit(CHTTP_Client *client, uint32_t limit);
void http_client_set_output_limit(HTTP_Client *client, uint32_t limit); void chttp_client_set_output_limit(CHTTP_Client *client, uint32_t limit);
// When a thread is blocked waiting for client events, // When a thread is blocked waiting for client events,
// other threads can call this function to wake it up. // other threads can call this function to wake it up.
int http_client_wakeup(HTTP_Client *client); int chttp_client_wakeup(CHTTP_Client *client);
typedef struct { typedef struct {
HTTP_Client *client; CHTTP_Client *client;
uint16_t index; uint16_t index;
uint16_t gen; uint16_t gen;
} HTTP_RequestBuilder; } CHTTP_RequestBuilder;
// Create a new request builder object. // Create a new request builder object.
HTTP_RequestBuilder http_client_get_builder(HTTP_Client *client); CHTTP_RequestBuilder chttp_client_get_builder(CHTTP_Client *client);
// TODO: comment // TODO: comment
void http_request_builder_set_user(HTTP_RequestBuilder builder, void chttp_request_builder_set_user(CHTTP_RequestBuilder builder,
void *user); void *user);
// TODO: comment // TODO: comment
void http_request_builder_trace(HTTP_RequestBuilder builder, void chttp_request_builder_trace(CHTTP_RequestBuilder builder,
bool trace_bytes); bool trace_bytes);
// TODO: comment // TODO: comment
void http_request_builder_insecure(HTTP_RequestBuilder builder, void chttp_request_builder_insecure(CHTTP_RequestBuilder builder,
bool insecure); bool insecure);
// Set the method of the current request. This is the first // Set the method of the current request. This is the first
// function of the request builder that the user must call. // function of the request builder that the user must call.
void http_request_builder_method(HTTP_RequestBuilder builder, void chttp_request_builder_method(CHTTP_RequestBuilder builder,
HTTP_Method method); CHTTP_Method method);
// Set the URL of the current request. This must be set after // Set the URL of the current request. This must be set after
// the method and before any header/body // the method and before any header/body
void http_request_builder_target(HTTP_RequestBuilder builder, void chttp_request_builder_target(CHTTP_RequestBuilder builder,
HTTP_String url); CHTTP_String url);
// After the URL, the user may set zero or more headers. // After the URL, the user may set zero or more headers.
void http_request_builder_header(HTTP_RequestBuilder builder, void chttp_request_builder_header(CHTTP_RequestBuilder builder,
HTTP_String str); CHTTP_String str);
// Append bytes to the request's body. You can call this // Append bytes to the request's body. You can call this
// any amount of times, as long as it's after having set // any amount of times, as long as it's after having set
// the URL. // the URL.
void http_request_builder_body(HTTP_RequestBuilder builder, void chttp_request_builder_body(CHTTP_RequestBuilder builder,
HTTP_String str); CHTTP_String str);
// Mark this request as complete. This invalidates the // Mark this request as complete. This invalidates the
// builder. // builder.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int http_request_builder_send(HTTP_RequestBuilder builder); int chttp_request_builder_send(CHTTP_RequestBuilder builder);
// Resets the event register with the list of descriptors // Resets the event register with the list of descriptors
// the client wants monitored. // the client wants monitored.
void http_client_register_events(HTTP_Client *client, void chttp_client_register_events(CHTTP_Client *client,
EventRegister *reg); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP client // I/O events to be triggered, so now the HTTP client
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
void http_client_process_events(HTTP_Client *client, void chttp_client_process_events(CHTTP_Client *client,
EventRegister reg); EventRegister reg);
// After some I/O events were processes, some responses // After some I/O events were processes, some responses
@@ -228,33 +228,33 @@ void http_client_process_events(HTTP_Client *client,
// buffered responses. If a request was available, true // buffered responses. If a request was available, true
// is returned. If no more are avaiable, false is returned. // is returned. If no more are avaiable, false is returned.
// The returned response must be freed using the // The returned response must be freed using the
// http_free_response function. // chttp_free_response function.
// TODO: Better comment talking about output arguments // TODO: Better comment talking about output arguments
bool http_client_next_response(HTTP_Client *client, bool chttp_client_next_response(CHTTP_Client *client,
int *result, void **user, HTTP_Response **response); int *result, void **user, CHTTP_Response **response);
// TODO: comment // TODO: comment
void http_client_wait_response(HTTP_Client *client, void chttp_client_wait_response(CHTTP_Client *client,
int *result, void **user, HTTP_Response **response); int *result, void **user, CHTTP_Response **response);
// Free a response object. You can't access its fields // Free a response object. You can't access its fields
// again after this. // again after this.
void http_free_response(HTTP_Response *response); void chttp_free_response(CHTTP_Response *response);
// Perform a blocking GET request // Perform a blocking GET request
int http_get(HTTP_String url, HTTP_String *headers, int chttp_get(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_Response **response); int num_headers, CHTTP_Response **response);
// Perform a blocking POST request // Perform a blocking POST request
int http_post(HTTP_String url, HTTP_String *headers, int chttp_post(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_String body, int num_headers, CHTTP_String body,
HTTP_Response **response); CHTTP_Response **response);
// Perform a blocking PUT request // Perform a blocking PUT request
int http_put(HTTP_String url, HTTP_String *headers, int chttp_put(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_String body, int num_headers, CHTTP_String body,
HTTP_Response **response); CHTTP_Response **response);
// Perform a blocking DELETE request // Perform a blocking DELETE request
int http_delete(HTTP_String url, HTTP_String *headers, int chttp_delete(CHTTP_String url, CHTTP_String *headers,
int num_headers, HTTP_Response **response); int num_headers, CHTTP_Response **response);
+155 -155
View File
@@ -128,7 +128,7 @@ consume_absolute_path(Scanner *s)
// path-absolute = "/" [ segment-nz *( "/" segment ) ] // path-absolute = "/" [ segment-nz *( "/" segment ) ]
// path-rootless = segment-nz *( "/" segment ) // path-rootless = segment-nz *( "/" segment )
// path-empty = 0<pchar> // path-empty = 0<pchar>
static int parse_path(Scanner *s, HTTP_String *path, int abempty) static int parse_path(Scanner *s, CHTTP_String *path, int abempty)
{ {
int start = s->cur; int start = s->cur;
@@ -175,7 +175,7 @@ static int parse_path(Scanner *s, HTTP_String *path, int abempty)
// (do nothing) // (do nothing)
} }
*path = (HTTP_String) { *path = (CHTTP_String) {
s->src + start, s->src + start,
s->cur - start, s->cur - start,
}; };
@@ -215,7 +215,7 @@ static void invert_bytes(void *p, int len)
} }
} }
static int parse_ipv4(Scanner *s, HTTP_IPv4 *ipv4) static int parse_ipv4(Scanner *s, CHTTP_IPv4 *ipv4)
{ {
unsigned int out = 0; unsigned int out = 0;
int i = 0; int i = 0;
@@ -289,7 +289,7 @@ static int parse_ipv6_comp(Scanner *s)
return (int) buf; return (int) buf;
} }
static int parse_ipv6(Scanner *s, HTTP_IPv6 *ipv6) static int parse_ipv6(Scanner *s, CHTTP_IPv6 *ipv6)
{ {
unsigned short head[8]; unsigned short head[8];
unsigned short tail[8]; unsigned short tail[8];
@@ -359,7 +359,7 @@ static int is_regname(char c)
return is_unreserved(c) || is_sub_delim(c); return is_unreserved(c) || is_sub_delim(c);
} }
static int parse_regname(Scanner *s, HTTP_String *regname) static int parse_regname(Scanner *s, CHTTP_String *regname)
{ {
if (s->cur == s->len || !is_regname(s->src[s->cur])) if (s->cur == s->len || !is_regname(s->src[s->cur]))
return -1; return -1;
@@ -372,7 +372,7 @@ static int parse_regname(Scanner *s, HTTP_String *regname)
return 0; return 0;
} }
static int parse_host(Scanner *s, HTTP_Host *host) static int parse_host(Scanner *s, CHTTP_Host *host)
{ {
int ret; int ret;
if (s->cur < s->len && s->src[s->cur] == '[') { if (s->cur < s->len && s->src[s->cur] == '[') {
@@ -380,13 +380,13 @@ static int parse_host(Scanner *s, HTTP_Host *host)
s->cur++; s->cur++;
int start = s->cur; int start = s->cur;
HTTP_IPv6 ipv6; CHTTP_IPv6 ipv6;
ret = parse_ipv6(s, &ipv6); ret = parse_ipv6(s, &ipv6);
if (ret < 0) return ret; if (ret < 0) return ret;
host->mode = HTTP_HOST_MODE_IPV6; host->mode = CHTTP_HOST_MODE_IPV6;
host->ipv6 = ipv6; host->ipv6 = ipv6;
host->text = (HTTP_String) { s->src + start, s->cur - start }; host->text = (CHTTP_String) { s->src + start, s->cur - start };
if (s->cur == s->len || s->src[s->cur] != ']') if (s->cur == s->len || s->src[s->cur] != ']')
return -1; return -1;
@@ -395,22 +395,22 @@ static int parse_host(Scanner *s, HTTP_Host *host)
} else { } else {
int start = s->cur; int start = s->cur;
HTTP_IPv4 ipv4; CHTTP_IPv4 ipv4;
ret = parse_ipv4(s, &ipv4); ret = parse_ipv4(s, &ipv4);
if (ret >= 0) { if (ret >= 0) {
host->mode = HTTP_HOST_MODE_IPV4; host->mode = CHTTP_HOST_MODE_IPV4;
host->ipv4 = ipv4; host->ipv4 = ipv4;
} else { } else {
s->cur = start; s->cur = start;
HTTP_String regname; CHTTP_String regname;
ret = parse_regname(s, &regname); ret = parse_regname(s, &regname);
if (ret < 0) return ret; if (ret < 0) return ret;
host->mode = HTTP_HOST_MODE_NAME; host->mode = CHTTP_HOST_MODE_NAME;
host->name = regname; host->name = regname;
} }
host->text = (HTTP_String) { s->src + start, s->cur - start }; host->text = (CHTTP_String) { s->src + start, s->cur - start };
} }
return 0; return 0;
@@ -439,16 +439,16 @@ static int is_userinfo(char c)
} }
// authority = [ userinfo "@" ] host [ ":" port ] // authority = [ userinfo "@" ] host [ ":" port ]
static int parse_authority(Scanner *s, HTTP_Authority *authority) static int parse_authority(Scanner *s, CHTTP_Authority *authority)
{ {
HTTP_String userinfo; CHTTP_String userinfo;
{ {
int start = s->cur; int start = s->cur;
CONSUME_OPTIONAL_SEQUENCE(s, is_userinfo); CONSUME_OPTIONAL_SEQUENCE(s, is_userinfo);
if (s->cur < s->len && s->src[s->cur] == '@') { if (s->cur < s->len && s->src[s->cur] == '@') {
userinfo = (HTTP_String) { userinfo = (CHTTP_String) {
s->src + start, s->src + start,
s->cur - start s->cur - start
}; };
@@ -456,11 +456,11 @@ static int parse_authority(Scanner *s, HTTP_Authority *authority)
} else { } else {
// Rollback // Rollback
s->cur = start; s->cur = start;
userinfo = (HTTP_String) {NULL, 0}; userinfo = (CHTTP_String) {NULL, 0};
} }
} }
HTTP_Host host; CHTTP_Host host;
{ {
int ret = parse_host(s, &host); int ret = parse_host(s, &host);
if (ret < 0) if (ret < 0)
@@ -487,9 +487,9 @@ static int parse_authority(Scanner *s, HTTP_Authority *authority)
return 0; return 0;
} }
static int parse_uri(Scanner *s, HTTP_URL *url, int allow_fragment) static int parse_uri(Scanner *s, CHTTP_URL *url, int allow_fragment)
{ {
HTTP_String scheme = {0}; CHTTP_String scheme = {0};
{ {
int start = s->cur; int start = s->cur;
if (s->cur == s->len || !is_scheme_head(s->src[s->cur])) if (s->cur == s->len || !is_scheme_head(s->src[s->cur]))
@@ -497,7 +497,7 @@ static int parse_uri(Scanner *s, HTTP_URL *url, int allow_fragment)
do do
s->cur++; s->cur++;
while (s->cur < s->len && is_scheme_body(s->src[s->cur])); while (s->cur < s->len && is_scheme_body(s->src[s->cur]));
scheme = (HTTP_String) { scheme = (CHTTP_String) {
s->src + start, s->src + start,
s->cur - start, s->cur - start,
}; };
@@ -508,7 +508,7 @@ static int parse_uri(Scanner *s, HTTP_URL *url, int allow_fragment)
} }
int abempty = 0; int abempty = 0;
HTTP_Authority authority = {0}; CHTTP_Authority authority = {0};
if (s->len - s->cur > 1 if (s->len - s->cur > 1
&& s->src[s->cur+0] == '/' && s->src[s->cur+0] == '/'
&& s->src[s->cur+1] == '/') { && s->src[s->cur+1] == '/') {
@@ -521,29 +521,29 @@ static int parse_uri(Scanner *s, HTTP_URL *url, int allow_fragment)
abempty = 1; abempty = 1;
} }
HTTP_String path; CHTTP_String path;
int ret = parse_path(s, &path, abempty); int ret = parse_path(s, &path, abempty);
if (ret < 0) return ret; if (ret < 0) return ret;
HTTP_String query = {0}; CHTTP_String query = {0};
if (s->cur < s->len && s->src[s->cur] == '?') { if (s->cur < s->len && s->src[s->cur] == '?') {
int start = s->cur; int start = s->cur;
do do
s->cur++; s->cur++;
while (s->cur < s->len && is_query(s->src[s->cur])); while (s->cur < s->len && is_query(s->src[s->cur]));
query = (HTTP_String) { query = (CHTTP_String) {
s->src + start, s->src + start,
s->cur - start, s->cur - start,
}; };
} }
HTTP_String fragment = {0}; CHTTP_String fragment = {0};
if (allow_fragment && s->cur < s->len && s->src[s->cur] == '#') { if (allow_fragment && s->cur < s->len && s->src[s->cur] == '#') {
int start = s->cur; int start = s->cur;
do do
s->cur++; s->cur++;
while (s->cur < s->len && is_fragment(s->src[s->cur])); while (s->cur < s->len && is_fragment(s->src[s->cur]));
fragment = (HTTP_String) { fragment = (CHTTP_String) {
s->src + start, s->src + start,
s->cur - start, s->cur - start,
}; };
@@ -562,7 +562,7 @@ static int parse_uri(Scanner *s, HTTP_URL *url, int allow_fragment)
// host = IP-literal / IPv4address / reg-name // host = IP-literal / IPv4address / reg-name
// IP-literal = "[" ( IPv6address / IPvFuture ) "]" // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
// reg-name = *( unreserved / pct-encoded / sub-delims ) // reg-name = *( unreserved / pct-encoded / sub-delims )
static int parse_authority_form(Scanner *s, HTTP_Host *host, int *port) static int parse_authority_form(Scanner *s, CHTTP_Host *host, int *port)
{ {
int ret; int ret;
@@ -591,23 +591,23 @@ static int parse_authority_form(Scanner *s, HTTP_Host *host, int *port)
return 0; return 0;
} }
static int parse_origin_form(Scanner *s, HTTP_String *path, HTTP_String *query) static int parse_origin_form(Scanner *s, CHTTP_String *path, CHTTP_String *query)
{ {
int ret, start; int ret, start;
start = s->cur; start = s->cur;
ret = consume_absolute_path(s); ret = consume_absolute_path(s);
if (ret < 0) return ret; if (ret < 0) return ret;
*path = (HTTP_String) { s->src + start, s->cur - start }; *path = (CHTTP_String) { s->src + start, s->cur - start };
if (s->cur < s->len && s->src[s->cur] == '?') { if (s->cur < s->len && s->src[s->cur] == '?') {
start = s->cur; start = s->cur;
do do
s->cur++; s->cur++;
while (s->cur < s->len && is_query(s->src[s->cur])); while (s->cur < s->len && is_query(s->src[s->cur]));
*query = (HTTP_String) { s->src + start, s->cur - start }; *query = (CHTTP_String) { s->src + start, s->cur - start };
} else } else
*query = (HTTP_String) { NULL, 0 }; *query = (CHTTP_String) { NULL, 0 };
return 0; return 0;
} }
@@ -622,11 +622,11 @@ static int parse_asterisk_form(Scanner *s)
return 0; return 0;
} }
static int parse_request_target(Scanner *s, HTTP_URL *url) static int parse_request_target(Scanner *s, CHTTP_URL *url)
{ {
int ret; int ret;
memset(url, 0, sizeof(HTTP_URL)); memset(url, 0, sizeof(CHTTP_URL));
// asterisk-form // asterisk-form
ret = parse_asterisk_form(s); ret = parse_asterisk_form(s);
@@ -644,7 +644,7 @@ static int parse_request_target(Scanner *s, HTTP_URL *url)
return -1; return -1;
} }
bool consume_str(Scanner *scan, HTTP_String token) bool consume_str(Scanner *scan, CHTTP_String token)
{ {
assert(token.len > 0); assert(token.len > 0);
@@ -664,10 +664,10 @@ static int is_header_body(char c)
return is_vchar(c) || c == ' ' || c == '\t'; return is_vchar(c) || c == ' ' || c == '\t';
} }
static int parse_headers(Scanner *s, HTTP_Header *headers, int max_headers) static int parse_headers(Scanner *s, CHTTP_Header *headers, int max_headers)
{ {
int num_headers = 0; int num_headers = 0;
while (!consume_str(s, HTTP_STR("\r\n"))) { while (!consume_str(s, CHTTP_STR("\r\n"))) {
// RFC 9112: // RFC 9112:
// field-line = field-name ":" OWS field-value OWS // field-line = field-name ":" OWS field-value OWS
@@ -687,7 +687,7 @@ static int parse_headers(Scanner *s, HTTP_Header *headers, int max_headers)
do do
s->cur++; s->cur++;
while (s->cur < s->len && is_tchar(s->src[s->cur])); while (s->cur < s->len && is_tchar(s->src[s->cur]));
HTTP_String name = { s->src + start, s->cur - start }; CHTTP_String name = { s->src + start, s->cur - start };
if (s->cur == s->len || s->src[s->cur] != ':') if (s->cur == s->len || s->src[s->cur] != ':')
return -1; // ERROR return -1; // ERROR
@@ -695,13 +695,13 @@ static int parse_headers(Scanner *s, HTTP_Header *headers, int max_headers)
start = s->cur; start = s->cur;
CONSUME_OPTIONAL_SEQUENCE(s, is_header_body); CONSUME_OPTIONAL_SEQUENCE(s, is_header_body);
HTTP_String body = { s->src + start, s->cur - start }; CHTTP_String body = { s->src + start, s->cur - start };
body = http_trim(body); body = chttp_trim(body);
if (num_headers < max_headers) if (num_headers < max_headers)
headers[num_headers++] = (HTTP_Header) { name, body }; headers[num_headers++] = (CHTTP_Header) { name, body };
if (!consume_str(s, HTTP_STR("\r\n"))) { if (!consume_str(s, CHTTP_STR("\r\n"))) {
return -1; return -1;
} }
} }
@@ -722,7 +722,7 @@ static bool is_space(char c)
} }
static int static int
parse_transfer_encoding(HTTP_String src, TransferEncodingOption *dst, int max) parse_transfer_encoding(CHTTP_String src, TransferEncodingOption *dst, int max)
{ {
Scanner s = { src.ptr, src.len, 0 }; Scanner s = { src.ptr, src.len, 0 };
@@ -733,10 +733,10 @@ parse_transfer_encoding(HTTP_String src, TransferEncodingOption *dst, int max)
TransferEncodingOption opt; TransferEncodingOption opt;
if (0) {} if (0) {}
else if (consume_str(&s, HTTP_STR("chunked"))) opt = TRANSFER_ENCODING_OPTION_CHUNKED; else if (consume_str(&s, CHTTP_STR("chunked"))) opt = TRANSFER_ENCODING_OPTION_CHUNKED;
else if (consume_str(&s, HTTP_STR("compress"))) opt = TRANSFER_ENCODING_OPTION_COMPRESS; else if (consume_str(&s, CHTTP_STR("compress"))) opt = TRANSFER_ENCODING_OPTION_COMPRESS;
else if (consume_str(&s, HTTP_STR("deflate"))) opt = TRANSFER_ENCODING_OPTION_DEFLATE; else if (consume_str(&s, CHTTP_STR("deflate"))) opt = TRANSFER_ENCODING_OPTION_DEFLATE;
else if (consume_str(&s, HTTP_STR("gzip"))) opt = TRANSFER_ENCODING_OPTION_GZIP; else if (consume_str(&s, CHTTP_STR("gzip"))) opt = TRANSFER_ENCODING_OPTION_GZIP;
else return -1; // Invalid option else return -1; // Invalid option
if (num == max) if (num == max)
@@ -778,8 +778,8 @@ parse_content_length(const char *src, int len, uint64_t *out)
} }
static int parse_body(Scanner *s, static int parse_body(Scanner *s,
HTTP_Header *headers, int num_headers, CHTTP_Header *headers, int num_headers,
HTTP_String *body, bool body_expected) CHTTP_String *body, bool body_expected)
{ {
// RFC 9112 section 6: // RFC 9112 section 6:
@@ -787,7 +787,7 @@ static int parse_body(Scanner *s,
// Transfer-Encoding header field. Request message framing is independent of method // Transfer-Encoding header field. Request message framing is independent of method
// semantics. // semantics.
int header_index = http_find_header(headers, num_headers, HTTP_STR("Transfer-Encoding")); int header_index = chttp_find_header(headers, num_headers, CHTTP_STR("Transfer-Encoding"));
if (header_index != -1) { if (header_index != -1) {
// RFC 9112 section 6.1: // RFC 9112 section 6.1:
@@ -795,10 +795,10 @@ static int parse_body(Scanner *s,
// or process such a request in accordance with the Transfer-Encoding alone. Regardless, // or process such a request in accordance with the Transfer-Encoding alone. Regardless,
// the server MUST close the connection after responding to such a request to avoid the // the server MUST close the connection after responding to such a request to avoid the
// potential attacks. // potential attacks.
if (http_find_header(headers, num_headers, HTTP_STR("Content-Length")) != -1) if (chttp_find_header(headers, num_headers, CHTTP_STR("Content-Length")) != -1)
return -1; return -1;
HTTP_String value = headers[header_index].value; CHTTP_String value = headers[header_index].value;
// RFC 9112 section 6.1: // RFC 9112 section 6.1:
// If any transfer coding other than chunked is applied to a request's content, the // If any transfer coding other than chunked is applied to a request's content, the
@@ -808,14 +808,14 @@ static int parse_body(Scanner *s,
// coding or terminate the message by closing the connection. // coding or terminate the message by closing the connection.
TransferEncodingOption opts[8]; TransferEncodingOption opts[8];
int num = parse_transfer_encoding(value, opts, HTTP_COUNT(opts)); int num = parse_transfer_encoding(value, opts, CHTTP_COUNT(opts));
if (num != 1 || opts[0] != TRANSFER_ENCODING_OPTION_CHUNKED) if (num != 1 || opts[0] != TRANSFER_ENCODING_OPTION_CHUNKED)
return -1; return -1;
HTTP_String chunks_maybe[128]; CHTTP_String chunks_maybe[128];
HTTP_String *chunks = chunks_maybe; CHTTP_String *chunks = chunks_maybe;
int num_chunks = 0; int num_chunks = 0;
int max_chunks = HTTP_COUNT(chunks_maybe); int max_chunks = CHTTP_COUNT(chunks_maybe);
#define FREE_CHUNK_LIST \ #define FREE_CHUNK_LIST \
if (chunks != chunks_maybe) \ if (chunks != chunks_maybe) \
@@ -905,7 +905,7 @@ static int parse_body(Scanner *s,
max_chunks *= 2; max_chunks *= 2;
HTTP_String *new_chunks = malloc(max_chunks * sizeof(HTTP_String)); CHTTP_String *new_chunks = malloc(max_chunks * sizeof(CHTTP_String));
if (new_chunks == NULL) { if (new_chunks == NULL) {
if (chunks != chunks_maybe) if (chunks != chunks_maybe)
free(chunks); free(chunks);
@@ -920,7 +920,7 @@ static int parse_body(Scanner *s,
chunks = new_chunks; chunks = new_chunks;
} }
chunks[num_chunks++] = (HTTP_String) { chunk_ptr, chunk_len }; chunks[num_chunks++] = (CHTTP_String) { chunk_ptr, chunk_len };
} }
char *content_ptr = content_start; char *content_ptr = content_start;
@@ -929,7 +929,7 @@ static int parse_body(Scanner *s,
content_ptr += chunks[i].len; content_ptr += chunks[i].len;
} }
*body = (HTTP_String) { *body = (CHTTP_String) {
content_start, content_start,
content_ptr - content_start content_ptr - content_start
}; };
@@ -944,11 +944,11 @@ static int parse_body(Scanner *s,
// If a valid Content-Length header field is present without Transfer-Encoding, // If a valid Content-Length header field is present without Transfer-Encoding,
// its decimal value defines the expected message body length in octets. // its decimal value defines the expected message body length in octets.
header_index = http_find_header(headers, num_headers, HTTP_STR("Content-Length")); header_index = chttp_find_header(headers, num_headers, CHTTP_STR("Content-Length"));
if (header_index != -1) { if (header_index != -1) {
// Have Content-Length // Have Content-Length
HTTP_String value = headers[header_index].value; CHTTP_String value = headers[header_index].value;
uint64_t tmp; uint64_t tmp;
if (parse_content_length(value.ptr, value.len, &tmp) < 0) if (parse_content_length(value.ptr, value.len, &tmp) < 0)
@@ -960,7 +960,7 @@ static int parse_body(Scanner *s,
if (len > s->len - s->cur) if (len > s->len - s->cur)
return 0; // Incomplete request return 0; // Incomplete request
*body = (HTTP_String) { s->src + s->cur, len }; *body = (CHTTP_String) { s->src + s->cur, len };
s->cur += len; s->cur += len;
return 1; return 1;
@@ -969,7 +969,7 @@ static int parse_body(Scanner *s,
// No Content-Length or Transfer-Encoding // No Content-Length or Transfer-Encoding
if (body_expected) return -1; if (body_expected) return -1;
*body = (HTTP_String) { NULL, 0 }; *body = (CHTTP_String) { NULL, 0 };
return 1; return 1;
} }
@@ -987,7 +987,7 @@ static int contains_head(char *src, int len)
return 0; return 0;
} }
static int parse_request(Scanner *s, HTTP_Request *req) static int parse_request(Scanner *s, CHTTP_Request *req)
{ {
if (!contains_head(s->src + s->cur, s->len - s->cur)) if (!contains_head(s->src + s->cur, s->len - s->cur))
return 0; return 0;
@@ -995,15 +995,15 @@ static int parse_request(Scanner *s, HTTP_Request *req)
req->secure = false; req->secure = false;
if (0) {} if (0) {}
else if (consume_str(s, HTTP_STR("GET "))) req->method = HTTP_METHOD_GET; else if (consume_str(s, CHTTP_STR("GET "))) req->method = CHTTP_METHOD_GET;
else if (consume_str(s, HTTP_STR("POST "))) req->method = HTTP_METHOD_POST; else if (consume_str(s, CHTTP_STR("POST "))) req->method = CHTTP_METHOD_POST;
else if (consume_str(s, HTTP_STR("PUT "))) req->method = HTTP_METHOD_PUT; else if (consume_str(s, CHTTP_STR("PUT "))) req->method = CHTTP_METHOD_PUT;
else if (consume_str(s, HTTP_STR("HEAD "))) req->method = HTTP_METHOD_HEAD; else if (consume_str(s, CHTTP_STR("HEAD "))) req->method = CHTTP_METHOD_HEAD;
else if (consume_str(s, HTTP_STR("DELETE "))) req->method = HTTP_METHOD_DELETE; else if (consume_str(s, CHTTP_STR("DELETE "))) req->method = CHTTP_METHOD_DELETE;
else if (consume_str(s, HTTP_STR("CONNECT "))) req->method = HTTP_METHOD_CONNECT; else if (consume_str(s, CHTTP_STR("CONNECT "))) req->method = CHTTP_METHOD_CONNECT;
else if (consume_str(s, HTTP_STR("OPTIONS "))) req->method = HTTP_METHOD_OPTIONS; else if (consume_str(s, CHTTP_STR("OPTIONS "))) req->method = CHTTP_METHOD_OPTIONS;
else if (consume_str(s, HTTP_STR("TRACE "))) req->method = HTTP_METHOD_TRACE; else if (consume_str(s, CHTTP_STR("TRACE "))) req->method = CHTTP_METHOD_TRACE;
else if (consume_str(s, HTTP_STR("PATCH "))) req->method = HTTP_METHOD_PATCH; else if (consume_str(s, CHTTP_STR("PATCH "))) req->method = CHTTP_METHOD_PATCH;
else return -1; else return -1;
{ {
@@ -1021,47 +1021,47 @@ static int parse_request(Scanner *s, HTTP_Request *req)
s->cur = s2.cur; s->cur = s2.cur;
} }
if (consume_str(s, HTTP_STR(" HTTP/1.1\r\n"))) { if (consume_str(s, CHTTP_STR(" HTTP/1.1\r\n"))) {
req->minor = 1; req->minor = 1;
} else if (consume_str(s, HTTP_STR(" HTTP/1.0\r\n")) || consume_str(s, HTTP_STR(" HTTP/1\r\n"))) { } else if (consume_str(s, CHTTP_STR(" HTTP/1.0\r\n")) || consume_str(s, CHTTP_STR(" HTTP/1\r\n"))) {
req->minor = 0; req->minor = 0;
} else { } else {
return -1; return -1;
} }
int num_headers = parse_headers(s, req->headers, HTTP_MAX_HEADERS); int num_headers = parse_headers(s, req->headers, CHTTP_MAX_HEADERS);
if (num_headers < 0) if (num_headers < 0)
return num_headers; return num_headers;
req->num_headers = num_headers; req->num_headers = num_headers;
// Request methods that typically don't have a body // Request methods that typically don't have a body
bool body_expected = true; bool body_expected = true;
if (req->method == HTTP_METHOD_GET || if (req->method == CHTTP_METHOD_GET ||
req->method == HTTP_METHOD_HEAD || req->method == CHTTP_METHOD_HEAD ||
req->method == HTTP_METHOD_DELETE || req->method == CHTTP_METHOD_DELETE ||
req->method == HTTP_METHOD_OPTIONS || req->method == CHTTP_METHOD_OPTIONS ||
req->method == HTTP_METHOD_TRACE) req->method == CHTTP_METHOD_TRACE)
body_expected = false; body_expected = false;
return parse_body(s, req->headers, req->num_headers, &req->body, body_expected); return parse_body(s, req->headers, req->num_headers, &req->body, body_expected);
} }
int http_find_header(HTTP_Header *headers, int num_headers, HTTP_String name) int chttp_find_header(CHTTP_Header *headers, int num_headers, CHTTP_String name)
{ {
for (int i = 0; i < num_headers; i++) for (int i = 0; i < num_headers; i++)
if (http_streqcase(name, headers[i].name)) if (chttp_streqcase(name, headers[i].name))
return i; return i;
return -1; return -1;
} }
static int parse_response(Scanner *s, HTTP_Response *res) static int parse_response(Scanner *s, CHTTP_Response *res)
{ {
if (!contains_head(s->src + s->cur, s->len - s->cur)) if (!contains_head(s->src + s->cur, s->len - s->cur))
return 0; return 0;
if (consume_str(s, HTTP_STR("HTTP/1.1 "))) { if (consume_str(s, CHTTP_STR("HTTP/1.1 "))) {
res->minor = 1; res->minor = 1;
} else if (consume_str(s, HTTP_STR("HTTP/1.0 ")) || consume_str(s, HTTP_STR("HTTP/1 "))) { } else if (consume_str(s, CHTTP_STR("HTTP/1.0 ")) || consume_str(s, CHTTP_STR("HTTP/1 "))) {
res->minor = 0; res->minor = 0;
} else { } else {
return -1; return -1;
@@ -1093,7 +1093,7 @@ static int parse_response(Scanner *s, HTTP_Response *res)
return -1; return -1;
s->cur += 2; s->cur += 2;
int num_headers = parse_headers(s, res->headers, HTTP_MAX_HEADERS); int num_headers = parse_headers(s, res->headers, CHTTP_MAX_HEADERS);
if (num_headers < 0) if (num_headers < 0)
return num_headers; return num_headers;
res->num_headers = num_headers; res->num_headers = num_headers;
@@ -1113,7 +1113,7 @@ static int parse_response(Scanner *s, HTTP_Response *res)
return parse_body(s, res->headers, res->num_headers, &res->body, body_expected); return parse_body(s, res->headers, res->num_headers, &res->body, body_expected);
} }
int http_parse_ipv4(char *src, int len, HTTP_IPv4 *ipv4) int chttp_parse_ipv4(char *src, int len, CHTTP_IPv4 *ipv4)
{ {
Scanner s = {src, len, 0}; Scanner s = {src, len, 0};
int ret = parse_ipv4(&s, ipv4); int ret = parse_ipv4(&s, ipv4);
@@ -1121,7 +1121,7 @@ int http_parse_ipv4(char *src, int len, HTTP_IPv4 *ipv4)
return s.cur; return s.cur;
} }
int http_parse_ipv6(char *src, int len, HTTP_IPv6 *ipv6) int chttp_parse_ipv6(char *src, int len, CHTTP_IPv6 *ipv6)
{ {
Scanner s = {src, len, 0}; Scanner s = {src, len, 0};
int ret = parse_ipv6(&s, ipv6); int ret = parse_ipv6(&s, ipv6);
@@ -1129,7 +1129,7 @@ int http_parse_ipv6(char *src, int len, HTTP_IPv6 *ipv6)
return s.cur; return s.cur;
} }
int http_parse_url(char *src, int len, HTTP_URL *url) int chttp_parse_url(char *src, int len, CHTTP_URL *url)
{ {
Scanner s = {src, len, 0}; Scanner s = {src, len, 0};
int ret = parse_uri(&s, url, 1); int ret = parse_uri(&s, url, 1);
@@ -1138,7 +1138,7 @@ int http_parse_url(char *src, int len, HTTP_URL *url)
return ret; return ret;
} }
int http_parse_request(char *src, int len, HTTP_Request *req) int chttp_parse_request(char *src, int len, CHTTP_Request *req)
{ {
Scanner s = {src, len, 0}; Scanner s = {src, len, 0};
int ret = parse_request(&s, req); int ret = parse_request(&s, req);
@@ -1147,7 +1147,7 @@ int http_parse_request(char *src, int len, HTTP_Request *req)
return ret; return ret;
} }
int http_parse_response(char *src, int len, HTTP_Response *res) int chttp_parse_response(char *src, int len, CHTTP_Response *res)
{ {
Scanner s = {src, len, 0}; Scanner s = {src, len, 0};
int ret = parse_response(&s, res); int ret = parse_response(&s, res);
@@ -1156,14 +1156,14 @@ int http_parse_response(char *src, int len, HTTP_Response *res)
return ret; return ret;
} }
HTTP_String http_get_cookie(HTTP_Request *req, HTTP_String name) CHTTP_String chttp_get_cookie(CHTTP_Request *req, CHTTP_String name)
{ {
// Simple cookie parsing - does not handle quoted values or special characters // Simple cookie parsing - does not handle quoted values or special characters
// See RFC 6265 for full cookie specification // See RFC 6265 for full cookie specification
for (int i = 0; i < req->num_headers; i++) { for (int i = 0; i < req->num_headers; i++) {
if (!http_streqcase(req->headers[i].name, HTTP_STR("Cookie"))) if (!chttp_streqcase(req->headers[i].name, CHTTP_STR("Cookie")))
continue; continue;
char *src = req->headers[i].value.ptr; char *src = req->headers[i].value.ptr;
@@ -1181,7 +1181,7 @@ HTTP_String http_get_cookie(HTTP_Request *req, HTTP_String name)
while (cur < len && src[cur] != '=') while (cur < len && src[cur] != '=')
cur++; cur++;
HTTP_String cookie_name = { src + off, cur - off }; CHTTP_String cookie_name = { src + off, cur - off };
if (cur == len) if (cur == len)
break; break;
@@ -1191,9 +1191,9 @@ HTTP_String http_get_cookie(HTTP_Request *req, HTTP_String name)
while (cur < len && src[cur] != ';') while (cur < len && src[cur] != ';')
cur++; cur++;
HTTP_String cookie_value = { src + off, cur - off }; CHTTP_String cookie_value = { src + off, cur - off };
if (http_streq(name, cookie_name)) if (chttp_streq(name, cookie_name))
return cookie_value; return cookie_value;
if (cur == len) if (cur == len)
@@ -1202,10 +1202,10 @@ HTTP_String http_get_cookie(HTTP_Request *req, HTTP_String name)
} }
} }
return HTTP_STR(""); return CHTTP_STR("");
} }
HTTP_String http_get_param(HTTP_String body, HTTP_String str, char *mem, int cap) CHTTP_String chttp_get_param(CHTTP_String body, CHTTP_String str, char *mem, int cap)
{ {
// This is just a best-effort implementation // This is just a best-effort implementation
@@ -1218,29 +1218,29 @@ HTTP_String http_get_param(HTTP_String body, HTTP_String str, char *mem, int cap
while (cur < len) { while (cur < len) {
HTTP_String name; CHTTP_String name;
{ {
int off = cur; int off = cur;
while (cur < len && src[cur] != '=' && src[cur] != '&') while (cur < len && src[cur] != '=' && src[cur] != '&')
cur++; cur++;
name = (HTTP_String) { src + off, cur - off }; name = (CHTTP_String) { src + off, cur - off };
} }
HTTP_String body = HTTP_STR(""); CHTTP_String body = CHTTP_STR("");
if (cur < len) { if (cur < len) {
cur++; cur++;
if (src[cur-1] == '=') { if (src[cur-1] == '=') {
int off = cur; int off = cur;
while (cur < len && src[cur] != '&') while (cur < len && src[cur] != '&')
cur++; cur++;
body = (HTTP_String) { src + off, cur - off }; body = (CHTTP_String) { src + off, cur - off };
if (cur < len) if (cur < len)
cur++; cur++;
} }
} }
if (http_streq(str, name)) { if (chttp_streq(str, name)) {
bool percent_encoded = false; bool percent_encoded = false;
for (int i = 0; i < body.len; i++) for (int i = 0; i < body.len; i++)
@@ -1253,9 +1253,9 @@ HTTP_String http_get_param(HTTP_String body, HTTP_String str, char *mem, int cap
return body; return body;
if (body.len > cap) if (body.len > cap)
return (HTTP_String) { NULL, 0 }; return (CHTTP_String) { NULL, 0 };
HTTP_String decoded = { mem, 0 }; CHTTP_String decoded = { mem, 0 };
for (int i = 0; i < body.len; i++) { for (int i = 0; i < body.len; i++) {
char c = body.ptr[i]; char c = body.ptr[i];
@@ -1266,7 +1266,7 @@ HTTP_String http_get_param(HTTP_String body, HTTP_String str, char *mem, int cap
if (body.len - i < 3 if (body.len - i < 3
|| !is_hex_digit(body.ptr[i+1]) || !is_hex_digit(body.ptr[i+1])
|| !is_hex_digit(body.ptr[i+2])) || !is_hex_digit(body.ptr[i+2]))
return (HTTP_String) { NULL, 0 }; return (CHTTP_String) { NULL, 0 };
int h = hex_digit_to_int(body.ptr[i+1]); int h = hex_digit_to_int(body.ptr[i+1]);
int l = hex_digit_to_int(body.ptr[i+2]); int l = hex_digit_to_int(body.ptr[i+2]);
@@ -1283,13 +1283,13 @@ HTTP_String http_get_param(HTTP_String body, HTTP_String str, char *mem, int cap
} }
} }
return HTTP_STR(""); return CHTTP_STR("");
} }
int http_get_param_i(HTTP_String body, HTTP_String str) int chttp_get_param_i(CHTTP_String body, CHTTP_String str)
{ {
char buf[128]; char buf[128];
HTTP_String out = http_get_param(body, str, buf, (int) sizeof(buf)); CHTTP_String out = chttp_get_param(body, str, buf, (int) sizeof(buf));
if (out.len == 0 || !is_digit(out.ptr[0])) if (out.len == 0 || !is_digit(out.ptr[0]))
return -1; return -1;
@@ -1305,38 +1305,38 @@ int http_get_param_i(HTTP_String body, HTTP_String str)
return res; return res;
} }
bool http_match_host(HTTP_Request *req, HTTP_String domain, int port) bool chttp_match_host(CHTTP_Request *req, CHTTP_String domain, int port)
{ {
int idx = http_find_header(req->headers, req->num_headers, HTTP_STR("Host")); int idx = chttp_find_header(req->headers, req->num_headers, CHTTP_STR("Host"));
assert(idx != -1); // Requests without the host header are always rejected assert(idx != -1); // Requests without the host header are always rejected
char tmp[1<<8]; char tmp[1<<8];
if (port > -1 && port != 80) { if (port > -1 && port != 80) {
int ret = snprintf(tmp, sizeof(tmp), "%.*s:%d", domain.len, domain.ptr, port); int ret = snprintf(tmp, sizeof(tmp), "%.*s:%d", domain.len, domain.ptr, port);
assert(ret > 0); assert(ret > 0);
domain = (HTTP_String) { tmp, ret }; domain = (CHTTP_String) { tmp, ret };
} }
HTTP_String host = req->headers[idx].value; CHTTP_String host = req->headers[idx].value;
return http_streqcase(host, domain); return chttp_streqcase(host, domain);
} }
// <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT // <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
static int parse_date(Scanner *s, HTTP_Date *out) static int parse_date(Scanner *s, CHTTP_Date *out)
{ {
struct { HTTP_String str; HTTP_WeekDay val; } week_day_table[] = { struct { CHTTP_String str; CHTTP_WeekDay val; } week_day_table[] = {
{ HTTP_STR("Mon, "), HTTP_WEEKDAY_MON }, { CHTTP_STR("Mon, "), CHTTP_WEEKDAY_MON },
{ HTTP_STR("Tue, "), HTTP_WEEKDAY_TUE }, { CHTTP_STR("Tue, "), CHTTP_WEEKDAY_TUE },
{ HTTP_STR("Wed, "), HTTP_WEEKDAY_WED }, { CHTTP_STR("Wed, "), CHTTP_WEEKDAY_WED },
{ HTTP_STR("Thu, "), HTTP_WEEKDAY_THU }, { CHTTP_STR("Thu, "), CHTTP_WEEKDAY_THU },
{ HTTP_STR("Fri, "), HTTP_WEEKDAY_FRI }, { CHTTP_STR("Fri, "), CHTTP_WEEKDAY_FRI },
{ HTTP_STR("Sat, "), HTTP_WEEKDAY_SAT }, { CHTTP_STR("Sat, "), CHTTP_WEEKDAY_SAT },
{ HTTP_STR("Sun, "), HTTP_WEEKDAY_SUN }, { CHTTP_STR("Sun, "), CHTTP_WEEKDAY_SUN },
}; };
bool found = false; bool found = false;
for (int i = 0; i < HTTP_COUNT(week_day_table); i++) for (int i = 0; i < CHTTP_COUNT(week_day_table); i++)
if (consume_str(s, week_day_table[i].str)) { if (consume_str(s, week_day_table[i].str)) {
out->week_day = week_day_table[i].val; out->week_day = week_day_table[i].val;
found = true; found = true;
@@ -1354,23 +1354,23 @@ static int parse_date(Scanner *s, HTTP_Date *out)
+ (s->src[s->cur+1] - '0') * 1; + (s->src[s->cur+1] - '0') * 1;
s->cur += 2; s->cur += 2;
struct { HTTP_String str; HTTP_Month val; } month_table[] = { struct { CHTTP_String str; CHTTP_Month val; } month_table[] = {
{ HTTP_STR(" Jan "), HTTP_MONTH_JAN }, { CHTTP_STR(" Jan "), CHTTP_MONTH_JAN },
{ HTTP_STR(" Feb "), HTTP_MONTH_FEB }, { CHTTP_STR(" Feb "), CHTTP_MONTH_FEB },
{ HTTP_STR(" Mar "), HTTP_MONTH_MAR }, { CHTTP_STR(" Mar "), CHTTP_MONTH_MAR },
{ HTTP_STR(" Apr "), HTTP_MONTH_APR }, { CHTTP_STR(" Apr "), CHTTP_MONTH_APR },
{ HTTP_STR(" May "), HTTP_MONTH_MAY }, { CHTTP_STR(" May "), CHTTP_MONTH_MAY },
{ HTTP_STR(" Jun "), HTTP_MONTH_JUN }, { CHTTP_STR(" Jun "), CHTTP_MONTH_JUN },
{ HTTP_STR(" Jul "), HTTP_MONTH_JUL }, { CHTTP_STR(" Jul "), CHTTP_MONTH_JUL },
{ HTTP_STR(" Aug "), HTTP_MONTH_AUG }, { CHTTP_STR(" Aug "), CHTTP_MONTH_AUG },
{ HTTP_STR(" Sep "), HTTP_MONTH_SEP }, { CHTTP_STR(" Sep "), CHTTP_MONTH_SEP },
{ HTTP_STR(" Oct "), HTTP_MONTH_OCT }, { CHTTP_STR(" Oct "), CHTTP_MONTH_OCT },
{ HTTP_STR(" Nov "), HTTP_MONTH_NOV }, { CHTTP_STR(" Nov "), CHTTP_MONTH_NOV },
{ HTTP_STR(" Dec "), HTTP_MONTH_DEC }, { CHTTP_STR(" Dec "), CHTTP_MONTH_DEC },
}; };
found = false; found = false;
for (int i = 0; i < HTTP_COUNT(month_table); i++) for (int i = 0; i < CHTTP_COUNT(month_table); i++)
if (consume_str(s, month_table[i].str)) { if (consume_str(s, month_table[i].str)) {
out->month = month_table[i].val; out->month = month_table[i].val;
found = true; found = true;
@@ -1436,7 +1436,7 @@ static bool is_cookie_octet(char c)
(c >= 0x5D && c <= 0x7E); (c >= 0x5D && c <= 0x7E);
} }
int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out) int chttp_parse_set_cookie(CHTTP_String str, CHTTP_SetCookie *out)
{ {
Scanner s = { str.ptr, str.len, 0 }; Scanner s = { str.ptr, str.len, 0 };
@@ -1447,7 +1447,7 @@ int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out)
do do
s.cur++; s.cur++;
while (s.cur < s.len && is_tchar(s.src[s.cur])); while (s.cur < s.len && is_tchar(s.src[s.cur]));
out->name = (HTTP_String) { s.src + off, s.cur - off }; out->name = (CHTTP_String) { s.src + off, s.cur - off };
// cookie-pair = cookie-name "=" cookie-value // cookie-pair = cookie-name "=" cookie-value
if (s.cur == s.len || s.src[s.cur] != '=') if (s.cur == s.len || s.src[s.cur] != '=')
@@ -1462,13 +1462,13 @@ int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out)
s.cur++; s.cur++;
if (s.cur == s.len || s.src[s.cur] != '"') if (s.cur == s.len || s.src[s.cur] != '"')
return -1; // Missing closing double quote return -1; // Missing closing double quote
out->value = (HTTP_String) { s.src + off, s.cur - off }; out->value = (CHTTP_String) { s.src + off, s.cur - off };
s.cur++; // Consume closing double quote s.cur++; // Consume closing double quote
} else { } else {
int off = s.cur; int off = s.cur;
while (s.cur < s.len && is_cookie_octet(s.src[s.cur])) while (s.cur < s.len && is_cookie_octet(s.src[s.cur]))
s.cur++; s.cur++;
out->value = (HTTP_String) { s.src + off, s.cur - off }; out->value = (CHTTP_String) { s.src + off, s.cur - off };
} }
// *( ";" SP cookie-av ) // *( ";" SP cookie-av )
@@ -1477,20 +1477,20 @@ int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out)
// path-av / secure-av / httponly-av / // path-av / secure-av / httponly-av /
// extension-av // extension-av
out->secure = false; out->secure = false;
out->http_only = false; out->chttp_only = false;
out->have_date = false; out->have_date = false;
out->have_max_age = false; out->have_max_age = false;
out->have_domain = false; out->have_domain = false;
out->have_path = false; out->have_path = false;
while (consume_str(&s, HTTP_STR("; "))) { while (consume_str(&s, CHTTP_STR("; "))) {
if (consume_str(&s, HTTP_STR("Expires="))) { if (consume_str(&s, CHTTP_STR("Expires="))) {
// expires-av = "Expires=" sane-cookie-date // expires-av = "Expires=" sane-cookie-date
if (parse_date(&s, &out->date) < 0) if (parse_date(&s, &out->date) < 0)
return -1; return -1;
out->have_date = true; out->have_date = true;
} else if (consume_str(&s, HTTP_STR("Max-Age="))) { } else if (consume_str(&s, CHTTP_STR("Max-Age="))) {
// max-age-av = "Max-Age=" non-zero-digit *DIGIT // max-age-av = "Max-Age=" non-zero-digit *DIGIT
@@ -1507,7 +1507,7 @@ int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out)
out->have_max_age = true; out->have_max_age = true;
out->max_age = value; out->max_age = value;
} else if (consume_str(&s, HTTP_STR("Domain="))) { } else if (consume_str(&s, CHTTP_STR("Domain="))) {
// domain-av = "Domain=" domain-value // domain-av = "Domain=" domain-value
// domain-value = <subdomain> // domain-value = <subdomain>
@@ -1557,9 +1557,9 @@ int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out)
} }
out->have_domain = true; out->have_domain = true;
out->domain = (HTTP_String) { s.src + off, s.cur - off }; out->domain = (CHTTP_String) { s.src + off, s.cur - off };
} else if (consume_str(&s, HTTP_STR("Path="))) { } else if (consume_str(&s, CHTTP_STR("Path="))) {
// path-av = "Path=" path-value // path-av = "Path=" path-value
// path-value = <any CHAR except CTLs or ";"> // path-value = <any CHAR except CTLs or ";">
@@ -1569,17 +1569,17 @@ int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out)
s.cur++; s.cur++;
out->have_path = true; out->have_path = true;
out->path = (HTTP_String) { s.src + off, s.cur - off }; out->path = (CHTTP_String) { s.src + off, s.cur - off };
} else if (consume_str(&s, HTTP_STR("Secure"))) { } else if (consume_str(&s, CHTTP_STR("Secure"))) {
// secure-av = "Secure" // secure-av = "Secure"
out->secure = true; out->secure = true;
} else if (consume_str(&s, HTTP_STR("HttpOnly"))) { } else if (consume_str(&s, CHTTP_STR("HttpOnly"))) {
// httponly-av = "HttpOnly" // httponly-av = "HttpOnly"
out->http_only = true; out->chttp_only = true;
} else { } else {
return -1; // Invalid attribute return -1; // Invalid attribute
+87 -87
View File
@@ -1,155 +1,155 @@
#define HTTP_MAX_HEADERS 32 #define CHTTP_MAX_HEADERS 32
typedef struct { typedef struct {
unsigned int data; unsigned int data;
} HTTP_IPv4; } CHTTP_IPv4;
typedef struct { typedef struct {
unsigned short data[8]; unsigned short data[8];
} HTTP_IPv6; } CHTTP_IPv6;
typedef enum { typedef enum {
HTTP_HOST_MODE_VOID = 0, CHTTP_HOST_MODE_VOID = 0,
HTTP_HOST_MODE_NAME, CHTTP_HOST_MODE_NAME,
HTTP_HOST_MODE_IPV4, CHTTP_HOST_MODE_IPV4,
HTTP_HOST_MODE_IPV6, CHTTP_HOST_MODE_IPV6,
} HTTP_HostMode; } CHTTP_HostMode;
typedef struct { typedef struct {
HTTP_HostMode mode; CHTTP_HostMode mode;
HTTP_String text; CHTTP_String text;
union { union {
HTTP_String name; CHTTP_String name;
HTTP_IPv4 ipv4; CHTTP_IPv4 ipv4;
HTTP_IPv6 ipv6; CHTTP_IPv6 ipv6;
}; };
} HTTP_Host; } CHTTP_Host;
typedef struct { typedef struct {
HTTP_String userinfo; CHTTP_String userinfo;
HTTP_Host host; CHTTP_Host host;
int port; int port;
} HTTP_Authority; } CHTTP_Authority;
// ZII // ZII
typedef struct { typedef struct {
HTTP_String scheme; CHTTP_String scheme;
HTTP_Authority authority; CHTTP_Authority authority;
HTTP_String path; CHTTP_String path;
HTTP_String query; CHTTP_String query;
HTTP_String fragment; CHTTP_String fragment;
} HTTP_URL; } CHTTP_URL;
typedef enum { typedef enum {
HTTP_METHOD_GET, CHTTP_METHOD_GET,
HTTP_METHOD_HEAD, CHTTP_METHOD_HEAD,
HTTP_METHOD_POST, CHTTP_METHOD_POST,
HTTP_METHOD_PUT, CHTTP_METHOD_PUT,
HTTP_METHOD_DELETE, CHTTP_METHOD_DELETE,
HTTP_METHOD_CONNECT, CHTTP_METHOD_CONNECT,
HTTP_METHOD_OPTIONS, CHTTP_METHOD_OPTIONS,
HTTP_METHOD_TRACE, CHTTP_METHOD_TRACE,
HTTP_METHOD_PATCH, CHTTP_METHOD_PATCH,
} HTTP_Method; } CHTTP_Method;
typedef struct { typedef struct {
HTTP_String name; CHTTP_String name;
HTTP_String value; CHTTP_String value;
} HTTP_Header; } CHTTP_Header;
typedef struct { typedef struct {
bool secure; bool secure;
HTTP_Method method; CHTTP_Method method;
HTTP_URL url; CHTTP_URL url;
int minor; int minor;
int num_headers; int num_headers;
HTTP_Header headers[HTTP_MAX_HEADERS]; CHTTP_Header headers[CHTTP_MAX_HEADERS];
HTTP_String body; CHTTP_String body;
} HTTP_Request; } CHTTP_Request;
typedef struct { typedef struct {
void* context; void* context;
int minor; int minor;
int status; int status;
HTTP_String reason; CHTTP_String reason;
int num_headers; int num_headers;
HTTP_Header headers[HTTP_MAX_HEADERS]; CHTTP_Header headers[CHTTP_MAX_HEADERS];
HTTP_String body; CHTTP_String body;
} HTTP_Response; } CHTTP_Response;
int http_parse_ipv4 (char *src, int len, HTTP_IPv4 *ipv4); int chttp_parse_ipv4 (char *src, int len, CHTTP_IPv4 *ipv4);
int http_parse_ipv6 (char *src, int len, HTTP_IPv6 *ipv6); int chttp_parse_ipv6 (char *src, int len, CHTTP_IPv6 *ipv6);
int http_parse_url (char *src, int len, HTTP_URL *url); int chttp_parse_url (char *src, int len, CHTTP_URL *url);
int http_parse_request (char *src, int len, HTTP_Request *req); int chttp_parse_request (char *src, int len, CHTTP_Request *req);
int http_parse_response (char *src, int len, HTTP_Response *res); int chttp_parse_response (char *src, int len, CHTTP_Response *res);
int http_find_header (HTTP_Header *headers, int num_headers, HTTP_String name); int chttp_find_header (CHTTP_Header *headers, int num_headers, CHTTP_String name);
HTTP_String http_get_cookie (HTTP_Request *req, HTTP_String name); CHTTP_String chttp_get_cookie (CHTTP_Request *req, CHTTP_String name);
HTTP_String http_get_param (HTTP_String body, HTTP_String str, char *mem, int cap); CHTTP_String chttp_get_param (CHTTP_String body, CHTTP_String str, char *mem, int cap);
int http_get_param_i (HTTP_String body, HTTP_String str); int chttp_get_param_i (CHTTP_String body, CHTTP_String str);
// Checks whether the request was meant for the host with the given // 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. // 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); bool chttp_match_host(CHTTP_Request *req, CHTTP_String domain, int port);
// Date and cookie types for Set-Cookie header parsing // Date and cookie types for Set-Cookie header parsing
typedef enum { typedef enum {
HTTP_WEEKDAY_MON, CHTTP_WEEKDAY_MON,
HTTP_WEEKDAY_TUE, CHTTP_WEEKDAY_TUE,
HTTP_WEEKDAY_WED, CHTTP_WEEKDAY_WED,
HTTP_WEEKDAY_THU, CHTTP_WEEKDAY_THU,
HTTP_WEEKDAY_FRI, CHTTP_WEEKDAY_FRI,
HTTP_WEEKDAY_SAT, CHTTP_WEEKDAY_SAT,
HTTP_WEEKDAY_SUN, CHTTP_WEEKDAY_SUN,
} HTTP_WeekDay; } CHTTP_WeekDay;
typedef enum { typedef enum {
HTTP_MONTH_JAN, CHTTP_MONTH_JAN,
HTTP_MONTH_FEB, CHTTP_MONTH_FEB,
HTTP_MONTH_MAR, CHTTP_MONTH_MAR,
HTTP_MONTH_APR, CHTTP_MONTH_APR,
HTTP_MONTH_MAY, CHTTP_MONTH_MAY,
HTTP_MONTH_JUN, CHTTP_MONTH_JUN,
HTTP_MONTH_JUL, CHTTP_MONTH_JUL,
HTTP_MONTH_AUG, CHTTP_MONTH_AUG,
HTTP_MONTH_SEP, CHTTP_MONTH_SEP,
HTTP_MONTH_OCT, CHTTP_MONTH_OCT,
HTTP_MONTH_NOV, CHTTP_MONTH_NOV,
HTTP_MONTH_DEC, CHTTP_MONTH_DEC,
} HTTP_Month; } CHTTP_Month;
typedef struct { typedef struct {
HTTP_WeekDay week_day; CHTTP_WeekDay week_day;
int day; int day;
HTTP_Month month; CHTTP_Month month;
int year; int year;
int hour; int hour;
int minute; int minute;
int second; int second;
} HTTP_Date; } CHTTP_Date;
typedef struct { typedef struct {
HTTP_String name; CHTTP_String name;
HTTP_String value; CHTTP_String value;
bool secure; bool secure;
bool http_only; bool chttp_only;
bool have_date; bool have_date;
HTTP_Date date; CHTTP_Date date;
bool have_max_age; bool have_max_age;
uint32_t max_age; uint32_t max_age;
bool have_domain; bool have_domain;
HTTP_String domain; CHTTP_String domain;
bool have_path; bool have_path;
HTTP_String path; CHTTP_String path;
} HTTP_SetCookie; } CHTTP_SetCookie;
// Parses a Set-Cookie header value // Parses a Set-Cookie header value
// Returns 0 on success, -1 on error // Returns 0 on success, -1 on error
int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out); int chttp_parse_set_cookie(CHTTP_String str, CHTTP_SetCookie *out);
+2 -2
View File
@@ -76,7 +76,7 @@ static int servername_callback(SSL *ssl, int *ad, void *arg)
#endif #endif
int server_secure_context_init(ServerSecureContext *ctx, int server_secure_context_init(ServerSecureContext *ctx,
HTTP_String cert_file, HTTP_String key_file) CHTTP_String cert_file, CHTTP_String key_file)
{ {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
SSL_CTX *p = SSL_CTX_new(TLS_server_method()); SSL_CTX *p = SSL_CTX_new(TLS_server_method());
@@ -145,7 +145,7 @@ void server_secure_context_free(ServerSecureContext *ctx)
} }
int server_secure_context_add_certificate(ServerSecureContext *ctx, int server_secure_context_add_certificate(ServerSecureContext *ctx,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file) CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file)
{ {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
if (ctx->num_certs == SERVER_CERTIFICATE_LIMIT) if (ctx->num_certs == SERVER_CERTIFICATE_LIMIT)
+2 -2
View File
@@ -34,7 +34,7 @@ typedef struct {
} ServerSecureContext; } ServerSecureContext;
int server_secure_context_init(ServerSecureContext *ctx, int server_secure_context_init(ServerSecureContext *ctx,
HTTP_String cert_file, HTTP_String key_file); CHTTP_String cert_file, CHTTP_String key_file);
void server_secure_context_free(ServerSecureContext *ctx); void server_secure_context_free(ServerSecureContext *ctx);
int server_secure_context_add_certificate(ServerSecureContext *ctx, int server_secure_context_add_certificate(ServerSecureContext *ctx,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
+109 -109
View File
@@ -1,22 +1,22 @@
static void http_server_conn_init(HTTP_ServerConn *conn, static void chttp_server_conn_init(CHTTP_ServerConn *conn,
SocketHandle handle, uint32_t input_buffer_limit, SocketHandle handle, uint32_t input_buffer_limit,
uint32_t output_buffer_limit) uint32_t output_buffer_limit)
{ {
conn->state = HTTP_SERVER_CONN_BUFFERING; conn->state = CHTTP_SERVER_CONN_BUFFERING;
conn->handle = handle; conn->handle = handle;
conn->closing = false; conn->closing = false;
byte_queue_init(&conn->input, input_buffer_limit); byte_queue_init(&conn->input, input_buffer_limit);
byte_queue_init(&conn->output, output_buffer_limit); byte_queue_init(&conn->output, output_buffer_limit);
} }
static void http_server_conn_free(HTTP_ServerConn *conn) static void chttp_server_conn_free(CHTTP_ServerConn *conn)
{ {
byte_queue_free(&conn->output); byte_queue_free(&conn->output);
byte_queue_free(&conn->input); byte_queue_free(&conn->input);
} }
int http_server_init(HTTP_Server *server) int chttp_server_init(CHTTP_Server *server)
{ {
server->input_buffer_limit = 1<<20; server->input_buffer_limit = 1<<20;
server->output_buffer_limit = 1<<20; server->output_buffer_limit = 1<<20;
@@ -26,8 +26,8 @@ int http_server_init(HTTP_Server *server)
server->backlog = 32; server->backlog = 32;
server->num_conns = 0; server->num_conns = 0;
for (int i = 0; i < HTTP_SERVER_CAPACITY; i++) { for (int i = 0; i < CHTTP_SERVER_CAPACITY; i++) {
server->conns[i].state = HTTP_SERVER_CONN_FREE; server->conns[i].state = CHTTP_SERVER_CONN_FREE;
server->conns[i].gen = 0; server->conns[i].gen = 0;
} }
@@ -35,77 +35,77 @@ int http_server_init(HTTP_Server *server)
server->ready_head = 0; server->ready_head = 0;
return socket_manager_init(&server->sockets, return socket_manager_init(&server->sockets,
server->socket_pool, HTTP_SERVER_CAPACITY); server->socket_pool, CHTTP_SERVER_CAPACITY);
} }
void http_server_free(HTTP_Server *server) void chttp_server_free(CHTTP_Server *server)
{ {
socket_manager_free(&server->sockets); socket_manager_free(&server->sockets);
for (int i = 0, j = 0; j < server->num_conns; i++) { for (int i = 0, j = 0; j < server->num_conns; i++) {
HTTP_ServerConn *conn = &server->conns[i]; CHTTP_ServerConn *conn = &server->conns[i];
if (conn->state == HTTP_SERVER_CONN_FREE) if (conn->state == CHTTP_SERVER_CONN_FREE)
continue; continue;
j++; j++;
http_server_conn_free(conn); chttp_server_conn_free(conn);
} }
} }
void http_server_set_input_limit(HTTP_Server *server, uint32_t limit) void chttp_server_set_input_limit(CHTTP_Server *server, uint32_t limit)
{ {
server->input_buffer_limit = limit; server->input_buffer_limit = limit;
} }
void http_server_set_output_limit(HTTP_Server *server, uint32_t limit) void chttp_server_set_output_limit(CHTTP_Server *server, uint32_t limit)
{ {
server->output_buffer_limit = limit; server->output_buffer_limit = limit;
} }
void http_server_set_trace_bytes(HTTP_Server *server, bool value) void chttp_server_set_trace_bytes(CHTTP_Server *server, bool value)
{ {
server->trace_bytes = value; server->trace_bytes = value;
} }
void http_server_set_reuse_addr(HTTP_Server *server, bool reuse) void chttp_server_set_reuse_addr(CHTTP_Server *server, bool reuse)
{ {
server->reuse_addr = reuse; server->reuse_addr = reuse;
} }
void http_server_set_backlog(HTTP_Server *server, int backlog) void chttp_server_set_backlog(CHTTP_Server *server, int backlog)
{ {
server->backlog = backlog; server->backlog = backlog;
} }
int http_server_listen_tcp(HTTP_Server *server, int chttp_server_listen_tcp(CHTTP_Server *server,
HTTP_String addr, Port port) CHTTP_String addr, Port port)
{ {
return socket_manager_listen_tcp(&server->sockets, return socket_manager_listen_tcp(&server->sockets,
addr, port, server->backlog, server->reuse_addr); addr, port, server->backlog, server->reuse_addr);
} }
int http_server_listen_tls(HTTP_Server *server, int chttp_server_listen_tls(CHTTP_Server *server,
HTTP_String addr, Port port, HTTP_String cert_file_name, CHTTP_String addr, Port port, CHTTP_String cert_file_name,
HTTP_String key_file_name) CHTTP_String key_file_name)
{ {
return socket_manager_listen_tls(&server->sockets, return socket_manager_listen_tls(&server->sockets,
addr, port, server->backlog, server->reuse_addr, addr, port, server->backlog, server->reuse_addr,
cert_file_name, key_file_name); cert_file_name, key_file_name);
} }
int http_server_add_certificate(HTTP_Server *server, int chttp_server_add_certificate(CHTTP_Server *server,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file) CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file)
{ {
return socket_manager_add_certificate(&server->sockets, return socket_manager_add_certificate(&server->sockets,
domain, cert_file, key_file); domain, cert_file, key_file);
} }
int http_server_wakeup(HTTP_Server *server) int chttp_server_wakeup(CHTTP_Server *server)
{ {
return socket_manager_wakeup(&server->sockets); return socket_manager_wakeup(&server->sockets);
} }
void http_server_register_events(HTTP_Server *server, void chttp_server_register_events(CHTTP_Server *server,
EventRegister *reg) EventRegister *reg)
{ {
socket_manager_register_events(&server->sockets, reg); socket_manager_register_events(&server->sockets, reg);
@@ -117,12 +117,12 @@ void http_server_register_events(HTTP_Server *server,
// to the ready queue. If the request is invalid, // to the ready queue. If the request is invalid,
// close the socket. // close the socket.
static void static void
check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn) check_request_buffer(CHTTP_Server *server, CHTTP_ServerConn *conn)
{ {
assert(conn->state == HTTP_SERVER_CONN_BUFFERING); assert(conn->state == CHTTP_SERVER_CONN_BUFFERING);
ByteView src = byte_queue_read_buf(&conn->input); ByteView src = byte_queue_read_buf(&conn->input);
int ret = http_parse_request(src.ptr, src.len, &conn->request); int ret = chttp_parse_request(src.ptr, src.len, &conn->request);
if (ret < 0) { if (ret < 0) {
// Invalid request // Invalid request
@@ -147,22 +147,22 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn)
// Stop receiving I/O events while we are building the response // Stop receiving I/O events while we are building the response
socket_silent(&server->sockets, conn->handle, true); socket_silent(&server->sockets, conn->handle, true);
conn->state = HTTP_SERVER_CONN_WAIT_STATUS; conn->state = CHTTP_SERVER_CONN_WAIT_STATUS;
conn->request_len = ret; conn->request_len = ret;
conn->response_offset = byte_queue_offset(&conn->output); conn->response_offset = byte_queue_offset(&conn->output);
// Push to the ready queue // Push to the ready queue
assert(server->num_ready < HTTP_SERVER_CAPACITY); assert(server->num_ready < CHTTP_SERVER_CAPACITY);
int tail = (server->ready_head + server->num_ready) % HTTP_SERVER_CAPACITY; int tail = (server->ready_head + server->num_ready) % CHTTP_SERVER_CAPACITY;
server->ready[tail] = conn - server->conns; server->ready[tail] = conn - server->conns;
server->num_ready++; server->num_ready++;
} }
} }
static void static void
http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn) chttp_server_conn_process_events(CHTTP_Server *server, CHTTP_ServerConn *conn)
{ {
if (conn->state == HTTP_SERVER_CONN_FLUSHING) { if (conn->state == CHTTP_SERVER_CONN_FLUSHING) {
ByteView src = byte_queue_read_buf(&conn->output); ByteView src = byte_queue_read_buf(&conn->output);
@@ -171,7 +171,7 @@ http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn)
num = socket_send(&server->sockets, conn->handle, src.ptr, src.len); num = socket_send(&server->sockets, conn->handle, src.ptr, src.len);
if (server->trace_bytes) if (server->trace_bytes)
print_bytes(HTTP_STR("<< "), (HTTP_String) { src.ptr, num }); print_bytes(CHTTP_STR("<< "), (CHTTP_String) { src.ptr, num });
byte_queue_read_ack(&conn->output, num); byte_queue_read_ack(&conn->output, num);
@@ -188,11 +188,11 @@ http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn)
socket_close(&server->sockets, conn->handle); socket_close(&server->sockets, conn->handle);
return; return;
} }
conn->state = HTTP_SERVER_CONN_BUFFERING; conn->state = CHTTP_SERVER_CONN_BUFFERING;
} }
} }
if (conn->state == HTTP_SERVER_CONN_BUFFERING) { if (conn->state == CHTTP_SERVER_CONN_BUFFERING) {
int min_recv = 1<<10; int min_recv = 1<<10;
byte_queue_write_setmincap(&conn->input, min_recv); byte_queue_write_setmincap(&conn->input, min_recv);
@@ -208,7 +208,7 @@ http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn)
num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len); num = socket_recv(&server->sockets, conn->handle, dst.ptr, dst.len);
if (server->trace_bytes) if (server->trace_bytes)
print_bytes(HTTP_STR(">> "), (HTTP_String) { dst.ptr, num }); print_bytes(CHTTP_STR(">> "), (CHTTP_String) { dst.ptr, num });
byte_queue_write_ack(&conn->input, num); byte_queue_write_ack(&conn->input, num);
@@ -220,38 +220,38 @@ http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn)
} }
} }
void http_server_process_events(HTTP_Server *server, void chttp_server_process_events(CHTTP_Server *server,
EventRegister reg) EventRegister reg)
{ {
SocketEvent events[HTTP_SERVER_CAPACITY]; SocketEvent events[CHTTP_SERVER_CAPACITY];
int num_events = socket_manager_translate_events(&server->sockets, events, reg); int num_events = socket_manager_translate_events(&server->sockets, events, reg);
for (int i = 0; i < num_events; i++) { for (int i = 0; i < num_events; i++) {
HTTP_ServerConn *conn = events[i].user; CHTTP_ServerConn *conn = events[i].user;
if (events[i].type == SOCKET_EVENT_DISCONNECT) { if (events[i].type == SOCKET_EVENT_DISCONNECT) {
http_server_conn_free(conn); // TODO: what if this was in the ready queue? chttp_server_conn_free(conn); // TODO: what if this was in the ready queue?
server->num_conns--; server->num_conns--;
} else if (events[i].type == SOCKET_EVENT_READY) { } else if (events[i].type == SOCKET_EVENT_READY) {
if (events[i].user == NULL) { if (events[i].user == NULL) {
if (server->num_conns == HTTP_SERVER_CAPACITY) { if (server->num_conns == CHTTP_SERVER_CAPACITY) {
socket_close(&server->sockets, events[i].handle); socket_close(&server->sockets, events[i].handle);
continue; continue;
} }
int j = 0; int j = 0;
while (server->conns[j].state != HTTP_SERVER_CONN_FREE) { while (server->conns[j].state != CHTTP_SERVER_CONN_FREE) {
j++; j++;
assert(i < HTTP_SERVER_CAPACITY); assert(i < CHTTP_SERVER_CAPACITY);
} }
conn = &server->conns[j]; conn = &server->conns[j];
http_server_conn_init(conn, chttp_server_conn_init(conn,
events[i].handle, events[i].handle,
server->input_buffer_limit, server->input_buffer_limit,
server->output_buffer_limit); server->output_buffer_limit);
@@ -261,44 +261,44 @@ void http_server_process_events(HTTP_Server *server,
} }
while (socket_ready(&server->sockets, events[i].handle) while (socket_ready(&server->sockets, events[i].handle)
&& conn->state != HTTP_SERVER_CONN_WAIT_STATUS) && conn->state != CHTTP_SERVER_CONN_WAIT_STATUS)
http_server_conn_process_events(server, conn); chttp_server_conn_process_events(server, conn);
} }
} }
} }
bool http_server_next_request(HTTP_Server *server, bool chttp_server_next_request(CHTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder) CHTTP_Request **request, CHTTP_ResponseBuilder *builder)
{ {
if (server->num_ready == 0) if (server->num_ready == 0)
return false; return false;
HTTP_ServerConn *conn = &server->conns[server->ready[server->ready_head]]; CHTTP_ServerConn *conn = &server->conns[server->ready[server->ready_head]];
server->ready_head = (server->ready_head + 1) % HTTP_SERVER_CAPACITY; server->ready_head = (server->ready_head + 1) % CHTTP_SERVER_CAPACITY;
server->num_ready--; server->num_ready--;
assert(conn->state == HTTP_SERVER_CONN_WAIT_STATUS); assert(conn->state == CHTTP_SERVER_CONN_WAIT_STATUS);
*request = &conn->request; *request = &conn->request;
*builder = (HTTP_ResponseBuilder) { server, conn - server->conns, conn->gen }; *builder = (CHTTP_ResponseBuilder) { server, conn - server->conns, conn->gen };
return true; return true;
} }
void http_server_wait_request(HTTP_Server *server, void chttp_server_wait_request(CHTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder) CHTTP_Request **request, CHTTP_ResponseBuilder *builder)
{ {
for (;;) { for (;;) {
void *ptrs[HTTP_SERVER_POLL_CAPACITY]; void *ptrs[CHTTP_SERVER_POLL_CAPACITY];
struct pollfd polled[HTTP_SERVER_POLL_CAPACITY]; struct pollfd polled[CHTTP_SERVER_POLL_CAPACITY];
EventRegister reg = { ptrs, polled, 0 }; EventRegister reg = { ptrs, polled, 0 };
http_server_register_events(server, &reg); chttp_server_register_events(server, &reg);
if (reg.num_polled > 0) if (reg.num_polled > 0)
POLL(reg.polled, reg.num_polled, -1); POLL(reg.polled, reg.num_polled, -1);
http_server_process_events(server, reg); chttp_server_process_events(server, reg);
if (http_server_next_request(server, request, builder)) if (chttp_server_next_request(server, request, builder))
break; break;
} }
} }
@@ -309,17 +309,17 @@ void http_server_wait_request(HTTP_Server *server,
// can be returned, as any builder is invalidated by // can be returned, as any builder is invalidated by
// incrementing the connection's generation counter // incrementing the connection's generation counter
// when a response is completed. // when a response is completed.
static HTTP_ServerConn* static CHTTP_ServerConn*
builder_to_conn(HTTP_ResponseBuilder builder) builder_to_conn(CHTTP_ResponseBuilder builder)
{ {
HTTP_Server *server = builder.server; CHTTP_Server *server = builder.server;
if (server == NULL) if (server == NULL)
return NULL; return NULL;
if (builder.index > HTTP_SERVER_CAPACITY) if (builder.index > CHTTP_SERVER_CAPACITY)
return NULL; return NULL;
HTTP_ServerConn *conn = &server->conns[builder.index]; CHTTP_ServerConn *conn = &server->conns[builder.index];
if (builder.gen != conn->gen) if (builder.gen != conn->gen)
return NULL; return NULL;
@@ -394,31 +394,31 @@ get_status_text(int code)
} }
static void static void
write_status(HTTP_ServerConn *conn, int status) write_status(CHTTP_ServerConn *conn, int status)
{ {
byte_queue_write_fmt(&conn->output, byte_queue_write_fmt(&conn->output,
"HTTP/1.1 %d %s\r\n", "HTTP/1.1 %d %s\r\n",
status, get_status_text(status)); status, get_status_text(status));
} }
void http_response_builder_status(HTTP_ResponseBuilder builder, int status) void chttp_response_builder_status(CHTTP_ResponseBuilder builder, int status)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); CHTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->state != HTTP_SERVER_CONN_WAIT_STATUS) { if (conn->state != CHTTP_SERVER_CONN_WAIT_STATUS) {
// Reset all response content and start from scrach. // Reset all response content and start from scrach.
byte_queue_remove_from_offset(&conn->output, conn->response_offset); byte_queue_remove_from_offset(&conn->output, conn->response_offset);
conn->state = HTTP_SERVER_CONN_WAIT_STATUS; conn->state = CHTTP_SERVER_CONN_WAIT_STATUS;
} }
write_status(conn, status); write_status(conn, status);
conn->state = HTTP_SERVER_CONN_WAIT_HEADER; conn->state = CHTTP_SERVER_CONN_WAIT_HEADER;
} }
static bool is_header_valid(HTTP_String str) static bool is_header_valid(CHTTP_String str)
{ {
bool has_colon = false; bool has_colon = false;
for (int i = 0; i < str.len; i++) { for (int i = 0; i < str.len; i++) {
@@ -432,13 +432,13 @@ static bool is_header_valid(HTTP_String str)
return has_colon; return has_colon;
} }
void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str) void chttp_response_builder_header(CHTTP_ResponseBuilder builder, CHTTP_String str)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); CHTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->state != HTTP_SERVER_CONN_WAIT_HEADER) if (conn->state != CHTTP_SERVER_CONN_WAIT_HEADER)
return; return;
// Header must contain a colon and no control characters // Header must contain a colon and no control characters
@@ -449,19 +449,19 @@ void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str)
byte_queue_write(&conn->output, "\r\n", 2); byte_queue_write(&conn->output, "\r\n", 2);
} }
static void append_special_headers(HTTP_ServerConn *conn) static void append_special_headers(CHTTP_ServerConn *conn)
{ {
HTTP_String s; CHTTP_String s;
if (conn->closing) { if (conn->closing) {
s = HTTP_STR("Connection: Close\r\n"); s = CHTTP_STR("Connection: Close\r\n");
byte_queue_write(&conn->output, s.ptr, s.len); byte_queue_write(&conn->output, s.ptr, s.len);
} else { } else {
s = HTTP_STR("Connection: Keep-Alive\r\n"); s = CHTTP_STR("Connection: Keep-Alive\r\n");
byte_queue_write(&conn->output, s.ptr, s.len); byte_queue_write(&conn->output, s.ptr, s.len);
} }
s = HTTP_STR("Content-Length: "); s = CHTTP_STR("Content-Length: ");
byte_queue_write(&conn->output, s.ptr, s.len); byte_queue_write(&conn->output, s.ptr, s.len);
conn->content_length_value_offset = byte_queue_offset(&conn->output); conn->content_length_value_offset = byte_queue_offset(&conn->output);
@@ -469,14 +469,14 @@ static void append_special_headers(HTTP_ServerConn *conn)
#define TEN_SPACES " " #define TEN_SPACES " "
_Static_assert(sizeof(TEN_SPACES) == 10+1); _Static_assert(sizeof(TEN_SPACES) == 10+1);
s = HTTP_STR(TEN_SPACES "\r\n"); s = CHTTP_STR(TEN_SPACES "\r\n");
byte_queue_write(&conn->output, s.ptr, s.len); byte_queue_write(&conn->output, s.ptr, s.len);
byte_queue_write(&conn->output, "\r\n", 2); byte_queue_write(&conn->output, "\r\n", 2);
conn->content_length_offset = byte_queue_offset(&conn->output); conn->content_length_offset = byte_queue_offset(&conn->output);
} }
static void patch_special_headers(HTTP_ServerConn *conn) static void patch_special_headers(CHTTP_ServerConn *conn)
{ {
int content_length = byte_queue_size_from_offset(&conn->output, conn->content_length_offset); int content_length = byte_queue_size_from_offset(&conn->output, conn->content_length_offset);
@@ -487,52 +487,52 @@ static void patch_special_headers(HTTP_ServerConn *conn)
byte_queue_patch(&conn->output, conn->content_length_value_offset, tmp, len); byte_queue_patch(&conn->output, conn->content_length_value_offset, tmp, len);
} }
void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str) void chttp_response_builder_body(CHTTP_ResponseBuilder builder, CHTTP_String str)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); CHTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->state == HTTP_SERVER_CONN_WAIT_HEADER) { if (conn->state == CHTTP_SERVER_CONN_WAIT_HEADER) {
append_special_headers(conn); append_special_headers(conn);
conn->state = HTTP_SERVER_CONN_WAIT_BODY; conn->state = CHTTP_SERVER_CONN_WAIT_BODY;
} }
if (conn->state != HTTP_SERVER_CONN_WAIT_BODY) if (conn->state != CHTTP_SERVER_CONN_WAIT_BODY)
return; return;
byte_queue_write(&conn->output, str.ptr, str.len); byte_queue_write(&conn->output, str.ptr, str.len);
} }
void http_response_builder_body_cap(HTTP_ResponseBuilder builder, int cap) void chttp_response_builder_body_cap(CHTTP_ResponseBuilder builder, int cap)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); CHTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->state == HTTP_SERVER_CONN_WAIT_HEADER) { if (conn->state == CHTTP_SERVER_CONN_WAIT_HEADER) {
append_special_headers(conn); append_special_headers(conn);
conn->state = HTTP_SERVER_CONN_WAIT_BODY; conn->state = CHTTP_SERVER_CONN_WAIT_BODY;
} }
if (conn->state != HTTP_SERVER_CONN_WAIT_BODY) if (conn->state != CHTTP_SERVER_CONN_WAIT_BODY)
return; return;
byte_queue_write_setmincap(&conn->output, cap); byte_queue_write_setmincap(&conn->output, cap);
} }
char *http_response_builder_body_buf(HTTP_ResponseBuilder builder, int *cap) char *chttp_response_builder_body_buf(CHTTP_ResponseBuilder builder, int *cap)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); CHTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return NULL; return NULL;
if (conn->state == HTTP_SERVER_CONN_WAIT_HEADER) { if (conn->state == CHTTP_SERVER_CONN_WAIT_HEADER) {
append_special_headers(conn); append_special_headers(conn);
conn->state = HTTP_SERVER_CONN_WAIT_BODY; conn->state = CHTTP_SERVER_CONN_WAIT_BODY;
} }
if (conn->state != HTTP_SERVER_CONN_WAIT_BODY) if (conn->state != CHTTP_SERVER_CONN_WAIT_BODY)
return NULL; return NULL;
ByteView tmp = byte_queue_write_buf(&conn->output); ByteView tmp = byte_queue_write_buf(&conn->output);
@@ -540,45 +540,45 @@ char *http_response_builder_body_buf(HTTP_ResponseBuilder builder, int *cap)
return tmp.ptr; return tmp.ptr;
} }
void http_response_builder_body_ack(HTTP_ResponseBuilder builder, int num) void chttp_response_builder_body_ack(CHTTP_ResponseBuilder builder, int num)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); CHTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->state != HTTP_SERVER_CONN_WAIT_BODY) if (conn->state != CHTTP_SERVER_CONN_WAIT_BODY)
return; return;
byte_queue_write_ack(&conn->output, num); byte_queue_write_ack(&conn->output, num);
} }
void http_response_builder_send(HTTP_ResponseBuilder builder) void chttp_response_builder_send(CHTTP_ResponseBuilder builder)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); CHTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
return; return;
if (conn->state == HTTP_SERVER_CONN_WAIT_STATUS) { if (conn->state == CHTTP_SERVER_CONN_WAIT_STATUS) {
write_status(conn, 500); write_status(conn, 500);
conn->state = HTTP_SERVER_CONN_WAIT_HEADER; conn->state = CHTTP_SERVER_CONN_WAIT_HEADER;
} }
if (conn->state == HTTP_SERVER_CONN_WAIT_HEADER) { if (conn->state == CHTTP_SERVER_CONN_WAIT_HEADER) {
append_special_headers(conn); append_special_headers(conn);
conn->state = HTTP_SERVER_CONN_WAIT_BODY; conn->state = CHTTP_SERVER_CONN_WAIT_BODY;
} }
assert(conn->state == HTTP_SERVER_CONN_WAIT_BODY); assert(conn->state == CHTTP_SERVER_CONN_WAIT_BODY);
patch_special_headers(conn); patch_special_headers(conn);
// Remove the buffered request // Remove the buffered request
byte_queue_read_ack(&conn->input, conn->request_len); byte_queue_read_ack(&conn->input, conn->request_len);
conn->state = HTTP_SERVER_CONN_FLUSHING; conn->state = CHTTP_SERVER_CONN_FLUSHING;
conn->gen++; conn->gen++;
// Enable back I/O events // Enable back I/O events
socket_silent(&builder.server->sockets, conn->handle, false); socket_silent(&builder.server->sockets, conn->handle, false);
http_server_conn_process_events(builder.server, conn); chttp_server_conn_process_events(builder.server, conn);
} }
+48 -48
View File
@@ -1,49 +1,49 @@
#ifndef HTTP_SERVER_CAPACITY #ifndef CHTTP_SERVER_CAPACITY
// The maximum ammount of requests that can be handled // The maximum ammount of requests that can be handled
// in parallel. // in parallel.
#define HTTP_SERVER_CAPACITY (1<<9) #define CHTTP_SERVER_CAPACITY (1<<9)
#endif #endif
// Maximum number of descriptors the server will want // Maximum number of descriptors the server will want
// to wait on. It's one per connection plus two for the // to wait on. It's one per connection plus two for the
// TCP and TLS listener, plus one for the wakeup self-pipe. // TCP and TLS listener, plus one for the wakeup self-pipe.
#define HTTP_SERVER_POLL_CAPACITY (HTTP_SERVER_CAPACITY+3) #define CHTTP_SERVER_POLL_CAPACITY (CHTTP_SERVER_CAPACITY+3)
typedef enum { typedef enum {
// This struct is unused // This struct is unused
HTTP_SERVER_CONN_FREE, CHTTP_SERVER_CONN_FREE,
// No request was buffered yet. // No request was buffered yet.
HTTP_SERVER_CONN_BUFFERING, CHTTP_SERVER_CONN_BUFFERING,
// A request was just buffered and is waiting for // A request was just buffered and is waiting for
// the user to build a response. To be specific, // the user to build a response. To be specific,
// it's waiting for the user to set a response status. // it's waiting for the user to set a response status.
HTTP_SERVER_CONN_WAIT_STATUS, CHTTP_SERVER_CONN_WAIT_STATUS,
// A request is buffered and a status was set. Now // A request is buffered and a status was set. Now
// the user can set a header or append the first // the user can set a header or append the first
// bytes of the response body. // bytes of the response body.
HTTP_SERVER_CONN_WAIT_HEADER, CHTTP_SERVER_CONN_WAIT_HEADER,
// A request is buffered and some bytes were appended // A request is buffered and some bytes were appended
// to the response. Now the user can either append more // to the response. Now the user can either append more
// bytes or send out the response. // bytes or send out the response.
HTTP_SERVER_CONN_WAIT_BODY, CHTTP_SERVER_CONN_WAIT_BODY,
// A response has been produced and it's being flushed. // A response has been produced and it's being flushed.
HTTP_SERVER_CONN_FLUSHING, CHTTP_SERVER_CONN_FLUSHING,
} HTTP_ServerConnState; } CHTTP_ServerConnState;
// This structure represents the HTTP connection to // This structure represents the HTTP connection to
// a client. // a client.
typedef struct { typedef struct {
// If false, this struct is unused // If false, this struct is unused
HTTP_ServerConnState state; CHTTP_ServerConnState state;
// Handle to the socket // Handle to the socket
SocketHandle handle; SocketHandle handle;
@@ -68,7 +68,7 @@ typedef struct {
// When the state is WAIT_STATUS, WAIT_HEADER, // When the state is WAIT_STATUS, WAIT_HEADER,
// or WAIT_BODY, this contains the parsed version // or WAIT_BODY, this contains the parsed version
// of the buffered request. // of the buffered request.
HTTP_Request request; CHTTP_Request request;
// Length of the buffered request when the request // Length of the buffered request when the request
// field is valid. // field is valid.
@@ -93,7 +93,7 @@ typedef struct {
// it from the offset reached when the response is marked // it from the offset reached when the response is marked
// as done. // as done.
ByteQueueOffset content_length_offset; ByteQueueOffset content_length_offset;
} HTTP_ServerConn; } CHTTP_ServerConn;
typedef struct { typedef struct {
@@ -109,13 +109,13 @@ typedef struct {
// Array of connections. The counter contains the // Array of connections. The counter contains the
// number of structs such that state=FREE. // number of structs such that state=FREE.
int num_conns; int num_conns;
HTTP_ServerConn conns[HTTP_SERVER_CAPACITY]; CHTTP_ServerConn conns[CHTTP_SERVER_CAPACITY];
// Queue of indices referring to connections that // Queue of indices referring to connections that
// are in the WAIT_STATUS state. // are in the WAIT_STATUS state.
int num_ready; int num_ready;
int ready_head; int ready_head;
int ready[HTTP_SERVER_CAPACITY]; int ready[CHTTP_SERVER_CAPACITY];
// Asynchronous TCP and TLS socket abstraction // Asynchronous TCP and TLS socket abstraction
SocketManager sockets; SocketManager sockets;
@@ -125,74 +125,74 @@ typedef struct {
// manager with a pointer to it. This allows // manager with a pointer to it. This allows
// allocating the exact number of sockets we // allocating the exact number of sockets we
// will need. // will need.
Socket socket_pool[HTTP_SERVER_CAPACITY]; Socket socket_pool[CHTTP_SERVER_CAPACITY];
} HTTP_Server; } CHTTP_Server;
// Initialize the HTTP server object. By default, it won't // Initialize the HTTP server object. By default, it won't
// listen for connections. You need to call // listen for connections. You need to call
// //
// http_server_listen_tcp // chttp_server_listen_tcp
// http_server_listen_tls // chttp_server_listen_tls
// //
// to listen for connection. Note that you can have a // to listen for connection. Note that you can have a
// single server listening for HTTP and HTTPS requests // single server listening for HTTP and HTTPS requests
// by calling both. // by calling both.
int http_server_init(HTTP_Server *server); int chttp_server_init(CHTTP_Server *server);
// Release resources associated to the server. // Release resources associated to the server.
void http_server_free(HTTP_Server *server); void chttp_server_free(CHTTP_Server *server);
// Set input and output buffer size limit for any // Set input and output buffer size limit for any
// given connection. The default value is 1MB // given connection. The default value is 1MB
void http_server_set_input_limit(HTTP_Server *server, uint32_t limit); void chttp_server_set_input_limit(CHTTP_Server *server, uint32_t limit);
void http_server_set_output_limit(HTTP_Server *server, uint32_t limit); void chttp_server_set_output_limit(CHTTP_Server *server, uint32_t limit);
// TODO: Comment // TODO: Comment
void http_server_set_trace_bytes(HTTP_Server *server, bool value); void chttp_server_set_trace_bytes(CHTTP_Server *server, bool value);
// TODO: Comment // TODO: Comment
void http_server_set_reuse_addr(HTTP_Server *server, bool reuse); void chttp_server_set_reuse_addr(CHTTP_Server *server, bool reuse);
// TODO: comment // TODO: comment
void http_server_set_backlog(HTTP_Server *server, int backlog); void chttp_server_set_backlog(CHTTP_Server *server, int backlog);
// Enable listening for plain HTTP requests at the // Enable listening for plain HTTP requests at the
// specified interface. // specified interface.
int http_server_listen_tcp(HTTP_Server *server, int chttp_server_listen_tcp(CHTTP_Server *server,
HTTP_String addr, Port port); CHTTP_String addr, Port port);
// Enable listening for HTTPS requests at the specified // Enable listening for HTTPS requests at the specified
// interfact, using the specified certificate and key // interfact, using the specified certificate and key
// to verify the connection. // to verify the connection.
int http_server_listen_tls(HTTP_Server *server, HTTP_String addr, Port port, int chttp_server_listen_tls(CHTTP_Server *server, CHTTP_String addr, Port port,
HTTP_String cert_file_name, HTTP_String key_file_name); CHTTP_String cert_file_name, CHTTP_String key_file_name);
// Add the certificate for an additional domain when // Add the certificate for an additional domain when
// the server is listening for HTTPS requests. // the server is listening for HTTPS requests.
int http_server_add_certificate(HTTP_Server *server, int chttp_server_add_certificate(CHTTP_Server *server,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
// When a thread is blocked waiting for server events, // When a thread is blocked waiting for server events,
// other threads can call this function to wake it up. // other threads can call this function to wake it up.
int http_server_wakeup(HTTP_Server *server); int chttp_server_wakeup(CHTTP_Server *server);
// Resets the event register with the list of descriptors // Resets the event register with the list of descriptors
// the server wants monitored. // the server wants monitored.
void http_server_register_events(HTTP_Server *server, void chttp_server_register_events(CHTTP_Server *server,
EventRegister *reg); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP server // I/O events to be triggered, so now the HTTP server
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
void http_server_process_events(HTTP_Server *server, void chttp_server_process_events(CHTTP_Server *server,
EventRegister reg); EventRegister reg);
typedef struct { typedef struct {
HTTP_Server *server; CHTTP_Server *server;
uint16_t index; uint16_t index;
uint16_t gen; uint16_t gen;
} HTTP_ResponseBuilder; } CHTTP_ResponseBuilder;
// After some I/O events were processes, some requests // After some I/O events were processes, some requests
// may be availabe. This function returns one of the // may be availabe. This function returns one of the
@@ -202,32 +202,32 @@ typedef struct {
// respond in batches. // respond in batches.
// For each request returned by this function, the user // For each request returned by this function, the user
// must build a response using the response builder API. // must build a response using the response builder API.
bool http_server_next_request(HTTP_Server *server, bool chttp_server_next_request(CHTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder); CHTTP_Request **request, CHTTP_ResponseBuilder *builder);
// TODO: comment // TODO: comment
void http_server_wait_request(HTTP_Server *server, void chttp_server_wait_request(CHTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder); CHTTP_Request **request, CHTTP_ResponseBuilder *builder);
// This function is called to set the status code of // This function is called to set the status code of
// a request's response. If this function is called // a request's response. If this function is called
// after the other response builder functions, it will // after the other response builder functions, it will
// reset the response and set a new status. // reset the response and set a new status.
void http_response_builder_status(HTTP_ResponseBuilder builder, int status); void chttp_response_builder_status(CHTTP_ResponseBuilder builder, int status);
// Append a header to the response. This can only be // Append a header to the response. This can only be
// used after having set the status and before appending // used after having set the status and before appending
// to the body. // to the body.
void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str); void chttp_response_builder_header(CHTTP_ResponseBuilder builder, CHTTP_String str);
// Append some bytes to the response's body // Append some bytes to the response's body
void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str); void chttp_response_builder_body(CHTTP_ResponseBuilder builder, CHTTP_String str);
// TODO: comment // TODO: comment
void http_response_builder_body_cap(HTTP_ResponseBuilder builder, int cap); void chttp_response_builder_body_cap(CHTTP_ResponseBuilder builder, int cap);
char *http_response_builder_body_buf(HTTP_ResponseBuilder builder, int *cap); char *chttp_response_builder_body_buf(CHTTP_ResponseBuilder builder, int *cap);
void http_response_builder_body_ack(HTTP_ResponseBuilder builder, int num); void chttp_response_builder_body_ack(CHTTP_ResponseBuilder builder, int num);
// Mark the response as complete. This will invalidate // Mark the response as complete. This will invalidate
// the response builder handle. // the response builder handle.
void http_response_builder_send(HTTP_ResponseBuilder builder); void chttp_response_builder_send(CHTTP_ResponseBuilder builder);
+47 -47
View File
@@ -39,7 +39,7 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
WSADATA wsaData; WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2); WORD wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData)) if (WSAStartup(wVersionRequested, &wsaData))
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET && *global_cleanup) if (sock == INVALID_SOCKET && *global_cleanup)
@@ -49,7 +49,7 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
if (*global_cleanup) if (*global_cleanup)
WSACleanup(); WSACleanup();
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
} }
// Bind to loopback address with port 0 (dynamic port assignment) // Bind to loopback address with port 0 (dynamic port assignment)
@@ -64,21 +64,21 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
closesocket(sock); closesocket(sock);
if (*global_cleanup) if (*global_cleanup)
WSACleanup(); WSACleanup();
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
} }
if (getsockname(sock, (struct sockaddr*)&addr, &addr_len) == SOCKET_ERROR) { if (getsockname(sock, (struct sockaddr*)&addr, &addr_len) == SOCKET_ERROR) {
closesocket(sock); closesocket(sock);
if (*global_cleanup) if (*global_cleanup)
WSACleanup(); WSACleanup();
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
} }
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
closesocket(sock); closesocket(sock);
if (*global_cleanup) if (*global_cleanup)
WSACleanup(); WSACleanup();
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
} }
// Optional: Set socket to non-blocking mode // Optional: Set socket to non-blocking mode
@@ -88,20 +88,20 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
closesocket(sock); closesocket(sock);
if (*global_cleanup) if (*global_cleanup)
WSACleanup(); WSACleanup();
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
} }
*a = sock; *a = sock;
*b = sock; *b = sock;
return HTTP_OK; return CHTTP_OK;
#else #else
*global_cleanup = false; *global_cleanup = false;
int fds[2]; int fds[2];
if (pipe(fds) < 0) if (pipe(fds) < 0)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
*a = fds[0]; *a = fds[0];
*b = fds[1]; *b = fds[1];
return HTTP_OK; return CHTTP_OK;
#endif #endif
} }
@@ -110,23 +110,23 @@ static int set_socket_blocking(NATIVE_SOCKET sock, bool value)
#ifdef _WIN32 #ifdef _WIN32
u_long mode = !value; u_long mode = !value;
if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR) if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
return HTTP_OK; return CHTTP_OK;
#endif #endif
#ifdef __linux__ #ifdef __linux__
int flags = fcntl(sock, F_GETFL, 0); int flags = fcntl(sock, F_GETFL, 0);
if (flags < 0) if (flags < 0)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
if (value) flags &= ~O_NONBLOCK; if (value) flags &= ~O_NONBLOCK;
else flags |= O_NONBLOCK; else flags |= O_NONBLOCK;
if (fcntl(sock, F_SETFL, flags) < 0) if (fcntl(sock, F_SETFL, flags) < 0)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
return HTTP_OK; return CHTTP_OK;
#endif #endif
} }
static NATIVE_SOCKET create_listen_socket(HTTP_String addr, static NATIVE_SOCKET create_listen_socket(CHTTP_String addr,
Port port, bool reuse_addr, int backlog) Port port, bool reuse_addr, int backlog)
{ {
NATIVE_SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); NATIVE_SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -212,7 +212,7 @@ int socket_manager_init(SocketManager *sm, Socket *socks,
socks[i].state = SOCKET_STATE_FREE; socks[i].state = SOCKET_STATE_FREE;
socks[i].gen = 1; socks[i].gen = 1;
} }
return HTTP_OK; return CHTTP_OK;
} }
void socket_manager_free(SocketManager *sm) void socket_manager_free(SocketManager *sm)
@@ -238,57 +238,57 @@ void socket_manager_free(SocketManager *sm)
} }
int socket_manager_listen_tcp(SocketManager *sm, int socket_manager_listen_tcp(SocketManager *sm,
HTTP_String addr, Port port, int backlog, CHTTP_String addr, Port port, int backlog,
bool reuse_addr) bool reuse_addr)
{ {
if (sm->plain_sock != NATIVE_SOCKET_INVALID) if (sm->plain_sock != NATIVE_SOCKET_INVALID)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog); sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog);
if (sm->plain_sock == NATIVE_SOCKET_INVALID) if (sm->plain_sock == NATIVE_SOCKET_INVALID)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
return HTTP_OK; return CHTTP_OK;
} }
int socket_manager_listen_tls(SocketManager *sm, int socket_manager_listen_tls(SocketManager *sm,
HTTP_String addr, Port port, int backlog, CHTTP_String addr, Port port, int backlog,
bool reuse_addr, HTTP_String cert_file, bool reuse_addr, CHTTP_String cert_file,
HTTP_String key_file) CHTTP_String key_file)
{ {
#ifndef HTTPS_ENABLED #ifndef HTTPS_ENABLED
return HTTP_ERROR_NOTLS; return CHTTP_ERROR_NOTLS;
#endif #endif
if (sm->secure_sock != NATIVE_SOCKET_INVALID) if (sm->secure_sock != NATIVE_SOCKET_INVALID)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog); sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog);
if (sm->secure_sock == NATIVE_SOCKET_INVALID) if (sm->secure_sock == NATIVE_SOCKET_INVALID)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
if (server_secure_context_init(&sm->server_secure_context, if (server_secure_context_init(&sm->server_secure_context,
cert_file, key_file) < 0) { cert_file, key_file) < 0) {
CLOSE_NATIVE_SOCKET(sm->secure_sock); CLOSE_NATIVE_SOCKET(sm->secure_sock);
sm->secure_sock = NATIVE_SOCKET_INVALID; sm->secure_sock = NATIVE_SOCKET_INVALID;
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
} }
return HTTP_OK; return CHTTP_OK;
} }
int socket_manager_add_certificate(SocketManager *sm, int socket_manager_add_certificate(SocketManager *sm,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file) CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file)
{ {
if (sm->secure_sock == NATIVE_SOCKET_INVALID) if (sm->secure_sock == NATIVE_SOCKET_INVALID)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
int ret = server_secure_context_add_certificate( int ret = server_secure_context_add_certificate(
&sm->server_secure_context, domain, cert_file, key_file); &sm->server_secure_context, domain, cert_file, key_file);
if (ret < 0) if (ret < 0)
return ret; return ret;
return HTTP_OK; return CHTTP_OK;
} }
static bool is_secure(Socket *s) static bool is_secure(Socket *s)
@@ -428,13 +428,13 @@ static void socket_update(Socket *s)
struct sockaddr_in buf; struct sockaddr_in buf;
buf.sin_family = AF_INET; buf.sin_family = AF_INET;
buf.sin_port = htons(addr.port); buf.sin_port = htons(addr.port);
memcpy(&buf.sin_addr, &addr.ipv4, sizeof(HTTP_IPv4)); memcpy(&buf.sin_addr, &addr.ipv4, sizeof(CHTTP_IPv4));
ret = connect(sock, (struct sockaddr*) &buf, sizeof(buf)); ret = connect(sock, (struct sockaddr*) &buf, sizeof(buf));
} else { } else {
struct sockaddr_in6 buf; struct sockaddr_in6 buf;
buf.sin6_family = AF_INET6; buf.sin6_family = AF_INET6;
buf.sin6_port = htons(addr.port); buf.sin6_port = htons(addr.port);
memcpy(&buf.sin6_addr, &addr.ipv6, sizeof(HTTP_IPv6)); memcpy(&buf.sin6_addr, &addr.ipv6, sizeof(CHTTP_IPv6));
ret = connect(sock, (struct sockaddr*) &buf, sizeof(buf)); ret = connect(sock, (struct sockaddr*) &buf, sizeof(buf));
} }
@@ -693,12 +693,12 @@ int socket_manager_wakeup(SocketManager *sm)
char byte = 1; char byte = 1;
#ifdef _WIN32 #ifdef _WIN32
if (send(sm->signal_sock, &byte, 1, 0) < 0) if (send(sm->signal_sock, &byte, 1, 0) < 0)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
#else #else
if (write(sm->signal_sock, &byte, 1) < 0) if (write(sm->signal_sock, &byte, 1) < 0)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
#endif #endif
return HTTP_OK; return CHTTP_OK;
} }
void socket_manager_register_events( void socket_manager_register_events(
@@ -929,7 +929,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
RegisteredName *name = malloc(sizeof(RegisteredName) + targets[i].name.len + 1); RegisteredName *name = malloc(sizeof(RegisteredName) + targets[i].name.len + 1);
if (name == NULL) { if (name == NULL) {
free_addr_list(resolved, num_resolved); free_addr_list(resolved, num_resolved);
return HTTP_ERROR_OOM; return CHTTP_ERROR_OOM;
} }
name->refs = 0; name->refs = 0;
memcpy(name->data, targets[i].name.ptr, targets[i].name.len); memcpy(name->data, targets[i].name.ptr, targets[i].name.len);
@@ -939,7 +939,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
// 512 bytes is more than enough for a DNS hostname (max 253 chars) // 512 bytes is more than enough for a DNS hostname (max 253 chars)
char hostname[1<<9]; char hostname[1<<9];
if (targets[i].name.len >= (int) sizeof(hostname)) if (targets[i].name.len >= (int) sizeof(hostname))
return HTTP_ERROR_OOM; return CHTTP_ERROR_OOM;
memcpy(hostname, targets[i].name.ptr, targets[i].name.len); memcpy(hostname, targets[i].name.ptr, targets[i].name.len);
hostname[targets[i].name.len] = '\0'; hostname[targets[i].name.len] = '\0';
#endif #endif
@@ -951,12 +951,12 @@ static int resolve_connect_targets(ConnectTarget *targets,
free(name); free(name);
#endif #endif
free_addr_list(resolved, num_resolved); free_addr_list(resolved, num_resolved);
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
} }
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) { for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
if (rp->ai_family == AF_INET) { if (rp->ai_family == AF_INET) {
HTTP_IPv4 ipv4 = *(HTTP_IPv4*) &((struct sockaddr_in*)rp->ai_addr)->sin_addr; CHTTP_IPv4 ipv4 = *(CHTTP_IPv4*) &((struct sockaddr_in*)rp->ai_addr)->sin_addr;
if (num_resolved < max_resolved) { if (num_resolved < max_resolved) {
resolved[num_resolved].is_ipv4 = true; resolved[num_resolved].is_ipv4 = true;
resolved[num_resolved].ipv4 = ipv4; resolved[num_resolved].ipv4 = ipv4;
@@ -968,7 +968,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
num_resolved++; num_resolved++;
} }
} else if (rp->ai_family == AF_INET6) { } else if (rp->ai_family == AF_INET6) {
HTTP_IPv6 ipv6 = *(HTTP_IPv6*) &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr; CHTTP_IPv6 ipv6 = *(CHTTP_IPv6*) &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr;
if (num_resolved < max_resolved) { if (num_resolved < max_resolved) {
resolved[num_resolved].is_ipv4 = false; resolved[num_resolved].is_ipv4 = false;
resolved[num_resolved].ipv6 = ipv6; resolved[num_resolved].ipv6 = ipv6;
@@ -1024,17 +1024,17 @@ int socket_connect(SocketManager *sm, int num_targets,
void *user) void *user)
{ {
if (sm->num_used == sm->max_used) if (sm->num_used == sm->max_used)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
if (!sm->at_least_one_secure_connect) { if (!sm->at_least_one_secure_connect) {
if (client_secure_context_init(&sm->client_secure_context) < 0) if (client_secure_context_init(&sm->client_secure_context) < 0)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
sm->at_least_one_secure_connect = true; sm->at_least_one_secure_connect = true;
} }
#else #else
if (secure) if (secure)
return HTTP_ERROR_NOTLS; return CHTTP_ERROR_NOTLS;
#endif #endif
AddressAndPort resolved[MAX_CONNECT_TARGETS]; AddressAndPort resolved[MAX_CONNECT_TARGETS];
@@ -1042,7 +1042,7 @@ int socket_connect(SocketManager *sm, int num_targets,
targets, num_targets, resolved, MAX_CONNECT_TARGETS); targets, num_targets, resolved, MAX_CONNECT_TARGETS);
if (num_resolved <= 0) if (num_resolved <= 0)
return HTTP_ERROR_UNSPECIFIED; return CHTTP_ERROR_UNSPECIFIED;
Socket *s = sm->sockets; Socket *s = sm->sockets;
while (s->state != SOCKET_STATE_FREE) { while (s->state != SOCKET_STATE_FREE) {
@@ -1059,7 +1059,7 @@ int socket_connect(SocketManager *sm, int num_targets,
s->next_addr = 0; s->next_addr = 0;
s->addrs = malloc(num_resolved * sizeof(AddressAndPort)); s->addrs = malloc(num_resolved * sizeof(AddressAndPort));
if (s->addrs == NULL) if (s->addrs == NULL)
return HTTP_ERROR_OOM; return CHTTP_ERROR_OOM;
for (int i = 0; i < num_resolved; i++) for (int i = 0; i < num_resolved; i++)
s->addrs[i] = resolved[i]; s->addrs[i] = resolved[i];
} }
@@ -1083,7 +1083,7 @@ int socket_connect(SocketManager *sm, int num_targets,
sm->num_used++; sm->num_used++;
socket_update(s); socket_update(s);
return HTTP_OK; return CHTTP_OK;
} }
static bool would_block(void) static bool would_block(void)
+10 -10
View File
@@ -123,8 +123,8 @@ typedef struct {
// Internal use only // Internal use only
typedef struct { typedef struct {
union { union {
HTTP_IPv4 ipv4; CHTTP_IPv4 ipv4;
HTTP_IPv6 ipv6; CHTTP_IPv6 ipv6;
}; };
bool is_ipv4; bool is_ipv4;
Port port; Port port;
@@ -241,7 +241,7 @@ void socket_manager_free(SocketManager *sm);
// can only be used once per manager. // can only be used once per manager.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tcp(SocketManager *sm, int socket_manager_listen_tcp(SocketManager *sm,
HTTP_String addr, Port port, int backlog, CHTTP_String addr, Port port, int backlog,
bool reuse_addr); bool reuse_addr);
// Same as the previous function, but incoming // Same as the previous function, but incoming
@@ -252,9 +252,9 @@ int socket_manager_listen_tcp(SocketManager *sm,
// and secure connections. // and secure connections.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tls(SocketManager *sm, int socket_manager_listen_tls(SocketManager *sm,
HTTP_String addr, Port port, int backlog, CHTTP_String addr, Port port, int backlog,
bool reuse_addr, HTTP_String cert_file, bool reuse_addr, CHTTP_String cert_file,
HTTP_String key_file); CHTTP_String key_file);
// If the socket manager was configures to accept // If the socket manager was configures to accept
// TLS connections, this adds additional certificates // TLS connections, this adds additional certificates
@@ -262,7 +262,7 @@ int socket_manager_listen_tls(SocketManager *sm,
// authenticity. // authenticity.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_add_certificate(SocketManager *sm, int socket_manager_add_certificate(SocketManager *sm,
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file); CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
// When a thread is blocked on a poll() call for // When a thread is blocked on a poll() call for
// descriptors associated to this socket manager, // descriptors associated to this socket manager,
@@ -305,9 +305,9 @@ typedef struct {
ConnectTargetType type; ConnectTargetType type;
Port port; Port port;
union { union {
HTTP_IPv4 ipv4; CHTTP_IPv4 ipv4;
HTTP_IPv6 ipv6; CHTTP_IPv6 ipv6;
HTTP_String name; CHTTP_String name;
}; };
} ConnectTarget; } ConnectTarget;