瀏覽代碼

Merge branch 'cgi' of https://github.com/civetweb/civetweb

- 4 年之前
父節點
當前提交
77329cd0a6
共有 3 個文件被更改,包括 179 次插入67 次删除
  1. 14 7
      docs/UserManual.md
  2. 137 58
      src/civetweb.c
  3. 28 2
      src/main.c

+ 14 - 7
docs/UserManual.md

@@ -250,6 +250,13 @@ allows CGI files be anywhere. To restrict CGIs to a certain directory,
 use `/path/to/cgi-bin/**.cgi` as the pattern. Note that the full file path is
 use `/path/to/cgi-bin/**.cgi` as the pattern. Note that the full file path is
 matched against the pattern, not the URI.
 matched against the pattern, not the URI.
 
 
+Depending on the build configuration, additional patterns `cgi2_pattern`,
+`cgi3_pattern` and `cgi4_pattern` may be available.
+This allows to use different cgi interpreter programs (`cgi2_interpreter`,
+...), environments (`cgi2_environment` ...) and interpreter arguments
+(`cgi2_interpreter_argument`, ...). The default for all additional CGI file
+patterns is empty - they are not used unless they are configured explicitly.
+
 ### cgi\_timeout\_ms
 ### cgi\_timeout\_ms
 Maximum allowed runtime for CGI scripts.  CGI processes are terminated by
 Maximum allowed runtime for CGI scripts.  CGI processes are terminated by
 the server after this time.  The default is "no timeout", so scripts may
 the server after this time.  The default is "no timeout", so scripts may
@@ -441,12 +448,12 @@ communicate the port number to clients via other means, for example mDNS
 In case the server has been built with the `USE_X_DOM_SOCKET` option set,
 In case the server has been built with the `USE_X_DOM_SOCKET` option set,
 it can listen to unix domain sockets as well. They are specified by a
 it can listen to unix domain sockets as well. They are specified by a
 lower case `x` followed by the domain socket path, e.g. `x/tmp/sockname`.
 lower case `x` followed by the domain socket path, e.g. `x/tmp/sockname`.
-Domain sockets do not require a port number, always use HTTP (not HTTPS) 
-and never redirect. Thus `:` is not allowed, while `r` or `s` at the end 
+Domain sockets do not require a port number, always use HTTP (not HTTPS)
+and never redirect. Thus `:` is not allowed, while `r` or `s` at the end
 of the configuration is interpreted as part of the domain socket path.
 of the configuration is interpreted as part of the domain socket path.
-The domain sochet path must be a valid path to a non-existing file on a 
+The domain sochet path must be a valid path to a non-existing file on a
 Unix/Linux system. The CivetWeb process needs write/create access rights
 Unix/Linux system. The CivetWeb process needs write/create access rights
-to create the domain socket in the Unix/Linux file system. 
+to create the domain socket in the Unix/Linux file system.
 Use only alphanumerical characters, underscore and `/` in a domain socket
 Use only alphanumerical characters, underscore and `/` in a domain socket
 path (in particular, `,;:` must be avoided).
 path (in particular, `,;:` must be avoided).
 
 
@@ -463,8 +470,8 @@ files, ...), check for external resources, remove old log files, etc.
 
 
 The Lua state remains open until the server is stopped.
 The Lua state remains open until the server is stopped.
 
 
-For a detailed descriotion of available Lua callbacks see section 
-"Lua background script" below. 
+For a detailed descriotion of available Lua callbacks see section
+"Lua background script" below.
 
 
 ### lua\_background\_script\_params
 ### lua\_background\_script\_params
 Can add dynamic parameters to background script.
 Can add dynamic parameters to background script.
@@ -1037,7 +1044,7 @@ before any client is able to connect. It can be used for preparation and
 maintenance tasks, e.g., for preparing the web contents, cleaning log files,
 maintenance tasks, e.g., for preparing the web contents, cleaning log files,
 etc.
 etc.
 
 
-The Name of the script file including path is configured as `lua_background_script`. 
+The Name of the script file including path is configured as `lua_background_script`.
 Additional parameters can be supplied using `lua_background_script_params`.
 Additional parameters can be supplied using `lua_background_script_params`.
 
 
 The background script is loaded before the server is ready to start.
 The background script is loaded before the server is ready to start.

+ 137 - 58
src/civetweb.c

@@ -2099,19 +2099,40 @@ enum {
 	DOCUMENT_ROOT,
 	DOCUMENT_ROOT,
 
 
 	CGI_EXTENSIONS,
 	CGI_EXTENSIONS,
-	CGI2_EXTENSIONS,
 	CGI_ENVIRONMENT,
 	CGI_ENVIRONMENT,
-	CGI2_ENVIRONMENT,
 	CGI_INTERPRETER,
 	CGI_INTERPRETER,
-	CGI2_INTERPRETER,
 	CGI_INTERPRETER_ARGS,
 	CGI_INTERPRETER_ARGS,
-	CGI2_INTERPRETER_ARGS,
 #if defined(USE_TIMERS)
 #if defined(USE_TIMERS)
 	CGI_TIMEOUT,
 	CGI_TIMEOUT,
+#endif
+
+	CGI2_EXTENSIONS,
+	CGI2_ENVIRONMENT,
+	CGI2_INTERPRETER,
+	CGI2_INTERPRETER_ARGS,
+#if defined(USE_TIMERS)
 	CGI2_TIMEOUT,
 	CGI2_TIMEOUT,
 #endif
 #endif
 
 
-	PUT_DELETE_PASSWORDS_FILE,
+#if defined(USE_4_CGI)
+	CGI3_EXTENSIONS,
+	CGI3_ENVIRONMENT,
+	CGI3_INTERPRETER,
+	CGI3_INTERPRETER_ARGS,
+#if defined(USE_TIMERS)
+	CGI3_TIMEOUT,
+#endif
+
+	CGI4_EXTENSIONS,
+	CGI4_ENVIRONMENT,
+	CGI4_INTERPRETER,
+	CGI4_INTERPRETER_ARGS,
+#if defined(USE_TIMERS)
+	CGI4_TIMEOUT,
+#endif
+#endif
+
+	PUT_DELETE_PASSWORDS_FILE, /* must follow CGI_* */
 	PROTECT_URI,
 	PROTECT_URI,
 	AUTHENTICATION_DOMAIN,
 	AUTHENTICATION_DOMAIN,
 	ENABLE_AUTH_DOMAIN_CHECK,
 	ENABLE_AUTH_DOMAIN_CHECK,
@@ -2218,18 +2239,39 @@ static const struct mg_option config_options[] = {
     {"document_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
     {"document_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
 
 
     {"cgi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
     {"cgi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
-    {"cgi2_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
     {"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
     {"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
-    {"cgi2_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
     {"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL},
     {"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL},
-    {"cgi2_interpreter", MG_CONFIG_TYPE_FILE, NULL},
     {"cgi_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
     {"cgi_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
-    {"cgi2_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
 #if defined(USE_TIMERS)
 #if defined(USE_TIMERS)
     {"cgi_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
     {"cgi_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
+#endif
+
+    {"cgi2_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
+    {"cgi2_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
+    {"cgi2_interpreter", MG_CONFIG_TYPE_FILE, NULL},
+    {"cgi2_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
+#if defined(USE_TIMERS)
     {"cgi2_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
     {"cgi2_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
 #endif
 #endif
 
 
+#if defined(USE_4_CGI)
+    {"cgi3_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
+    {"cgi3_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
+    {"cgi3_interpreter", MG_CONFIG_TYPE_FILE, NULL},
+    {"cgi3_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
+#if defined(USE_TIMERS)
+    {"cgi3_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
+#endif
+
+    {"cgi2_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
+    {"cgi4_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
+    {"cgi4_interpreter", MG_CONFIG_TYPE_FILE, NULL},
+    {"cgi4_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
+#if defined(USE_TIMERS)
+    {"cgi4_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
+#endif
+#endif
+
     {"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
     {"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
     {"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL},
     {"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL},
     {"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"},
     {"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"},
@@ -5548,7 +5590,8 @@ spawn_process(struct mg_connection *conn,
               int fdin[2],
               int fdin[2],
               int fdout[2],
               int fdout[2],
               int fderr[2],
               int fderr[2],
-              const char *dir)
+              const char *dir,
+              unsigned char cgi_config_idx)
 {
 {
 	HANDLE me;
 	HANDLE me;
 	char *interp;
 	char *interp;
@@ -5605,11 +5648,12 @@ spawn_process(struct mg_connection *conn,
 
 
 	/* First check, if there is a CGI interpreter configured for all CGI
 	/* First check, if there is a CGI interpreter configured for all CGI
 	 * scripts. */
 	 * scripts. */
-	interp = conn->dom_ctx->config[CGI_INTERPRETER];
+	interp = conn->dom_ctx->config[CGI_INTERPRETER + cgi_config_idx];
 	if (interp != NULL) {
 	if (interp != NULL) {
 		/* If there is a configured interpreter, check for additional arguments
 		/* If there is a configured interpreter, check for additional arguments
 		 */
 		 */
-		interp_arg = conn->dom_ctx->config[CGI_INTERPRETER_ARGS];
+		interp_arg =
+		    conn->dom_ctx->config[CGI_INTERPRETER_ARGS + cgi_config_idx];
 	} else {
 	} else {
 		/* Otherwise, the interpreter must be stated in the first line of the
 		/* Otherwise, the interpreter must be stated in the first line of the
 		 * CGI script file, after a #! (shebang) mark. */
 		 * CGI script file, after a #! (shebang) mark. */
@@ -5858,7 +5902,8 @@ spawn_process(struct mg_connection *conn,
               int fdin[2],
               int fdin[2],
               int fdout[2],
               int fdout[2],
               int fderr[2],
               int fderr[2],
-              const char *dir)
+              const char *dir,
+              unsigned char cgi_config_idx)
 {
 {
 	pid_t pid;
 	pid_t pid;
 	const char *interp;
 	const char *interp;
@@ -5921,7 +5966,7 @@ spawn_process(struct mg_connection *conn,
 			sa.sa_handler = SIG_DFL;
 			sa.sa_handler = SIG_DFL;
 			sigaction(SIGCHLD, &sa, NULL);
 			sigaction(SIGCHLD, &sa, NULL);
 
 
-			interp = conn->dom_ctx->config[CGI_INTERPRETER];
+			interp = conn->dom_ctx->config[CGI_INTERPRETER + cgi_config_idx];
 			if (interp == NULL) {
 			if (interp == NULL) {
 				/* no interpreter configured, call the programm directly */
 				/* no interpreter configured, call the programm directly */
 				(void)execle(prog, prog, NULL, envp);
 				(void)execle(prog, prog, NULL, envp);
@@ -5933,7 +5978,8 @@ spawn_process(struct mg_connection *conn,
 			} else {
 			} else {
 				/* call the configured interpreter */
 				/* call the configured interpreter */
 				const char *interp_args =
 				const char *interp_args =
-				    conn->dom_ctx->config[CGI_INTERPRETER_ARGS];
+				    conn->dom_ctx
+				        ->config[CGI_INTERPRETER_ARGS + cgi_config_idx];
 
 
 				if ((interp_args != NULL) && (interp_args[0] != 0)) {
 				if ((interp_args != NULL) && (interp_args[0] != 0)) {
 					(void)execle(interp, interp, interp_args, prog, NULL, envp);
 					(void)execle(interp, interp, interp_args, prog, NULL, envp);
@@ -7391,15 +7437,9 @@ extention_matches_script(
 )
 )
 {
 {
 #if !defined(NO_CGI)
 #if !defined(NO_CGI)
-	if (match_prefix_strlen(conn->dom_ctx->config[CGI_EXTENSIONS], filename)
-	    > 0) {
-		return 1;
-	}
-	if (match_prefix_strlen(conn->dom_ctx->config[CGI2_EXTENSIONS], filename)
-	    > 0) {
-		return 1;
-	}
+	unsigned char cgi_config_idx, inc, max;
 #endif
 #endif
+
 #if defined(USE_LUA)
 #if defined(USE_LUA)
 	if (match_prefix_strlen(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
 	if (match_prefix_strlen(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
 	                        filename)
 	                        filename)
@@ -7414,6 +7454,19 @@ extention_matches_script(
 		return 1;
 		return 1;
 	}
 	}
 #endif
 #endif
+#if !defined(NO_CGI)
+	inc = CGI2_EXTENSIONS - CGI_EXTENSIONS;
+	max = PUT_DELETE_PASSWORDS_FILE - CGI_EXTENSIONS;
+	for (cgi_config_idx = 0; cgi_config_idx < max; cgi_config_idx += inc) {
+		if ((conn->dom_ctx->config[CGI_EXTENSIONS + cgi_config_idx] != NULL)
+		    && (match_prefix_strlen(
+		            conn->dom_ctx->config[CGI_EXTENSIONS + cgi_config_idx],
+		            filename)
+		        > 0)) {
+			return 1;
+		}
+	}
+#endif
 	/* filename and conn could be unused, if all preocessor conditions
 	/* filename and conn could be unused, if all preocessor conditions
 	 * are false (no script language supported). */
 	 * are false (no script language supported). */
 	(void)filename;
 	(void)filename;
@@ -11023,7 +11076,8 @@ addenv(struct cgi_environment *env, const char *fmt, ...)
 static int
 static int
 prepare_cgi_environment(struct mg_connection *conn,
 prepare_cgi_environment(struct mg_connection *conn,
                         const char *prog,
                         const char *prog,
-                        struct cgi_environment *env)
+                        struct cgi_environment *env,
+                        unsigned char cgi_config_idx)
 {
 {
 	const char *s;
 	const char *s;
 	struct vec var_vec;
 	struct vec var_vec;
@@ -11198,7 +11252,7 @@ prepare_cgi_environment(struct mg_connection *conn,
 	}
 	}
 
 
 	/* Add user-specified variables */
 	/* Add user-specified variables */
-	s = conn->dom_ctx->config[CGI_ENVIRONMENT];
+	s = conn->dom_ctx->config[CGI_ENVIRONMENT + cgi_config_idx];
 	while ((s = next_option(s, &var_vec, NULL)) != NULL) {
 	while ((s = next_option(s, &var_vec, NULL)) != NULL) {
 		addenv(env, "%.*s", (int)var_vec.len, var_vec.ptr);
 		addenv(env, "%.*s", (int)var_vec.len, var_vec.ptr);
 	}
 	}
@@ -11252,7 +11306,9 @@ abort_cgi_process(void *data)
 
 
 /* Local (static) function assumes all arguments are valid. */
 /* Local (static) function assumes all arguments are valid. */
 static void
 static void
-handle_cgi_request(struct mg_connection *conn, const char *prog)
+handle_cgi_request(struct mg_connection *conn,
+                   const char *prog,
+                   unsigned char cgi_config_idx)
 {
 {
 	char *buf;
 	char *buf;
 	size_t buflen;
 	size_t buflen;
@@ -11269,9 +11325,10 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 
 
 #if defined(USE_TIMERS)
 #if defined(USE_TIMERS)
 	double cgi_timeout;
 	double cgi_timeout;
-	if (conn->dom_ctx->config[CGI_TIMEOUT]) {
+	if (conn->dom_ctx->config[CGI_TIMEOUT + cgi_config_idx]) {
 		/* Get timeout in seconds */
 		/* Get timeout in seconds */
-		cgi_timeout = atof(conn->dom_ctx->config[CGI_TIMEOUT]) * 0.001;
+		cgi_timeout =
+		    atof(conn->dom_ctx->config[CGI_TIMEOUT + cgi_config_idx]) * 0.001;
 	} else {
 	} else {
 		cgi_timeout =
 		cgi_timeout =
 		    atof(config_options[REQUEST_TIMEOUT].default_value) * 0.001;
 		    atof(config_options[REQUEST_TIMEOUT].default_value) * 0.001;
@@ -11281,7 +11338,7 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 
 
 	buf = NULL;
 	buf = NULL;
 	buflen = conn->phys_ctx->max_request_size;
 	buflen = conn->phys_ctx->max_request_size;
-	i = prepare_cgi_environment(conn, prog, &blk);
+	i = prepare_cgi_environment(conn, prog, &blk, cgi_config_idx);
 	if (i != 0) {
 	if (i != 0) {
 		blk.buf = NULL;
 		blk.buf = NULL;
 		blk.var = NULL;
 		blk.var = NULL;
@@ -11330,7 +11387,8 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 	}
 	}
 
 
 	DEBUG_TRACE("CGI: spawn %s %s\n", dir, p);
 	DEBUG_TRACE("CGI: spawn %s %s\n", dir, p);
-	pid = spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir);
+	pid = spawn_process(
+	    conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir, cgi_config_idx);
 
 
 	if (pid == (pid_t)-1) {
 	if (pid == (pid_t)-1) {
 		status = strerror(ERRNO);
 		status = strerror(ERRNO);
@@ -14502,15 +14560,18 @@ handle_file_based_request(struct mg_connection *conn,
                           const char *path,
                           const char *path,
                           struct mg_file *file)
                           struct mg_file *file)
 {
 {
+#if !defined(NO_CGI)
+	unsigned char cgi_config_idx, inc, max;
+#endif
+
 	if (!conn || !conn->dom_ctx) {
 	if (!conn || !conn->dom_ctx) {
 		return;
 		return;
 	}
 	}
 
 
-	if (0) {
 #if defined(USE_LUA)
 #if defined(USE_LUA)
-	} else if (match_prefix_strlen(
-	               conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS], path)
-	           > 0) {
+	if (match_prefix_strlen(conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
+	                        path)
+	    > 0) {
 		if (is_in_script_path(conn, path)) {
 		if (is_in_script_path(conn, path)) {
 			/* Lua server page: an SSI like page containing mostly plain
 			/* Lua server page: an SSI like page containing mostly plain
 			 * html code plus some tags with server generated contents. */
 			 * html code plus some tags with server generated contents. */
@@ -14519,25 +14580,27 @@ handle_file_based_request(struct mg_connection *conn,
 			/* Script was in an illegal path */
 			/* Script was in an illegal path */
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 		}
 		}
+		return;
+	}
 
 
-	} else if (match_prefix_strlen(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
-	                               path)
-	           > 0) {
+	if (match_prefix_strlen(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS], path)
+	    > 0) {
 		if (is_in_script_path(conn, path)) {
 		if (is_in_script_path(conn, path)) {
 			/* Lua in-server module script: a CGI like script used to
 			/* Lua in-server module script: a CGI like script used to
-			 * generate
-			 * the
-			 * entire reply. */
+			 * generate the entire reply. */
 			mg_exec_lua_script(conn, path, NULL);
 			mg_exec_lua_script(conn, path, NULL);
 		} else {
 		} else {
 			/* Script was in an illegal path */
 			/* Script was in an illegal path */
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 		}
 		}
+		return;
+	}
 #endif
 #endif
+
 #if defined(USE_DUKTAPE)
 #if defined(USE_DUKTAPE)
-	} else if (match_prefix_strlen(
-	               conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS], path)
-	           > 0) {
+	if (match_prefix_strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
+	                        path)
+	    > 0) {
 		if (is_in_script_path(conn, path)) {
 		if (is_in_script_path(conn, path)) {
 			/* Call duktape to generate the page */
 			/* Call duktape to generate the page */
 			mg_exec_duktape_script(conn, path);
 			mg_exec_duktape_script(conn, path);
@@ -14545,35 +14608,51 @@ handle_file_based_request(struct mg_connection *conn,
 			/* Script was in an illegal path */
 			/* Script was in an illegal path */
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 		}
 		}
+		return;
+	}
 #endif
 #endif
+
 #if !defined(NO_CGI)
 #if !defined(NO_CGI)
-	} else if (match_prefix_strlen(conn->dom_ctx->config[CGI_EXTENSIONS], path)
-	           > 0) {
-		if (is_in_script_path(conn, path)) {
-			/* CGI scripts may support all HTTP methods */
-			handle_cgi_request(conn, path);
-		} else {
-			/* Script was in an illegal path */
-			mg_send_http_error(conn, 403, "%s", "Forbidden");
+	inc = CGI2_EXTENSIONS - CGI_EXTENSIONS;
+	max = PUT_DELETE_PASSWORDS_FILE - CGI_EXTENSIONS;
+	for (cgi_config_idx = 0; cgi_config_idx < max; cgi_config_idx += inc) {
+		if (conn->dom_ctx->config[CGI_EXTENSIONS + cgi_config_idx] != NULL) {
+			if (match_prefix_strlen(
+			        conn->dom_ctx->config[CGI_EXTENSIONS + cgi_config_idx],
+			        path)
+			    > 0) {
+				if (is_in_script_path(conn, path)) {
+					/* CGI scripts may support all HTTP methods */
+					handle_cgi_request(conn, path, 0);
+				} else {
+					/* Script was in an illegal path */
+					mg_send_http_error(conn, 403, "%s", "Forbidden");
+				}
+				return;
+			}
 		}
 		}
+	}
 #endif /* !NO_CGI */
 #endif /* !NO_CGI */
-	} else if (match_prefix_strlen(conn->dom_ctx->config[SSI_EXTENSIONS], path)
-	           > 0) {
+
+	if (match_prefix_strlen(conn->dom_ctx->config[SSI_EXTENSIONS], path) > 0) {
 		if (is_in_script_path(conn, path)) {
 		if (is_in_script_path(conn, path)) {
 			handle_ssi_file_request(conn, path, file);
 			handle_ssi_file_request(conn, path, file);
 		} else {
 		} else {
 			/* Script was in an illegal path */
 			/* Script was in an illegal path */
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 			mg_send_http_error(conn, 403, "%s", "Forbidden");
 		}
 		}
+		return;
+	}
+
 #if !defined(NO_CACHING)
 #if !defined(NO_CACHING)
-	} else if ((!conn->in_error_handler)
-	           && is_not_modified(conn, &file->stat)) {
+	if ((!conn->in_error_handler) && is_not_modified(conn, &file->stat)) {
 		/* Send 304 "Not Modified" - this must not send any body data */
 		/* Send 304 "Not Modified" - this must not send any body data */
 		handle_not_modified_static_file_request(conn, file);
 		handle_not_modified_static_file_request(conn, file);
-#endif /* !NO_CACHING */
-	} else {
-		handle_static_file_request(conn, path, file, NULL, NULL);
+		return;
 	}
 	}
+#endif /* !NO_CACHING */
+
+	handle_static_file_request(conn, path, file, NULL, NULL);
 }
 }
 #endif /* NO_FILESYSTEMS */
 #endif /* NO_FILESYSTEMS */
 
 

+ 28 - 2
src/main.c

@@ -2276,6 +2276,32 @@ add_control(struct dlg_complete *dlg,
 }
 }
 
 
 
 
+static int
+optioncmp(const char *o1, const char *o2)
+{
+	/* string compare for option names */
+	while (*o1 || *o2) {
+		int c1 = 256 * (int)*o1;
+		int c2 = 256 * (int)*o2;
+		if (isalpha(*o1))
+			c1 = toupper(*o1);
+		else if (*o1 == '_')
+			c1 = 1;
+		if (isalpha(*o2))
+			c2 = toupper(*o2);
+		else if (*o2 == '_')
+			c2 = 1;
+		if (c1 < c2)
+			return -1;
+		if (c1 > c2)
+			return +1;
+		o1++;
+		o2++;
+	}
+	return 0;
+}
+
+
 static void
 static void
 show_settings_dialog()
 show_settings_dialog()
 {
 {
@@ -2352,8 +2378,8 @@ show_settings_dialog()
 	for (;;) {
 	for (;;) {
 		int swapped = 0;
 		int swapped = 0;
 		for (i = 1; i < NO_OF_OPTIONS; i++) {
 		for (i = 1; i < NO_OF_OPTIONS; i++) {
-			if (strcmp(cv_options[option_index[i - 1]].name,
-			           cv_options[option_index[i]].name)
+			if (optioncmp(cv_options[option_index[i - 1]].name,
+			              cv_options[option_index[i]].name)
 			    > 0) {
 			    > 0) {
 				short swap = option_index[i];
 				short swap = option_index[i];
 				option_index[i] = option_index[i - 1];
 				option_index[i] = option_index[i - 1];