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
|
#ifndef LANDER_HTTP_TYPES
|
||||||
#define HTTP
|
#define LANDER_HTTP_TYPES
|
||||||
|
|
||||||
#include <regex.h>
|
#include <sys/types.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];
|
|
||||||
|
|
||||||
// Array mapping the http_request_method enum to strings
|
// Array mapping the http_request_method enum to strings
|
||||||
extern const char *request_method_names[];
|
extern const char *http_method_names[];
|
||||||
extern const size_t request_method_names_len;
|
extern const size_t http_method_names_len;
|
||||||
|
|
||||||
typedef enum http_request_method {
|
typedef enum http_method {
|
||||||
http_get = 0,
|
http_get = 0,
|
||||||
http_post = 1,
|
http_post = 1,
|
||||||
http_put = 2,
|
http_put = 2,
|
||||||
http_patch = 3,
|
http_patch = 3,
|
||||||
http_delete = 4
|
http_delete = 4
|
||||||
} http_request_method;
|
} http_method;
|
||||||
|
|
||||||
typedef enum http_body_type {
|
// Array mapping the http_response_type enum to strings
|
||||||
http_body_buf = 0,
|
extern const char *http_status_names[][32];
|
||||||
http_body_file = 1
|
|
||||||
} http_body_type;
|
|
||||||
|
|
||||||
/*
|
typedef enum http_status {
|
||||||
* 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 {
|
|
||||||
// 1xx
|
// 1xx
|
||||||
http_continue = 100,
|
http_continue = 100,
|
||||||
http_switching_protocols = 101,
|
http_switching_protocols = 101,
|
||||||
|
@ -135,37 +83,10 @@ typedef enum http_response_type {
|
||||||
http_loop_detected = 508,
|
http_loop_detected = 508,
|
||||||
http_not_extended = 510,
|
http_not_extended = 510,
|
||||||
http_network_authentication_required = 511
|
http_network_authentication_required = 511
|
||||||
} http_response_type;
|
} http_status;
|
||||||
|
|
||||||
typedef enum http_header {
|
// Array mapping the http_mime_type enum to strings
|
||||||
http_header_connection = 0,
|
extern const char *http_mime_type_names[][2];
|
||||||
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;
|
|
||||||
|
|
||||||
typedef enum http_mime_type {
|
typedef enum http_mime_type {
|
||||||
http_mime_aac = 0,
|
http_mime_aac = 0,
|
||||||
|
@ -194,4 +115,18 @@ typedef enum http_mime_type {
|
||||||
http_mime_7z
|
http_mime_7z
|
||||||
} http_mime_type;
|
} 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
|
#endif
|
|
@ -4,7 +4,9 @@
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
||||||
#include "event_loop.h"
|
#include "event_loop.h"
|
||||||
#include "http.h"
|
#include "http/req.h"
|
||||||
|
#include "http/res.h"
|
||||||
|
#include "http/types.h"
|
||||||
#include "trie.h"
|
#include "trie.h"
|
||||||
|
|
||||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
@ -17,7 +19,7 @@ typedef enum http_route_type {
|
||||||
|
|
||||||
typedef struct http_route {
|
typedef struct http_route {
|
||||||
http_route_type type;
|
http_route_type type;
|
||||||
http_request_method method;
|
http_method method;
|
||||||
char *path;
|
char *path;
|
||||||
regex_t *regex;
|
regex_t *regex;
|
||||||
bool (*steps[5])(event_loop_conn *);
|
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);
|
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
|
* 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
|
// Very important that this is in the same order as http_request_method
|
||||||
const char *request_method_names[] = {"GET", "POST", "PUT", "PATCH", "DELETE"};
|
const char *http_method_names[] = {"GET", "POST", "PUT", "PATCH", "DELETE"};
|
||||||
const size_t request_method_names_len =
|
const size_t http_method_names_len =
|
||||||
sizeof(request_method_names) / sizeof(request_method_names[0]);
|
sizeof(http_method_names) / sizeof(http_method_names[0]);
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
const char *http_response_type_names[][32] = {
|
const char *http_status_names[][32] = {
|
||||||
// 1xx
|
// 1xx
|
||||||
{
|
{
|
||||||
"Continue", // 100
|
"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 <regex.h>
|
||||||
|
|
||||||
#include "http.h"
|
#include "http/types.h"
|
||||||
#include "http_loop.h"
|
#include "http_loop.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "http.h"
|
#include "http/types.h"
|
||||||
#include "http_loop.h"
|
#include "http_loop.h"
|
||||||
|
|
||||||
http_loop_gctx *http_loop_gctx_init() {
|
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;
|
bool match = false;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
for (i = 0; i < request_method_names_len; i++) {
|
for (i = 0; i < http_method_names_len; i++) {
|
||||||
if (strncmp(method, request_method_names[i], method_len) == 0) {
|
if (strncmp(method, http_method_names[i], method_len) == 0) {
|
||||||
req->method = i;
|
req->method = i;
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ void http_loop_route_request(event_loop_conn *conn) {
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
http_loop_gctx *gctx = ctx->g;
|
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);
|
ctx->req.path);
|
||||||
|
|
||||||
http_route *route;
|
http_route *route;
|
||||||
|
|
|
@ -17,7 +17,7 @@ void http_loop_init_header(http_response *res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *response_type_name =
|
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
|
// First we calculate the size of the start of the header
|
||||||
int buf_size = snprintf(NULL, 0, http_response_format, res->status,
|
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) {
|
bool lander_get_index(event_loop_conn *conn) {
|
||||||
http_loop_ctx *ctx = conn->ctx;
|
http_loop_ctx *ctx = conn->ctx;
|
||||||
|
|
||||||
http_loop_res_set_body_buf(ctx, index_page, sizeof(index_page) - 1, false);
|
http_res_set_body_buf(&ctx->res, index_page, sizeof(index_page) - 1, false);
|
||||||
http_loop_res_set_mime_type(ctx, http_mime_html);
|
http_res_set_mime_type(&ctx->res, http_mime_html);
|
||||||
|
|
||||||
conn->state = event_loop_conn_state_res;
|
conn->state = event_loop_conn_state_res;
|
||||||
return true;
|
return true;
|
||||||
|
@ -35,12 +35,12 @@ bool lander_get_entry(event_loop_conn *conn) {
|
||||||
ctx->res.status = http_not_found;
|
ctx->res.status = http_not_found;
|
||||||
} else if (entry->type == Redirect) {
|
} else if (entry->type == Redirect) {
|
||||||
ctx->res.status = http_moved_permanently;
|
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) {
|
} else if (entry->type == Paste) {
|
||||||
char fname[8 + key_len];
|
char fname[8 + key_len];
|
||||||
sprintf(fname, "pastes/%.*s", key_len, key);
|
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;
|
conn->state = event_loop_conn_state_res;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "http/res.h"
|
||||||
#include "lander.h"
|
#include "lander.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ bool lander_post_redirect(event_loop_conn *conn) {
|
||||||
|
|
||||||
free(key);
|
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;
|
conn->state = event_loop_conn_state_res;
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ bool lander_post_paste(event_loop_conn *conn) {
|
||||||
buf[0] = '/';
|
buf[0] = '/';
|
||||||
buf[key_len + 1] = '\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
|
// TODO free this
|
||||||
char *fname = malloc(8 + key_len);
|
char *fname = malloc(8 + key_len);
|
||||||
|
|
Loading…
Reference in New Issue