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 <sys/stat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "http_loop.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++;
 | 
					  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