// Posix includes.
#include <sys/stat.h>
+// Local includes.
+#include "constants.h"
+
void print_usage(void) {
puts("Usage:");
puts(" -p <port> | --port <port>");
puts(" Note that this option is case-insensitive");
puts(" --enable-reload-config-on-change");
puts(" --enable-cache-dir=<DIR>");
+ puts(" --cache-entry-lifetime-seconds=<SECONDS>");
}
Args parse_args(int32_t argc, char **argv) {
Args args;
memset(&args, 0, sizeof(Args));
args.list_of_headers_to_log = simple_archiver_list_init();
+ args.cache_lifespan_seconds = C_SIMPLE_HTTP_DEFAULT_CACHE_LIFESPAN_SECONDS;
while (argc > 0) {
if ((strcmp(argv[0], "-p") == 0 || strcmp(argv[0], "--port") == 0)
printf("Directory \"%s\" exists.\n", args.cache_dir);
}
closedir(d);
+ } else if (strncmp(argv[0], "--cache-entry-lifetime-seconds=", 31) == 0) {
+ args.cache_lifespan_seconds = strtoul(argv[0] + 31, NULL, 10);
+ if (args.cache_lifespan_seconds == 0) {
+ fprintf(
+ stderr,
+ "ERROR: Invalid --cache-entry-lifetime-seconds=%s entry!\n",
+ argv[0] + 31);
+ print_usage();
+ exit(1);
+ } else {
+ printf(
+ "NOTICE set cache-entry-lifetime to %lu\n",
+ args.cache_lifespan_seconds);
+ }
} else {
fprintf(stderr, "ERROR: Invalid args!\n");
print_usage();
// Non-NULL if cache-dir is specified and cache is to be used.
// Does not need to be free'd since it points to a string in argv.
const char *cache_dir;
+ size_t cache_lifespan_seconds;
} Args;
void print_usage(void);
#define C_SIMPLE_HTTP_CONFIG_BUF_SIZE 1024
#define C_SIMPLE_HTTP_QUOTE_COUNT_MAX 3
#define C_SIMPLE_HTTP_TRY_CONFIG_RELOAD_MAX_ATTEMPTS 20
+#define C_SIMPLE_HTTP_DEFAULT_CACHE_LIFESPAN_SECONDS 604800
#endif
#include <sys/stat.h>
#include <errno.h>
+// libc includes.
+#include <time.h>
+
// Third-party includes.
#include <SimpleArchiver/src/data_structures/linked_list.h>
#include <SimpleArchiver/src/data_structures/hash_map.h>
const char *config_filename,
const char *cache_dir,
C_SIMPLE_HTTP_HTTPTemplates *templates,
+ size_t cache_entry_lifespan,
char **buf_out) {
if (!path) {
fprintf(stderr, "ERROR cache_path function: path is NULL!\n");
}
// Compare modification times.
+ struct timespec current_time;
+ if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) {
+ memset(¤t_time, 0, sizeof(struct timespec));
+ }
CACHE_FILE_WRITE_CHECK:
if (force_cache_update
|| cache_file_stat.st_mtim.tv_sec < config_file_stat.st_mtim.tv_sec
|| (cache_file_stat.st_mtim.tv_sec == config_file_stat.st_mtim.tv_sec
- && cache_file_stat.st_mtim.tv_nsec < config_file_stat.st_mtim.tv_nsec))
+ && cache_file_stat.st_mtim.tv_nsec < config_file_stat.st_mtim.tv_nsec)
+ || (current_time.tv_sec - cache_file_stat.st_mtim.tv_sec
+ > (ssize_t)cache_entry_lifespan))
{
// Cache file is out of date.
const char *config_filename,
const char *cache_dir,
C_SIMPLE_HTTP_HTTPTemplates *templates,
+ size_t cache_entry_lifespan,
char **buf_out);
#endif
C_SIMPLE_HTTP_HTTPTemplates *templates,
size_t *out_size,
enum C_SIMPLE_HTTP_ResponseCode *out_response_code,
- const char *cache_dir,
- const char *config_filename) {
+ const Args *args) {
if (out_size) {
*out_size = 0;
}
char *generated_buf = NULL;
- if (cache_dir) {
+ if (args->cache_dir) {
int ret = c_simple_http_cache_path(
stripped_path ? stripped_path : request_path_unescaped,
- config_filename,
- cache_dir,
+ args->config_file,
+ args->cache_dir,
templates,
+ args->cache_lifespan_seconds,
&generated_buf);
if (ret < 0) {
fprintf(stderr, "ERROR Failed to generate template with cache!\n");
#include <SimpleArchiver/src/data_structures/hash_map.h>
// Local includes.
+#include "arg_parse.h"
#include "config.h"
typedef C_SIMPLE_HTTP_ParsedConfig C_SIMPLE_HTTP_HTTPTemplates;
C_SIMPLE_HTTP_HTTPTemplates *templates,
size_t *out_size,
enum C_SIMPLE_HTTP_ResponseCode *out_response_code,
- const char *cache_dir,
- const char *config_filename
+ const Args *args
);
/// Takes a PATH string and returns a "bare" path.
&parsed_config,
&response_size,
&response_code,
- args.cache_dir,
- args.config_file);
+ &args);
if (response && response_code == C_SIMPLE_HTTP_Response_200_OK) {
CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 200 OK\n", 16));
CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
#include "http_template.h"
#include "http.h"
#include "html_cache.h"
+#include "constants.h"
// Third party includes.
#include <SimpleArchiver/src/helpers.h>
test_http_template_filename5,
"/tmp/c_simple_http_cache_dir",
&templates,
+ 0xFFFFFFFF,
&buf);
CHECK_TRUE(int_ret > 0);
test_http_template_filename5,
"/tmp/c_simple_http_cache_dir",
&templates,
+ 0xFFFFFFFF,
&buf);
CHECK_TRUE(int_ret == 0);
ASSERT_TRUE(buf);
test_http_template_filename5,
"/tmp/c_simple_http_cache_dir",
&templates,
+ 0xFFFFFFFF,
&buf);
CHECK_TRUE(int_ret > 0);
ASSERT_TRUE(buf);
test_http_template_filename5,
"/tmp/c_simple_http_cache_dir",
&templates,
+ 0xFFFFFFFF,
&buf);
CHECK_TRUE(int_ret == 0);
ASSERT_TRUE(buf);
CHECK_TRUE(cache_file_size_2 == cache_file_size_3);
// Edit config file.
+ puts("Sleeping for two seconds to ensure edited file's timestamp has "
+ "changed...");
+ sleep(2);
+ puts("Done sleeping.");
test_file = fopen(test_http_template_filename5, "w");
ASSERT_TRUE(test_file);
test_http_template_filename5,
"/tmp/c_simple_http_cache_dir",
&templates,
+ 0xFFFFFFFF,
+ &buf);
+ CHECK_TRUE(int_ret > 0);
+ ASSERT_TRUE(buf);
+ CHECK_TRUE(strcmp(buf, "<h1>Alternate test text.<br>Yep.</h1>") == 0);
+ free(buf);
+ buf = NULL;
+
+ puts("Sleeping for two seconds to ensure cache file has aged...");
+ sleep(2);
+ puts("Done sleeping.");
+ // Re-run cache function, checking that it is invalidated.
+ int_ret = c_simple_http_cache_path(
+ "/",
+ test_http_template_filename5,
+ "/tmp/c_simple_http_cache_dir",
+ &templates,
+ 1,
&buf);
CHECK_TRUE(int_ret > 0);
ASSERT_TRUE(buf);