diff --git a/src/arg_parse.c b/src/arg_parse.c index 7cb7611..7801ca2 100644 --- a/src/arg_parse.c +++ b/src/arg_parse.c @@ -29,6 +29,9 @@ // Posix includes. #include +// Local includes. +#include "constants.h" + void print_usage(void) { puts("Usage:"); puts(" -p | --port "); @@ -39,6 +42,7 @@ void print_usage(void) { puts(" Note that this option is case-insensitive"); puts(" --enable-reload-config-on-change"); puts(" --enable-cache-dir="); + puts(" --cache-entry-lifetime-seconds="); } Args parse_args(int32_t argc, char **argv) { @@ -49,6 +53,7 @@ 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) @@ -109,6 +114,20 @@ Args parse_args(int32_t argc, char **argv) { 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(); diff --git a/src/arg_parse.h b/src/arg_parse.h index c14ee90..24ba5f7 100644 --- a/src/arg_parse.h +++ b/src/arg_parse.h @@ -37,6 +37,7 @@ typedef struct Args { // 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); diff --git a/src/constants.h b/src/constants.h index c6ba249..b8d1ebf 100644 --- a/src/constants.h +++ b/src/constants.h @@ -25,5 +25,6 @@ #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 diff --git a/src/html_cache.c b/src/html_cache.c index 4ab6fab..4b8403f 100644 --- a/src/html_cache.c +++ b/src/html_cache.c @@ -25,6 +25,9 @@ #include #include +// libc includes. +#include + // Third-party includes. #include #include @@ -208,6 +211,7 @@ int c_simple_http_cache_path( 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"); @@ -391,11 +395,17 @@ int c_simple_http_cache_path( } // 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. diff --git a/src/html_cache.h b/src/html_cache.h index ebaa385..5167425 100644 --- a/src/html_cache.h +++ b/src/html_cache.h @@ -37,6 +37,7 @@ int c_simple_http_cache_path( const char *config_filename, const char *cache_dir, C_SIMPLE_HTTP_HTTPTemplates *templates, + size_t cache_entry_lifespan, char **buf_out); #endif diff --git a/src/http.c b/src/http.c index 9ced398..0e688aa 100644 --- a/src/http.c +++ b/src/http.c @@ -65,8 +65,7 @@ char *c_simple_http_request_response( 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; } @@ -177,12 +176,13 @@ char *c_simple_http_request_response( 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"); diff --git a/src/http.h b/src/http.h index 87618c4..7b7a52a 100644 --- a/src/http.h +++ b/src/http.h @@ -25,6 +25,7 @@ #include // Local includes. +#include "arg_parse.h" #include "config.h" typedef C_SIMPLE_HTTP_ParsedConfig C_SIMPLE_HTTP_HTTPTemplates; @@ -49,8 +50,7 @@ char *c_simple_http_request_response( 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. diff --git a/src/main.c b/src/main.c index 9c9f51c..976f245 100644 --- a/src/main.c +++ b/src/main.c @@ -360,8 +360,7 @@ int main(int argc, char **argv) { &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)); diff --git a/src/test.c b/src/test.c index b397679..d47079f 100644 --- a/src/test.c +++ b/src/test.c @@ -15,6 +15,7 @@ #include "http_template.h" #include "http.h" #include "html_cache.h" +#include "constants.h" // Third party includes. #include @@ -808,6 +809,7 @@ int main(void) { test_http_template_filename5, "/tmp/c_simple_http_cache_dir", &templates, + 0xFFFFFFFF, &buf); CHECK_TRUE(int_ret > 0); @@ -830,6 +832,7 @@ int main(void) { test_http_template_filename5, "/tmp/c_simple_http_cache_dir", &templates, + 0xFFFFFFFF, &buf); CHECK_TRUE(int_ret == 0); ASSERT_TRUE(buf); @@ -870,6 +873,7 @@ int main(void) { test_http_template_filename5, "/tmp/c_simple_http_cache_dir", &templates, + 0xFFFFFFFF, &buf); CHECK_TRUE(int_ret > 0); ASSERT_TRUE(buf); @@ -892,6 +896,7 @@ int main(void) { test_http_template_filename5, "/tmp/c_simple_http_cache_dir", &templates, + 0xFFFFFFFF, &buf); CHECK_TRUE(int_ret == 0); ASSERT_TRUE(buf); @@ -909,6 +914,10 @@ int main(void) { 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); @@ -935,6 +944,24 @@ int main(void) { 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, "

Alternate test text.
Yep.

") == 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);