Browse Source

introduced struct mg_config. Fixed Range response.

Sergey Lyubka 15 years ago
parent
commit
5425b94f39
4 changed files with 299 additions and 537 deletions
  1. 111 37
      main.c
  2. 135 433
      mongoose.c
  3. 50 64
      mongoose.h
  4. 3 3
      test/test.pl

+ 111 - 37
main.c

@@ -32,6 +32,7 @@
 #include <string.h>
 #include <string.h>
 #include <errno.h>
 #include <errno.h>
 #include <limits.h>
 #include <limits.h>
+#include <stddef.h>
 
 
 #include "mongoose.h"
 #include "mongoose.h"
 
 
@@ -71,16 +72,6 @@ signal_handler(int sig_num)
 }
 }
 
 
 /*
 /*
- * Show usage string and exit.
- */
-static void
-show_usage_and_exit(void)
-{
-	mg_show_usage_string(stderr);
-	exit(EXIT_FAILURE);
-}
-
-/*
  * Edit the passwords file.
  * Edit the passwords file.
  */
  */
 static int
 static int
@@ -88,18 +79,89 @@ mg_edit_passwords(const char *fname, const char *domain,
 		const char *user, const char *pass)
 		const char *user, const char *pass)
 {
 {
 	struct mg_context	*ctx;
 	struct mg_context	*ctx;
+	struct mg_config	config;
 	int			retval;
 	int			retval;
 
 
-	ctx = mg_start();
-	(void) mg_set_option(ctx, "auth_realm", domain);
+	memset(&config, 0, sizeof(config));
+	config.auth_domain = (char *) domain;
+	config.num_threads = "0";
+	config.listening_ports = "";
+	ctx = mg_start(&config);
 	retval = mg_modify_passwords_file(ctx, fname, user, pass);
 	retval = mg_modify_passwords_file(ctx, fname, user, pass);
 	mg_stop(ctx);
 	mg_stop(ctx);
 
 
 	return (retval);
 	return (retval);
 }
 }
 
 
+#define OFFSET(x) offsetof(struct mg_config, x)
+
+static struct option_descriptor {
+	const char *name;
+	const char *description;
+	size_t offset;
+} known_options[] = {
+	{"root", "\tWeb root directory", OFFSET(document_root)},
+	{"index_files",	"Index files", OFFSET(index_files)},
+	{"ssl_cert", "SSL certificate file", OFFSET(ssl_certificate)},
+	{"ports", "Listening ports", OFFSET(listening_ports)},
+	{"dir_list", "Directory listing", OFFSET(enable_directory_listing)},
+	{"protect", "URI to htpasswd mapping", OFFSET(protect)},
+	{"cgi_ext", "CGI extensions", OFFSET(cgi_extensions)},
+	{"cgi_interp", "CGI interpreter to use", OFFSET(cgi_interpreter)},
+	{"cgi_env", "Custom CGI enviroment variables", OFFSET(cgi_environment)},
+	{"ssi_ext", "SSI extensions", OFFSET(ssi_extensions)},
+	{"auth_realm", "Authentication domain name", OFFSET(auth_domain)},
+	{"auth_gpass", "Global passwords file", OFFSET(global_passwords_file)},
+	{"auth_PUT", "PUT,DELETE auth file", OFFSET(put_delete_passwords_file)},
+	{"uid", "\tRun as user", OFFSET(uid)},
+	{"access_log", "Access log file", OFFSET(access_log_file)},
+	{"error_log", "Error log file", OFFSET(error_log_file)},
+	{"acl", "\tAllow/deny IP addresses/subnets", OFFSET(acl)},
+	{"num_threads", "Threads to spawn", OFFSET(num_threads)},
+	{"mime_types", "Extra mime types to use", OFFSET(mime_types)},
+	{NULL, NULL, 0}
+};
+
+static void
+show_usage_and_exit(const struct mg_config *config)
+{
+	const struct option_descriptor	*o;
+	const char			*value;
+
+	(void) fprintf(stderr,
+	    "Mongoose version %s (c) Sergey Lyubka\n"
+	    "usage: mongoose [options] [config_file]\n", mg_version());
+
+	fprintf(stderr, "  -A <htpasswd_file> <realm> <user> <passwd>\n");
+
+	for (o = known_options; o->name != NULL; o++) {
+		(void) fprintf(stderr, "  -%s\t%s", o->name, o->description);
+		value = * (char **) ((char *) config + o->offset);
+		if (value != NULL)
+			fprintf(stderr, " (default: \"%s\")", value);
+		fputc('\n', stderr);
+	}
+
+	exit(EXIT_FAILURE);
+}
+
+static void
+set_option(struct mg_config *config, const char *name, char *value)
+{
+	const struct option_descriptor *o;
+
+	for (o = known_options; o->name != NULL; o++)
+		if (strcmp(name, o->name) == 0) {
+			* (char **) ((char *) config + o->offset) = value;
+			break;
+		}
+
+	if (o->name == NULL)
+		show_usage_and_exit(config);
+}
+
 static void
 static void
