From e7ccb97c1998fb099031c8e7c06d5aab323bbb50 Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Sat, 10 Dec 2016 22:11:48 +0100 Subject: [PATCH] Moved SSI functions to own file --- Makefile | 1 + src/httplib_ssi.c | 239 +++++++++++++++++++++++++++++++++++++++ src/libhttp-private.h | 13 ++- src/libhttp.c | 253 ++++-------------------------------------- 4 files changed, 272 insertions(+), 234 deletions(-) create mode 100644 src/httplib_ssi.c diff --git a/Makefile b/Makefile index 7ccbe71a..c895d675 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,7 @@ LIB_SOURCES = src/libhttp.c \ src/httplib_set_throttle.c \ src/httplib_set_uid_option.c \ src/httplib_set_websocket_handler.c \ + src/httplib_ssi.c \ src/httplib_ssl_error.c \ src/httplib_ssl_get_client_cert_info.c \ src/httplib_ssl_get_protocol.c \ diff --git a/src/httplib_ssi.c b/src/httplib_ssi.c new file mode 100644 index 00000000..8f9cf61b --- /dev/null +++ b/src/httplib_ssi.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +static void send_ssi_file(struct mg_connection *, const char *, struct file *, int); + + +static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level) { + + char file_name[MG_BUF_LEN]; + char path[512]; + char *p; + struct file file = STRUCT_FILE_INITIALIZER; + size_t len; + int truncated = 0; + + if ( conn == NULL ) return; + + /* 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=\"%511[^\"]\"", file_name) == 1) { + /* File name is relative to the webserver root */ + file_name[511] = 0; + XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s/%s", conn->ctx->config[DOCUMENT_ROOT], file_name); + + } else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) { + /* File name is relative to the webserver working directory + * or it is absolute system path */ + file_name[511] = 0; + XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name); + + } else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1 + || sscanf(tag, " \"%511[^\"]\"", file_name) == 1) { + /* File name is relative to the currect document */ + file_name[511] = 0; + XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi); + + if (!truncated) { + if ((p = strrchr(path, '/')) != NULL) p[1] = '\0'; + len = strlen(path); + XX_httplib_snprintf(conn, &truncated, path + len, sizeof(path) - len, "%s", file_name); + } + + } else { + mg_cry(conn, "Bad SSI #include: [%s]", tag); + return; + } + + if (truncated) { + mg_cry(conn, "SSI #include path length overflow: [%s]", tag); + return; + } + + if (!XX_httplib_fopen(conn, path, "rb", &file)) { + mg_cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", tag, path, strerror(ERRNO)); + } else { + XX_httplib_fclose_on_exec(&file, conn); + if (XX_httplib_match_prefix(conn->ctx->config[SSI_EXTENSIONS], strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) { + + send_ssi_file(conn, path, &file, include_level + 1); + } else { + XX_httplib_send_file_data(conn, &file, 0, INT64_MAX); + } + XX_httplib_fclose(&file); + } +} + + +#if !defined(NO_POPEN) +static void do_ssi_exec(struct mg_connection *conn, char *tag) { + + char cmd[1024] = ""; + struct file file = STRUCT_FILE_INITIALIZER; + + if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) { + mg_cry(conn, "Bad SSI #exec: [%s]", tag); + } else { + cmd[1023] = 0; + if ((file.fp = popen(cmd, "r")) == NULL) { + mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO)); + } else { + XX_httplib_send_file_data(conn, &file, 0, INT64_MAX); + pclose(file.fp); + } + } +} +#endif /* !NO_POPEN */ + + +static int mg_fgetc( struct file *filep, int offset ) { + + if ( filep == NULL ) return EOF; + if ( filep->membuf != NULL && offset >= 0 && ((unsigned int)(offset)) < filep->size ) return ((const unsigned char *)filep->membuf)[offset]; + if ( filep->fp != NULL ) return fgetc( filep->fp ); + + return EOF; + +} /* mg_fgetc */ + + +static void send_ssi_file( struct mg_connection *conn, const char *path, struct file *filep, int include_level ) { + + char buf[MG_BUF_LEN]; + int ch; + int offset; + int len; + int in_ssi_tag; + + if (include_level > 10) { + mg_cry(conn, "SSI #include level is too deep (%s)", path); + return; + } + + in_ssi_tag = len = offset = 0; + while ((ch = mg_fgetc(filep, offset)) != EOF) { + if (in_ssi_tag && ch == '>') { + in_ssi_tag = 0; + buf[len++] = (char)ch; + buf[len] = '\0'; + /* assert(len <= (int) sizeof(buf)); */ + if (len > (int)sizeof(buf)) break; + if (len < 6 || memcmp(buf, "