feat(lnm): add request parser
	
		
			
	
		
	
	
		
			
				
	
				ci/woodpecker/push/build Pipeline was successful
				
					Details
				
			
		
	
				
					
				
			
				
	
				ci/woodpecker/push/build Pipeline was successful
				
					Details
				
			
		
	
							parent
							
								
									e59ee38ae2
								
							
						
					
					
						commit
						4c2b85d436
					
				| 
						 | 
					@ -12,7 +12,7 @@ typedef enum lnm_http_method {
 | 
				
			||||||
  http_method_put,
 | 
					  http_method_put,
 | 
				
			||||||
  http_method_patch,
 | 
					  http_method_patch,
 | 
				
			||||||
  http_method_delete
 | 
					  http_method_delete
 | 
				
			||||||
} http_method;
 | 
					} lnm_http_method;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const char *lnm_http_status_names[][32];
 | 
					extern const char *lnm_http_status_names[][32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,9 +3,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lnm/common.h"
 | 
					#include "lnm/common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LNM_HTTP_MAX_REQ_HEADERS 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct lnm_loop lnm_http_loop;
 | 
					typedef struct lnm_loop lnm_http_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct lnm_http_conn lnm_http_conn;
 | 
					typedef struct lnm_conn lnm_http_conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct lnm_http_step lnm_http_step;
 | 
					typedef struct lnm_http_step lnm_http_step;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,14 +22,6 @@ typedef lnm_err (*lnm_http_step_fn)(lnm_http_conn *conn);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
lnm_err lnm_http_loop_init(lnm_http_loop **out);
 | 
					lnm_err lnm_http_loop_init(lnm_http_loop **out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Initialize a first step
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param out where to store pointer to new `lnm_http_step`
 | 
					 | 
				
			||||||
 * @param fn step function associated with the step
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
lnm_err lnm_http_step_init(lnm_http_step **out, lnm_http_step_fn fn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Append the given step fn to the step.
 | 
					 * Append the given step fn to the step.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -67,4 +61,15 @@ lnm_err lnm_http_route_init_regex(lnm_http_route **out, const char *pattern,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void lnm_http_loop_route_add(lnm_http_loop *hl, lnm_http_route *route);
 | 
					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 {
 | 
				
			||||||
 | 
					  lnm_http_loop_state_parse_req = 0,
 | 
				
			||||||
 | 
					} lnm_http_loop_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct lnm_http_loop_ctx {
 | 
				
			||||||
 | 
					  lnm_http_loop_state state;
 | 
				
			||||||
 | 
					} lnm_http_loop_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					#ifndef LNM_HTTP_REQ
 | 
				
			||||||
 | 
					#define LNM_HTTP_REQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "picohttpparser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lnm/http/consts.h"
 | 
				
			||||||
 | 
					#include "lnm/http/loop.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Represents the parsed HTTP request
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct lnm_http_req {
 | 
				
			||||||
 | 
					  size_t len;
 | 
				
			||||||
 | 
					  int minor_version;
 | 
				
			||||||
 | 
					  lnm_http_method method;
 | 
				
			||||||
 | 
					  struct {
 | 
				
			||||||
 | 
					    const char *s;
 | 
				
			||||||
 | 
					    size_t len;
 | 
				
			||||||
 | 
					  } path;
 | 
				
			||||||
 | 
					  struct {
 | 
				
			||||||
 | 
					    const char *s;
 | 
				
			||||||
 | 
					    size_t len;
 | 
				
			||||||
 | 
					  } query;
 | 
				
			||||||
 | 
					  struct {
 | 
				
			||||||
 | 
					    struct phr_header arr[LNM_HTTP_MAX_REQ_HEADERS];
 | 
				
			||||||
 | 
					    size_t len;
 | 
				
			||||||
 | 
					  } headers;
 | 
				
			||||||
 | 
					} lnm_http_req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum lnm_http_parse_err {
 | 
				
			||||||
 | 
					  lnm_http_parse_err_ok = 0,
 | 
				
			||||||
 | 
					  lnm_http_parse_err_incomplete,
 | 
				
			||||||
 | 
					  lnm_http_parse_err_invalid,
 | 
				
			||||||
 | 
					  lnm_http_parse_err_unknown_method,
 | 
				
			||||||
 | 
					} lnm_http_parse_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Try to parse the given buffer into an HTTP request.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param req request to store parsed data in
 | 
				
			||||||
 | 
					 * @param buf buffer to parse; might be modified
 | 
				
			||||||
 | 
					 * @param len length of buf
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					lnm_http_parse_err lnm_http_req_parse(lnm_http_req *req, char *buf, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -5,10 +5,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lnm/http/loop.h"
 | 
					#include "lnm/http/loop.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct lnm_http_conn {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} lnm_http_conn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct lnm_http_step {
 | 
					typedef struct lnm_http_step {
 | 
				
			||||||
  lnm_http_step_fn fn;
 | 
					  lnm_http_step_fn fn;
 | 
				
			||||||
  struct lnm_http_step *next;
 | 
					  struct lnm_http_step *next;
 | 
				
			||||||
| 
						 | 
					@ -29,6 +25,19 @@ typedef struct lnm_http_route {
 | 
				
			||||||
  lnm_http_step *step;
 | 
					  lnm_http_step *step;
 | 
				
			||||||
} lnm_http_route;
 | 
					} lnm_http_route;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a new empty route.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param out where to store pointer to new `lnm_http_route`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
lnm_err lnm_http_route_init(lnm_http_route **out);
 | 
					lnm_err lnm_http_route_init(lnm_http_route **out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a first step.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param out where to store pointer to new `lnm_http_step`
 | 
				
			||||||
 | 
					 * @param fn step function associated with the step
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					lnm_err lnm_http_step_init(lnm_http_step **out, lnm_http_step_fn fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,58 @@
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lnm/http/consts.h"
 | 
				
			||||||
 | 
					#include "lnm/http/loop.h"
 | 
				
			||||||
 | 
					#include "lnm/http/req.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lnm_http_parse_err lnm_http_req_parse(lnm_http_req *req, char *buf,
 | 
				
			||||||
 | 
					                                      size_t len) {
 | 
				
			||||||
 | 
					  const char *method;
 | 
				
			||||||
 | 
					  char *path;
 | 
				
			||||||
 | 
					  size_t method_len, path_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  req->headers.len = LNM_HTTP_MAX_REQ_HEADERS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int req_len = phr_parse_request(
 | 
				
			||||||
 | 
					      buf, len, &method, &method_len, (const char **)&path, &path_len,
 | 
				
			||||||
 | 
					      &req->minor_version, req->headers.arr, &req->headers.len, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (req_len == -1) {
 | 
				
			||||||
 | 
					    return lnm_http_parse_err_invalid;
 | 
				
			||||||
 | 
					  } else if (req_len == -2) {
 | 
				
			||||||
 | 
					    return lnm_http_parse_err_incomplete;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool known_method = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < lnm_http_method_names_len && !known_method; i++) {
 | 
				
			||||||
 | 
					    if (strncmp(method, lnm_http_method_names[i], method_len) == 0) {
 | 
				
			||||||
 | 
					      req->method = i;
 | 
				
			||||||
 | 
					      known_method = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!known_method) {
 | 
				
			||||||
 | 
					    return lnm_http_parse_err_unknown_method;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  char *question_mark = strchr(path, '?');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Only store query if the path doesn't simply end with a question mark
 | 
				
			||||||
 | 
					  if ((question_mark != NULL) && (path_len - (question_mark + 1 - path) > 0)) {
 | 
				
			||||||
 | 
					    req->query.s = question_mark + 1;
 | 
				
			||||||
 | 
					    req->query.len = path_len - (question_mark + 1 - path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    path_len = question_mark - path;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // All parsed strings should be null-terminated. This character is either a
 | 
				
			||||||
 | 
					  // newline (if at the end of the path), or a question mark (if a query is
 | 
				
			||||||
 | 
					  // present).
 | 
				
			||||||
 | 
					  path[path_len] = '\0';
 | 
				
			||||||
 | 
					  req->path.len = path_len;
 | 
				
			||||||
 | 
					  req->path.s = path;
 | 
				
			||||||
 | 
					  req->len = req_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return lnm_http_parse_err_ok;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue