docs: document event & http loop
							parent
							
								
									323fa65921
								
							
						
					
					
						commit
						62c42331d4
					
				|  | @ -47,50 +47,90 @@ typedef struct event_loop { | |||
|   size_t connection_count; | ||||
|   // Global context passed to every connection
 | ||||
|   void *gctx; | ||||
|   // Function to initialize a context for a connection
 | ||||
|   /**
 | ||||
|    * Function to initialize a connection context. | ||||
|    * | ||||
|    * @param gctx global context of the event loop | ||||
|    * @return pointer to the allocated object. | ||||
|    */ | ||||
|   void *(*ctx_init)(void *gctx); | ||||
|   // Function to free a context for a connection
 | ||||
|   /**
 | ||||
|    * Function to free a connection context object. | ||||
|    * | ||||
|    * @param ctx context to free | ||||
|    */ | ||||
|   void (*ctx_free)(void *ctx); | ||||
|   // Function that processes incoming data
 | ||||
|   /**
 | ||||
|    * Function to process incoming data while in the req state. | ||||
|    * | ||||
|    * @param conn connection to process | ||||
|    * @return whether the function can be called again immediately in the same | ||||
|    * event loop cycle. This allows quicly processing multiple requests without | ||||
|    * waiting for I/O. | ||||
|    */ | ||||
|   bool (*handle_data)(event_loop_conn *conn); | ||||
|   // Function that writes outgoing data
 | ||||
|   /**
 | ||||
|    * Function to process outgoing data while in the res state. | ||||
|    * | ||||
|    * @param conn connection to proces | ||||
|    */ | ||||
|   void (*write_data)(event_loop_conn *conn); | ||||
| } event_loop; | ||||
| 
 | ||||
| /*
 | ||||
|  * Initialize a new connection struct | ||||
|  * | ||||
|  * @param el the event loop | ||||
|  * @return pointer to the newly allocated connection struct | ||||
|  */ | ||||
| event_loop_conn *event_loop_conn_init(event_loop *el); | ||||
| 
 | ||||
| /*
 | ||||
|  * Free a connection struct | ||||
|  * | ||||
|  * @param el the event loop | ||||
|  * @param conn connection struct to free | ||||
|  */ | ||||
| void event_loop_conn_free(event_loop *el, event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
|  * Handle I/O for a connection, be it reading input or writing output. | ||||
|  * | ||||
|  * @param el the event loop | ||||
|  * @param conn the connection to process | ||||
|  */ | ||||
| void event_loop_conn_io(event_loop *el, event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
|  * Initialize a new event loop struct | ||||
|  * | ||||
|  * @return pointer to the newly allocated event loop struct | ||||
|  */ | ||||
| event_loop *event_loop_init(); | ||||
| 
 | ||||
| /*
 | ||||
|  * Place a new connection into the event loop's internal array. | ||||
|  * | ||||
|  * Returns -1 if the internal realloc failed | ||||
|  * @param el the event loop | ||||
|  * @param conn connection to insert | ||||
|  * @return 0 on success, -1 if the internal realloc failed. | ||||
|  */ | ||||
| int event_loop_put(event_loop *el, event_loop_conn *conn); | ||||
| 
 | ||||
| /**
 | ||||
|  * Accept a new connection for the given file descriptor. | ||||
|  * | ||||
|  * @param el the event loop | ||||
|  * @param fd file descriptor for the connection | ||||
|  * @return 0 if successful, negative value otherwise | ||||
|  */ | ||||
| int event_loop_accept(event_loop *el, int fd); | ||||
| 
 | ||||
| /*
 | ||||
|  * Run the event loop. This function never returns. | ||||
|  * | ||||
|  * @param el the event loop | ||||
|  * @param port on what port to listen | ||||
|  */ | ||||
| void event_loop_run(event_loop *el, int port); | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| #define HTTP_MAX_ALLOWED_HEADERS 16 | ||||
| #define HTTP_MAX_REGEX_GROUPS 4 | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Struct representing the specific type of request | ||||
|  */ | ||||
| typedef struct http_request { | ||||
|  | @ -29,6 +29,9 @@ typedef struct http_request { | |||
|   size_t num_headers; | ||||
| } http_request; | ||||
| 
 | ||||
| /**
 | ||||
|  * Result of the HTTP parse function | ||||
|  */ | ||||
| typedef enum http_parse_error { | ||||
|   http_parse_error_ok = 0, | ||||
|   http_parse_error_incomplete = 1, | ||||
|  |  | |||
|  | @ -6,12 +6,18 @@ | |||
| 
 | ||||
| #include "http/types.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * Struct describing a header for the response. | ||||
|  */ | ||||
| typedef struct http_response_header { | ||||
|   http_header type; | ||||
|   const char *value; | ||||
|   bool owned; | ||||
| } http_response_header; | ||||
| 
 | ||||
| /**
 | ||||
|  * Struct representing an HTTP response. | ||||
|  */ | ||||
| typedef struct http_response { | ||||
|   http_status status; | ||||
|   const char *head; | ||||
|  | @ -22,26 +28,41 @@ typedef struct http_response { | |||
|   size_t header_count; | ||||
| } http_response; | ||||
| 
 | ||||
| /*
 | ||||
|  * Set the request body to the given buffer. If owned is set to true, the body | ||||
|  * buffer will be free'd after the request has finished. | ||||
| /**
 | ||||
|  * Set the request body to the given buffer. | ||||
|  * | ||||
|  * @param res response to modify | ||||
|  * @param body pointer to the buf containing the body | ||||
|  * @param body_len length of the body | ||||
|  * @owned whether the body should be freed after processing the request | ||||
|  */ | ||||
| void http_res_set_body_buf(http_response *res, const char *body, | ||||
|                            size_t body_len, bool owned); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Set the request body to the given filename. | ||||
|  * | ||||
|  * @param res response to modify | ||||
|  * @param filename path to the file to return | ||||
|  */ | ||||
| void http_res_set_body_file(http_response *res, const char *filename); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Add a header to the response. | ||||
|  * | ||||
|  * @param res response to modify | ||||
|  * @param type type of the header | ||||
|  * @param value value of the header | ||||
|  * @param owned whether the value should be freed after processing the request | ||||
|  */ | ||||
| void http_res_add_header(http_response *res, http_header type, | ||||
|                          const char *value, bool owned); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Add a Content-Type header corresponding to the mime type. | ||||
|  * | ||||
|  * @param res response to modiy | ||||
|  * @param mime_type mime type of the response | ||||
|  */ | ||||
| void http_res_set_mime_type(http_response *res, http_mime_type mime_type); | ||||
| 
 | ||||
|  |  | |||
|  | @ -147,10 +147,25 @@ typedef struct http_body { | |||
|   size_t len; | ||||
| } http_body; | ||||
| 
 | ||||
| /**
 | ||||
|  * Initialize a new body struct. | ||||
|  * | ||||
|  * @return pointer to the newly allocated object. | ||||
|  */ | ||||
| http_body *http_body_init(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reset a body, allowing it to be reused as if newly allocated. | ||||
|  * | ||||
|  * @param body body to reset | ||||
|  */ | ||||
| void http_body_reset(http_body *body); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free a body. Internally, this calls http_body_reset. | ||||
|  * | ||||
|  * @param body body to free | ||||
|  */ | ||||
| void http_body_free(http_body *body); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -9,25 +9,44 @@ | |||
| #include "http/types.h" | ||||
| #include "trie.h" | ||||
| 
 | ||||
| // Max amount of steps a route can use
 | ||||
| #define HTTP_LOOP_MAX_STEPS 17 | ||||
| 
 | ||||
| #define MIN(x, y) (((x) < (y)) ? (x) : (y)) | ||||
| #define MAX(x, y) (((x) > (y)) ? (x) : (y)) | ||||
| 
 | ||||
| /**
 | ||||
|  * Type of a route | ||||
|  */ | ||||
| typedef enum http_route_type { | ||||
|   http_route_literal = 0, | ||||
|   http_route_regex = 1, | ||||
| } http_route_type; | ||||
| 
 | ||||
| /**
 | ||||
|  * Function describing a step in a route's processing. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  * @return whether the processing can immediately advance to the next step. A | ||||
|  * step should return false if it's e.g. waiting for I/O, and can therefore not | ||||
|  * finish its task in the current cycle of the event loop. | ||||
|  */ | ||||
| typedef bool (*step)(event_loop_conn *conn); | ||||
| 
 | ||||
| /**
 | ||||
|  * Struct describing a route a request can take. | ||||
|  */ | ||||
| typedef struct http_route { | ||||
|   http_route_type type; | ||||
|   http_method method; | ||||
|   char *path; | ||||
|   // Compiled regex for a regex route. This value gets set at runtime when
 | ||||
|   // starting the http loop
 | ||||
|   regex_t *regex; | ||||
|   bool (*steps[HTTP_LOOP_MAX_STEPS])(event_loop_conn *); | ||||
|   step steps[HTTP_LOOP_MAX_STEPS]; | ||||
| } http_route; | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Global context passed to every connection using the same pointer | ||||
|  */ | ||||
| typedef struct http_loop_gctx { | ||||
|  | @ -37,12 +56,14 @@ typedef struct http_loop_gctx { | |||
|   const char *api_key; | ||||
| } http_loop_gctx; | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Initialize a new global context | ||||
|  * | ||||
|  * @return pointer to the newly allocated object. | ||||
|  */ | ||||
| http_loop_gctx *http_loop_gctx_init(); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Invidivual context initialized for every connection | ||||
|  */ | ||||
| typedef struct http_loop_ctx { | ||||
|  | @ -53,70 +74,116 @@ typedef struct http_loop_ctx { | |||
|   http_loop_gctx *g; | ||||
| } http_loop_ctx; | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Initialize a context struct | ||||
|  * | ||||
|  * @param g global context | ||||
|  * @return pointer to the newly allocated context | ||||
|  */ | ||||
| http_loop_ctx *http_loop_ctx_init(http_loop_gctx *g); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Resets an already allocated context so that it can be reused for a new | ||||
|  * request. | ||||
|  * | ||||
|  * @param ctx context to reset | ||||
|  */ | ||||
| void http_loop_ctx_reset(http_loop_ctx *ctx); | ||||
| 
 | ||||
| /*
 | ||||
|  * Free a context struct | ||||
| /**
 | ||||
|  * Free a context struct. Internally this first calls http_loop_ctx_reset. | ||||
|  * | ||||
|  * @param ctx context to free | ||||
|  */ | ||||
| void http_loop_ctx_free(http_loop_ctx *ctx); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Process incoming data as an HTTP request. This is the "handle_data" function | ||||
|  * for the event loop. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  * @return whether another request can be processed immediately. | ||||
|  */ | ||||
| bool http_loop_handle_request(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Write the HTTP response to the file descriptor. This is the "write_data" | ||||
|  * function for the event loop. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  */ | ||||
| void http_loop_write_response(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Try to parse the incoming data as an HTTP request. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  * @return result of the parse | ||||
|  */ | ||||
| http_parse_error http_loop_parse_request(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Try to match the parsed request with one of the defined routes, aka route the | ||||
|  * request. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  */ | ||||
| void http_loop_route_request(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * Advance the processing of the routed request's processing by cycling through | ||||
|  * the request's various steps. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  */ | ||||
| void http_loop_process_request(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
|  * Request step that consumes the request body and stores it in a buffer | ||||
| /**
 | ||||
|  * Request step that consumes the request body and stores it in a buffer. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  * @return true if the body has been fully received, false otherwise | ||||
|  */ | ||||
| bool http_loop_step_body_to_buf(event_loop_conn *conn); | ||||
| 
 | ||||
| /**
 | ||||
|  * Request step that consumes the request body and stores it in a file. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  * @return true if the body has been fully received, false otherwise | ||||
|  */ | ||||
| bool http_loop_step_body_to_file(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
|  * Authenticate the request using the X-Api-Key header | ||||
| /**
 | ||||
|  * Authenticate the request using the X-Api-Key header. | ||||
|  * | ||||
|  * @param conn connection to check | ||||
|  * @return always true | ||||
|  */ | ||||
| bool http_loop_step_auth(event_loop_conn *conn); | ||||
| 
 | ||||
| /**
 | ||||
|  * A step that simply sets the connection's state to res. | ||||
|  * | ||||
|  * @param conn connection to process | ||||
|  * @return always true | ||||
|  */ | ||||
| bool http_loop_step_switch_res(event_loop_conn *conn); | ||||
| 
 | ||||
| /**
 | ||||
|  * Initialize a new http loop | ||||
|  * Initialize a new http loop. | ||||
|  * | ||||
|  * @param gctx global context for the event loop | ||||
|  * @return pointer to the newly allocated object | ||||
|  */ | ||||
| event_loop *http_loop_init(http_loop_gctx *gctx); | ||||
| 
 | ||||
| /**
 | ||||
|  * Run the HTTP loop. This function never returns. | ||||
|  * | ||||
|  * @param el the event loop | ||||
|  * @param port on what port to listen | ||||
|  */ | ||||
| void http_loop_run(event_loop *el, int port); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -115,7 +115,7 @@ bool http_loop_step_auth(event_loop_conn *conn) { | |||
| 
 | ||||
|     if ((strncmp("X-Api-Key", header->name, header->name_len) == 0) && | ||||
|         (strncmp(header->value, ctx->g->api_key, header->value_len) == 0) && | ||||
|         strlen(ctx->g->api_key) == header->value_len) { | ||||
|         (strlen(ctx->g->api_key) == header->value_len)) { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue