From 5f25a88821da66e14f0fdf3f1a947d439cdd4bbe Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sun, 2 Mar 2014 18:27:51 +0000 Subject: [PATCH] Restored SSI functionality --- mongoose.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/mongoose.c b/mongoose.c index 30b58f0b..62f92b58 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1094,6 +1094,9 @@ enum { #ifndef _WIN32 RUN_AS_USER, #endif +#ifndef MONGOOSE_NO_SSI + SSI_PATTERN, +#endif #ifdef NS_ENABLE_SSL SSL_CERTIFICATE, #endif @@ -1132,6 +1135,9 @@ static const char *static_config_options[] = { #ifndef _WIN32 "run_as_user", NULL, #endif +#ifndef MONGOOSE_NO_SSI + "ssi_pattern", "**.shtml$|**.shtm$", +#endif #ifdef NS_ENABLE_SSL "ssl_certificate", NULL, #endif @@ -3944,6 +3950,162 @@ static void handle_lsp_request(struct connection *conn, const char *path, } #endif // MONGOOSE_USE_LUA +#ifndef MONGOOSE_NO_SSI +static void send_ssi_file(struct mg_connection *, const char *, FILE *, int); + +static void send_file_data(struct mg_connection *conn, FILE *fp) { + char buf[IOBUF_SIZE]; + int n; + while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { + mg_write(conn, buf, n); + } +} + +static void do_ssi_include(struct mg_connection *conn, const char *ssi, + char *tag, int include_level) { + char file_name[IOBUF_SIZE], path[MAX_PATH_SIZE], *p; + char **opts = (MG_CONN_2_CONN(conn))->server->config_options; + FILE *fp; + + // sscanf() is safe here, since send_ssi_file() also uses buffer + // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN. + if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) { + // File name is relative to the webserver root + mg_snprintf(path, sizeof(path), "%s%c%s", + opts[DOCUMENT_ROOT], '/', file_name); + } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) { + // File name is relative to the webserver working directory + // or it is absolute system path + mg_snprintf(path, sizeof(path), "%s", file_name); + } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 || + sscanf(tag, " \"%[^\"]\"", file_name) == 1) { + // File name is relative to the currect document + mg_snprintf(path, sizeof(path), "%s", ssi); + if ((p = strrchr(path, '/')) != NULL) { + p[1] = '\0'; + } + mg_snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s", + file_name); + } else { + mg_printf(conn, "Bad SSI #include: [%s]", tag); + return; + } + + if ((fp = fopen(path, "rb")) == NULL) { + mg_printf(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", + tag, path, strerror(errno)); + } else { + ns_set_close_on_exec(fileno(fp)); + if (match_prefix(opts[SSI_PATTERN], strlen(opts[SSI_PATTERN]), path) > 0) { + send_ssi_file(conn, path, fp, include_level + 1); + } else { + send_file_data(conn, fp); + } + fclose(fp); + } +} + +#ifndef MONGOOSE_NO_POPEN +static void do_ssi_exec(struct mg_connection *conn, char *tag) { + char cmd[IOBUF_SIZE]; + FILE *fp; + + if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) { + mg_printf(conn, "Bad SSI #exec: [%s]", tag); + } else if ((fp = popen(cmd, "r")) == NULL) { + mg_printf(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno)); + } else { + send_file_data(conn, fp); + pclose(fp); + } +} +#endif // !MONGOOSE_NO_POPEN + +static void send_ssi_file(struct mg_connection *conn, const char *path, + FILE *fp, int include_level) { + char buf[IOBUF_SIZE]; + int ch, offset, len, in_ssi_tag; + + if (include_level > 10) { + mg_printf(conn, "SSI #include level is too deep (%s)", path); + return; + } + + in_ssi_tag = len = offset = 0; + while ((ch = fgetc(fp)) != EOF) { + if (in_ssi_tag && ch == '>') { + in_ssi_tag = 0; + buf[len++] = (char) ch; + buf[len] = '\0'; + assert(len <= (int) sizeof(buf)); + if (len < 6 || memcmp(buf, "