Compare commits
2 commits
6cfaf4edd8
...
21f3a3a103
Author | SHA1 | Date | |
---|---|---|---|
21f3a3a103 | |||
af942c927b |
5 changed files with 135 additions and 23 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
/c_simple_http
|
/c_simple_http
|
||||||
/objs/
|
/objs/
|
||||||
/unit_test
|
/unit_test
|
||||||
|
/build*/
|
||||||
|
|
81
CMakeLists.txt
Normal file
81
CMakeLists.txt
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
cmake_minimum_required(VERSION 3.25)
|
||||||
|
project(c_simple_http C)
|
||||||
|
|
||||||
|
set(c_simple_http_SOURCES
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/arg_parse.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/big_endian.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/tcp_socket.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/signal_handling.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/globals.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/http.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/config.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/http_template.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/SimpleArchiver/src/helpers.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/SimpleArchiver/src/data_structures/linked_list.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/SimpleArchiver/src/data_structures/hash_map.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/SimpleArchiver/src/data_structures/priority_heap.c"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/SimpleArchiver/src/algorithms/linear_congruential_gen.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_BUILD_TYPE OR "${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||||
|
message("Defaulting to \"Debug\" build type.")
|
||||||
|
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type" FORCE)
|
||||||
|
else()
|
||||||
|
message("Using build type \"${CMAKE_BUILD_TYPE}\".")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(c_simple_http
|
||||||
|
${c_simple_http_SOURCES}
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/main.c"
|
||||||
|
)
|
||||||
|
target_include_directories(c_simple_http PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/third_party")
|
||||||
|
|
||||||
|
add_executable(unit_tests
|
||||||
|
${c_simple_http_SOURCES}
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/test.c"
|
||||||
|
)
|
||||||
|
target_include_directories(unit_tests PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/third_party")
|
||||||
|
|
||||||
|
target_compile_options(c_simple_http PUBLIC
|
||||||
|
$<IF:$<CONFIG:Debug>,-Og,-fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -ftrivial-auto-var-init=zero>
|
||||||
|
-Wall -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough
|
||||||
|
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
|
||||||
|
-D_GLIBCXX_ASSERTIONS
|
||||||
|
-fstrict-flex-arrays=3
|
||||||
|
-fstack-clash-protection -fstack-protector-strong
|
||||||
|
-fPIC
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_options(c_simple_http PUBLIC
|
||||||
|
$<IF:$<CONFIG:Debug>,-Og,-fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -ftrivial-auto-var-init=zero>
|
||||||
|
-Wall -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough
|
||||||
|
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
|
||||||
|
-D_GLIBCXX_ASSERTIONS
|
||||||
|
-fstrict-flex-arrays=3
|
||||||
|
-fstack-clash-protection -fstack-protector-strong
|
||||||
|
-Wl,-z,noexecstack
|
||||||
|
-Wl,-z,relro -Wl,-z,now
|
||||||
|
-fPIC
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_options(unit_tests PUBLIC
|
||||||
|
$<IF:$<CONFIG:Debug>,-Og,-fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -ftrivial-auto-var-init=zero>
|
||||||
|
-Wall -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough
|
||||||
|
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
|
||||||
|
-D_GLIBCXX_ASSERTIONS
|
||||||
|
-fstrict-flex-arrays=3
|
||||||
|
-fstack-clash-protection -fstack-protector-strong
|
||||||
|
-fPIC
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_options(unit_tests PUBLIC
|
||||||
|
$<IF:$<CONFIG:Debug>,-Og,-fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -ftrivial-auto-var-init=zero>
|
||||||
|
-Wall -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough
|
||||||
|
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
|
||||||
|
-D_GLIBCXX_ASSERTIONS
|
||||||
|
-fstrict-flex-arrays=3
|
||||||
|
-fstack-clash-protection -fstack-protector-strong
|
||||||
|
-Wl,-z,noexecstack
|
||||||
|
-Wl,-z,relro -Wl,-z,now
|
||||||
|
-fPIC
|
||||||
|
)
|
13
src/config.c
13
src/config.c
|
@ -237,10 +237,11 @@ typedef struct C_SIMPLE_HTTP_INTERNAL_RequiredIter {
|
||||||
|
|
||||||
int c_simple_http_required_iter_fn(void *data, void *ud) {
|
int c_simple_http_required_iter_fn(void *data, void *ud) {
|
||||||
C_SIMPLE_HTTP_INTERNAL_RequiredIter *req_iter_struct = ud;
|
C_SIMPLE_HTTP_INTERNAL_RequiredIter *req_iter_struct = ud;
|
||||||
|
unsigned int data_str_length = (unsigned int)strlen(data) + 1;
|
||||||
if (simple_archiver_hash_map_get(
|
if (simple_archiver_hash_map_get(
|
||||||
req_iter_struct->hash_map,
|
req_iter_struct->hash_map,
|
||||||
data,
|
data,
|
||||||
strlen(data) + 1) == NULL) {
|
data_str_length) == NULL) {
|
||||||
if (req_iter_struct->path) {
|
if (req_iter_struct->path) {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
|
@ -266,11 +267,12 @@ typedef struct C_SIMPLE_HTTP_INTERNAL_RequiredCheck {
|
||||||
|
|
||||||
int c_simple_http_check_required_iter_fn(void *path_void_str, void *ud) {
|
int c_simple_http_check_required_iter_fn(void *path_void_str, void *ud) {
|
||||||
C_SIMPLE_HTTP_INTERNAL_RequiredCheck *req = ud;
|
C_SIMPLE_HTTP_INTERNAL_RequiredCheck *req = ud;
|
||||||
|
unsigned int path_void_str_len = (unsigned int)strlen(path_void_str) + 1;
|
||||||
C_SIMPLE_HTTP_HashMapWrapper *wrapper =
|
C_SIMPLE_HTTP_HashMapWrapper *wrapper =
|
||||||
simple_archiver_hash_map_get(
|
simple_archiver_hash_map_get(
|
||||||
req->map_of_paths_and_their_vars,
|
req->map_of_paths_and_their_vars,
|
||||||
path_void_str,
|
path_void_str,
|
||||||
strlen(path_void_str) + 1);
|
path_void_str_len);
|
||||||
if (!wrapper) {
|
if (!wrapper) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"WARNING: Map of paths does not have path \"%s\"!\n",
|
"WARNING: Map of paths does not have path \"%s\"!\n",
|
||||||
|
@ -301,7 +303,8 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
|
||||||
fprintf(stderr, "ERROR: separating_key argument is NULL!\n");
|
fprintf(stderr, "ERROR: separating_key argument is NULL!\n");
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
const unsigned int separating_key_size = strlen(separating_key) + 1;
|
const unsigned int separating_key_size =
|
||||||
|
(unsigned int)strlen(separating_key) + 1;
|
||||||
|
|
||||||
config.hash_map = simple_archiver_hash_map_init();
|
config.hash_map = simple_archiver_hash_map_init();
|
||||||
|
|
||||||
|
@ -384,7 +387,7 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
|
||||||
}
|
}
|
||||||
if ((state & 1) == 0) {
|
if ((state & 1) == 0) {
|
||||||
if (c != '=') {
|
if (c != '=') {
|
||||||
key_buf[key_idx++] = c;
|
key_buf[key_idx++] = (unsigned char)c;
|
||||||
if (key_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
|
if (key_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ERROR: config file \"key\" is larger than %u bytes!\n",
|
"ERROR: config file \"key\" is larger than %u bytes!\n",
|
||||||
|
@ -408,7 +411,7 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
|
||||||
}
|
}
|
||||||
} else if ((state & 1) == 1) {
|
} else if ((state & 1) == 1) {
|
||||||
if ((c != '\n' && c != '\r') || (state & 0xC) != 0) {
|
if ((c != '\n' && c != '\r') || (state & 0xC) != 0) {
|
||||||
value_buf[value_idx++] = c;
|
value_buf[value_idx++] = (unsigned char)c;
|
||||||
if (value_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
|
if (value_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ERROR: config file \"value\" is larger than %u bytes!\n",
|
"ERROR: config file \"value\" is larger than %u bytes!\n",
|
||||||
|
|
|
@ -103,8 +103,14 @@ char *c_simple_http_path_to_generated(
|
||||||
if (output_buf_size) {
|
if (output_buf_size) {
|
||||||
*output_buf_size = 0;
|
*output_buf_size = 0;
|
||||||
}
|
}
|
||||||
|
size_t path_len_size_t = strlen(path) + 1;
|
||||||
|
if (path_len_size_t > 0xFFFFFFFF) {
|
||||||
|
fprintf(stderr, "ERROR: Path string is too large!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
unsigned int path_len = (unsigned int)path_len_size_t;
|
||||||
C_SIMPLE_HTTP_ParsedConfig *wrapped_hash_map =
|
C_SIMPLE_HTTP_ParsedConfig *wrapped_hash_map =
|
||||||
simple_archiver_hash_map_get(templates->hash_map, path, strlen(path) + 1);
|
simple_archiver_hash_map_get(templates->hash_map, path, path_len);
|
||||||
if (!wrapped_hash_map) {
|
if (!wrapped_hash_map) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -129,13 +135,13 @@ char *c_simple_http_path_to_generated(
|
||||||
if (fseek(f, 0, SEEK_SET) != 0) {
|
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
html_buf = malloc(html_file_size + 1);
|
html_buf = malloc((size_t)html_file_size + 1);
|
||||||
size_t ret = fread(html_buf, 1, html_file_size, f);
|
size_t ret = fread(html_buf, 1, (size_t)html_file_size, f);
|
||||||
if (ret != (size_t)html_file_size) {
|
if (ret != (size_t)html_file_size) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
html_buf[html_file_size] = 0;
|
html_buf[html_file_size] = 0;
|
||||||
html_buf_size = html_file_size;
|
html_buf_size = (size_t)html_file_size;
|
||||||
} else {
|
} else {
|
||||||
char *stored_html =
|
char *stored_html =
|
||||||
simple_archiver_hash_map_get(wrapped_hash_map->hash_map, "HTML", 5);
|
simple_archiver_hash_map_get(wrapped_hash_map->hash_map, "HTML", 5);
|
||||||
|
@ -215,7 +221,7 @@ char *c_simple_http_path_to_generated(
|
||||||
simple_archiver_hash_map_get(
|
simple_archiver_hash_map_get(
|
||||||
wrapped_hash_map->hash_map,
|
wrapped_hash_map->hash_map,
|
||||||
var,
|
var,
|
||||||
var_size + 1);
|
(unsigned int)var_size + 1);
|
||||||
if (value_c_str) {
|
if (value_c_str) {
|
||||||
if (c_simple_http_internal_ends_with_FILE(var) == 0) {
|
if (c_simple_http_internal_ends_with_FILE(var) == 0) {
|
||||||
// Load from file specified by "value_c_str".
|
// Load from file specified by "value_c_str".
|
||||||
|
|
47
src/main.c
47
src/main.c
|
@ -39,6 +39,13 @@
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
|
|
||||||
|
#define CHECK_ERROR_WRITE(write_expr) \
|
||||||
|
if (write_expr < 0) { \
|
||||||
|
close(connection_fd); \
|
||||||
|
fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
Args args = parse_args(argc, argv);
|
Args args = parse_args(argc, argv);
|
||||||
|
|
||||||
|
@ -113,6 +120,13 @@ int main(int argc, char **argv) {
|
||||||
puts("");
|
puts("");
|
||||||
int connection_fd = ret;
|
int connection_fd = ret;
|
||||||
read_ret = read(connection_fd, recv_buf, C_SIMPLE_HTTP_RECV_BUF_SIZE);
|
read_ret = read(connection_fd, recv_buf, C_SIMPLE_HTTP_RECV_BUF_SIZE);
|
||||||
|
if (read_ret < 0) {
|
||||||
|
close(connection_fd);
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"WARNING Failed to read from new connection, closing...\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// DEBUG print received buf.
|
// DEBUG print received buf.
|
||||||
for (unsigned int idx = 0;
|
for (unsigned int idx = 0;
|
||||||
idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
|
idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
|
||||||
|
@ -128,11 +142,11 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
size_t response_size = 0;
|
size_t response_size = 0;
|
||||||
const char *response = c_simple_http_request_response(
|
const char *response = c_simple_http_request_response(
|
||||||
(const char*)recv_buf, read_ret, &parsed_config, &response_size);
|
(const char*)recv_buf, (unsigned int)read_ret, &parsed_config, &response_size);
|
||||||
if (response) {
|
if (response) {
|
||||||
write(connection_fd, "HTTP/1.1 200 OK\n", 16);
|
CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 200 OK\n", 16));
|
||||||
write(connection_fd, "Allow: GET\n", 11);
|
CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
|
||||||
write(connection_fd, "Content-Type: text/html\n", 24);
|
CHECK_ERROR_WRITE(write(connection_fd, "Content-Type: text/html\n", 24));
|
||||||
char content_length_buf[128];
|
char content_length_buf[128];
|
||||||
size_t content_length_buf_size = 0;
|
size_t content_length_buf_size = 0;
|
||||||
memcpy(content_length_buf, "Content-Length: ", 16);
|
memcpy(content_length_buf, "Content-Length: ", 16);
|
||||||
|
@ -144,19 +158,26 @@ int main(int argc, char **argv) {
|
||||||
"%lu\n%n",
|
"%lu\n%n",
|
||||||
response_size,
|
response_size,
|
||||||
&written);
|
&written);
|
||||||
content_length_buf_size += written;
|
if (written <= 0) {
|
||||||
write(connection_fd, content_length_buf, content_length_buf_size);
|
close(connection_fd);
|
||||||
write(connection_fd, "\n", 1);
|
fprintf(
|
||||||
write(connection_fd, response, response_size);
|
stderr,
|
||||||
|
"WARNING Failed to write in response, closing connection...\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
content_length_buf_size += (size_t)written;
|
||||||
|
CHECK_ERROR_WRITE(write(connection_fd, content_length_buf, content_length_buf_size));
|
||||||
|
CHECK_ERROR_WRITE(write(connection_fd, "\n", 1));
|
||||||
|
CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
|
||||||
|
|
||||||
free((void*)response);
|
free((void*)response);
|
||||||
} else {
|
} else {
|
||||||
// TODO handle internal errors also.
|
// TODO handle internal errors also.
|
||||||
write(connection_fd, "HTTP/1.1 404 Not Found\n", 23);
|
CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 404 Not Found\n", 23));
|
||||||
write(connection_fd, "Allow: GET\n", 11);
|
CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
|
||||||
write(connection_fd, "Content-Type: text/html\n", 24);
|
CHECK_ERROR_WRITE(write(connection_fd, "Content-Type: text/html\n", 24));
|
||||||
write(connection_fd, "Content-Length: 14\n", 19);
|
CHECK_ERROR_WRITE(write(connection_fd, "Content-Length: 14\n", 19));
|
||||||
write(connection_fd, "\n404 Not Found\n", 15);
|
CHECK_ERROR_WRITE(write(connection_fd, "\n404 Not Found\n", 15));
|
||||||
}
|
}
|
||||||
close(connection_fd);
|
close(connection_fd);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue