feat: PoC uploading of pastes
							parent
							
								
									dfbd179c7a
								
							
						
					
					
						commit
						87312f2d84
					
				|  | @ -48,6 +48,7 @@ typedef struct http_request { | |||
|   } 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; | ||||
|  |  | |||
|  | @ -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_file(event_loop_conn *conn); | ||||
| 
 | ||||
| /*
 | ||||
|  * Authenticate the request using the X-Api-Key header | ||||
|  */ | ||||
| bool http_loop_step_auth(event_loop_conn *conn); | ||||
| 
 | ||||
| bool http_loop_step_switch_res(event_loop_conn *conn); | ||||
| 
 | ||||
| /**
 | ||||
|  * Initialize a new http loop | ||||
|  */ | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| 
 | ||||
| #include "http_loop.h" | ||||
| 
 | ||||
| extern http_route lander_routes[3]; | ||||
| extern http_route lander_routes[4]; | ||||
| 
 | ||||
| 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_paste(event_loop_conn *conn); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -53,10 +53,14 @@ static bool string_to_num(size_t *res, const char *s, size_t len) { | |||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool http_loop_step_body_to_buf(event_loop_conn *conn) { | ||||
| /*
 | ||||
|  * 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; | ||||
| 
 | ||||
|   if (ctx->req.body_len == 0) { | ||||
|   for (size_t i = 0; i < ctx->req.num_headers; i++) { | ||||
|     struct phr_header *header = &ctx->req.headers[i]; | ||||
| 
 | ||||
|  | @ -68,11 +72,11 @@ bool http_loop_step_body_to_buf(event_loop_conn *conn) { | |||
|         ctx->res.status = http_bad_request; | ||||
|         conn->state = event_loop_conn_state_res; | ||||
| 
 | ||||
|           return true; | ||||
|         return false; | ||||
|       } | ||||
|       // The content length was actually 0, so we can instantly return here
 | ||||
|       else if (ctx->req.body_len == 0) { | ||||
|           return true; | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | @ -82,6 +86,17 @@ bool http_loop_step_body_to_buf(event_loop_conn *conn) { | |||
|     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; | ||||
|     } | ||||
| 
 | ||||
|  | @ -95,6 +110,30 @@ bool http_loop_step_body_to_buf(event_loop_conn *conn) { | |||
|   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; | ||||
| } | ||||
|  | @ -116,3 +155,9 @@ bool http_loop_step_auth(event_loop_conn *conn) { | |||
| 
 | ||||
|   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, | ||||
|      .path = "/s/", | ||||
|      .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; | ||||
| } | ||||
| 
 | ||||
| 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