diff --git a/main.c b/main.c index e8a842f8..b767e1e3 100644 --- a/main.c +++ b/main.c @@ -55,11 +55,13 @@ #define vsnprintf _vsnprintf #define sleep(x) Sleep((x) * 1000) #define WINCDECL __cdecl +#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size)) #else #include #include #define DIRSEP '/' #define WINCDECL +#define abs_path(rel, abs, abs_size) realpath((rel), (abs)) #endif // _WIN32 #define MAX_OPTIONS 100 @@ -190,16 +192,16 @@ static char *sdup(const char *str) { static void set_option(char **options, const char *name, const char *value) { int i; - if (!strcmp(name, "document_root") || !(strcmp(name, "r"))) { - verify_document_root(value); - } - for (i = 0; i < MAX_OPTIONS - 3; i++) { if (options[i] == NULL) { options[i] = sdup(name); options[i + 1] = sdup(value); options[i + 2] = NULL; break; + } else if (!strcmp(options[i], name)) { + free(options[i + 1]); + options[i + 1] = sdup(value); + break; } } @@ -213,8 +215,6 @@ static void process_command_line_arguments(char *argv[], char **options) { FILE *fp = NULL; size_t i, cmd_line_opts_start = 1, line_no = 0; - options[0] = NULL; - // Should we use a config file ? if (argv[1] != NULL && argv[1][0] != '-') { snprintf(config_file, sizeof(config_file), "%s", argv[1]); @@ -285,6 +285,54 @@ static int log_message(const struct mg_connection *conn, const char *message) { return 0; } +static int is_path_absolute(const char *path) { +#ifdef _WIN32 + return path != NULL && + ((path[0] == '\\' && path[1] == '\\') || // UNC path, e.g. \\server\dir + (isalpha(path[0]) && path[1] == ':' && path[2] == '\\')); // E.g. X:\dir +#else + return path != NULL && path[0] == '/'; +#endif +} + +static void set_absolute_document_root(char *options[], + const char *path_to_mongoose_exe) { + char path[PATH_MAX], abs[PATH_MAX]; + const char *p; + int i; + + // Check whether document root is already set + for (i = 0; options[i] != NULL; i++) + if (!strcmp(options[i], "document_root")) + break; + + // If document root is already set and it is an absolute path, + // leave it as it is -- it's already absolute. + if (options[i] == NULL || !is_path_absolute(options[i + 1])) { + // Not absolute. Use the directory where mongoose executable lives + // be the relative directory for everything. + // Extract mongoose executable directory into path. + if ((p = strrchr(path_to_mongoose_exe, DIRSEP)) == NULL) { + getcwd(path, sizeof(path)); + } else { + snprintf(path, sizeof(path), "%.*s", (int) (p - path_to_mongoose_exe), + path_to_mongoose_exe); + } + + // If document_root option is specified, it is relative. + // Append it to the mongoose's directory + if (options[i] != NULL && options[i + 1] != NULL) { + strncat(path, "/", sizeof(path) - 1); + strncat(path, options[i + 1], sizeof(path) - 1); + } + + // Absolutize the path, and set the option + abs_path(path, abs, sizeof(abs)); + verify_document_root(abs); + set_option(options, "document_root", abs); + } +} + static void start_mongoose(int argc, char *argv[]) { struct mg_callbacks callbacks; char *options[MAX_OPTIONS]; @@ -304,14 +352,20 @@ static void start_mongoose(int argc, char *argv[]) { show_usage_and_exit(); } - /* Update config based on command line arguments */ + options[0] = NULL; + + // Update config based on command line arguments process_command_line_arguments(argv, options); - /* Setup signal handler: quit on Ctrl-C */ + // Make sure we have absolute path in document_root, see discussion at + // https://github.com/valenok/mongoose/issues/181 + set_absolute_document_root(options, argv[0]); + + // Setup signal handler: quit on Ctrl-C signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); - /* Start Mongoose */ + // Start Mongoose memset(&callbacks, 0, sizeof(callbacks)); callbacks.log_message = &log_message; ctx = mg_start(&callbacks, NULL, (const char **) options); diff --git a/test/test.pl b/test/test.pl index d455741e..13370a94 100644 --- a/test/test.pl +++ b/test/test.pl @@ -4,6 +4,7 @@ use IO::Socket; use File::Path; +use Cwd; use strict; use warnings; #use diagnostics; @@ -243,8 +244,10 @@ write_file($path, read_file($root . $dir_separator . 'env.cgi')); chmod(0755, $path); o("GET /$test_dir_uri/x/ HTTP/1.0\n\n", "Content-Type: text/html\r\n\r\n", 'index.cgi execution'); + +my $cwd = getcwd(); o("GET /$test_dir_uri/x/ HTTP/1.0\n\n", - "SCRIPT_FILENAME=test/test_dir/x/index.cgi", 'SCRIPT_FILENAME'); + "SCRIPT_FILENAME=$cwd/test/test_dir/x/index.cgi", 'SCRIPT_FILENAME'); o("GET /ta/x/ HTTP/1.0\n\n", "SCRIPT_NAME=/ta/x/index.cgi", 'Aliases SCRIPT_NAME'); o("GET /hello.txt HTTP/1.1\nConnection: close\n\n", 'Connection: close',