General

Introduction

38-Moths is a web-framework written for masochists and tribal rituals.

38-Moths

Macros

VERSION

#define VERSION "0.2"

The current version of the 38-Moths.

MAX_READ_LEN

#define MAX_READ_LEN 1024

The maximum amount of bytes to be read when receiving a request.

VERB_SIZE

#define VERB_SIZE 16

The maximum size of an HTTP verb.

MAX_MATCHES

#define MAX_MATCHES 4

The maximum number of matches one can have on a given url.

RESPONSE_OK

#define RESPONSE_OK(status_code) (status_code >= 200 && status_code < 400)

Macro used to check whether a status code is 'good'.

WISDOM_OF_WORDS

#define WISDOM_OF_WORDS 32

The maximum size of a greshunkel variable name.

MAX_GSHKL_STR_SIZE

#define MAX_GSHKL_STR_SIZE 512

The maximum size of a greshunkel string.

INT_LEN(x)

#define INT_LEN(x) x == 0 ? 1 : floor(log10(abs(x))) + 1

Returns the length of an integer if it were rendered as a string.

UINT_LEN(x)

#define UINT_LEN(x) x == 0 ? 1 : floor(log10(x)) + 1

Returns the length of an unsigned integer if it were rendered as a string.

UNUSED(x)

#define UNUSED(x) (void)x

If an argument is unused, use this to avoid compiler warnings. Use with care.

HASH_STR_SIZE

#define HASH_STR_SIZE 65

The length of a 64-character hash string + NULL terminator. Used for the fnv1a function.

Type Definitions

Enums

greshunkel_type

typedef enum {
	GSHKL_ARR,
	GSHKL_STR,
	GSHKL_SUBCTEXT
} greshunkel_type;

Used to tell greshunkel_vars apart.

GSHKL_ARR: A greshunkel array.

GSHKL_STR: A greshunkel string.

Structures

m38_http_request

typedef struct {
	char verb[VERB_SIZE];
	char resource[512];
	regmatch_t matches[MAX_MATCHES];
	char *full_header;
	size_t header_len;
	unsigned char *full_body;
	size_t body_len;
} m38_http_request;

A representation of an HTTP request object. This will be passed to views.

verb: The HTTP verb for the given request.

resource[128]: The path for this request. (eg. '/articles/182')

matches: Any REGEX matches from your path are stored here.

header_len: The length of the header, or 0.

full_header: The full header text of the request.

body_len: The length of the POST body, or 0.

full_body: The full body.

m38_http_response

typedef struct {
	unsigned char *out;
	size_t outsize;
	char mimetype[32];
	void *extra_data;
	struct vector *extra_headers;
} m38_http_response;

Fill this out and return it, signed by your parents. Only *out and outsize are really necessary.

*out: A buffer of characters that will be written back to the requester.

outsize: The size of out.

mimetype[32]: Optional, will be inferred from the m38_http_request's file extension if left blank.

*extra_data: Optional, use this to pass things to the clean up function. For instance, mmap_file() uses extra_data to store the size of the file allocated.

*extra_headers: A vector containing extra headers. Use `insert_custom_header` to manage this parameter.

m38_header_pair

typedef struct {
	const char *header;
	const size_t header_len;
	const char *value;
	const size_t value_len;
} m38_header_pair;

Object used to hold extra header information in an m38_http_request object.

*header: The actual header, eg. "Content-Length"

header_len: Length of the header, in bytes.

*value: The value of the header, eg. "1762"

value_len: Length of the value, in bytes.

m38_route

typedef struct {
	char verb[VERB_SIZE];
	char name[64];
	char route_match[256];
	size_t expected_matches;
	int (*handler)(const m38_http_request *request, m38_http_response *response);
	void (*cleanup)(const int status_code, m38_http_response *response);
} m38_route;

An array of these is how 38-Moths knows how to route requests.

verb[VERB_SIZE]: The verb that this route will handle.

name[64]: The name of the route. Used only logging.

route_match[256]: The POSIX regular expression used to match the route to your handler.

(*handler): A function pointer to your route handler.

(*cleanup): If your route needs to do any cleanup (eg. de-allocating memory), this function will becalled when 38-Moths is done with it.

greshunkel_ctext

typedef struct greshunkel_ctext {
	vector *values;
	vector *filter_functions;
	const struct greshunkel_ctext *parent;
} greshunkel_ctext;

The context is a collection of variables, filters and other stuff that will be used to render a file.

*values: The values stored in this context. Strings, arrays, etc.

*filter_functions: The filter functions stored in this context.

*parent: Used internally, this is used to recurse back up to the parent context if a variable is unavailable in the current one.

greshunkel_named_item

typedef struct greshunkel_named_item {
	char name[WISDOM_OF_WORDS];
} greshunkel_named_item;

Dirty fucking hack to have a generic baseclass-like thing for both greshunkel_tuple and greshunkel_filter objects.

name[WISDOM_OF_WORDS]: The name of this thing. Somehow works. C is fucking scary.

greshunkel_tuple

typedef struct greshunkel_tuple {
	char name[WISDOM_OF_WORDS];
	const greshunkel_type type;
	greshunkel_var value;
} greshunkel_tuple;

Basically the representation of a GRESHUNKEL variable inside of a context.

name[WISDOM_OF_WORDS]: The name of this thing.

type: The type of this thing.

value: The actual value of this thing.

greshunkel_filter

typedef struct greshunkel_filter {
	char name[WISDOM_OF_WORDS];
	char *(*filter_func)(const char *argument);
	void (*clean_up)(char *result);
} greshunkel_filter;

A function that can be applied during template rendering.

name[WISDOM_OF_WORDS]: The name of this thing.

*(*filter_func): Function pointer to the C function you want to have access to in the template.

(*clean_up): If your filter needs any kind of cleanup, set this to a function other than null and you can do whatever.

vector

typedef struct vector {
	const size_t item_size;
	size_t max_size;
	size_t count;
	void *items;
} vector;

A simple vector object. Auto-expands and whatever.

item_size: The maximum size of each item.

max_size: Used internally to track the current vector's maximum number of elements.

count: Used internally to track the current vector's current count of items.

*items: The actual memory used for the items stored.

Functions

m38_get_header_value_raw

char *m38_get_header_value_request(const m38_http_request *req, const char header[static 1]);

Gets the value of `header` (eg. Content-Length) from an http_request object. Wraps get_header_value_raw.

Returns: The char string representing the header value, or NULL. Must be free'd.

m38_get_header_value_raw

char *m38_get_header_value_raw(const char *request, const size_t request_siz, const char header[static 1]);

Gets the value of `header` (eg. Content-Length) from a raw http request string.

Returns: The char string representing the header value, or NULL. Must be free'd.

m38_parse_request

int m38_parse_request(const unsigned char *, const size_t, m38_http_request *);

Turns a raw string buffer into an http_request object.

Returns: 0 on sucess, -1 on failure.

m38_mmap_file

int m38_mmap_file(const char *file_path, m38_http_response *response);

The primary way of serving static assets in 38-Moths. mmap()'s a file into memory and writes it to the requester.

*file_path: The file to mmap().

*response: The m38_http_response object your handler was passed.

Returns: An HTTP status code. 200 on success, 404 on not found, etc.

m38_render_file

int m38_render_file(const struct greshunkel_ctext *ctext, const char *file_path, m38_http_response *response);

The easiest way to render a file with GRESHUNKEL.

*ctext: The context you want your file to have. This should contain all variables, loops, etc.

*file_path: The template to render.

*response: The m38_http_response object your handler was passed.

Returns: An HTTP status code. 200 on success, 404 on not found, etc.

m38_heap_cleanup

void m38_heap_cleanup(const int status_code, m38_http_response *response);

Simple function that free()'s memory in out.

status_code: The status code returned from the handler.

*response: The m38_http_response object returned from the handler.

Returns: Nothing.

m38_mmap_cleanup

void m38_mmap_cleanup(const int status_code, m38_http_response *response);

The cleanup handler for mmap_file. Expects *extradata to be a struct stat object.

status_code: The status code returned from the handler.

*response: The m38_http_response object returned from the handler.

Returns: Nothing.

m38_generate_response

m38_handled_request *m38_generate_response(const int accept_fd, const m38_route *all_routes, const size_t route_num_elements);

Generates and HTTP response from an accepted connection

accept_fd: The successfully accept(2)'d file descriptor for the requester's socket.

*all_routes: The array of all routes for your application.

route_num_elements: The number of routes in *all_routes.

Returns: A fully formatted HTTP response, NULL otherwise.

m38_send_response

m38_handled_request *m38_send_response(m38_handled_request *hreq);

Takes a handled_request object rom generate_response and sends chunks of it down the wire.

*hreq: A handled_request object either from send_response or generate_response.

Returns: If there is anything left to send, an updated handled_request will be returned. NULL will be reutnred when the object has either been fully sent, or errored out.

gshkl_init_context

greshunkel_ctext *gshkl_init_context();

Used to create a new, empty GRESHUNKEL context.

Returns: A new greshunkel context.

gshkl_free_context

void gshkl_free_context(greshunkel_ctext *ctext);

Frees an cleans up a previously created context.

Returns: Nothing.

gshkl_add_string

int gshkl_add_string(greshunkel_ctext *ctext, const char name[WISDOM_OF_WORDS], const char *value);

Adds a string with the given name to a context.

*ctext: The context to add the string to.

name[WISDOM_OF_WORDS]: The name used to reference this variable later.

*value: The NULL terminated string that will be returned later.

Returns: 0 on success, 1 otherwise.

gshkl_add_int

