feat(lnm): more request processing code
	
		
			
	
		
	
	
		
			
				
	
				ci/woodpecker/push/build Pipeline was successful
				
					Details
				
			
		
	
				
					
				
			
				
	
				ci/woodpecker/push/build Pipeline was successful
				
					Details
				
			
		
	
							parent
							
								
									8c21ccf58b
								
							
						
					
					
						commit
						77b62825a6
					
				|  | @ -5,6 +5,7 @@ | |||
| 
 | ||||
| #include "lnm/common.h" | ||||
| #include "lnm/http/req.h" | ||||
| #include "lnm/http/res.h" | ||||
| 
 | ||||
| typedef struct lnm_loop lnm_http_loop; | ||||
| 
 | ||||
|  | @ -14,14 +15,14 @@ typedef struct lnm_http_step lnm_http_step; | |||
| 
 | ||||
| typedef struct lnm_http_route lnm_http_route; | ||||
| 
 | ||||
| typedef enum lnm_step_err { | ||||
|   lnm_step_err_done = 0, | ||||
|   lnm_step_err_io_needed, | ||||
|   lnm_step_err_close, | ||||
|   lnm_step_err_res, | ||||
| } lnm_step_err; | ||||
| typedef enum lnm_http_step_err { | ||||
|   lnm_http_step_err_done = 0, | ||||
|   lnm_http_step_err_io_needed, | ||||
|   lnm_http_step_err_close, | ||||
|   lnm_http_step_err_res, | ||||
| } lnm_http_step_err; | ||||
| 
 | ||||
| typedef lnm_step_err (*lnm_http_step_fn)(lnm_http_conn *conn); | ||||
| typedef lnm_http_step_err (*lnm_http_step_fn)(lnm_http_conn *conn); | ||||
| 
 | ||||
| typedef lnm_err (*lnm_http_ctx_init_fn)(void **c_ctx, void *gctx); | ||||
| 
 | ||||
|  | @ -84,9 +85,22 @@ void lnm_http_loop_route_add(lnm_http_loop *hl, lnm_http_route *route); | |||
|  * Represents what state an HTTP loop request is currently in. | ||||
|  */ | ||||
| typedef enum lnm_http_loop_state { | ||||
|   // Parse the HTTP request
 | ||||
|   lnm_http_loop_state_parse_req = 0, | ||||
|   // Route the request
 | ||||
|   lnm_http_loop_state_route, | ||||
|   // Parse specific headers (e.g. Content-Length)
 | ||||
|   lnm_http_loop_state_parse_headers, | ||||
|   // Execute the various steps defined for the route
 | ||||
|   lnm_http_loop_state_steps, | ||||
|   // Write the response status line
 | ||||
|   lnm_http_loop_state_write_status_line, | ||||
|   // Write the various response headers
 | ||||
|   lnm_http_loop_state_write_headers, | ||||
|   // Write the request body
 | ||||
|   lnm_http_loop_state_write_body, | ||||
|   // Clean up the request and reset the state for a next request
 | ||||
|   lnm_http_loop_state_finish, | ||||
| } lnm_http_loop_state; | ||||
| 
 | ||||