-process_command_line_arguments(struct mg_context *ctx, char *argv[])
+process_command_line_arguments(struct mg_config *config, char *argv[])
 {
 {
 	const char	*config_file = CONFIG_FILE;
 	const char	*config_file = CONFIG_FILE;
 	char		line[512], opt[512], *vals[100],
 	char		line[512], opt[512], *vals[100],
@@ -110,11 +172,11 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
 	/* First find out, which config file to open */
 	/* First find out, which config file to open */
 	for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
 	for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
 		if (argv[i + 1] == NULL)
 		if (argv[i + 1] == NULL)
-			show_usage_and_exit();
+			show_usage_and_exit(config);
 
 
 	if (argv[i] != NULL && argv[i + 1] != NULL) {
 	if (argv[i] != NULL && argv[i + 1] != NULL) {
 		/* More than one non-option arguments are given */
 		/* More than one non-option arguments are given */
-		show_usage_and_exit();
+		show_usage_and_exit(config);
 	} else if (argv[i] != NULL) {
 	} else if (argv[i] != NULL) {
 		/* Just one non-option argument is given, this is config file */
 		/* Just one non-option argument is given, this is config file */
 		config_file = argv[i];
 		config_file = argv[i];
@@ -140,7 +202,8 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
 	(void) memset(vals, 0, sizeof(vals));
 	(void) memset(vals, 0, sizeof(vals));
 
 
 	if (fp != NULL) {
 	if (fp != NULL) {
-		(void) printf("Loading config file %s\n", config_file);
+		(void) printf("Loading config file %s, "
+		    "ignoring command line arguments\n", config_file);
 
 
 		/* Loop over the lines in config file */
 		/* Loop over the lines in config file */
 		while (fgets(line, sizeof(line), fp) != NULL) {
 		while (fgets(line, sizeof(line), fp) != NULL) {
@@ -156,56 +219,67 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
 				    config_file, (int) line_no);
 				    config_file, (int) line_no);
 				exit(EXIT_FAILURE);
 				exit(EXIT_FAILURE);
 			}
 			}
-			if (mg_set_option(ctx, opt, val) != 1)
-				exit(EXIT_FAILURE);
+			/* TODO(lsm): free this at some point */
+			p = malloc(strlen(val) + 1);
+			(void) strcpy(p, val);
+			set_option(config, opt, p);
 		}
 		}
 
 
 		(void) fclose(fp);
 		(void) fclose(fp);
+	} else {
+		for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
+			set_option(config, &argv[i][1], argv[i + 1]);
 	}
 	}
-
-	/* Now pass through the command line options */
-	for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
-		if (mg_set_option(ctx, &argv[i][1], argv[i + 1]) != 1)
-			exit(EXIT_FAILURE);
 }
 }
 
 
 int
 int
 main(int argc, char *argv[])
 main(int argc, char *argv[])
 {
 {
+	struct mg_config	config;
 	struct mg_context	*ctx;
 	struct mg_context	*ctx;
-	char			ports[1024], web_root[1024];
 
 
+	/* Initialize configuration with default values */
+	(void) memset(&config, 0, sizeof(config));
+        config.document_root = ".";
+        config.enable_directory_listing = "yes";
+        config.auth_domain = "mydomain.com";
+        config.num_threads = "20";
+        config.index_files = "index.html,index.htm,index.cgi";
+        config.cgi_extensions = ".cgi,.pl,.php";
+        config.ssi_extensions = ".shtml,.shtm";
+	config.listening_ports = "8080";
+
+	/* Edit passwords file if -A option is specified */
 	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') {
 	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') {
 		if (argc != 6)
 		if (argc != 6)
-			show_usage_and_exit();
+			show_usage_and_exit(&config);
 		exit(mg_edit_passwords(argv[2], argv[3], argv[4], argv[5]) ==
 		exit(mg_edit_passwords(argv[2], argv[3], argv[4], argv[5]) ==
 		    MG_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE);
 		    MG_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE);
 	}
 	}
 
 
+	/* Show usage if -h or --help options are specified */
 	if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
 	if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
-		show_usage_and_exit();
+		show_usage_and_exit(&config);
+
+	/* Update config based on command line arguments */
+	process_command_line_arguments(&config, argv);
 
 
+	/* Setup signal handler: quit on Ctrl-C */
 #ifndef _WIN32
 #ifndef _WIN32
 	(void) signal(SIGCHLD, signal_handler);
 	(void) signal(SIGCHLD, signal_handler);
 #endif /* _WIN32 */
 #endif /* _WIN32 */
 	(void) signal(SIGTERM, signal_handler);
 	(void) signal(SIGTERM, signal_handler);
 	(void) signal(SIGINT, signal_handler);
 	(void) signal(SIGINT, signal_handler);
 
 
-	if ((ctx = mg_start()) == NULL) {
+	/* Start Mongoose */
+	if ((ctx = mg_start(&config)) == NULL) {
 		(void) printf("%s\n", "Cannot initialize Mongoose context");
 		(void) printf("%s\n", "Cannot initialize Mongoose context");
 		exit(EXIT_FAILURE);
 		exit(EXIT_FAILURE);
 	}
 	}
 
 
-	process_command_line_arguments(ctx, argv);
-	(void) mg_get_option(ctx, "ports", ports, sizeof(ports));
-	if (ports[0] == '\0' &&
-	    mg_set_option(ctx, "ports", "8080") != MG_SUCCESS)
-		exit(EXIT_FAILURE);
-
-	(void) mg_get_option(ctx, "ports", ports, sizeof(ports));
-	(void) mg_get_option(ctx, "root", web_root, sizeof(web_root));
-	(void) printf("Mongoose %s started on port(s) \"%s\", "
-	    "serving directory \"%s\"\n", mg_version(), ports, web_root);
+	(void) printf("Mongoose %s started on port(s) %s "
+	    "with web root [%s]\n",
+	    mg_version(), config.listening_ports, config.document_root);
 
 
 	fflush(stdout);
 	fflush(stdout);
 	while (exit_flag == 0)
 	while (exit_flag == 0)

File diff suppressed because it is too large
+ 135 - 433
mongoose.c


+ 50 - 64
mongoose.h

@@ -59,8 +59,21 @@ struct mg_request_info {
 
 
 
 
 /*
 /*
- * Error codes for all functions that return 'int'.
+ * User-defined handler function. It must return MG_SUCCESS or MG_ERROR.
+ *
+ * If handler returns MG_SUCCESS, that means that handler has processed the
+ * request by sending appropriate HTTP reply to the client. Mongoose treats
+ * the request as served.
+ *
+ * If callback returns MG_ERROR, that means that callback has not processed
+ * the request. Handler must not send any data to the client in this case.
+ * Mongoose proceeds with request handling as if nothing happened.
+ *
+ * NOTE: ssl_password_handler must have the following prototype:
+ *      int (*)(char *, int, int, void *)
+ * Refer to OpenSSL documentation for more details.
  */
  */
+
 enum mg_error_t {
 enum mg_error_t {
 	MG_ERROR,
 	MG_ERROR,
 	MG_SUCCESS,
 	MG_SUCCESS,
@@ -68,15 +81,48 @@ enum mg_error_t {
 	MG_BUFFER_TOO_SMALL
 	MG_BUFFER_TOO_SMALL
 };
 };
 
 
+typedef enum mg_error_t (*mg_callback_t)(struct mg_connection *,
+		const struct mg_request_info *);
+
+/*
+ * This structure describes Mongoose configuration.
+ */
+struct mg_config {
+	char *document_root;
+	char *index_files;
+	char *ssl_certificate;
+	char *listening_ports;
+	char *cgi_extensions;
+	char *cgi_interpreter;
+	char *cgi_environment;
+	char *ssi_extensions;
+	char *auth_domain;
+	char *protect;
+	char *global_passwords_file;
+	char *put_delete_passwords_file;
+	char *access_log_file;
+	char *error_log_file;
+	char *acl;
+	char *uid;
+	char *mime_types;
+	char *enable_directory_listing;
+	char *num_threads;
+
+	mg_callback_t new_request_handler;
+	mg_callback_t http_error_handler;
+	mg_callback_t event_log_handler;
+	mg_callback_t ssl_password_handler;
+};
+
 
 
 /*
 /*
  * Start the web server.
  * Start the web server.
  *
  *
  * This must be the first function called by the application.
  * This must be the first function called by the application.
  * It creates a serving thread, and returns a context structure that
  * It creates a serving thread, and returns a context structure that
- * can be used to alter the configuration, and stop the server.
+ * can be used to stop the server.
  */
  */
-struct mg_context *mg_start(void);
+struct mg_context *mg_start(struct mg_config *);
 
 
 
 
 /*
 /*
@@ -90,32 +136,6 @@ void mg_stop(struct mg_context *);
 
 
 
 
 /*
 /*
- * Get the current value of a particular option.
- *
- * Return:
- *  MG_SUCCESS, MG_NOT_FOUND, MG_BUFFER_TOO_SMALL
- */
-enum mg_error_t mg_get_option(struct mg_context *,
-		const char *option_name, char *buf, size_t buf_len);
-
-
-/*
- * Set a value for a particular option.
- *
- * Mongoose makes an internal copy of the option value string, which must be
- * valid nul-terminated ASCII or UTF-8 string. It is safe to change any option
- * at any time. The order of setting various options is also irrelevant with
- * one exception: if "ports" option contains SSL listening ports, a "ssl_cert"
- * option must be set BEFORE the "ports" option.
- *
- * Return:
- *  MG_ERROR, MG_SUCCESS, or MG_NOT_FOUND if option is unknown.
- */
-enum mg_error_t mg_set_option(struct mg_context *,
-		const char *name, const char *value);
-
-
-/*
  * Add, edit or delete the entry in the passwords file.
  * Add, edit or delete the entry in the passwords file.
  *
  *
  * This function allows an application to manipulate .htpasswd files on the
  * This function allows an application to manipulate .htpasswd files on the
@@ -134,36 +154,6 @@ enum mg_error_t mg_modify_passwords_file(struct mg_context *ctx,
 
 
 
 
 /*
 /*
- * Attach a callback function to certain event.
- * Callback must return MG_SUCCESS or MG_ERROR.
- *
- * If callback returns MG_SUCCESS, that means that callback has processed the
- * request by sending appropriate HTTP reply to the client. Mongoose treats
- * the request as served.
- *
- * If callback returns MG_ERROR, that means that callback has not processed
- * the request. Callback must not send any data to client in this case.
- * Mongoose proceeds with request handling.
- *
- * NOTE: for MG_EVENT_SSL_PASSWORD event the callback must have
- * int (*)(char *, int, int, void *) prototype. Refer to OpenSSL documentation
- * for more details about the SSL password callback.
- */
-enum mg_event_t {
-	MG_EVENT_NEW_REQUEST,	/* New HTTP request has arrived		*/
-	MG_EVENT_HTTP_ERROR,	/* Mongoose is about to send HTTP error	*/
-	MG_EVENT_LOG,		/* Mongoose is about to log a message	*/
-	MG_EVENT_SSL_PASSWORD,	/* SSL certificate needs verification	*/
-	NUM_EVENTS
-};
-
-typedef enum mg_error_t (*mg_callback_t)(struct mg_connection *,
-		const struct mg_request_info *);
-
-void mg_set_callback(struct mg_context *, enum mg_event_t, mg_callback_t);
-
-
-/*
  * Send data to the client.
  * Send data to the client.
  */
  */
 int mg_write(struct mg_connection *, const void *buf, size_t len);
 int mg_write(struct mg_connection *, const void *buf, size_t len);
@@ -185,6 +175,7 @@ int mg_printf(struct mg_connection *, const char *fmt, ...);
  */
  */
 int mg_read(struct mg_connection *, void *buf, size_t len);
 int mg_read(struct mg_connection *, void *buf, size_t len);
 
 
+
 /*
 /*
  * Get the value of particular HTTP header.
  * Get the value of particular HTTP header.
  *
  *
@@ -247,11 +238,6 @@ const char *mg_version(void);
 void mg_md5(char *buf, ...);
 void mg_md5(char *buf, ...);
 
 
 
 
-/*
- * Print command line usage string.
- */
-void mg_show_usage_string(FILE *fp);
-
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif /* __cplusplus */
 #endif /* __cplusplus */

+ 3 - 3
test/test.pl

@@ -13,12 +13,11 @@ sub on_windows { $^O =~ /win32/i; }
 my $port = 23456;
 my $port = 23456;
 my $pid = undef;
 my $pid = undef;
 my $num_requests;
 my $num_requests;
-my $root = 'test';
 my $dir_separator = on_windows() ? '\\' : '/';
 my $dir_separator = on_windows() ? '\\' : '/';
 my $copy_cmd = on_windows() ? 'copy' : 'cp';
 my $copy_cmd = on_windows() ? 'copy' : 'cp';
 my $test_dir_uri = "test_dir";
 my $test_dir_uri = "test_dir";
+my $root = 'test';
 my $test_dir = $root . $dir_separator. $test_dir_uri;
 my $test_dir = $root . $dir_separator. $test_dir_uri;
-my $alias = "/aliased=/etc/,/ta=$test_dir";
 my $config = 'mongoose.conf';
 my $config = 'mongoose.conf';
 my $exe = '.' . $dir_separator . 'mongoose';
 my $exe = '.' . $dir_separator . 'mongoose';
 my $embed_exe = '.' . $dir_separator . 'embed';
 my $embed_exe = '.' . $dir_separator . 'embed';
@@ -89,6 +88,7 @@ sub o {
 # Spawn a server listening on specified port
 # Spawn a server listening on specified port
 sub spawn {
 sub spawn {
   my ($cmdline) = @_;
   my ($cmdline) = @_;
+  print 'Executing: ', @_, "\n";
   if (on_windows()) {
   if (on_windows()) {
     my @args = split /\s+/, $cmdline;
     my @args = split /\s+/, $cmdline;
     my $executable = $args[0];
     my $executable = $args[0];
@@ -159,7 +159,7 @@ kill_spawned_child();
 my $cmd = "$exe -ports $port -access_log access.log -error_log debug.log ".
 my $cmd = "$exe -ports $port -access_log access.log -error_log debug.log ".
 "-cgi_env CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
 "-cgi_env CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
 "-mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " .
 "-mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " .
-"-root test -aliases $alias -admin_uri /hh";
+"-root $root,/aiased=/etc/,/ta=$test_dir";
 $cmd .= ' -cgi_interp perl' if on_windows();
 $cmd .= ' -cgi_interp perl' if on_windows();
 spawn($cmd);
 spawn($cmd);
 
 

Some files were not shown because too many files changed in this diff