int gshkl_add_int(greshunkel_ctext *ctext, const char name[WISDOM_OF_WORDS], const int value);

Adds an integer with the given name to a context.

*ctext: The context to add the integer to.

name[WISDOM_OF_WORDS]: The name used to reference this variable later.

value: The integer that will be added to this context.

Returns: 0 on success, 1 otherwise.

gshkl_add_array

greshunkel_var gshkl_add_array(greshunkel_ctext *ctext, const char name[WISDOM_OF_WORDS]);

Creates a new array object inside of the given context.

*ctext: The context to add the array to.

name[WISDOM_OF_WORDS]: The name used to reference this variable later.

Returns: The newly created loop object.

gshkl_add_string_to_loop

int gshkl_add_string_to_loop(greshunkel_var *loop, const char *value);

Adds a string to a greshunkel array.

*loop: A pointer to a loop created with gshkl_add_array.

*value: The NULL terminated string to be added.

Returns: 0 on success, 1 otherwise.

gshkl_add_int_to_loop

int gshkl_add_int_to_loop(greshunkel_var *loop, const int value);

Adds an integer to a greshunkel array.

*loop: A pointer to a loop created with gshkl_add_array.

value: The integer to be added.

Returns: 0 on success, 1 otherwise.

gshkl_add_sub_context_to_loop

int gshkl_add_sub_context_to_loop(greshunkel_var *loop, const greshunkel_ctext *child);

Adds a name sub-context to a loop.

*loop: The loop to add the context to.

*child: The pre-built child context.

Returns: 0 on success, 1 otherwise.

gshkl_add_sub_context

int gshkl_add_sub_context(greshunkel_ctext *parent, const char name[WISDOM_OF_WORDS], const greshunkel_ctext *child);

Adds a name sub-context to a parent context. Sub-context values can be references via the '

*parent: The parent context to add the child to.

name: The name of the child context.

*child: The pre-built child context.

Returns: 0 on success, 1 otherwise.

gshkl_add_filter

int gshkl_add_filter(greshunkel_ctext *ctext,
		const char name[WISDOM_OF_WORDS],
		char *(*filter_func)(const char *argument),
		void (*clean_up)(char *filter_result));

Adds a filter function to the given context.

*ctext: The context that the filter will be added to.

name[WISDOM_OF_WORDS]: The name used to reference this filter function.

(*filter_func): The function that will be called from the template.

(*clean_up): The clean up function that will be called after GRESHUNKEL is done calling filter_func.

Returns: 0 on success, 1 otherwise.

gshkl_filter_cleanup

void gshkl_filter_cleanup(char *result);

Commonly used helper clean-up function that just calls free on the result.

*result: The value obtained from calling your filter function.

Returns: Nothing.

endswith

int endswith(const char *string, const char *suffix);

Helper function determine if a string ends with another string.

*string: The source string to test.

*suffix: The suffix to check for.

Returns: 1 if string ends with suffix.

strnstr

char *strnstr(const char *haystack, const char *needle, size_t len);

Like strstr, but only checks up to n chars.

*haystack: Go look at strstr().

*needle: Go look at strstr().

len: Maximum number of characters to look through.

Returns: Whatever the hell strstr() returns.

get_file_creation_date

time_t get_file_creation_date(const char *file_path);

Gets the file creation date.

*file_path: The path of the file to get the creation date of.

Returns: The file creation date.

get_file_size

size_t get_file_size(const char *file_path);

Gets the file size.

*file_path: The path of the file to get the size of.

Returns: The file size.

vector_new

vector *vector_new(const size_t item_size, const size_t initial_element_count);

Creates a new vector object.

item_size: The maximum size of each item.

initial_element_count: If you know your amount of objects ahead of time, set this accordingly. Otherwise just guess. The closer you get the fewer mallocs will happen.

Returns: A new vector object.

vector_append

int vector_append(vector *vec, const void *item, const size_t item_size);

Adds a new element to a vector.

*vec: The vector to add the new item to.

*item: The item to add to the vector.

item_size: The size of the item to be added.

Returns: 1 on success.

vector_append_ptr

int vector_append_ptr(vector *vec, const void *pointer);

Similar to vector_append but copies just the pointer value, not what it points to.

*vec: The vector to add the pointer to.

*pointer: The item to add to the vector.

Returns: 1 on success.

vector_get

const void *vector_get(const vector *vec, const unsigned int i);

Gets the nth element of the given vector.

*vec: The vector to get the item from.

i: The item you want to retrieve.

Returns: A constant pointer to the nth item in the vector.

vector_reverse

int vector_reverse(vector *vec);

Reverses the vector, from beginning to end.

*vec: The vector to be reversed.

Returns: 1 on success.

vector_free

void vector_free(vector *to_free);

Cleans up and removes a vector's allocated memory.

*to_free: The vector to free.

Returns: Nothing.