| typedef struct lnm_http_loop_gctx { | ||||
|  | @ -103,7 +117,9 @@ typedef struct lnm_http_loop_gctx { | |||
| typedef struct lnm_http_loop_ctx { | ||||
|   lnm_http_loop_state state; | ||||
|   lnm_http_req req; | ||||
|   lnm_http_res res; | ||||
|   lnm_http_route *route; | ||||
|   lnm_http_step *cur_step; | ||||
|   lnm_http_loop_gctx *g; | ||||
|   void *c; | ||||
| } lnm_http_loop_ctx; | ||||
|  |  | |||
|  | @ -0,0 +1,30 @@ | |||
| #ifndef LNM_HTTP_RES | ||||
| #define LNM_HTTP_RES | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #include "lnm/http/consts.h" | ||||
| 
 | ||||
| typedef struct lnm_http_res_header { | ||||
|   struct { | ||||
|     char *s; | ||||
|     size_t len; | ||||
|     bool owned; | ||||
|   } name; | ||||
|   struct { | ||||
|     char *s; | ||||
|     size_t len; | ||||
|     bool owned; | ||||
|   } value; | ||||
|   struct lnm_http_res_header *next; | ||||
| } lnm_http_res_header; | ||||
| 
 | ||||
| typedef struct lnm_http_res { | ||||
|   lnm_http_status status; | ||||
|   struct { | ||||
|     lnm_http_res_header *head; | ||||
|     lnm_http_res_header *current; | ||||
|   } headers; | ||||
| } lnm_http_res; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,12 +1,18 @@ | |||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "lnm/http/consts.h" | ||||
| #include "lnm/http/loop.h" | ||||
| #include "lnm/http/loop_internal.h" | ||||
| #include "lnm/http/req.h" | ||||
| #include "lnm/loop.h" | ||||
| #include "lnm/loop_internal.h" | ||||
| 
 | ||||
| /* static const lnm_http_loop_state lnm_http_loop_state_first_req =
 | ||||
|  * lnm_http_loop_state_parse_req; */ | ||||
| static const lnm_http_loop_state lnm_http_loop_state_first_res = | ||||
|     lnm_http_loop_state_write_headers; | ||||
| 
 | ||||
| void lnm_http_loop_process_parse_req(lnm_http_conn *conn) { | ||||
|   lnm_http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|  | @ -16,7 +22,7 @@ void lnm_http_loop_process_parse_req(lnm_http_conn *conn) { | |||
|   switch (res) { | ||||
|   case lnm_http_parse_err_ok: | ||||
|     conn->r.read += ctx->req.len; | ||||
|     ctx->state = lnm_http_loop_state_steps; | ||||
|     ctx->state = lnm_http_loop_state_route; | ||||
|     break; | ||||
|   case lnm_http_parse_err_incomplete: | ||||
|     // If the request is already the size of the read buffer, we close the
 | ||||
|  | @ -29,8 +35,8 @@ void lnm_http_loop_process_parse_req(lnm_http_conn *conn) { | |||
|     conn->state = lnm_loop_state_end; | ||||
|     break; | ||||
|   case lnm_http_parse_err_unknown_method: | ||||
|     // TODO set status code here
 | ||||
|     conn->state = lnm_loop_state_end; | ||||
|     ctx->res.status = lnm_http_status_method_not_implemented; | ||||
|     ctx->state = lnm_http_loop_state_first_res; | ||||
|     break; | ||||
|   } | ||||
| } | ||||
|  | @ -65,31 +71,80 @@ void lnm_http_loop_process_route(lnm_http_conn *conn) { | |||
|     match_level = match_level < new_match_level ? new_match_level : match_level; | ||||
|   } | ||||
| 
 | ||||
|   ctx->route = match_level == 2 ? route : NULL; | ||||
|   switch (match_level) { | ||||
|   case 0: | ||||
|     ctx->res.status = lnm_http_status_not_found; | ||||
|     ctx->state = lnm_http_loop_state_first_res; | ||||
|     break; | ||||
|   case 1: | ||||
|     ctx->res.status = lnm_http_status_method_not_allowed; | ||||
|     ctx->state = lnm_http_loop_state_first_res; | ||||
|     break; | ||||
|   case 2: | ||||
|     ctx->route = route; | ||||
|     ctx->cur_step = route->step; | ||||
|     ctx->state = lnm_http_loop_state_parse_headers; | ||||
|     break; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void lnm_http_loop_process_parse_headers(lnm_http_conn *conn) { | ||||
|   lnm_http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   // TODO
 | ||||
| 
 | ||||
|   ctx->state = lnm_http_loop_state_steps; | ||||
| } | ||||
| 
 | ||||
| void lnm_http_loop_process_steps(lnm_http_conn *conn) { | ||||
|   /* lnm_http_loop_ctx *ctx = conn->ctx; */ | ||||
|   lnm_http_loop_ctx *ctx = conn->ctx; | ||||
|   lnm_http_step *step; | ||||
| 
 | ||||
|   /* while () */ | ||||
|   do { | ||||
|     step = ctx->cur_step; | ||||
| 
 | ||||
|     switch (step->fn(conn)) { | ||||
|     case lnm_http_step_err_done: | ||||
|       ctx->cur_step = ctx->cur_step->next; | ||||
|       break; | ||||
|     case lnm_http_step_err_io_needed: | ||||
|       break; | ||||
|     case lnm_http_step_err_close: | ||||
|       conn->state = lnm_loop_state_end; | ||||
|       break; | ||||
|     case lnm_http_step_err_res: | ||||
|       ctx->state = lnm_http_loop_state_first_res; | ||||
|       break; | ||||
|     } | ||||
|   } while ((step != ctx->cur_step) && (ctx->cur_step != NULL)); | ||||
| 
 | ||||
|   if (ctx->cur_step == NULL) { | ||||
|     ctx->state = lnm_http_loop_state_write_headers; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void (*process_fns[])(lnm_http_conn *conn) = { | ||||
|     lnm_http_loop_process_parse_req, | ||||
|     lnm_http_loop_process_route, | ||||
|     lnm_http_loop_process_parse_headers, | ||||
|     lnm_http_loop_process_steps, | ||||
| }; | ||||
| 
 | ||||
| void lnm_http_loop_process(lnm_http_conn *conn) { | ||||
|   lnm_http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   lnm_http_loop_state cur_state; | ||||
|   lnm_http_loop_state http_loop_state; | ||||
|   lnm_loop_state loop_state; | ||||
| 
 | ||||
|   // As long as the processing is able to advance to a next state, we keep
 | ||||
|   // progressing
 | ||||
|   // We stop processing if:
 | ||||
|   // - the event loop state has changed, as we need to switch to the other I/O
 | ||||
|   // loop
 | ||||
|   // - the process fn returned without changing the HTTP loop state, indicating
 | ||||
|   // it's waiting for I/O
 | ||||
|   do { | ||||
|     cur_state = ctx->state; | ||||
|     http_loop_state = ctx->state; | ||||
|     loop_state = conn->state; | ||||
| 
 | ||||
|     process_fns[cur_state](conn); | ||||
|   } while (conn->state == lnm_loop_state_req && cur_state != ctx->state); | ||||
|     process_fns[http_loop_state](conn); | ||||
|   } while ((conn->state == loop_state) && (http_loop_state != ctx->state)); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue