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/common.h"
 | 
				
			||||||
#include "lnm/http/req.h"
 | 
					#include "lnm/http/req.h"
 | 
				
			||||||
 | 
					#include "lnm/http/res.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct lnm_loop lnm_http_loop;
 | 
					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 struct lnm_http_route lnm_http_route;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum lnm_step_err {
 | 
					typedef enum lnm_http_step_err {
 | 
				
			||||||
  lnm_step_err_done = 0,
 | 
					  lnm_http_step_err_done = 0,
 | 
				
			||||||
  lnm_step_err_io_needed,
 | 
					  lnm_http_step_err_io_needed,
 | 
				
			||||||
  lnm_step_err_close,
 | 
					  lnm_http_step_err_close,
 | 
				
			||||||
  lnm_step_err_res,
 | 
					  lnm_http_step_err_res,
 | 
				
			||||||
} lnm_step_err;
 | 
					} 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);
 | 
					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.
 | 
					 * Represents what state an HTTP loop request is currently in.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef enum lnm_http_loop_state {
 | 
					typedef enum lnm_http_loop_state {
 | 
				
			||||||
 | 
					  // Parse the HTTP request
 | 
				
			||||||
  lnm_http_loop_state_parse_req = 0,
 | 
					  lnm_http_loop_state_parse_req = 0,
 | 
				
			||||||
 | 
					  // Route the request
 | 
				
			||||||
  lnm_http_loop_state_route,
 | 
					  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,
 | 
					  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;
 | 
					} lnm_http_loop_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct lnm_http_loop_gctx {
 | 
					typedef struct lnm_http_loop_gctx {
 | 
				
			||||||
| 
						 | 
					@ -103,7 +117,9 @@ typedef struct lnm_http_loop_gctx {
 | 
				
			||||||
typedef struct lnm_http_loop_ctx {
 | 
					typedef struct lnm_http_loop_ctx {
 | 
				
			||||||
  lnm_http_loop_state state;
 | 
					  lnm_http_loop_state state;
 | 
				
			||||||
  lnm_http_req req;
 | 
					  lnm_http_req req;
 | 
				
			||||||
 | 
					  lnm_http_res res;
 | 
				
			||||||
  lnm_http_route *route;
 | 
					  lnm_http_route *route;
 | 
				
			||||||
 | 
					  lnm_http_step *cur_step;
 | 
				
			||||||
  lnm_http_loop_gctx *g;
 | 
					  lnm_http_loop_gctx *g;
 | 
				
			||||||
  void *c;
 | 
					  void *c;
 | 
				
			||||||
} lnm_http_loop_ctx;
 | 
					} 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 <stdbool.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lnm/http/consts.h"
 | 
				
			||||||
#include "lnm/http/loop.h"
 | 
					#include "lnm/http/loop.h"
 | 
				
			||||||
#include "lnm/http/loop_internal.h"
 | 
					#include "lnm/http/loop_internal.h"
 | 
				
			||||||
#include "lnm/http/req.h"
 | 
					#include "lnm/http/req.h"
 | 
				
			||||||
#include "lnm/loop.h"
 | 
					#include "lnm/loop.h"
 | 
				
			||||||
#include "lnm/loop_internal.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) {
 | 
					void lnm_http_loop_process_parse_req(lnm_http_conn *conn) {
 | 
				
			||||||
  lnm_http_loop_ctx *ctx = conn->ctx;
 | 
					  lnm_http_loop_ctx *ctx = conn->ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +22,7 @@ void lnm_http_loop_process_parse_req(lnm_http_conn *conn) {
 | 
				
			||||||
  switch (res) {
 | 
					  switch (res) {
 | 
				
			||||||
  case lnm_http_parse_err_ok:
 | 
					  case lnm_http_parse_err_ok:
 | 
				
			||||||
    conn->r.read += ctx->req.len;
 | 
					    conn->r.read += ctx->req.len;
 | 
				
			||||||
    ctx->state = lnm_http_loop_state_steps;
 | 
					    ctx->state = lnm_http_loop_state_route;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case lnm_http_parse_err_incomplete:
 | 
					  case lnm_http_parse_err_incomplete:
 | 
				
			||||||
    // If the request is already the size of the read buffer, we close the
 | 
					    // 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;
 | 
					    conn->state = lnm_loop_state_end;
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case lnm_http_parse_err_unknown_method:
 | 
					  case lnm_http_parse_err_unknown_method:
 | 
				
			||||||
    // TODO set status code here
 | 
					    ctx->res.status = lnm_http_status_method_not_implemented;
 | 
				
			||||||
    conn->state = lnm_loop_state_end;
 | 
					    ctx->state = lnm_http_loop_state_first_res;
 | 
				
			||||||
    break;
 | 
					    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;
 | 
					    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) {
 | 
					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) = {
 | 
					void (*process_fns[])(lnm_http_conn *conn) = {
 | 
				
			||||||
    lnm_http_loop_process_parse_req,
 | 
					    lnm_http_loop_process_parse_req,
 | 
				
			||||||
    lnm_http_loop_process_route,
 | 
					    lnm_http_loop_process_route,
 | 
				
			||||||
 | 
					    lnm_http_loop_process_parse_headers,
 | 
				
			||||||
    lnm_http_loop_process_steps,
 | 
					    lnm_http_loop_process_steps,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void lnm_http_loop_process(lnm_http_conn *conn) {
 | 
					void lnm_http_loop_process(lnm_http_conn *conn) {
 | 
				
			||||||
  lnm_http_loop_ctx *ctx = conn->ctx;
 | 
					  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
 | 
					  // We stop processing if:
 | 
				
			||||||
  // progressing
 | 
					  // - 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 {
 | 
					  do {
 | 
				
			||||||
    cur_state = ctx->state;
 | 
					    http_loop_state = ctx->state;
 | 
				
			||||||
 | 
					    loop_state = conn->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    process_fns[cur_state](conn);
 | 
					    process_fns[http_loop_state](conn);
 | 
				
			||||||
  } while (conn->state == lnm_loop_state_req && cur_state != ctx->state);
 | 
					  } while ((conn->state == loop_state) && (http_loop_state != ctx->state));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue