Compare commits

..

No commits in common. "37e0c3a98bd90d852674fea9baa2a892db4d9037" and "faa262ba95be60e47a072382749723583e6528c2" have entirely different histories.

7 changed files with 154 additions and 225 deletions

View file

@ -13,7 +13,6 @@ set(c_simple_http_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/src/helpers.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/helpers.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/html_cache.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/html_cache.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/static.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/static.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/generate.c"
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/SimpleArchiver/src/helpers.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/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/hash_map.c"

View file

@ -44,8 +44,7 @@ HEADERS = \
src/http_template.h \ src/http_template.h \
src/helpers.h \ src/helpers.h \
src/html_cache.h \ src/html_cache.h \
src/static.h \ src/static.h
src/generate.h
SOURCES = \ SOURCES = \
src/main.c \ src/main.c \
@ -60,7 +59,6 @@ SOURCES = \
src/helpers.c \ src/helpers.c \
src/html_cache.c \ src/html_cache.c \
src/static.c \ src/static.c \
src/generate.c \
third_party/SimpleArchiver/src/helpers.c \ third_party/SimpleArchiver/src/helpers.c \
third_party/SimpleArchiver/src/data_structures/linked_list.c \ third_party/SimpleArchiver/src/data_structures/linked_list.c \
third_party/SimpleArchiver/src/data_structures/hash_map.c \ third_party/SimpleArchiver/src/data_structures/hash_map.c \

View file

@ -126,6 +126,7 @@ void internal_double_quote_decrement(uint_fast8_t *double_quote_count,
/// Returns non-zero if config should be returned. /// Returns non-zero if config should be returned.
int internal_check_add_value(uint32_t *state, int internal_check_add_value(uint32_t *state,
char **key_buf, char **key_buf,
uint32_t *key_capacity,
uint32_t *key_idx, uint32_t *key_idx,
char **value_buf, char **value_buf,
uint32_t *value_capacity, uint32_t *value_capacity,
@ -495,6 +496,7 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
} else { } else {
if (internal_check_add_value(&state, if (internal_check_add_value(&state,
&key_buf, &key_buf,
&key_capacity,
&key_idx, &key_idx,
&value_buf, &value_buf,
&value_capacity, &value_capacity,
@ -518,6 +520,7 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
if (internal_check_add_value(&state, if (internal_check_add_value(&state,
&key_buf, &key_buf,
&key_capacity,
&key_idx, &key_idx,
&value_buf, &value_buf,
&value_capacity, &value_capacity,

View file

@ -1,175 +0,0 @@
// ISC License
//
// Copyright (c) 2024 Stephen Seo
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "generate.h"
// Standard library includes.
#include <string.h>
// Linux/Unix includes.
#include <libgen.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
// Local includes.
#include "helpers.h"
#include "http_template.h"
// Third party includes.
#include <SimpleArchiver/src/helpers.h>
#include <SimpleArchiver/src/data_structures/hash_map.h>
#include <SimpleArchiver/src/data_structures/linked_list.h>
int c_simple_http_generate_paths_fn(const void *key,
size_t key_size,
__attribute__((unused)) const void *value,
void *ud) {
const char *path = key;
const ConnectionContext *ctx = ud;
const char *generate_dir = ctx->args->generate_dir;
const unsigned long path_len = key_size - 1;
const unsigned long generate_dir_len = strlen(generate_dir);
__attribute__((cleanup(simple_archiver_list_free)))
SDArchiverLinkedList *string_parts = simple_archiver_list_init();
// Add generate_dir as first path of paths to join.
c_simple_http_add_string_part(string_parts, generate_dir, 0);
// Ensure next character after generate_dir contains a '/' if generate_dir
// didn't contain one at the end.
if (generate_dir_len > 0 && generate_dir[generate_dir_len - 1] != '/') {
c_simple_http_add_string_part(string_parts, "/", 0);
}
// Append the path.
if (strcmp(path, "/") != 0) {
// Is not root.
uint32_t idx = 0;
while (idx <= path_len && path[idx] == '/') {
++idx;
}
c_simple_http_add_string_part(string_parts, path + idx, 0);
}
// Add the final '/'.
if (path_len > 0 && path[path_len - 1] != '/') {
c_simple_http_add_string_part(string_parts, "/", 0);
}
// Add the ending "index.html".
c_simple_http_add_string_part(string_parts, "index.html", 0);
// Get the combined string.
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
char *generated_path = c_simple_http_combine_string_parts(string_parts);
if (!generated_path) {
fprintf(stderr, "ERROR Failed to get generated path (path: %s)!\n", path);
return 1;
}
if ((ctx->args->flags & 4) == 0) {
// Overwrite not enabled, check if file already exists.
FILE *fd = fopen(generated_path, "rb");
if (fd) {
fclose(fd);
fprintf(
stderr,
"WARNING Path \"%s\" exists and \"--generate-enable-overwrite\" not "
"specified, skipping!\n",
generated_path);
return 0;
}
}
// Ensure the required dirs exist.
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
char *generated_path_dup = strdup(generated_path);
uint_fast8_t did_make_generated_path_dir = 0;
char *generated_path_dir = dirname(generated_path_dup);
if (generated_path_dir) {
DIR *fd = opendir(generated_path_dir);
if (!fd) {
if (errno == ENOENT) {
c_simple_http_helper_mkdir_tree(generated_path_dir);
did_make_generated_path_dir = 1;
} else {
fprintf(stderr,
"ERROR opendir on path dirname failed unexpectedly (path: %s)!"
"\n",
path);
return 1;
}
} else {
// Directory already exists.
closedir(fd);
}
} else {
fprintf(stderr,
"ERROR Failed to get dirname of generated path dir (path: %s)"
"!\n",
path);
return 1;
}
// Generate the html.
size_t html_buf_size = 0;
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
char *html_buf = c_simple_http_path_to_generated(path,
ctx->parsed,
&html_buf_size,
NULL);
if (!html_buf || html_buf_size == 0) {
fprintf(stderr,
"WARNING Failed to generate html for generate (path: %s), "
"skipping!\n",
path);
if (did_make_generated_path_dir) {
if (rmdir(generated_path_dir) == -1) {
fprintf(stderr,
"WARNING rmdir on generated_path_dir failed, errno: %d\n",
errno);
}
}
return 0;
}
// Save the html.
FILE *fd = fopen(generated_path, "wb");
if (!fd) {
fprintf(stderr,
"WARNING Failed to open \"%s\" for writing, skipping!\n",
generated_path);
return 0;
}
unsigned long fwrite_ret = fwrite(html_buf, 1, html_buf_size, fd);
if (fwrite_ret < html_buf_size) {
fclose(fd);
unlink(generated_path);
fprintf(stderr,
"ERROR Unable to write entirely to \"%s\"!\n",
generated_path);
return 1;
} else {
fclose(fd);
}
return 0;
}

View file

@ -1,30 +0,0 @@
// ISC License
//
// Copyright (c) 2024 Stephen Seo
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef SEODISPARATE_COM_C_SIMPLE_HTTP_GENERATE_H_
#define SEODISPARATE_COM_C_SIMPLE_HTTP_GENERATE_H_
#include <stdlib.h>
/// See this function's usage in main.c.
int c_simple_http_generate_paths_fn(const void *key,
size_t key_size,
const void *value,
void *ud);
#endif
// vim: et ts=2 sts=2 sw=2

View file

@ -21,23 +21,9 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
// libc includes.
#include <time.h>
// Local includes.
#include "config.h"
#include "arg_parse.h"
// Third-party includes. // Third-party includes.
#include <SimpleArchiver/src/data_structures/linked_list.h> #include <SimpleArchiver/src/data_structures/linked_list.h>
typedef struct ConnectionContext {
char *buf;
const Args *args;
C_SIMPLE_HTTP_ParsedConfig *parsed;
struct timespec current_time;
} ConnectionContext;
typedef struct C_SIMPLE_HTTP_String_Part { typedef struct C_SIMPLE_HTTP_String_Part {
char *buf; char *buf;
size_t size; size_t size;

View file

@ -21,7 +21,10 @@
#include <stdint.h> #include <stdint.h>
// Linux/Unix includes. // Linux/Unix includes.
#include <libgen.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h>
#include <dirent.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
@ -43,7 +46,6 @@
#include "http_template.h" #include "http_template.h"
#include "tcp_socket.h" #include "tcp_socket.h"
#include "signal_handling.h" #include "signal_handling.h"
#include "generate.h"
#include "globals.h" #include "globals.h"
#include "constants.h" #include "constants.h"
#include "http.h" #include "http.h"
@ -78,6 +80,13 @@ typedef struct ConnectionItem {
struct in6_addr peer_addr; struct in6_addr peer_addr;
} ConnectionItem; } ConnectionItem;
typedef struct ConnectionContext {
char *buf;
const Args *args;
C_SIMPLE_HTTP_ParsedConfig *parsed;
struct timespec current_time;
} ConnectionContext;
void c_simple_http_cleanup_connection_item(void *data) { void c_simple_http_cleanup_connection_item(void *data) {
ConnectionItem *citem = data; ConnectionItem *citem = data;
if (citem) { if (citem) {
@ -323,6 +332,145 @@ int c_simple_http_manage_connections(void *data, void *ud) {
return 1; return 1;
} }
int generate_paths_fn(const void *key,
size_t key_size,
const void *value,
void *ud) {
const char *path = key;
const ConnectionContext *ctx = ud;
const char *generate_dir = ctx->args->generate_dir;
const unsigned long path_len = strlen(path);
const unsigned long generate_dir_len = strlen(generate_dir);
__attribute__((cleanup(simple_archiver_list_free)))
SDArchiverLinkedList *string_parts = simple_archiver_list_init();
// Add generate_dir as first path of paths to join.
c_simple_http_add_string_part(string_parts, generate_dir, 0);
// Ensure next character after generate_dir contains a '/' if generate_dir
// didn't contain one at the end.
if (generate_dir_len > 0 && generate_dir[generate_dir_len - 1] != '/') {
c_simple_http_add_string_part(string_parts, "/", 0);
}
// Append the path.
if (strcmp(path, "/") != 0) {
// Is not root.
uint32_t idx = 0;
while (idx <= path_len && path[idx] == '/') {
++idx;
}
c_simple_http_add_string_part(string_parts, path + idx, 0);
}
// Add the final '/'.
if (path_len > 0 && path[path_len - 1] != '/') {
c_simple_http_add_string_part(string_parts, "/", 0);
}
// Add the ending "index.html".
c_simple_http_add_string_part(string_parts, "index.html", 0);
// Get the combined string.
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
char *generated_path = c_simple_http_combine_string_parts(string_parts);
if (!generated_path) {
fprintf(stderr, "ERROR Failed to get generated path (path: %s)!\n", path);
return 1;
}
if ((ctx->args->flags & 4) == 0) {
// Overwrite not enabled, check if file already exists.
FILE *fd = fopen(generated_path, "rb");
if (fd) {
fclose(fd);
fprintf(
stderr,
"WARNING Path \"%s\" exists and \"--generate-enable-overwrite\" not "
"specified, skipping!\n",
generated_path);
return 0;
}
}
// Ensure the required dirs exist.
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
char *generated_path_dup = strdup(generated_path);
uint_fast8_t did_make_generated_path_dir = 0;
char *generated_path_dir = dirname(generated_path_dup);
if (generated_path_dir) {
DIR *fd = opendir(generated_path_dir);
if (!fd) {
if (errno == ENOENT) {
c_simple_http_helper_mkdir_tree(generated_path_dir);
did_make_generated_path_dir = 1;
} else {
fprintf(stderr,
"ERROR opendir on path dirname failed unexpectedly (path: %s)!"
"\n",
path);
return 1;
}
} else {
// Directory already exists.
closedir(fd);
}
} else {
fprintf(stderr,
"ERROR Failed to get dirname of generated path dir (path: %s)"
"!\n",
path);
return 1;
}
// Generate the html.
size_t html_buf_size = 0;
__attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
char *html_buf = c_simple_http_path_to_generated(path,
ctx->parsed,
&html_buf_size,
NULL);
if (!html_buf || html_buf_size == 0) {
fprintf(stderr,
"WARNING Failed to generate html for generate (path: %s), "
"skipping!\n",
path);
if (did_make_generated_path_dir) {
if (rmdir(generated_path_dir) == -1) {
fprintf(stderr,
"WARNING rmdir on generated_path_dir failed, errno: %d\n",
errno);
}
}
return 0;
}
// Save the html.
FILE *fd = fopen(generated_path, "wb");
if (!fd) {
fprintf(stderr,
"WARNING Failed to open \"%s\" for writing, skipping!\n",
generated_path);
return 0;
}
unsigned long fwrite_ret = fwrite(html_buf, 1, html_buf_size, fd);
if (fwrite_ret < html_buf_size) {
fclose(fd);
unlink(generated_path);
fprintf(stderr,
"ERROR Unable to write entirely to \"%s\"!\n",
generated_path);
return 1;
} else {
fclose(fd);
}
return 0;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
__attribute__((cleanup(c_simple_http_free_args))) __attribute__((cleanup(c_simple_http_free_args)))
Args args = parse_args(argc, argv); Args args = parse_args(argc, argv);
@ -352,7 +500,7 @@ int main(int argc, char **argv) {
ctx.args = &args; ctx.args = &args;
ctx.parsed = &parsed_config; ctx.parsed = &parsed_config;
if (simple_archiver_hash_map_iter(parsed_config.paths, if (simple_archiver_hash_map_iter(parsed_config.paths,
c_simple_http_generate_paths_fn, generate_paths_fn,
&ctx)) { &ctx)) {
fprintf(stderr, "ERROR during generating!\n"); fprintf(stderr, "ERROR during generating!\n");
return 1; return 1;