refactor: move steps to own file
							parent
							
								
									87312f2d84
								
							
						
					
					
						commit
						0d5c6d0f39
					
				|  | @ -1,3 +1,6 @@ | |||
| CMakeFiles/ | ||||
| build/ | ||||
| .git/ | ||||
| * | ||||
| 
 | ||||
| !src/ | ||||
| !Makefile | ||||
| !thirdparty/ | ||||
| !include/ | ||||
|  |  | |||
|  | @ -0,0 +1,132 @@ | |||
| #include <math.h> | ||||
| 
 | ||||
| #include "lander.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * Converts a string to a number, returning true if the string contained a valid | ||||
|  * positive number. | ||||
|  */ | ||||
| static bool string_to_num(size_t *res, const char *s, size_t len) { | ||||
|   *res = 0; | ||||
| 
 | ||||
|   for (size_t i = 0; i < len; i++) { | ||||
|     int val = s[i] - '0'; | ||||
| 
 | ||||
|     if (val < 0 || val > 9) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     *res += val * (int)pow(10, (len - 1) - i); | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Try to find and parse the Content-Length header. This function returns true | ||||
|  * if it was successful. If false is returned, the underlying step should | ||||
|  * immediately exit. | ||||
|  */ | ||||
| static bool try_parse_content_length(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   for (size_t i = 0; i < ctx->req.num_headers; i++) { | ||||
|     struct phr_header *header = &ctx->req.headers[i]; | ||||
| 
 | ||||
|     if (strncmp(header->name, "Content-Length", header->name_len) == 0) { | ||||
|       // If the content length header is present but contains an invalid
 | ||||
|       // number, we return a bad request error
 | ||||
|       if (!string_to_num(&ctx->req.body_len, header->value, | ||||
|                          header->value_len)) { | ||||
|         ctx->res.status = http_bad_request; | ||||
|         conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|         return false; | ||||
|       } | ||||
|       // The content length was actually 0, so we can instantly return here
 | ||||
|       else if (ctx->req.body_len == 0) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // A zero here means there's no content length header
 | ||||
|   if (ctx->req.body_len == 0) { | ||||
|     ctx->res.status = http_length_required; | ||||
|     conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_body_to_buf(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   if (ctx->req.body_len == 0) { | ||||
|     if (!try_parse_content_length(conn)) { | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     ctx->req.body_type = http_body_buf; | ||||
|     ctx->req.body.buf = malloc(ctx->req.body_len * sizeof(uint8_t)); | ||||
|     ctx->req.body_received = 0; | ||||
|   } | ||||
| 
 | ||||
|   size_t bytes_to_copy = MIN(conn->rbuf_size - conn->rbuf_read, | ||||
|                              ctx->req.body_len - ctx->req.body_received); | ||||
|   memcpy(&ctx->req.body.buf[ctx->req.body_received], | ||||
|          &conn->rbuf[conn->rbuf_read], bytes_to_copy); | ||||
|   ctx->req.body_received += bytes_to_copy; | ||||
|   conn->rbuf_read += bytes_to_copy; | ||||
| 
 | ||||
|   return ctx->req.body_received == ctx->req.body_len; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_body_to_file(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   if (ctx->req.body_len == 0) { | ||||
|     if (!try_parse_content_length(conn)) { | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     ctx->req.body_type = http_body_file; | ||||
|     ctx->req.body.file = fopen(ctx->req.body_file_name, "wb"); | ||||
|     ctx->req.body_received = 0; | ||||
|   } | ||||
| 
 | ||||
|   size_t bytes_to_write = MIN(conn->rbuf_size - conn->rbuf_read, | ||||
|                               ctx->req.body_len - ctx->req.body_received); | ||||
|   size_t bytes_written = fwrite(&conn->rbuf[conn->rbuf_read], sizeof(uint8_t), | ||||
|                                 bytes_to_write, ctx->req.body.file); | ||||
|   ctx->req.body_received += bytes_written; | ||||
|   conn->rbuf_read += bytes_written; | ||||
| 
 | ||||
|   return ctx->req.body_received == ctx->req.body_len; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_auth(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   for (size_t i = 0; i < ctx->req.num_headers; i++) { | ||||
|     struct phr_header *header = &ctx->req.headers[i]; | ||||
| 
 | ||||
|     if ((strncmp("X-Api-Key", header->name, header->name_len) == 0) && | ||||
|         (strncmp(header->value, ctx->g->api_key, header->value_len) == 0)) { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ctx->res.status = http_unauthorized; | ||||
|   conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_switch_res(event_loop_conn *conn) { | ||||
|   conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
|  | @ -1,5 +1,3 @@ | |||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/stat.h> | ||||
| 
 | ||||
| #include "http_loop.h" | ||||
|  | @ -32,132 +30,3 @@ void http_loop_res_add_header(http_loop_ctx *ctx, http_header type, | |||
| 
 | ||||
|   ctx->res.header_count++; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Converts a string to a number, returning true if the string contained a valid | ||||
|  * positive number. | ||||
|  */ | ||||
| static bool string_to_num(size_t *res, const char *s, size_t len) { | ||||
|   *res = 0; | ||||
| 
 | ||||
|   for (size_t i = 0; i < len; i++) { | ||||
|     int val = s[i] - '0'; | ||||
| 
 | ||||
|     if (val < 0 || val > 9) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     *res += val * (int)pow(10, (len - 1) - i); | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Try to find and parse the Content-Length header. This function returns true | ||||
|  * if it was successful. If false is returned, the underlying step should | ||||
|  * immediately exit. | ||||
|  */ | ||||
| static bool try_parse_content_length(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   for (size_t i = 0; i < ctx->req.num_headers; i++) { | ||||
|     struct phr_header *header = &ctx->req.headers[i]; | ||||
| 
 | ||||
|     if (strncmp(header->name, "Content-Length", header->name_len) == 0) { | ||||
|       // If the content length header is present but contains an invalid
 | ||||
|       // number, we return a bad request error
 | ||||
|       if (!string_to_num(&ctx->req.body_len, header->value, | ||||
|                          header->value_len)) { | ||||
|         ctx->res.status = http_bad_request; | ||||
|         conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|         return false; | ||||
|       } | ||||
|       // The content length was actually 0, so we can instantly return here
 | ||||
|       else if (ctx->req.body_len == 0) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // A zero here means there's no content length header
 | ||||
|   if (ctx->req.body_len == 0) { | ||||
|     ctx->res.status = http_length_required; | ||||
|     conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_body_to_buf(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   if (ctx->req.body_len == 0) { | ||||
|     if (!try_parse_content_length(conn)) { | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     ctx->req.body_type = http_body_buf; | ||||
|     ctx->req.body.buf = malloc(ctx->req.body_len * sizeof(uint8_t)); | ||||
|     ctx->req.body_received = 0; | ||||
|   } | ||||
| 
 | ||||
|   size_t bytes_to_copy = MIN(conn->rbuf_size - conn->rbuf_read, | ||||
|                              ctx->req.body_len - ctx->req.body_received); | ||||
|   memcpy(&ctx->req.body.buf[ctx->req.body_received], | ||||
|          &conn->rbuf[conn->rbuf_read], bytes_to_copy); | ||||
|   ctx->req.body_received += bytes_to_copy; | ||||
|   conn->rbuf_read += bytes_to_copy; | ||||
| 
 | ||||
|   return ctx->req.body_received == ctx->req.body_len; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_body_to_file(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   if (ctx->req.body_len == 0) { | ||||
|     if (!try_parse_content_length(conn)) { | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     ctx->req.body_type = http_body_file; | ||||
|     ctx->req.body.file = fopen(ctx->req.body_file_name, "wb"); | ||||
|     ctx->req.body_received = 0; | ||||
|   } | ||||
| 
 | ||||
|   size_t bytes_to_write = MIN(conn->rbuf_size - conn->rbuf_read, | ||||
|                               ctx->req.body_len - ctx->req.body_received); | ||||
|   size_t bytes_written = fwrite(&conn->rbuf[conn->rbuf_read], sizeof(uint8_t), | ||||
|                                 bytes_to_write, ctx->req.body.file); | ||||
|   ctx->req.body_received += bytes_written; | ||||
|   conn->rbuf_read += bytes_written; | ||||
| 
 | ||||
|   return ctx->req.body_received == ctx->req.body_len; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_auth(event_loop_conn *conn) { | ||||
|   http_loop_ctx *ctx = conn->ctx; | ||||
| 
 | ||||
|   for (size_t i = 0; i < ctx->req.num_headers; i++) { | ||||
|     struct phr_header *header = &ctx->req.headers[i]; | ||||
| 
 | ||||
|     if ((strncmp("X-Api-Key", header->name, header->name_len) == 0) && | ||||
|         (strncmp(header->value, ctx->g->api_key, header->value_len) == 0)) { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ctx->res.status = http_unauthorized; | ||||
|   conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_switch_res(event_loop_conn *conn) { | ||||
|   conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue