feat: PoC uploading of pastes
							parent
							
								
									dfbd179c7a
								
							
						
					
					
						commit
						87312f2d84
					
				|  | @ -48,6 +48,7 @@ typedef struct http_request { | ||||||
|   } body; |   } body; | ||||||
|   size_t body_len; |   size_t body_len; | ||||||
|   size_t body_received; |   size_t body_received; | ||||||
|  |   char *body_file_name; | ||||||
|   regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS]; |   regmatch_t regex_groups[HTTP_MAX_REGEX_GROUPS]; | ||||||
|   struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS]; |   struct phr_header headers[HTTP_MAX_ALLOWED_HEADERS]; | ||||||
|   size_t num_headers; |   size_t num_headers; | ||||||
|  |  | ||||||
|  | @ -111,11 +111,15 @@ void http_loop_res_add_header(http_loop_ctx *ctx, http_header type, | ||||||
|  */ |  */ | ||||||
| bool http_loop_step_body_to_buf(event_loop_conn *conn); | bool http_loop_step_body_to_buf(event_loop_conn *conn); | ||||||
| 
 | 
 | ||||||
|  | bool http_loop_step_body_to_file(event_loop_conn *conn); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Authenticate the request using the X-Api-Key header |  * Authenticate the request using the X-Api-Key header | ||||||
|  */ |  */ | ||||||
| bool http_loop_step_auth(event_loop_conn *conn); | bool http_loop_step_auth(event_loop_conn *conn); | ||||||
| 
 | 
 | ||||||
|  | bool http_loop_step_switch_res(event_loop_conn *conn); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Initialize a new http loop |  * Initialize a new http loop | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "http_loop.h" | #include "http_loop.h" | ||||||
| 
 | 
 | ||||||
| extern http_route lander_routes[3]; | extern http_route lander_routes[4]; | ||||||
| 
 | 
 | ||||||
| bool lander_get_index(event_loop_conn *conn); | bool lander_get_index(event_loop_conn *conn); | ||||||
| 
 | 
 | ||||||
|  | @ -11,4 +11,6 @@ bool lander_get_entry(event_loop_conn *conn); | ||||||
| 
 | 
 | ||||||
| bool lander_post_redirect(event_loop_conn *conn); | bool lander_post_redirect(event_loop_conn *conn); | ||||||
| 
 | 
 | ||||||
|  | bool lander_post_paste(event_loop_conn *conn); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -53,35 +53,50 @@ static bool string_to_num(size_t *res, const char *s, size_t len) { | ||||||
|   return true; |   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) { | bool http_loop_step_body_to_buf(event_loop_conn *conn) { | ||||||
|   http_loop_ctx *ctx = conn->ctx; |   http_loop_ctx *ctx = conn->ctx; | ||||||
| 
 | 
 | ||||||
|   if (ctx->req.body_len == 0) { |   if (ctx->req.body_len == 0) { | ||||||
|     for (size_t i = 0; i < ctx->req.num_headers; i++) { |     if (!try_parse_content_length(conn)) { | ||||||
|       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 true; |  | ||||||
|         } |  | ||||||
|         // The content length was actually 0, so we can instantly return here
 |  | ||||||
|         else if (ctx->req.body_len == 0) { |  | ||||||
|           return true; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // 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 true; |       return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -95,6 +110,30 @@ bool http_loop_step_body_to_buf(event_loop_conn *conn) { | ||||||
|   memcpy(&ctx->req.body.buf[ctx->req.body_received], |   memcpy(&ctx->req.body.buf[ctx->req.body_received], | ||||||
|          &conn->rbuf[conn->rbuf_read], bytes_to_copy); |          &conn->rbuf[conn->rbuf_read], bytes_to_copy); | ||||||
|   ctx->req.body_received += 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; |   return ctx->req.body_received == ctx->req.body_len; | ||||||
| } | } | ||||||
|  | @ -116,3 +155,9 @@ bool http_loop_step_auth(event_loop_conn *conn) { | ||||||
| 
 | 
 | ||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | bool http_loop_step_switch_res(event_loop_conn *conn) { | ||||||
|  |   conn->state = event_loop_conn_state_res; | ||||||
|  | 
 | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -15,4 +15,10 @@ http_route lander_routes[] = { | ||||||
|      .method = http_post, |      .method = http_post, | ||||||
|      .path = "/s/", |      .path = "/s/", | ||||||
|      .steps = {http_loop_step_auth, http_loop_step_body_to_buf, |      .steps = {http_loop_step_auth, http_loop_step_body_to_buf, | ||||||
|                lander_post_redirect, NULL}}}; |                lander_post_redirect, NULL}}, | ||||||
|  |     {.type = http_route_literal, | ||||||
|  |      .method = http_post, | ||||||
|  |      .path = "/p/", | ||||||
|  |      .steps = {http_loop_step_auth, lander_post_paste, | ||||||
|  |                http_loop_step_body_to_file, http_loop_step_switch_res, NULL}}, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | @ -38,3 +38,40 @@ bool lander_post_redirect(event_loop_conn *conn) { | ||||||
| 
 | 
 | ||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | bool lander_post_paste(event_loop_conn *conn) { | ||||||
|  |   http_loop_ctx *ctx = conn->ctx; | ||||||
|  | 
 | ||||||
|  |   char *key; | ||||||
|  |   Entry *new_entry = entry_new(Paste, ""); | ||||||
|  |   TrieExitCode res = trie_add_random(ctx->g->trie, &key, new_entry, false); | ||||||
|  | 
 | ||||||
|  |   if (res != Ok) { | ||||||
|  |     error("trie_add_random failed with exit code %i", res); | ||||||
|  | 
 | ||||||
|  |     ctx->res.status = http_internal_server_error; | ||||||
|  |     conn->state = event_loop_conn_state_res; | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Add a slash to the key and add it as the location header
 | ||||||
|  |   size_t key_len = strlen(key); | ||||||
|  |   char *buf = malloc(key_len + 2); | ||||||
|  | 
 | ||||||
|  |   memcpy(&buf[1], key, key_len); | ||||||
|  |   buf[0] = '/'; | ||||||
|  |   buf[key_len + 1] = '\0'; | ||||||
|  | 
 | ||||||
|  |   http_loop_res_add_header(ctx, http_header_location, buf, true); | ||||||
|  | 
 | ||||||
|  |   // TODO free this
 | ||||||
|  |   char *fname = malloc(8 + key_len); | ||||||
|  |   sprintf(fname, "pastes/%s", key); | ||||||
|  | 
 | ||||||
|  |   ctx->req.body_file_name = fname; | ||||||
|  | 
 | ||||||
|  |   free(key); | ||||||
|  | 
 | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue