feat: basic http routing
							parent
							
								
									8250a5b8b0
								
							
						
					
					
						commit
						7ece0eb4e5
					
				|  | @ -16,15 +16,15 @@ typedef struct http_route { | |||
|   http_route_type type; | ||||
|   char *path; | ||||
|   regex_t *regex; | ||||
|   size_t step_count; | ||||
|   void (**steps)(event_loop_conn *); | ||||
|   bool (*steps[5])(event_loop_conn *); | ||||
| } http_route; | ||||
| 
 | ||||
| /*
 | ||||
|  * Global context passed to every connection using the same pointer | ||||
|  */ | ||||
| typedef struct http_loop_gctx { | ||||
|   http_route **routes; | ||||
|   http_route *routes; | ||||
|   size_t route_count; | ||||
|   Trie *trie; | ||||
| } http_loop_gctx; | ||||
| 
 | ||||
|  | @ -58,6 +58,8 @@ void http_loop_ctx_free(http_loop_ctx *ctx); | |||
|  */ | ||||
| bool http_loop_handle_request(event_loop_conn *conn); | ||||
| 
 | ||||
| bool http_loop_route_request(event_loop_conn *conn); | ||||
| 
 | ||||
| void http_loop_process_request(event_loop_conn *conn); | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -25,24 +25,28 @@ bool http_loop_handle_request(event_loop_conn *conn) { | |||
| 
 | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   http_parse_error res = | ||||
|       http_parse_request(&ctx->req, (const char *)&conn->rbuf[conn->rbuf_read], | ||||
|                          conn->rbuf_size - conn->rbuf_read); | ||||
|   // If route is defined, we're currently processing a request
 | ||||
|   if (ctx->route == NULL) { | ||||
|     http_parse_error res = http_parse_request( | ||||
|         &ctx->req, (const char *)&conn->rbuf[conn->rbuf_read], | ||||
|         conn->rbuf_size - conn->rbuf_read); | ||||
| 
 | ||||
|   if (res == http_parse_error_ok) { | ||||
|     // Perform the request
 | ||||
|     /* http_route(conn); */ | ||||
|   } | ||||
|   // Both in the case of an invalid HTTP request or one that's larger than the
 | ||||
|   // read buffer, we cannot determine when the next, possibly valid, HTTP
 | ||||
|   // request begins in the data stream. Therefore, we close the connection,
 | ||||
|   // even if additional pipelined requests are incoming.
 | ||||
|   else if (res == http_parse_error_invalid || | ||||
|            (res == http_parse_error_incomplete && | ||||
|             conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) { | ||||
|     conn->state = event_loop_conn_state_end; | ||||
|     if (res == http_parse_error_invalid || | ||||
|         (res == http_parse_error_incomplete && | ||||
|          conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) { | ||||
|       conn->state = event_loop_conn_state_end; | ||||
| 
 | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     // If the routing fails, we exit the handler
 | ||||
|     if (!http_loop_route_request(conn)) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   http_loop_process_request(conn); | ||||
| 
 | ||||
|   // TODO in highly concurrent situations, it might actually be better to always
 | ||||
|   // return false here, as this allows cycling better through all connections
 | ||||
|   return conn->state == event_loop_conn_state_req; | ||||
|  |  | |||
|  | @ -1,13 +1,48 @@ | |||
| #include <string.h> | ||||
| 
 | ||||
| #include "event_loop.h" | ||||
| #include "http.h" | ||||
| #include "http_loop.h" | ||||
| 
 | ||||
| void http_loop_process_request(event_loop_conn *conn) {} | ||||
| void http_loop_process_request(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
| /* void http_route(event_loop_conn *conn) { */ | ||||
| /*   // TODO routing */ | ||||
|   // The end of the list of steps is marked with a NULL. When this is reached,
 | ||||
|   // we simply set the route to NULL, letting the http loop know a new request
 | ||||
|   // can be handled.
 | ||||
|   if (ctx->route->steps[ctx->current_step] == NULL) { | ||||
|     ctx->route = NULL; | ||||
|     ctx->current_step = 0; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
| /*   // Fallthrough is to return a 404 */ | ||||
| /*   http_write_standard_response(conn, http_not_found); */ | ||||
| /* } */ | ||||
|   // We execute the next step
 | ||||
|   // NOTE can/should we execute more than one step at once here?
 | ||||
|   if (ctx->route->steps[ctx->current_step](conn)) { | ||||
|     ctx->current_step++; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool http_loop_route_request(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
|   http_loop_gctx *gctx = ctx->g; | ||||
| 
 | ||||
|   http_route *route; | ||||
| 
 | ||||
|   for (size_t i = 0; i < gctx->route_count; i++) { | ||||
|     route = &gctx->routes[i]; | ||||
| 
 | ||||
|     switch (route->type) { | ||||
|     case http_route_literal: | ||||
|       if (strncmp(route->path, ctx->req.method, ctx->req.method_len)) { | ||||
|         ctx->route = route; | ||||
|         return true; | ||||
|       } | ||||
|     // TODO
 | ||||
|     case http_route_regex:; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Fallthrough is to write a 404
 | ||||
|   http_write_standard_response(conn, http_not_found); | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										13
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										13
									
								
								src/main.c
								
								
								
								
							|  | @ -4,17 +4,18 @@ | |||
| #include "http_loop.h" | ||||
| #include "log.h" | ||||
| 
 | ||||
| void http_write_404(event_loop_conn *conn) { | ||||
|   memcpy(conn->wbuf, http_404, http_404_len); | ||||
| bool http_write_404(event_loop_conn *conn) { | ||||
|   memcpy(conn->wbuf, http_405, http_405_len); | ||||
| 
 | ||||
|   conn->state = event_loop_conn_state_res; | ||||
|   conn->wbuf_size = http_404_len; | ||||
|   conn->wbuf_size = http_405_len; | ||||
|   conn->wbuf_sent = 0; | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| void (*steps[])(event_loop_conn *) = {http_write_404, NULL}; | ||||
| http_route routes[] = { | ||||
|     {.type = http_route_literal, .path = "/", .step_count = 1, .steps = steps}}; | ||||
|     {.type = http_route_literal, .path = "/", .steps = {http_write_404, NULL}}}; | ||||
| 
 | ||||
| int main() { | ||||
|   setvbuf(stdout, NULL, _IONBF, 0); | ||||
|  | @ -32,6 +33,8 @@ int main() { | |||
| 
 | ||||
|   http_loop_gctx *gctx = http_loop_gctx_init(); | ||||
|   gctx->trie = trie; | ||||
|   gctx->routes = routes; | ||||
|   gctx->route_count = sizeof(routes) / sizeof(routes[0]); | ||||
|   event_loop *el = http_loop_init(gctx); | ||||
| 
 | ||||
|   event_loop_run(el, 8000); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue