refactor: modularize the http header files
							parent
							
								
									89fb77db7f
								
							
						
					
					
						commit
						f07042e798
					
				|  | @ -0,0 +1,46 @@ | |||
| #ifndef LANDER_HTTP_REQ | ||||
| #define LANDER_HTTP_REQ | ||||
| 
 | ||||
| #include <regex.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include "http/types.h" | ||||
| #include "picohttpparser.h" | ||||
| 
 | ||||
| #define HTTP_MAX_ALLOWED_HEADERS 16 | ||||
| #define HTTP_MAX_REGEX_GROUPS 4 | ||||
| 
 | ||||
| /*
 | ||||
|  * Struct representing the specific type of request | ||||
|  */ | ||||
| typedef struct http_request { | ||||
|   size_t len; | ||||
|   int minor_version; | ||||
|   http_method method; | ||||
|   const char *path; | ||||
|   size_t path_len; | ||||
|   const char *query; | ||||
|   size_t query_len; | ||||
|   http_body_type body_type; | ||||
|   union { | ||||
|     char *buf; | ||||
|     FILE *file; | ||||
|   } body; | ||||
|   size_t body_len; | ||||
|   size_t body_received; | ||||
|   char *body_file_name; | ||||
|   regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS]; | ||||
|   struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS]; | ||||
|   size_t num_headers; | ||||
| } http_request; | ||||
| 
 | ||||
| typedef enum http_parse_error { | ||||
|   http_parse_error_ok = 0, | ||||
|   http_parse_error_incomplete = 1, | ||||
|   http_parse_error_invalid = 2, | ||||
|   http_parse_error_unknown_method = 3 | ||||
| } http_parse_error; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,56 @@ | |||
| #ifndef LANDER_HTTP_RES | ||||
| #define LANDER_HTTP_RES | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include "http/types.h" | ||||
| 
 | ||||
| typedef struct http_response_header { | ||||
|   http_header type; | ||||
|   const char *value; | ||||
|   bool owned; | ||||
| } http_response_header; | ||||
| 
 | ||||
| typedef struct http_response { | ||||
|   http_status status; | ||||
|   const char *head; | ||||
|   size_t head_len; | ||||
|   size_t head_written; | ||||
|   http_body_type body_type; | ||||
|   union { | ||||
|     char *buf; | ||||
|     FILE *file; | ||||
|   } body; | ||||
|   size_t body_len; | ||||
|   size_t body_written; | ||||
|   // If false, the body won't be freed
 | ||||
|   bool owns_body; | ||||
|   http_response_header headers[4]; | ||||
|   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. | ||||
|  */ | ||||
| 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. | ||||
|  */ | ||||
| void http_res_set_body_file(http_response *res, const char *filename); | ||||
| 
 | ||||
| /*
 | ||||
|  * Add a header to the response. | ||||
|  */ | ||||
| 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. | ||||
|  */ | ||||
| void http_res_set_mime_type(http_response *res, http_mime_type mime_type); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,76 +1,24 @@ | |||
| #ifndef HTTP | ||||
| #define HTTP | ||||
| #ifndef LANDER_HTTP_TYPES | ||||
| #define LANDER_HTTP_TYPES | ||||
| 
 | ||||
| #include <regex.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include "picohttpparser.h" | ||||
| 
 | ||||
| #define HTTP_MAX_ALLOWED_HEADERS 16 | ||||
| #define HTTP_MAX_REGEX_GROUPS 4 | ||||
| 
 | ||||
| // Array mapping the http_response_type enum to strings
 | ||||
| extern const char *http_response_type_names[][32]; | ||||
| 
 | ||||
| // Array mapping the http_header enum to strings
 | ||||
| extern const char *http_header_names[]; | ||||
| 
 | ||||
| // Array mapping the http_mime_type enum to strings
 | ||||
| extern const char *http_mime_type_names[][2]; | ||||
| #include <sys/types.h> | ||||
| 
 | ||||
| // Array mapping the http_request_method enum to strings
 | ||||
| extern const char *request_method_names[]; | ||||
| extern const size_t request_method_names_len; | ||||
| extern const char *http_method_names[]; | ||||
| extern const size_t http_method_names_len; | ||||
| 
 | ||||
| typedef enum http_request_method { | ||||
| typedef enum http_method { | ||||
|   http_get = 0, | ||||
|   http_post = 1, | ||||
|   http_put = 2, | ||||
|   http_patch = 3, | ||||
|   http_delete = 4 | ||||
| } http_request_method; | ||||
| } http_method; | ||||
| 
 | ||||
| typedef enum http_body_type { | ||||
|   http_body_buf = 0, | ||||
|   http_body_file = 1 | ||||
| } http_body_type; | ||||
| // Array mapping the http_response_type enum to strings
 | ||||
| extern const char *http_status_names[][32]; | ||||
| 
 | ||||
| /*
 | ||||
|  * Struct representing the specific type of request | ||||
|  */ | ||||
| typedef struct http_request { | ||||
|   size_t len; | ||||
|   int minor_version; | ||||
|   http_request_method method; | ||||
|   const char *path; | ||||
|   size_t path_len; | ||||
|   const char *query; | ||||
|   size_t query_len; | ||||
|   http_body_type body_type; | ||||
|   union { | ||||
|     char *buf; | ||||
|     FILE *file; | ||||
|   } body; | ||||
|   size_t body_len; | ||||
|   size_t body_received; | ||||
|   char *body_file_name; | ||||
|   regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS]; | ||||
|   struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS]; | ||||
|   size_t num_headers; | ||||
| } http_request; | ||||
| 
 | ||||
| typedef enum http_parse_error { | ||||
|   http_parse_error_ok = 0, | ||||
|   http_parse_error_incomplete = 1, | ||||
|   http_parse_error_invalid = 2, | ||||
|   http_parse_error_unknown_method = 3 | ||||
| } http_parse_error; | ||||
| 
 | ||||
| /* void http_route(event_loop_conn *conn); */ | ||||
| 
 | ||||
| typedef enum http_response_type { | ||||
| typedef enum http_status { | ||||
|   // 1xx
 | ||||
|   http_continue = 100, | ||||
|   http_switching_protocols = 101, | ||||
|  | @ -135,37 +83,10 @@ typedef enum http_response_type { | |||
|   http_loop_detected = 508, | ||||
|   http_not_extended = 510, | ||||
|   http_network_authentication_required = 511 | ||||
| } http_response_type; | ||||
| } http_status; | ||||
| 
 | ||||
| typedef enum http_header { | ||||
|   http_header_connection = 0, | ||||
|   http_header_location, | ||||
|   http_header_content_type | ||||
| } http_header; | ||||
| 
 | ||||
| typedef struct http_response_header { | ||||
|   http_header type; | ||||
|   const char *value; | ||||
|   bool owned; | ||||
| } http_response_header; | ||||
| 
 | ||||
| typedef struct http_response { | ||||
|   http_response_type status; | ||||
|   const char *head; | ||||
|   size_t head_len; | ||||
|   size_t head_written; | ||||
|   http_body_type body_type; | ||||
|   union { | ||||
|     char *buf; | ||||
|     FILE *file; | ||||
|   } body; | ||||
|   size_t body_len; | ||||
|   size_t body_written; | ||||
|   // If false, the body won't be freed
 | ||||
|   bool owns_body; | ||||
|   http_response_header headers[4]; | ||||
|   size_t header_count; | ||||
| } http_response; | ||||
| // Array mapping the http_mime_type enum to strings
 | ||||
| extern const char *http_mime_type_names[][2]; | ||||
| 
 | ||||
| typedef enum http_mime_type { | ||||
|   http_mime_aac = 0, | ||||
|  | @ -194,4 +115,18 @@ typedef enum http_mime_type { | |||
|   http_mime_7z | ||||
| } http_mime_type; | ||||
| 
 | ||||
| // Array mapping the http_header enum to strings
 | ||||
| extern const char *http_header_names[]; | ||||
| 
 | ||||
| typedef enum http_header { | ||||
|   http_header_connection = 0, | ||||
|   http_header_location, | ||||
|   http_header_content_type | ||||
| } http_header; | ||||
| 
 | ||||
| typedef enum http_body_type { | ||||
|   http_body_buf = 0, | ||||
|   http_body_file = 1 | ||||
| } http_body_type; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -4,7 +4,9 @@ | |||
| #include <regex.h> | ||||
| 
 | ||||
| #include "event_loop.h" | ||||
| #include "http.h" | ||||
| #include "http/req.h" | ||||
| #include "http/res.h" | ||||
| #include "http/types.h" | ||||
| #include "trie.h" | ||||
| 
 | ||||
| #define MIN(x, y) (((x) < (y)) ? (x) : (y)) | ||||
|  | @ -17,7 +19,7 @@ typedef enum http_route_type { | |||
| 
 | ||||
| typedef struct http_route { | ||||
|   http_route_type type; | ||||
|   http_request_method method; | ||||
|   http_method method; | ||||
|   char *path; | ||||
|   regex_t *regex; | ||||
|   bool (*steps[5])(event_loop_conn *); | ||||
|  | @ -94,20 +96,6 @@ void http_loop_route_request(event_loop_conn *conn); | |||
|  */ | ||||
| void http_loop_process_request(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
|  * 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. | ||||
|  */ | ||||
| void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body, | ||||
|                                 size_t body_len, bool owned); | ||||
| 
 | ||||
| void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename); | ||||
| 
 | ||||
| void http_loop_res_add_header(http_loop_ctx *ctx, http_header type, | ||||
|                               const char *value, bool owned); | ||||
| 
 | ||||
| void http_loop_res_set_mime_type(http_loop_ctx *ctx, http_mime_type mime_type); | ||||
| 
 | ||||
| /*
 | ||||
|  * Request step that consumes the request body and stores it in a buffer | ||||
|  */ | ||||
|  |  | |||
|  | @ -1,13 +1,15 @@ | |||
| #include "http.h" | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include "http/types.h" | ||||
| 
 | ||||
| // Very important that this is in the same order as http_request_method
 | ||||
| const char *request_method_names[] = {"GET", "POST", "PUT", "PATCH", "DELETE"}; | ||||
| const size_t request_method_names_len = | ||||
|     sizeof(request_method_names) / sizeof(request_method_names[0]); | ||||
| const char *http_method_names[] = {"GET", "POST", "PUT", "PATCH", "DELETE"}; | ||||
| const size_t http_method_names_len = | ||||
|     sizeof(http_method_names) / sizeof(http_method_names[0]); | ||||
| 
 | ||||
| // clang-format off
 | ||||
| 
 | ||||
| const char *http_response_type_names[][32] = { | ||||
| const char *http_status_names[][32] = { | ||||
|   // 1xx
 | ||||
|   { | ||||
|     "Continue", // 100
 | ||||
|  |  | |||
|  | @ -0,0 +1,37 @@ | |||
| #include <sys/stat.h> | ||||
| 
 | ||||
| #include "http/res.h" | ||||
| 
 | ||||
| void http_res_set_body_buf(http_response *res, const char *body, | ||||
|                            size_t body_len, bool owned) { | ||||
|   res->body_type = http_body_buf; | ||||
|   res->body.buf = (char *)body; | ||||
|   res->body_len = body_len; | ||||
|   res->owns_body = owned; | ||||
| } | ||||
| 
 | ||||
| void http_res_set_body_file(http_response *res, const char *filename) { | ||||
|   struct stat st; | ||||
|   stat(filename, &st); | ||||
| 
 | ||||
|   // TODO error handling
 | ||||
|   FILE *f = fopen(filename, "r"); | ||||
| 
 | ||||
|   res->body_type = http_body_file; | ||||
|   res->body.file = f; | ||||
|   res->body_len = st.st_size; | ||||
| } | ||||
| 
 | ||||
| void http_res_add_header(http_response *res, http_header type, | ||||
|                          const char *value, bool owned) { | ||||
|   res->headers[res->header_count].type = type; | ||||
|   res->headers[res->header_count].value = value; | ||||
|   res->headers[res->header_count].owned = owned; | ||||
| 
 | ||||
|   res->header_count++; | ||||
| } | ||||
| 
 | ||||
| void http_res_set_mime_type(http_response *res, http_mime_type mime_type) { | ||||
|   http_res_add_header(res, http_header_content_type, | ||||
|                       http_mime_type_names[mime_type][1], false); | ||||
| } | ||||
|  | @ -1,6 +1,6 @@ | |||
| #include <regex.h> | ||||
| 
 | ||||
| #include "http.h" | ||||
| #include "http/types.h" | ||||
| #include "http_loop.h" | ||||
| #include "log.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| #include "http.h" | ||||
| #include "http/types.h" | ||||
| #include "http_loop.h" | ||||
| 
 | ||||
| http_loop_gctx *http_loop_gctx_init() { | ||||
|  |  | |||
|  | @ -34,8 +34,8 @@ http_parse_error http_loop_parse_request(event_loop_conn *conn) { | |||
|   bool match = false; | ||||
|   size_t i = 0; | ||||
| 
 | ||||
|   for (i = 0; i < request_method_names_len; i++) { | ||||
|     if (strncmp(method, request_method_names[i], method_len) == 0) { | ||||
|   for (i = 0; i < http_method_names_len; i++) { | ||||
|     if (strncmp(method, http_method_names[i], method_len) == 0) { | ||||
|       req->method = i; | ||||
|       match = true; | ||||
|     } | ||||
|  | @ -88,7 +88,7 @@ void http_loop_route_request(event_loop_conn *conn) { | |||
|   http_loop_ctx *ctx = conn->ctx; | ||||
|   http_loop_gctx *gctx = ctx->g; | ||||
| 
 | ||||
|   info("%s %.*s", request_method_names[ctx->req.method], ctx->req.path_len, | ||||
|   info("%s %.*s", http_method_names[ctx->req.method], ctx->req.path_len, | ||||
|        ctx->req.path); | ||||
| 
 | ||||
|   http_route *route; | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ void http_loop_init_header(http_response *res) { | |||
|   } | ||||
| 
 | ||||
|   const char *response_type_name = | ||||
|       http_response_type_names[res->status / 100 - 1][res->status % 100]; | ||||
|       http_status_names[res->status / 100 - 1][res->status % 100]; | ||||
| 
 | ||||
|   // First we calculate the size of the start of the header
 | ||||
|   int buf_size = snprintf(NULL, 0, http_response_format, res->status, | ||||
|  |  | |||
|  | @ -1,37 +0,0 @@ | |||
| #include <sys/stat.h> | ||||
| 
 | ||||
| #include "http_loop.h" | ||||
| 
 | ||||
| void http_loop_res_set_body_buf(http_loop_ctx *ctx, const char *body, | ||||
|                                 size_t body_len, bool owned) { | ||||
|   ctx->res.body_type = http_body_buf; | ||||
|   ctx->res.body.buf = (char *)body; | ||||
|   ctx->res.body_len = body_len; | ||||
|   ctx->res.owns_body = owned; | ||||
| } | ||||
| 
 | ||||
| void http_loop_res_set_body_file(http_loop_ctx *ctx, const char *filename) { | ||||
|   struct stat st; | ||||
|   stat(filename, &st); | ||||
| 
 | ||||
|   // TODO error handling
 | ||||
|   FILE *f = fopen(filename, "r"); | ||||
| 
 | ||||
|   ctx->res.body_type = http_body_file; | ||||
|   ctx->res.body.file = f; | ||||
|   ctx->res.body_len = st.st_size; | ||||
| } | ||||
| 
 | ||||
| void http_loop_res_add_header(http_loop_ctx *ctx, http_header type, | ||||
|                               const char *value, bool owned) { | ||||
|   ctx->res.headers[ctx->res.header_count].type = type; | ||||
|   ctx->res.headers[ctx->res.header_count].value = value; | ||||
|   ctx->res.headers[ctx->res.header_count].owned = owned; | ||||
| 
 | ||||
|   ctx->res.header_count++; | ||||
| } | ||||
| 
 | ||||
| void http_loop_res_set_mime_type(http_loop_ctx *ctx, http_mime_type mime_type) { | ||||
|   http_loop_res_add_header(ctx, http_header_content_type, | ||||
|                            http_mime_type_names[mime_type][1], false); | ||||
| } | ||||
|  | @ -15,8 +15,8 @@ static const char index_page[] = | |||
| bool lander_get_index(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   http_loop_res_set_body_buf(ctx, index_page, sizeof(index_page) - 1, false); | ||||
|   http_loop_res_set_mime_type(ctx, http_mime_html); | ||||
|   http_res_set_body_buf(&ctx->res, index_page, sizeof(index_page) - 1, false); | ||||
|   http_res_set_mime_type(&ctx->res, http_mime_html); | ||||
| 
 | ||||
|   conn->state = event_loop_conn_state_res; | ||||
|   return true; | ||||
|  | @ -35,12 +35,12 @@ bool lander_get_entry(event_loop_conn *conn) { | |||
|     ctx->res.status = http_not_found; | ||||
|   } else if (entry->type == Redirect) { | ||||
|     ctx->res.status = http_moved_permanently; | ||||
|     http_loop_res_add_header(ctx, http_header_location, entry->string, false); | ||||
|     http_res_add_header(&ctx->res, http_header_location, entry->string, false); | ||||
|   } else if (entry->type == Paste) { | ||||
|     char fname[8 + key_len]; | ||||
|     sprintf(fname, "pastes/%.*s", key_len, key); | ||||
| 
 | ||||
|     http_loop_res_set_body_file(ctx, fname); | ||||
|     http_res_set_body_file(&ctx->res, fname); | ||||
|   } | ||||
| 
 | ||||
|   conn->state = event_loop_conn_state_res; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| #include "http/res.h" | ||||
| #include "lander.h" | ||||
| #include "log.h" | ||||
| 
 | ||||
|  | @ -32,7 +33,7 @@ bool lander_post_redirect(event_loop_conn *conn) { | |||
| 
 | ||||
|   free(key); | ||||
| 
 | ||||
|   http_loop_res_add_header(ctx, http_header_location, buf, true); | ||||
|   http_res_add_header(&ctx->res, http_header_location, buf, true); | ||||
| 
 | ||||
|   conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|  | @ -63,7 +64,7 @@ bool lander_post_paste(event_loop_conn *conn) { | |||
|   buf[0] = '/'; | ||||
|   buf[key_len + 1] = '\0'; | ||||
| 
 | ||||
|   http_loop_res_add_header(ctx, http_header_location, buf, true); | ||||
|   http_res_add_header(&ctx->res, http_header_location, buf, true); | ||||
| 
 | ||||
|   // TODO free this
 | ||||
|   char *fname = malloc(8 + key_len); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue